From fc9b0c05eb052700a96032ba8179759ee9062fcc Mon Sep 17 00:00:00 2001 From: Panos Astithas Date: Tue, 16 Dec 2014 10:43:08 +0200 Subject: [PATCH 001/130] Make Scratchpad's reloadAndRun use the RDP and enable scratchpad tests with e10s (bug 1106702). r=harth --- browser/devtools/scratchpad/scratchpad.js | 27 +++++++------------- browser/devtools/scratchpad/test/browser.ini | 1 - 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/browser/devtools/scratchpad/scratchpad.js b/browser/devtools/scratchpad/scratchpad.js index 435cbe11ed85..00a7abb918b4 100644 --- a/browser/devtools/scratchpad/scratchpad.js +++ b/browser/devtools/scratchpad/scratchpad.js @@ -572,20 +572,11 @@ var Scratchpad = { return; } - let browser = this.gBrowser.selectedBrowser; - - this._reloadAndRunEvent = evt => { - if (evt.target !== browser.contentDocument) { - return; - } - - browser.removeEventListener("load", this._reloadAndRunEvent, true); - - this.run().then(aResults => deferred.resolve(aResults)); - }; - - browser.addEventListener("load", this._reloadAndRunEvent, true); - browser.contentWindow.location.reload(); + let target = TargetFactory.forTab(this.gBrowser.selectedTab); + target.once("navigate", () => { + this.run().then(results => deferred.resolve(results)); + }); + target.makeRemote().then(() => target.activeTab.reload()); return deferred.promise; }, @@ -2067,8 +2058,8 @@ ScratchpadTab.prototype = { /** * Initialize a debugger client and connect it to the debugger server. * - * @param object aSubject - * The tab or window to obtain the connection for. + * @param object aSubject + * The tab or window to obtain the connection for. * @return Promise * The promise for the result of connecting to this tab or window. */ @@ -2113,8 +2104,8 @@ ScratchpadTab.prototype = { /** * Attach to this tab. * - * @param object aSubject - * The tab or window to obtain the connection for. + * @param object aSubject + * The tab or window to obtain the connection for. * @return Promise * The promise for the TabTarget for this tab. */ diff --git a/browser/devtools/scratchpad/test/browser.ini b/browser/devtools/scratchpad/test/browser.ini index d7b036652b9f..569a2f66bfa1 100644 --- a/browser/devtools/scratchpad/test/browser.ini +++ b/browser/devtools/scratchpad/test/browser.ini @@ -1,5 +1,4 @@ [DEFAULT] -skip-if = e10s # Bug ?????? - devtools tests disabled with e10s subsuite = devtools support-files = head.js From 5ba90588b09540633dce7ce1f68bda980f587f41 Mon Sep 17 00:00:00 2001 From: Heather Arthur Date: Sat, 9 Aug 2014 20:20:20 +0300 Subject: [PATCH 002/130] Bug 1042253 - Enable devtools/webconsole tests with e10s; r=past --- browser/devtools/webconsole/test/browser.ini | 55 ++++- ...onsole_csp_ignore_reflected_xss_message.js | 44 ++-- ...g664688_sandbox_update_after_navigation.js | 148 +++++------- .../browser_bug_638949_copy_link_location.js | 115 ++++----- ...r_bug_862916_console_dir_and_filter_off.js | 35 ++- ...ser_bug_865288_repeat_different_objects.js | 72 +++--- ..._865871_variables_view_close_on_esc_key.js | 5 +- ..._bug_869003_inspect_cross_domain_object.js | 71 ++---- .../browser_bug_871156_ctrlw_close_tab.js | 110 ++++----- .../test/browser_cached_messages.js | 10 +- .../webconsole/test/browser_console.js | 42 +++- ...owser_console_addonsdk_loader_exception.js | 2 + .../test/browser_console_clear_on_reload.js | 87 +++---- .../test/browser_console_click_focus.js | 93 ++++--- .../test/browser_console_consolejsm_output.js | 226 +++++++++--------- .../test/browser_console_dead_objects.js | 3 +- .../browser_console_error_source_click.js | 6 +- .../test/browser_console_filters.js | 35 +-- .../test/browser_console_iframe_messages.js | 17 +- .../browser_console_keyboard_accessibility.js | 141 +++++------ .../browser_console_log_inspectable_object.js | 66 +++-- .../test/browser_console_native_getters.js | 116 ++++----- .../test/browser_console_navigation_marker.js | 118 +++++---- .../test/browser_console_private_browsing.js | 8 +- .../test/browser_console_variables_view.js | 112 +++++---- ...wser_console_variables_view_highlighter.js | 10 +- ..._console_variables_view_while_debugging.js | 17 +- ...les_view_while_debugging_and_inspecting.js | 19 +- .../browser_eval_in_debugger_stackframe.js | 14 +- .../webconsole/test/browser_jsterm_inspect.js | 39 ++- .../test/browser_longstring_hang.js | 89 +++---- .../browser_netpanel_longstring_expand.js | 8 +- ..._breaks_after_console_dir_uninspectable.js | 40 ++-- .../test/browser_output_longstring_expand.js | 116 ++++----- .../browser_repeated_messages_accuracy.js | 69 +++--- .../test/browser_result_format_as_string.js | 49 ++-- .../browser_warn_user_about_replaced_api.js | 130 +++++----- ...nsole_allow_mixedcontent_securityerrors.js | 70 +++--- .../test/browser_webconsole_assert.js | 24 +- ...-properties-with-non-alphanumeric-names.js | 48 ++-- ...ser_webconsole_autocomplete_and_selfxss.js | 20 +- ...ole_autocomplete_in_debugger_stackframe.js | 12 +- ..._autocomplete_popup_close_on_tab_switch.js | 43 ++-- .../browser_webconsole_basic_net_logging.js | 64 +++-- ...nsole_block_mixedcontent_securityerrors.js | 85 +++---- ...ug_1006027_message_timestamps_incorrect.js | 3 +- .../browser_webconsole_bug_1010953_cspro.js | 52 ++-- ...owser_webconsole_bug_578437_page_reload.js | 21 +- ...owser_webconsole_bug_579412_input_focus.js | 24 +- ...ole_bug_580001_closing_after_completion.js | 22 +- ...er_webconsole_bug_580454_timestamp_l10n.js | 38 ++- ..._webconsole_bug_582201_duplicate_errors.js | 65 +++-- ...bug_583816_No_input_and_Tab_key_pressed.js | 16 +- ...rowser_webconsole_bug_585237_line_limit.js | 45 +--- ...ser_webconsole_bug_585956_console_trace.js | 2 + ...webconsole_bug_585991_autocomplete_keys.js | 87 ++++--- ...ebconsole_bug_585991_autocomplete_popup.js | 21 +- ...rowser_webconsole_bug_586388_select_all.js | 147 ++++++------ ...owser_webconsole_bug_587617_output_copy.js | 29 ++- ...er_webconsole_bug_588342_document_focus.js | 40 ++-- ...bconsole_bug_588730_text_node_insertion.js | 20 +- ...r_webconsole_bug_588967_input_expansion.js | 19 +- ...rowser_webconsole_bug_589162_css_filter.js | 2 + ..._webconsole_bug_592442_closing_brackets.js | 20 +- ..._webconsole_bug_593003_iframe_wrong_hud.js | 23 +- ..._webconsole_bug_594477_clickable_output.js | 78 +++--- ...ebconsole_bug_594497_history_arrow_keys.js | 47 ++-- .../browser_webconsole_bug_595223_file_uri.js | 63 ++--- ...le_bug_595350_multiple_windows_and_tabs.js | 2 +- ...ebconsole_bug_595934_message_categories.js | 9 +- ...eactivateHUDForContext_unfocused_window.js | 13 +- ...bug_597136_network_requests_from_chrome.js | 2 +- ...ser_webconsole_bug_597460_filter_scroll.js | 39 +-- ...webconsole_bug_597756_reopen_closed_tab.js | 76 +++--- ..._webconsole_bug_599725_response_headers.js | 48 ++-- .../browser_webconsole_bug_600183_charset.js | 49 ++-- ...rowser_webconsole_bug_601177_log_levels.js | 122 +++++----- ...er_webconsole_bug_601667_filter_buttons.js | 22 +- ...bconsole_bug_602572_log_bodies_checkbox.js | 37 ++- ...browser_webconsole_bug_603750_websocket.js | 50 ++-- .../test/browser_webconsole_bug_611795.js | 60 ++--- ...ebconsole_bug_613013_console_api_iframe.js | 37 +-- ...owser_webconsole_bug_613280_jsterm_copy.js | 10 +- ...r_webconsole_bug_613642_maintain_scroll.js | 60 ++--- ...wser_webconsole_bug_613642_prune_scroll.js | 46 ++-- ...ser_webconsole_bug_614793_jsterm_scroll.js | 25 +- ...ebconsole_bug_618078_network_exceptions.js | 38 ++- ...wser_webconsole_bug_618311_close_panels.js | 42 ++-- ...ser_webconsole_bug_621644_jsterm_dollar.js | 31 ++- ...ebconsole_bug_622303_persistent_filters.js | 51 ++-- ...sole_bug_623749_ctrl_a_select_all_winnt.js | 20 +- ...le_bug_630733_response_redirect_headers.js | 61 +++-- ...nsole_bug_632275_getters_document_width.js | 9 +- ...console_bug_632347_iterators_generators.js | 8 +- .../test/browser_webconsole_bug_632817.js | 17 +- ...rowser_webconsole_bug_644419_log_limits.js | 74 +++--- ...onsole_bug_646025_console_file_location.js | 84 ++++--- ...e_bug_651501_document_body_autocomplete.js | 54 +++-- ...e_bug_653531_highlighter_console_helper.js | 8 +- ...wser_webconsole_bug_658368_time_methods.js | 117 ++++----- ...owser_webconsole_bug_659907_console_dir.js | 29 ++- ...owser_webconsole_bug_660806_history_nav.js | 27 ++- ...ser_webconsole_bug_664131_console_group.js | 114 +++++---- ..._bug_686937_autocomplete_JSTerm_helpers.js | 54 ++--- .../test/browser_webconsole_bug_704295.js | 19 +- ...061_No_input_change_and_Tab_key_pressed.js | 17 +- ...wser_webconsole_bug_737873_mixedcontent.js | 28 +-- ...2559_ineffective_iframe_sandbox_warning.js | 20 +- ...sswords_about_blank_web_console_warning.js | 37 ++- ..._insecure_passwords_web_console_warning.js | 64 +++-- ...r_webconsole_bug_764572_output_open_url.js | 65 ++--- ...nsole_bug_766001_JS_Console_in_Debugger.js | 1 + ...browser_webconsole_bug_770099_violation.js | 45 ++-- ...le_bug_782653_CSS_links_in_Style_Editor.js | 53 ++-- ...wser_webconsole_bug_804845_ctrl_key_nav.js | 23 +- ..._bug_817834_add_edited_input_to_history.js | 20 +- ...er_webconsole_bug_837351_securityerrors.js | 54 +++-- ...console_bug_846918_hsts_invalid-headers.js | 10 +- ...1_toggle_response_logging_with_keyboard.js | 1 + .../browser_webconsole_cached_autocomplete.js | 71 +++--- ...browser_webconsole_certificate_messages.js | 28 +-- .../browser_webconsole_change_font_size.js | 19 +- .../test/browser_webconsole_chrome.js | 2 + .../test/browser_webconsole_clickable_urls.js | 2 + .../browser_webconsole_closure_inspection.js | 10 +- .../test/browser_webconsole_column_numbers.js | 8 +- .../test/browser_webconsole_completion.js | 65 ++--- .../test/browser_webconsole_console_extras.js | 8 +- .../browser_webconsole_console_logging_api.js | 64 +++-- ...webconsole_dont_navigate_on_doubleclick.js | 2 + .../browser_webconsole_execution_scope.js | 33 +-- ...rowser_webconsole_expandable_timestamps.js | 95 ++++---- ...r_webconsole_filter_buttons_contextmenu.js | 8 +- .../test/browser_webconsole_for_of.js | 19 +- .../test/browser_webconsole_history.js | 19 +- ...nsole_input_field_focus_on_panel_select.js | 31 +-- ...ser_webconsole_inspect-parsed-documents.js | 3 +- .../browser_webconsole_js_input_expansion.js | 21 +- .../test/browser_webconsole_jsterm.js | 18 +- ...console_live_filtering_of_message_types.js | 33 +-- ...onsole_live_filtering_on_search_strings.js | 72 +++--- .../browser_webconsole_log_file_filter.js | 28 ++- .../browser_webconsole_message_node_id.js | 26 +- .../test/browser_webconsole_netlogging.js | 14 +- .../test/browser_webconsole_network_panel.js | 16 +- .../test/browser_webconsole_notifications.js | 115 ++++----- ..._webconsole_open-links-without-callback.js | 2 + .../test/browser_webconsole_output_01.js | 4 +- .../test/browser_webconsole_output_04.js | 1 + .../test/browser_webconsole_output_05.js | 3 +- .../test/browser_webconsole_output_06.js | 1 + ...browser_webconsole_output_copy_newlines.js | 112 ++++----- ...owser_webconsole_output_dom_elements_01.js | 1 + ...owser_webconsole_output_dom_elements_02.js | 31 ++- .../test/browser_webconsole_output_events.js | 78 +++--- .../test/browser_webconsole_output_order.js | 34 ++- .../browser_webconsole_property_provider.js | 5 +- .../test/browser_webconsole_reflow.js | 49 ++-- ...rowser_webconsole_scratchpad_panel_link.js | 6 +- .../test/browser_webconsole_split.js | 8 +- .../test/browser_webconsole_view_source.js | 10 +- browser/devtools/webconsole/test/head.js | 173 ++++++-------- .../webconsole/test/test-console-assert.html | 1 - .../test/test-console-output-events.html | 19 ++ 164 files changed, 3330 insertions(+), 3627 deletions(-) diff --git a/browser/devtools/webconsole/test/browser.ini b/browser/devtools/webconsole/test/browser.ini index 384d5d49a2f3..60d179a3c425 100644 --- a/browser/devtools/webconsole/test/browser.ini +++ b/browser/devtools/webconsole/test/browser.ini @@ -1,5 +1,4 @@ [DEFAULT] -skip-if = e10s # Bug ?????? - devtools tests disabled with e10s subsuite = devtools support-files = head.js @@ -130,25 +129,28 @@ support-files = [browser_bug1045902_console_csp_ignore_reflected_xss_message.js] [browser_bug664688_sandbox_update_after_navigation.js] +skip-if = e10s # Bug 1042253 - webconsole e10s tests (intermittent Linux debug) [browser_bug_638949_copy_link_location.js] [browser_bug_862916_console_dir_and_filter_off.js] [browser_bug_865288_repeat_different_objects.js] [browser_bug_865871_variables_view_close_on_esc_key.js] [browser_bug_869003_inspect_cross_domain_object.js] [browser_bug_871156_ctrlw_close_tab.js] +skip-if = e10s # Bug 1042253 - webconsole e10s tests (intermittent Linux debug) [browser_cached_messages.js] -skip-if = buildapp == 'mulet' +skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests (expectUncaughtException) [browser_console.js] [browser_console_addonsdk_loader_exception.js] [browser_console_clear_on_reload.js] [browser_console_click_focus.js] [browser_console_consolejsm_output.js] [browser_console_dead_objects.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_console_error_source_click.js] -skip-if = buildapp == 'mulet' +skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests [browser_console_filters.js] [browser_console_iframe_messages.js] -skip-if = buildapp == 'mulet' +skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests [browser_console_keyboard_accessibility.js] [browser_console_log_inspectable_object.js] [browser_console_native_getters.js] @@ -156,18 +158,24 @@ skip-if = buildapp == 'mulet' [browser_console_nsiconsolemessage.js] skip-if = buildapp == 'mulet' [browser_console_optimized_out_vars.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_console_private_browsing.js] -skip-if = buildapp == 'mulet' +skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests [browser_console_variables_view.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_console_variables_view_dom_nodes.js] [browser_console_variables_view_dont_sort_non_sortable_classes_properties.js] skip-if = buildapp == 'mulet' [browser_console_variables_view_while_debugging.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_console_variables_view_while_debugging_and_inspecting.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_eval_in_debugger_stackframe.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_jsterm_inspect.js] [browser_longstring_hang.js] [browser_netpanel_longstring_expand.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_output_breaks_after_console_dir_uninspectable.js] [browser_output_longstring_expand.js] [browser_repeated_messages_accuracy.js] @@ -184,37 +192,49 @@ skip-if = buildapp == 'mulet' [browser_webconsole_bug_579412_input_focus.js] [browser_webconsole_bug_580001_closing_after_completion.js] [browser_webconsole_bug_580030_errors_after_page_reload.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException) [browser_webconsole_bug_580454_timestamp_l10n.js] [browser_webconsole_bug_582201_duplicate_errors.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException) [browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js] [browser_webconsole_bug_585237_line_limit.js] [browser_webconsole_bug_585956_console_trace.js] [browser_webconsole_bug_585991_autocomplete_keys.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_bug_585991_autocomplete_popup.js] [browser_webconsole_bug_586388_select_all.js] [browser_webconsole_bug_587617_output_copy.js] [browser_webconsole_bug_588342_document_focus.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_bug_588730_text_node_insertion.js] [browser_webconsole_bug_588967_input_expansion.js] [browser_webconsole_bug_589162_css_filter.js] [browser_webconsole_bug_592442_closing_brackets.js] [browser_webconsole_bug_593003_iframe_wrong_hud.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_bug_594477_clickable_output.js] [browser_webconsole_bug_594497_history_arrow_keys.js] [browser_webconsole_bug_595223_file_uri.js] [browser_webconsole_bug_595350_multiple_windows_and_tabs.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_bug_595934_message_categories.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException) [browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_bug_597136_external_script_errors.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException) [browser_webconsole_bug_597136_network_requests_from_chrome.js] [browser_webconsole_bug_597460_filter_scroll.js] [browser_webconsole_bug_597756_reopen_closed_tab.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException) [browser_webconsole_bug_599725_response_headers.js] [browser_webconsole_bug_600183_charset.js] [browser_webconsole_bug_601177_log_levels.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException) [browser_webconsole_bug_601352_scroll.js] [browser_webconsole_bug_601667_filter_buttons.js] [browser_webconsole_bug_602572_log_bodies_checkbox.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_bug_603750_websocket.js] [browser_webconsole_bug_611795.js] [browser_webconsole_bug_613013_console_api_iframe.js] @@ -223,6 +243,7 @@ skip-if = buildapp == 'mulet' [browser_webconsole_bug_613642_prune_scroll.js] [browser_webconsole_bug_614793_jsterm_scroll.js] [browser_webconsole_bug_618078_network_exceptions.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException) [browser_webconsole_bug_618311_close_panels.js] [browser_webconsole_bug_621644_jsterm_dollar.js] [browser_webconsole_bug_622303_persistent_filters.js] @@ -231,13 +252,16 @@ run-if = os == "win" [browser_webconsole_bug_630733_response_redirect_headers.js] [browser_webconsole_bug_632275_getters_document_width.js] [browser_webconsole_bug_632347_iterators_generators.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_bug_632817.js] [browser_webconsole_bug_642108_pruneTest.js] [browser_webconsole_autocomplete_and_selfxss.js] [browser_webconsole_bug_644419_log_limits.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException) [browser_webconsole_bug_646025_console_file_location.js] [browser_webconsole_bug_651501_document_body_autocomplete.js] [browser_webconsole_bug_653531_highlighter_console_helper.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_bug_658368_time_methods.js] [browser_webconsole_bug_659907_console_dir.js] [browser_webconsole_bug_660806_history_nav.js] @@ -247,13 +271,15 @@ run-if = os == "win" [browser_webconsole_bug_734061_No_input_change_and_Tab_key_pressed.js] [browser_webconsole_bug_737873_mixedcontent.js] [browser_webconsole_bug_752559_ineffective_iframe_sandbox_warning.js] +skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout) [browser_webconsole_bug_762593_insecure_passwords_about_blank_web_console_warning.js] skip-if = buildapp == 'mulet' [browser_webconsole_bug_762593_insecure_passwords_web_console_warning.js] -skip-if = buildapp == 'mulet' +skip-if = true # Bug 1110500 - mouse event failure in test [browser_webconsole_bug_764572_output_open_url.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_bug_766001_JS_Console_in_Debugger.js] -skip-if = buildapp == 'mulet' +skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests (expectUncaughtException) [browser_webconsole_bug_770099_violation.js] [browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js] skip-if = buildapp == 'mulet' @@ -263,17 +289,21 @@ run-if = os == "mac" [browser_webconsole_bug_837351_securityerrors.js] skip-if = buildapp == 'mulet' [browser_webconsole_bug_846918_hsts_invalid-headers.js] -skip-if = buildapp == 'mulet' +skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests [browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js] [browser_webconsole_filter_buttons_contextmenu.js] [browser_webconsole_bug_1006027_message_timestamps_incorrect.js] +skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug intermittent) [browser_webconsole_bug_1010953_cspro.js] [browser_webconsole_certificate_messages.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_cached_autocomplete.js] [browser_webconsole_change_font_size.js] [browser_webconsole_chrome.js] [browser_webconsole_clickable_urls.js] +skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout) [browser_webconsole_closure_inspection.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_completion.js] [browser_webconsole_console_extras.js] [browser_webconsole_console_logging_api.js] @@ -286,6 +316,7 @@ skip-if = buildapp == 'mulet' [browser_webconsole_inspect-parsed-documents.js] [browser_webconsole_js_input_expansion.js] [browser_webconsole_jsterm.js] +skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout) [browser_webconsole_live_filtering_of_message_types.js] [browser_webconsole_live_filtering_on_search_strings.js] [browser_webconsole_message_node_id.js] @@ -296,20 +327,26 @@ skip-if = buildapp == 'mulet' [browser_webconsole_output_copy_newlines.js] [browser_webconsole_output_order.js] [browser_webconsole_property_provider.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_scratchpad_panel_link.js] [browser_webconsole_split.js] [browser_webconsole_split_escape_key.js] [browser_webconsole_split_focus.js] [browser_webconsole_split_persist.js] +skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout) [browser_webconsole_view_source.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException) [browser_webconsole_reflow.js] [browser_webconsole_log_file_filter.js] [browser_webconsole_expandable_timestamps.js] [browser_webconsole_autocomplete_in_debugger_stackframe.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_autocomplete_popup_close_on_tab_switch.js] +skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js] [browser_console_hide_jsterm_when_devtools_chrome_enabled_false.js] [browser_webconsole_output_01.js] +skip-if = e10s # Bug 1042253 - webconsole e10s tests [browser_webconsole_output_02.js] [browser_webconsole_output_03.js] [browser_webconsole_output_04.js] @@ -317,8 +354,10 @@ skip-if = buildapp == 'mulet' [browser_webconsole_output_06.js] [browser_webconsole_output_dom_elements_01.js] [browser_webconsole_output_dom_elements_02.js] +skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout) [browser_webconsole_output_dom_elements_03.js] [browser_webconsole_output_dom_elements_04.js] +skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout) [browser_webconsole_output_events.js] [browser_webconsole_output_table.js] [browser_console_variables_view_highlighter.js] diff --git a/browser/devtools/webconsole/test/browser_bug1045902_console_csp_ignore_reflected_xss_message.js b/browser/devtools/webconsole/test/browser_bug1045902_console_csp_ignore_reflected_xss_message.js index 6e846433406a..27cbf8ad0351 100644 --- a/browser/devtools/webconsole/test/browser_bug1045902_console_csp_ignore_reflected_xss_message.js +++ b/browser/devtools/webconsole/test/browser_bug1045902_console_csp_ignore_reflected_xss_message.js @@ -16,38 +16,44 @@ const TEST_FILE = "http://example.com/browser/browser/devtools/webconsole/test/" let hud = undefined; -function test() { - addTab("data:text/html;charset=utf8,Web Console CSP ignoring reflected XSS (bug 1045902)"); - browser.addEventListener("load", function _onLoad() { - browser.removeEventListener("load", _onLoad, true); - openConsole(null, loadDocument); - }, true); -} +let TEST_URI = "data:text/html;charset=utf8,Web Console CSP ignoring reflected XSS (bug 1045902)"; + +let test = asyncTest(function* () { + let { browser } = yield loadTab(TEST_URI); + + hud = yield openConsole(); + + yield loadDocument(browser); + yield testViolationMessage(); + + hud = null; +}); + + +function loadDocument(browser) { + let deferred = promise.defer(); -function loadDocument(theHud) { - hud = theHud; hud.jsterm.clearOutput() - browser.addEventListener("load", onLoad, true); + browser.addEventListener("load", function onLoad() { + browser.removeEventListener("load", onLoad, true); + deferred.resolve(); + }, true); content.location = TEST_FILE; -} -function onLoad(aEvent) { - browser.removeEventListener("load", onLoad, true); - testViolationMessage(); + return deferred.promise; } function testViolationMessage() { + let deferred = promise.defer(); let aOutputNode = hud.outputNode; - waitForSuccess({ + return waitForSuccess({ name: "Confirming that CSP logs messages to the console when 'reflected-xss' directive is used!", - validatorFn: function() { + validator: function() { console.log(hud.outputNode.textContent); let success = false; success = hud.outputNode.textContent.indexOf(EXPECTED_RESULT) > -1; return success; - }, - successFn: finishTest, - failureFn: finishTest, + } }); } diff --git a/browser/devtools/webconsole/test/browser_bug664688_sandbox_update_after_navigation.js b/browser/devtools/webconsole/test/browser_bug664688_sandbox_update_after_navigation.js index 7a994710338d..2203e22096f0 100644 --- a/browser/devtools/webconsole/test/browser_bug664688_sandbox_update_after_navigation.js +++ b/browser/devtools/webconsole/test/browser_bug664688_sandbox_update_after_navigation.js @@ -7,107 +7,85 @@ // domain to another, in order to avoid permission denied errors with a sandbox // created for a different origin. -function test() -{ +"use strict"; + +let test = asyncTest(function* () { const TEST_URI1 = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; const TEST_URI2 = "http://example.org/browser/browser/devtools/webconsole/test/test-console.html"; - let hud; - let msgForLocation1; + yield loadTab(TEST_URI1); + let hud = yield openConsole(); - waitForExplicitFinish(); + hud.jsterm.clearOutput(); + hud.jsterm.execute("window.location.href"); - gBrowser.selectedTab = gBrowser.addTab(TEST_URI1); - gBrowser.selectedBrowser.addEventListener("load", function onLoad() { - gBrowser.selectedBrowser.removeEventListener("load", onLoad, true); - openConsole(gBrowser.selectedTab, pageLoad1); - }, true); + info("wait for window.location.href"); - function pageLoad1(aHud) - { - hud = aHud; + let msgForLocation1 = { + webconsole: hud, + messages: [ + { + name: "window.location.href jsterm input", + text: "window.location.href", + category: CATEGORY_INPUT, + }, + { + name: "window.location.href result is displayed", + text: TEST_URI1, + category: CATEGORY_OUTPUT, + }, + ], + }; - hud.jsterm.clearOutput(); - hud.jsterm.execute("window.location.href"); + yield waitForMessages(msgForLocation1); - info("wait for window.location.href"); + // load second url + content.location = TEST_URI2; + yield loadBrowser(gBrowser.selectedBrowser); - msgForLocation1 = { - webconsole: hud, - messages: [ - { - name: "window.location.href jsterm input", - text: "window.location.href", - category: CATEGORY_INPUT, - }, - { - name: "window.location.href result is displayed", - text: TEST_URI1, - category: CATEGORY_OUTPUT, - }, - ] - }; + is(hud.outputNode.textContent.indexOf("Permission denied"), -1, + "no permission denied errors"); - waitForMessages(msgForLocation1).then(() => { - gBrowser.selectedBrowser.addEventListener("load", onPageLoad2, true); - content.location = TEST_URI2; - }); - } + hud.jsterm.clearOutput(); + hud.jsterm.execute("window.location.href"); - function onPageLoad2() { - gBrowser.selectedBrowser.removeEventListener("load", onPageLoad2, true); + info("wait for window.location.href after page navigation"); - is(hud.outputNode.textContent.indexOf("Permission denied"), -1, - "no permission denied errors"); + yield waitForMessages({ + webconsole: hud, + messages: [ + { + name: "window.location.href jsterm input", + text: "window.location.href", + category: CATEGORY_INPUT, + }, + { + name: "window.location.href result is displayed", + text: TEST_URI2, + category: CATEGORY_OUTPUT, + }, + ], + }); - hud.jsterm.clearOutput(); - hud.jsterm.execute("window.location.href"); + is(hud.outputNode.textContent.indexOf("Permission denied"), -1, + "no permission denied errors"); - info("wait for window.location.href after page navigation"); + gBrowser.goBack(); - waitForMessages({ - webconsole: hud, - messages: [ - { - name: "window.location.href jsterm input", - text: "window.location.href", - category: CATEGORY_INPUT, - }, - { - name: "window.location.href result is displayed", - text: TEST_URI2, - category: CATEGORY_OUTPUT, - }, - ] - }).then(() => { - is(hud.outputNode.textContent.indexOf("Permission denied"), -1, - "no permission denied errors"); - - gBrowser.goBack(); - waitForSuccess(waitForBack); - }); - } - - let waitForBack = { + yield waitForSuccess({ name: "go back", - validatorFn: function() - { + validator: function() { return content.location.href == TEST_URI1; }, - successFn: function() - { - hud.jsterm.clearOutput(); - executeSoon(() => { - hud.jsterm.execute("window.location.href"); - }); + }); - info("wait for window.location.href after goBack()"); - waitForMessages(msgForLocation1).then(() => executeSoon(() => { - is(hud.outputNode.textContent.indexOf("Permission denied"), -1, - "no permission denied errors"); - finishTest(); - })); - }, - failureFn: finishTest, - }; -} + hud.jsterm.clearOutput(); + executeSoon(() => { + hud.jsterm.execute("window.location.href"); + }); + + info("wait for window.location.href after goBack()"); + yield waitForMessages(msgForLocation1); + is(hud.outputNode.textContent.indexOf("Permission denied"), -1, + "no permission denied errors"); +}); diff --git a/browser/devtools/webconsole/test/browser_bug_638949_copy_link_location.js b/browser/devtools/webconsole/test/browser_bug_638949_copy_link_location.js index b3784b246425..40ae04394785 100644 --- a/browser/devtools/webconsole/test/browser_bug_638949_copy_link_location.js +++ b/browser/devtools/webconsole/test/browser_bug_638949_copy_link_location.js @@ -3,116 +3,103 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" + - "test/test-console.html?_date=" + Date.now(); -const COMMAND_NAME = "consoleCmd_copyURL"; -const CONTEXT_MENU_ID = "#menu_copyURL"; +// Test for the "Copy link location" context menu item shown when you right +// click network requests in the output. -let HUD = null; -let output = null; -let menu = null; +"use strict"; + +let test = asyncTest(function* () { + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" + + "test/test-console.html?_date=" + Date.now(); + const COMMAND_NAME = "consoleCmd_copyURL"; + const CONTEXT_MENU_ID = "#menu_copyURL"; -function test() { - let originalNetPref = Services.prefs.getBoolPref("devtools.webconsole.filter.networkinfo"); registerCleanupFunction(() => { - Services.prefs.setBoolPref("devtools.webconsole.filter.networkinfo", originalNetPref); - HUD = output = menu = null; + Services.prefs.clearUserPref("devtools.webconsole.filter.networkinfo"); }); Services.prefs.setBoolPref("devtools.webconsole.filter.networkinfo", true); - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); + yield loadTab(TEST_URI); + let hud = yield openConsole(); + let output = hud.outputNode; + let menu = hud.iframeWindow.document.getElementById("output-contextmenu"); - openConsole(null, function (aHud) { - HUD = aHud; - output = aHud.outputNode; - menu = HUD.iframeWindow.document.getElementById("output-contextmenu"); - - executeSoon(testWithoutNetActivity); - }); - }, true); -} - -// Return whether "Copy Link Location" command is enabled or not. -function isEnabled() { - let controller = top.document.commandDispatcher - .getControllerForCommand(COMMAND_NAME); - return controller && controller.isCommandEnabled(COMMAND_NAME); -} - -function testWithoutNetActivity() { - HUD.jsterm.clearOutput(); + hud.jsterm.clearOutput(); content.console.log("bug 638949"); // Test that the "Copy Link Location" command is disabled for non-network // messages. - waitForMessages({ - webconsole: HUD, + let [result] = yield waitForMessages({ + webconsole: hud, messages: [{ text: "bug 638949", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(onConsoleMessage); -} + }); -function onConsoleMessage(aResults) { output.focus(); - let message = [...aResults[0].matched][0]; + let message = [...result.matched][0]; goUpdateCommand(COMMAND_NAME); - ok(!isEnabled(), COMMAND_NAME + "is disabled"); + ok(!isEnabled(), COMMAND_NAME + " is disabled"); // Test that the "Copy Link Location" menu item is hidden for non-network // messages. message.scrollIntoView(); - waitForContextMenu(menu, message, () => { + + yield waitForContextMenu(menu, message, () => { let isHidden = menu.querySelector(CONTEXT_MENU_ID).hidden; ok(isHidden, CONTEXT_MENU_ID + " is hidden"); - }, testWithNetActivity); -} + }); -function testWithNetActivity() { - HUD.jsterm.clearOutput(); + hud.jsterm.clearOutput(); content.location.reload(); // Reloading will produce network logging // Test that the "Copy Link Location" command is enabled and works // as expected for any network-related message. // This command should copy only the URL. - waitForMessages({ - webconsole: HUD, + [result] = yield waitForMessages({ + webconsole: hud, messages: [{ text: "test-console.html", category: CATEGORY_NETWORK, severity: SEVERITY_LOG, }], - }).then(onNetworkMessage); -} + }); -function onNetworkMessage(aResults) { output.focus(); - let message = [...aResults[0].matched][0]; - HUD.ui.output.selectMessage(message); + message = [...result.matched][0]; + hud.ui.output.selectMessage(message); goUpdateCommand(COMMAND_NAME); ok(isEnabled(), COMMAND_NAME + " is enabled"); info("expected clipboard value: " + message.url); + let deferred = promise.defer(); + waitForClipboard((aData) => { return aData.trim() == message.url; }, - () => { goDoCommand(COMMAND_NAME) }, - testMenuWithNetActivity, testMenuWithNetActivity); + () => { goDoCommand(COMMAND_NAME); }, + () => { deferred.resolve(null); }, + () => { deferred.reject(null); }); - function testMenuWithNetActivity() { - // Test that the "Copy Link Location" menu item is visible for network-related - // messages. - message.scrollIntoView(); - waitForContextMenu(menu, message, () => { - let isVisible = !menu.querySelector(CONTEXT_MENU_ID).hidden; - ok(isVisible, CONTEXT_MENU_ID + " is visible"); - }, finishTest); + yield deferred.promise; + + // Test that the "Copy Link Location" menu item is visible for network-related + // messages. + message.scrollIntoView(); + + yield waitForContextMenu(menu, message, () => { + let isVisible = !menu.querySelector(CONTEXT_MENU_ID).hidden; + ok(isVisible, CONTEXT_MENU_ID + " is visible"); + }); + + // Return whether "Copy Link Location" command is enabled or not. + function isEnabled() { + let controller = top.document.commandDispatcher + .getControllerForCommand(COMMAND_NAME); + return controller && controller.isCommandEnabled(COMMAND_NAME); } -} - +}); diff --git a/browser/devtools/webconsole/test/browser_bug_862916_console_dir_and_filter_off.js b/browser/devtools/webconsole/test/browser_bug_862916_console_dir_and_filter_off.js index 6dfc00b8a21a..676fd5a93fc1 100644 --- a/browser/devtools/webconsole/test/browser_bug_862916_console_dir_and_filter_off.js +++ b/browser/devtools/webconsole/test/browser_bug_862916_console_dir_and_filter_off.js @@ -5,30 +5,27 @@ // Check that the output for console.dir() works even if Logging filter is off. +"use strict"; + const TEST_URI = "data:text/html;charset=utf8,

test for bug 862916"; -function test() -{ - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + let hud = yield openConsole(); -function consoleOpened(hud) -{ ok(hud, "web console opened"); hud.setFilterState("log", false); registerCleanupFunction(() => hud.setFilterState("log", true)); - content.wrappedJSObject.fooBarz = "bug862916"; - hud.jsterm.execute("console.dir(window)"); - hud.jsterm.once("variablesview-fetched", (aEvent, aVar) => { - ok(aVar, "variables view object"); - findVariableViewProperties(aVar, [ - { name: "fooBarz", value: "bug862916" }, - ], { webconsole: hud }).then(finishTest); - }); -} + hud.jsterm.execute("window.fooBarz = 'bug862916'; " + + "console.dir(window)"); + + let varView = yield hud.jsterm.once("variablesview-fetched"); + ok(varView, "variables view object"); + + yield findVariableViewProperties(varView, [ + { name: "fooBarz", value: "bug862916" }, + ], { webconsole: hud }); +}); + diff --git a/browser/devtools/webconsole/test/browser_bug_865288_repeat_different_objects.js b/browser/devtools/webconsole/test/browser_bug_865288_repeat_different_objects.js index 496b75f81216..a3e3a8abe20c 100644 --- a/browser/devtools/webconsole/test/browser_bug_865288_repeat_different_objects.js +++ b/browser/devtools/webconsole/test/browser_bug_865288_repeat_different_objects.js @@ -6,28 +6,20 @@ // Test that makes sure messages are not considered repeated when console.log() // is invoked with different objects, see bug 865288. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-repeated-messages.html"; -let hud = null; +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + let hud = yield openConsole(); -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} - -function consoleOpened(aHud) { - hud = aHud; - - // Check that css warnings are not coalesced if they come from different lines. info("waiting for 3 console.log objects"); hud.jsterm.clearOutput(true); - content.wrappedJSObject.testConsoleObjects(); + hud.jsterm.execute("window.testConsoleObjects()"); - waitForMessages({ + let [result] = yield waitForMessages({ webconsole: hud, messages: [{ name: "3 console.log messages", @@ -38,44 +30,34 @@ function consoleOpened(aHud) { repeats: 1, objects: true, }], - }).then(checkMessages); -} + }); -function checkMessages([result]) -{ let msgs = [...result.matched]; is(msgs.length, 3, "3 message elements"); - let m = -1; - function nextMessage() - { - let msg = msgs[++m]; - if (msg) { - ok(msg, "message element #" + m); + for (let i = 0; i < msgs.length; i++) { + info("test message element #" + i); - let clickable = msg.querySelector(".message-body a"); - ok(clickable, "clickable object #" + m); + let msg = msgs[i]; + let clickable = msg.querySelector(".message-body a"); + ok(clickable, "clickable object #" + i); - msg.scrollIntoView(false); - clickObject(clickable); - } - else { - finishTest(); - } + msg.scrollIntoView(false); + yield clickObject(clickable, i); } - nextMessage(); - - function clickObject(aObject) + function* clickObject(obj, i) { - hud.jsterm.once("variablesview-fetched", onObjectFetch); - EventUtils.synthesizeMouse(aObject, 2, 2, {}, hud.iframeWindow); - } + executeSoon(() => { + EventUtils.synthesizeMouse(obj, 2, 2, {}, hud.iframeWindow); + }); - function onObjectFetch(aEvent, aVar) - { - findVariableViewProperties(aVar, [ - { name: "id", value: "abba" + m }, - ], { webconsole: hud }).then(nextMessage); + let varView = yield hud.jsterm.once("variablesview-fetched"); + ok(varView, "variables view fetched #" + i); + + yield findVariableViewProperties(varView, [ + { name: "id", value: "abba" + i }, + ], { webconsole: hud }); } -} +}); + diff --git a/browser/devtools/webconsole/test/browser_bug_865871_variables_view_close_on_esc_key.js b/browser/devtools/webconsole/test/browser_bug_865871_variables_view_close_on_esc_key.js index 553cd5dcfd78..a4dd76dbe8e7 100644 --- a/browser/devtools/webconsole/test/browser_bug_865871_variables_view_close_on_esc_key.js +++ b/browser/devtools/webconsole/test/browser_bug_865871_variables_view_close_on_esc_key.js @@ -6,6 +6,8 @@ // Check that the variables view sidebar can be closed by pressing Escape in the // web console. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-eval-in-stackframe.html"; function test() @@ -44,9 +46,6 @@ function test() let prop = result.matchedProp; ok(prop, "matched the |testProp| property in the variables view"); - is(content.wrappedJSObject.fooObj.testProp, result.value, - "|fooObj.testProp| value is correct"); - vview.window.focus(); executeSoon(() => { diff --git a/browser/devtools/webconsole/test/browser_bug_869003_inspect_cross_domain_object.js b/browser/devtools/webconsole/test/browser_bug_869003_inspect_cross_domain_object.js index 81c7735d8fc1..8a5ad49afd1b 100644 --- a/browser/devtools/webconsole/test/browser_bug_869003_inspect_cross_domain_object.js +++ b/browser/devtools/webconsole/test/browser_bug_869003_inspect_cross_domain_object.js @@ -6,31 +6,22 @@ // Check that users can inspect objects logged from cross-domain iframes - // bug 869003. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-869003-top-window.html"; -let gWebConsole, gJSTerm, gVariablesView; - -function test() -{ +let test = asyncTest(function* () { // This test is slightly more involved: it opens the web console, then the // variables view for a given object, it updates a property in the view and // checks the result. We can get a timeout with debug builds on slower machines. requestLongerTimeout(2); - addTab("data:text/html;charset=utf8,

hello"); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} + yield loadTab("data:text/html;charset=utf8,

hello"); + let hud = yield openConsole(); -function consoleOpened(hud) -{ - gWebConsole = hud; - gJSTerm = hud.jsterm; content.location = TEST_URI; - waitForMessages({ + let [result] = yield waitForMessages({ webconsole: hud, messages: [{ name: "console.log message", @@ -39,61 +30,47 @@ function consoleOpened(hud) severity: SEVERITY_LOG, objects: true, }], - }).then(onConsoleMessage); -} + }); -function onConsoleMessage(aResults) -{ - let msg = [...aResults[0].matched][0]; + let msg = [...result.matched][0]; ok(msg, "message element"); let body = msg.querySelector(".message-body"); ok(body, "message body"); - let clickable = aResults[0].clickableElements[0]; + let clickable = result.clickableElements[0]; ok(clickable, "clickable object found"); ok(body.textContent.contains('{ hello: "world!",'), "message text check"); - gJSTerm.once("variablesview-fetched", onObjFetch); + executeSoon(() => { + EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow) + }); - EventUtils.synthesizeMouse(clickable, 2, 2, {}, gWebConsole.iframeWindow) -} + let aVar = yield hud.jsterm.once("variablesview-fetched"); + ok(aVar, "variables view fetched"); + ok(aVar._variablesView, "variables view object"); -function onObjFetch(aEvent, aVar) -{ - gVariablesView = aVar._variablesView; - ok(gVariablesView, "variables view object"); - - findVariableViewProperties(aVar, [ + [result] = yield findVariableViewProperties(aVar, [ { name: "hello", value: "world!" }, { name: "bug", value: 869003 }, - ], { webconsole: gWebConsole }).then(onPropFound); -} + ], { webconsole: hud }); -function onPropFound(aResults) -{ - let prop = aResults[0].matchedProp; + let prop = result.matchedProp; ok(prop, "matched the |hello| property in the variables view"); // Check that property value updates work. - updateVariablesViewProperty({ + aVar = yield updateVariablesViewProperty({ property: prop, field: "value", string: "'omgtest'", - webconsole: gWebConsole, - callback: onFetchAfterUpdate, + webconsole: hud, }); -} -function onFetchAfterUpdate(aEvent, aVar) -{ info("onFetchAfterUpdate"); - findVariableViewProperties(aVar, [ + yield findVariableViewProperties(aVar, [ { name: "hello", value: "omgtest" }, { name: "bug", value: 869003 }, - ], { webconsole: gWebConsole }).then(() => { - gWebConsole = gJSTerm = gVariablesView = null; - finishTest(); - }); -} + ], { webconsole: hud }); +}); + diff --git a/browser/devtools/webconsole/test/browser_bug_871156_ctrlw_close_tab.js b/browser/devtools/webconsole/test/browser_bug_871156_ctrlw_close_tab.js index 96b7201ef7dd..5031035664cc 100644 --- a/browser/devtools/webconsole/test/browser_bug_871156_ctrlw_close_tab.js +++ b/browser/devtools/webconsole/test/browser_bug_871156_ctrlw_close_tab.js @@ -6,78 +6,74 @@ // Check that Ctrl-W closes the Browser Console and that Ctrl-W closes the // current tab when using the Web Console - bug 871156. -function test() -{ +"use strict"; + +let test = asyncTest(function* () { const TEST_URI = "data:text/html;charset=utf8,bug871156\n" + "

hello world"; let firstTab = gBrowser.selectedTab; + Services.prefs.setBoolPref("browser.tabs.animate", false); + registerCleanupFunction(() => { + Services.prefs.clearUserPref("browser.tabs.animate"); + }); - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + yield loadTab(TEST_URI); - function consoleOpened(hud) - { - ok(hud, "Web Console opened"); + let hud = yield openConsole(); + ok(hud, "Web Console opened"); - let tabClosed = promise.defer(); - let toolboxDestroyed = promise.defer(); - let tabSelected = promise.defer(); + let tabClosed = promise.defer(); + let toolboxDestroyed = promise.defer(); + let tabSelected = promise.defer(); - let pageWindow = firstTab.linkedBrowser.contentWindow; - let toolbox = gDevTools.getToolbox(hud.target); + let target = TargetFactory.forTab(gBrowser.selectedTab); + let toolbox = gDevTools.getToolbox(target); - gBrowser.tabContainer.addEventListener("TabClose", function onTabClose() { - gBrowser.tabContainer.removeEventListener("TabClose", onTabClose); - info("tab closed"); - tabClosed.resolve(null); - }); + gBrowser.tabContainer.addEventListener("TabClose", function onTabClose() { + gBrowser.tabContainer.removeEventListener("TabClose", onTabClose); + info("tab closed"); + tabClosed.resolve(null); + }); - gBrowser.tabContainer.addEventListener("TabSelect", function onTabSelect() { - gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect); - if (gBrowser.selectedTab == firstTab) { - info("tab selected"); - tabSelected.resolve(null); - } - }); + gBrowser.tabContainer.addEventListener("TabSelect", function onTabSelect() { + gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect); + if (gBrowser.selectedTab == firstTab) { + info("tab selected"); + tabSelected.resolve(null); + } + }); - toolbox.once("destroyed", () => { - info("toolbox destroyed"); - toolboxDestroyed.resolve(null); - }); + toolbox.once("destroyed", () => { + info("toolbox destroyed"); + toolboxDestroyed.resolve(null); + }); - promise.all([tabClosed.promise, toolboxDestroyed.promise, tabSelected.promise ]).then(() => { - info("promise.all resolved"); - waitForFocus(testBrowserConsole, pageWindow, true); - }); + // Get out of the web console initialization. + executeSoon(() => { + EventUtils.synthesizeKey("w", { accelKey: true }); + }); - // Get out of the web console initialization. - executeSoon(() => { - EventUtils.synthesizeKey("w", { accelKey: true }); - }); - } - function testBrowserConsole() - { - info("test the Browser Console"); + yield promise.all([tabClosed.promise, toolboxDestroyed.promise, + tabSelected.promise]); + info("promise.all resolved. start testing the Browser Console"); - HUDService.toggleBrowserConsole().then((hud) => { - ok(hud, "Browser Console opened"); + hud = yield HUDService.toggleBrowserConsole(); + ok(hud, "Browser Console opened"); - Services.obs.addObserver(function onDestroy() { - Services.obs.removeObserver(onDestroy, "web-console-destroyed"); - ok(true, "the Browser Console closed"); + let deferred = promise.defer(); - Services.prefs.clearUserPref("browser.tabs.animate"); - waitForFocus(finish, content, true); - }, "web-console-destroyed", false); + Services.obs.addObserver(function onDestroy() { + Services.obs.removeObserver(onDestroy, "web-console-destroyed"); + ok(true, "the Browser Console closed"); - waitForFocus(() => { - EventUtils.synthesizeKey("w", { accelKey: true }, hud.iframeWindow); - }, hud.iframeWindow); - }); - } -} + deferred.resolve(null); + }, "web-console-destroyed", false); + + waitForFocus(() => { + EventUtils.synthesizeKey("w", { accelKey: true }, hud.iframeWindow); + }, hud.iframeWindow); + + yield deferred.promise; +}); diff --git a/browser/devtools/webconsole/test/browser_cached_messages.js b/browser/devtools/webconsole/test/browser_cached_messages.js index 6041fad850f3..a9a98ac17520 100644 --- a/browser/devtools/webconsole/test/browser_cached_messages.js +++ b/browser/devtools/webconsole/test/browser_cached_messages.js @@ -13,16 +13,12 @@ function test() expectUncaughtException(); - addTab(TEST_URI); - gBrowser.selectedBrowser.addEventListener("load", function onLoad() { - gBrowser.selectedBrowser.removeEventListener("load", onLoad, true); - testOpenUI(true); - }, true); + loadTab(TEST_URI).then(testOpenUI); } function testOpenUI(aTestReopen) { - openConsole(null, function(hud) { + openConsole().then((hud) => { waitForMessages({ webconsole: hud, messages: [ @@ -48,7 +44,7 @@ function testOpenUI(aTestReopen) }, ], }).then(() => { - closeConsole(gBrowser.selectedTab, function() { + closeConsole(gBrowser.selectedTab).then(() => { aTestReopen && info("will reopen the Web Console"); executeSoon(aTestReopen ? testOpenUI : finishTest); }); diff --git a/browser/devtools/webconsole/test/browser_console.js b/browser/devtools/webconsole/test/browser_console.js index 1fd3588585f2..f72b5a962e37 100644 --- a/browser/devtools/webconsole/test/browser_console.js +++ b/browser/devtools/webconsole/test/browser_console.js @@ -7,24 +7,23 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html?" + Date.now(); -function test() -{ - Services.obs.addObserver(function observer(aSubject) { - Services.obs.removeObserver(observer, "web-console-created"); - aSubject.QueryInterface(Ci.nsISupportsString); +"use strict"; - let hud = HUDService.getBrowserConsole(); - ok(hud, "browser console is open"); - is(aSubject.data, hud.hudId, "notification hudId is correct"); +let test = asyncTest(function*() { + yield loadTab(TEST_URI); - executeSoon(() => consoleOpened(hud)); - }, "web-console-created", false); + let opened = waitForConsole(); let hud = HUDService.getBrowserConsole(); ok(!hud, "browser console is not open"); info("wait for the browser console to open with ctrl-shift-j"); EventUtils.synthesizeKey("j", { accelKey: true, shiftKey: true }, window); -} + + hud = yield opened; + ok(hud, "browser console opened"); + + yield consoleOpened(hud); +}); function consoleOpened(hud) { @@ -50,7 +49,7 @@ function consoleOpened(hud) xhr.open("get", TEST_URI, true); xhr.send(); - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [ { @@ -84,5 +83,22 @@ function consoleOpened(hud) severity: SEVERITY_LOG, }, ], - }).then(finishTest); + }); +} + +function waitForConsole() { + let deferred = promise.defer(); + + Services.obs.addObserver(function observer(aSubject) { + Services.obs.removeObserver(observer, "web-console-created"); + aSubject.QueryInterface(Ci.nsISupportsString); + + let hud = HUDService.getBrowserConsole(); + ok(hud, "browser console is open"); + is(aSubject.data, hud.hudId, "notification hudId is correct"); + + executeSoon(() => deferred.resolve(hud)); + }, "web-console-created", false); + + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_console_addonsdk_loader_exception.js b/browser/devtools/webconsole/test/browser_console_addonsdk_loader_exception.js index 922ea329fd55..bc485ebb1559 100644 --- a/browser/devtools/webconsole/test/browser_console_addonsdk_loader_exception.js +++ b/browser/devtools/webconsole/test/browser_console_addonsdk_loader_exception.js @@ -7,6 +7,8 @@ // opened correctly in View Source from the Browser Console. // See bug 866950. +"use strict"; + const TEST_URI = "data:text/html;charset=utf8,

hello world from bug 866950"; function test() diff --git a/browser/devtools/webconsole/test/browser_console_clear_on_reload.js b/browser/devtools/webconsole/test/browser_console_clear_on_reload.js index 63103c368d0b..c88fdc7d51d8 100644 --- a/browser/devtools/webconsole/test/browser_console_clear_on_reload.js +++ b/browser/devtools/webconsole/test/browser_console_clear_on_reload.js @@ -5,69 +5,50 @@ // Check that clear output on page reload works - bug 705921. -function test() -{ +"use strict"; + +let test = asyncTest(function*() { const PREF = "devtools.webconsole.persistlog"; const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; - let hud = null; Services.prefs.setBoolPref(PREF, false); registerCleanupFunction(() => Services.prefs.clearUserPref(PREF)); - addTab(TEST_URI); + yield loadTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + let hud = yield openConsole(); + ok(hud, "Web Console opened"); - function consoleOpened(aHud) - { - hud = aHud; - ok(hud, "Web Console opened"); + hud.jsterm.clearOutput(); + hud.jsterm.execute("console.log('foobarz1')"); - hud.jsterm.clearOutput(); - content.console.log("foobarz1"); - waitForMessages({ - webconsole: hud, - messages: [{ - text: "foobarz1", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - }], - }).then(onConsoleMessage); - } + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "foobarz1", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }], + }); - function onConsoleMessage() - { - browser.addEventListener("load", onReload, true); - content.location.reload(); - } + BrowserReload(); + yield loadBrowser(gBrowser.selectedBrowser); - function onReload() - { - browser.removeEventListener("load", onReload, true); + hud.jsterm.execute("console.log('foobarz2')"); - content.console.log("foobarz2"); + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "test-console.html", + category: CATEGORY_NETWORK, + }, + { + text: "foobarz2", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }], + }); - waitForMessages({ - webconsole: hud, - messages: [{ - text: "test-console.html", - category: CATEGORY_NETWORK, - }, - { - text: "foobarz2", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - }], - }).then(onConsoleMessageAfterReload); - } - - function onConsoleMessageAfterReload() - { - is(hud.outputNode.textContent.indexOf("foobarz1"), -1, - "foobarz1 has been removed from output"); - finishTest(); - } -} + is(hud.outputNode.textContent.indexOf("foobarz1"), -1, + "foobarz1 has been removed from output"); +}); diff --git a/browser/devtools/webconsole/test/browser_console_click_focus.js b/browser/devtools/webconsole/test/browser_console_click_focus.js index f27d2d221738..30a18598c953 100644 --- a/browser/devtools/webconsole/test/browser_console_click_focus.js +++ b/browser/devtools/webconsole/test/browser_console_click_focus.js @@ -5,56 +5,51 @@ // Tests that the input field is focused when the console is opened. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("DOMContentLoaded", testInputFocus, false); -} +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); -function testInputFocus() { - browser.removeEventListener("DOMContentLoaded", testInputFocus, false); - - openConsole().then((hud) => { - waitForMessages({ - webconsole: hud, - messages: [{ - text: "Dolske Digs Bacon", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - }], - }).then(([result]) => { - let msg = [...result.matched][0]; - let outputItem = msg.querySelector(".message-body"); - ok(outputItem, "found a logged message"); - let inputNode = hud.jsterm.inputNode; - ok(inputNode.getAttribute("focused"), "input node is focused, first"); - - let lostFocus = () => { - inputNode.removeEventListener("blur", lostFocus); - info("input node lost focus"); - } - - inputNode.addEventListener("blur", lostFocus); - - browser.ownerDocument.getElementById("urlbar").click(); - - ok(!inputNode.getAttribute("focused"), "input node is not focused"); - - EventUtils.sendMouseEvent({type: "click"}, hud.outputNode); - - ok(inputNode.getAttribute("focused"), "input node is focused, second time") - - // test click-drags are not focusing the input element. - EventUtils.sendMouseEvent({type: "mousedown", clientX: 3, clientY: 4}, - outputItem); - EventUtils.sendMouseEvent({type: "click", clientX: 15, clientY: 5}, - outputItem); - - executeSoon(() => { - todo(!inputNode.getAttribute("focused"), "input node is not focused after drag"); - finishTest(); - }); - }); + let [result] = yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "Dolske Digs Bacon", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }], }); -} + + let msg = [...result.matched][0]; + let outputItem = msg.querySelector(".message-body"); + ok(outputItem, "found a logged message"); + + let inputNode = hud.jsterm.inputNode; + ok(inputNode.getAttribute("focused"), "input node is focused, first"); + + let lostFocus = () => { + inputNode.removeEventListener("blur", lostFocus); + info("input node lost focus"); + } + + inputNode.addEventListener("blur", lostFocus); + + document.getElementById("urlbar").click(); + + ok(!inputNode.getAttribute("focused"), "input node is not focused"); + + EventUtils.sendMouseEvent({type: "click"}, hud.outputNode); + + ok(inputNode.getAttribute("focused"), "input node is focused, second time") + + // test click-drags are not focusing the input element. + EventUtils.sendMouseEvent({type: "mousedown", clientX: 3, clientY: 4}, + outputItem); + EventUtils.sendMouseEvent({type: "click", clientX: 15, clientY: 5}, + outputItem); + + todo(!inputNode.getAttribute("focused"), "input node is not focused after drag"); +}); + diff --git a/browser/devtools/webconsole/test/browser_console_consolejsm_output.js b/browser/devtools/webconsole/test/browser_console_consolejsm_output.js index 85a678334360..0601c11a4a58 100644 --- a/browser/devtools/webconsole/test/browser_console_consolejsm_output.js +++ b/browser/devtools/webconsole/test/browser_console_consolejsm_output.js @@ -5,131 +5,133 @@ // Test that Console.jsm outputs messages to the Browser Console, bug 851231. -function test() -{ +"use strict"; + +let test = asyncTest(function*() { let storage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(Ci.nsIConsoleAPIStorage); storage.clearEvents(); let console = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console; console.log("bug861338-log-cached"); - HUDService.toggleBrowserConsole().then(consoleOpened); - let hud = null; + let hud = yield HUDService.toggleBrowserConsole(); - function consoleOpened(aHud) - { - hud = aHud; - waitForMessages({ - webconsole: hud, - messages: [{ - name: "cached console.log message", - text: "bug861338-log-cached", + yield waitForMessages({ + webconsole: hud, + messages: [{ + name: "cached console.log message", + text: "bug861338-log-cached", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }], + }); + + hud.jsterm.clearOutput(true); + + function testTrace() { + console.trace(); + } + + console.time("foobarTimer"); + let foobar = { bug851231prop: "bug851231value" }; + + console.log("bug851231-log"); + console.info("bug851231-info"); + console.warn("bug851231-warn"); + console.error("bug851231-error", foobar); + console.debug("bug851231-debug"); + console.dir(document); + testTrace(); + console.timeEnd("foobarTimer"); + + info("wait for the Console.jsm messages"); + + let results = yield waitForMessages({ + webconsole: hud, + messages: [ + { + name: "console.log output", + text: "bug851231-log", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, - }], - }).then(onCachedMessage); - } - - function onCachedMessage() - { - hud.jsterm.clearOutput(true); - - console.time("foobarTimer"); - let foobar = { bug851231prop: "bug851231value" }; - - console.log("bug851231-log"); - console.info("bug851231-info"); - console.warn("bug851231-warn"); - console.error("bug851231-error", foobar); - console.debug("bug851231-debug"); - console.trace(); - console.dir(document); - console.timeEnd("foobarTimer"); - - info("wait for the Console.jsm messages"); - - waitForMessages({ - webconsole: hud, - messages: [ - { - name: "console.log output", - text: "bug851231-log", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, + }, + { + name: "console.info output", + text: "bug851231-info", + category: CATEGORY_WEBDEV, + severity: SEVERITY_INFO, + }, + { + name: "console.warn output", + text: "bug851231-warn", + category: CATEGORY_WEBDEV, + severity: SEVERITY_WARNING, + }, + { + name: "console.error output", + text: /\bbug851231-error\b.+\{\s*bug851231prop:\s"bug851231value"\s*\}/, + category: CATEGORY_WEBDEV, + severity: SEVERITY_ERROR, + objects: true, + }, + { + name: "console.debug output", + text: "bug851231-debug", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }, + { + name: "console.trace output", + consoleTrace: { + file: "browser_console_consolejsm_output.js", + fn: "testTrace", }, - { - name: "console.info output", - text: "bug851231-info", - category: CATEGORY_WEBDEV, - severity: SEVERITY_INFO, - }, - { - name: "console.warn output", - text: "bug851231-warn", - category: CATEGORY_WEBDEV, - severity: SEVERITY_WARNING, - }, - { - name: "console.error output", - text: /\bbug851231-error\b.+\{\s*bug851231prop:\s"bug851231value"\s*\}/, - category: CATEGORY_WEBDEV, - severity: SEVERITY_ERROR, - objects: true, - }, - { - name: "console.debug output", - text: "bug851231-debug", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - }, - { - name: "console.trace output", - consoleTrace: { - file: "browser_console_consolejsm_output.js", - fn: "onCachedMessage", - }, - }, - { - name: "console.dir output", - consoleDir: /XULDocument\s+.+\s+chrome:\/\/.+\/browser\.xul/, - }, - { - name: "console.time output", - consoleTime: "foobarTimer", - }, - { - name: "console.timeEnd output", - consoleTimeEnd: "foobarTimer", - }, - ], - }).then((aResults) => { - let consoleErrorMsg = aResults[3]; - ok(consoleErrorMsg, "console.error message element found"); - let clickable = consoleErrorMsg.clickableElements[0]; - ok(clickable, "clickable object found for console.error"); + }, + { + name: "console.dir output", + consoleDir: /XULDocument\s+.+\s+chrome:\/\/.+\/browser\.xul/, + }, + { + name: "console.time output", + consoleTime: "foobarTimer", + }, + { + name: "console.timeEnd output", + consoleTimeEnd: "foobarTimer", + }, + ], + }); - let onFetch = (aEvent, aVar) => { - // Skip the notification from console.dir variablesview-fetched. - if (aVar._variablesView != hud.jsterm._variablesView) { - return; - } - hud.jsterm.off("variablesview-fetched", onFetch); + let consoleErrorMsg = results[3]; + ok(consoleErrorMsg, "console.error message element found"); + let clickable = consoleErrorMsg.clickableElements[0]; + ok(clickable, "clickable object found for console.error"); - ok(aVar, "object inspector opened on click"); + let deferred = promise.defer(); - findVariableViewProperties(aVar, [{ - name: "bug851231prop", - value: "bug851231value", - }], { webconsole: hud }).then(finishTest); - }; + let onFetch = (aEvent, aVar) => { + // Skip the notification from console.dir variablesview-fetched. + if (aVar._variablesView != hud.jsterm._variablesView) { + return; + } + hud.jsterm.off("variablesview-fetched", onFetch); - hud.jsterm.on("variablesview-fetched", onFetch); + deferred.resolve(aVar); + }; - clickable.scrollIntoView(false); + hud.jsterm.on("variablesview-fetched", onFetch); - info("wait for variablesview-fetched"); - executeSoon(() => - EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow)); - }); - } -} + clickable.scrollIntoView(false); + + info("wait for variablesview-fetched"); + executeSoon(() => + EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow)); + + let varView = yield deferred.promise; + ok(varView, "object inspector opened on click"); + + yield findVariableViewProperties(varView, [{ + name: "bug851231prop", + value: "bug851231value", + }], { webconsole: hud }); +}); diff --git a/browser/devtools/webconsole/test/browser_console_dead_objects.js b/browser/devtools/webconsole/test/browser_console_dead_objects.js index d0da652db370..f5186c697241 100644 --- a/browser/devtools/webconsole/test/browser_console_dead_objects.js +++ b/browser/devtools/webconsole/test/browser_console_dead_objects.js @@ -12,6 +12,8 @@ // - tries to use the object that was pointing to the now-defunct content // document. This is the dead object. +"use strict"; + const TEST_URI = "data:text/html;charset=utf8,

dead objects!"; function test() @@ -36,7 +38,6 @@ function test() hud.jsterm.clearOutput(); // Add the reference to the content document. - yield execute("Cu = Components.utils;" + "Cu.import('resource://gre/modules/Services.jsm');" + "chromeWindow = Services.wm.getMostRecentWindow('navigator:browser');" + diff --git a/browser/devtools/webconsole/test/browser_console_error_source_click.js b/browser/devtools/webconsole/test/browser_console_error_source_click.js index 0ac128f53054..5e2ecb97702d 100644 --- a/browser/devtools/webconsole/test/browser_console_error_source_click.js +++ b/browser/devtools/webconsole/test/browser_console_error_source_click.js @@ -13,11 +13,9 @@ function test() { let hud; - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); + loadTab(TEST_URI).then(() => { HUDService.toggleBrowserConsole().then(browserConsoleOpened); - }, true); + }); function browserConsoleOpened(aHud) { diff --git a/browser/devtools/webconsole/test/browser_console_filters.js b/browser/devtools/webconsole/test/browser_console_filters.js index 6568cba91922..1524b6bb1c60 100644 --- a/browser/devtools/webconsole/test/browser_console_filters.js +++ b/browser/devtools/webconsole/test/browser_console_filters.js @@ -6,22 +6,17 @@ // Check that the Browser Console does not use the same filter prefs as the Web // Console. See bug 878186. +"use strict"; + const TEST_URI = "data:text/html;charset=utf8,

browser console filters"; const WEB_CONSOLE_PREFIX = "devtools.webconsole.filter."; const BROWSER_CONSOLE_PREFIX = "devtools.browserconsole.filter."; -function test() -{ - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - info("open the web console"); - openConsole(null, consoleOpened); - }, true); -} +let test = asyncTest(function*() { + yield loadTab(TEST_URI); -function consoleOpened(hud) -{ + info("open the web console"); + let hud = yield openConsole(); ok(hud, "web console opened"); is(Services.prefs.getBoolPref(BROWSER_CONSOLE_PREFIX + "exception"), true, @@ -39,17 +34,13 @@ function consoleOpened(hud) hud.setFilterState("exception", true); - executeSoon(() => closeConsole(null, onWebConsoleClose)); -} + // We need to let the console opening event loop to finish. + let deferred = promise.defer(); + executeSoon(() => closeConsole().then(() => deferred.resolve(null))); + yield deferred.promise; -function onWebConsoleClose() -{ info("web console closed"); - HUDService.toggleBrowserConsole().then(onBrowserConsoleOpen); -} - -function onBrowserConsoleOpen(hud) -{ + hud = yield HUDService.toggleBrowserConsole(); ok(hud, "browser console opened"); is(Services.prefs.getBoolPref(BROWSER_CONSOLE_PREFIX + "exception"), true, @@ -66,6 +57,4 @@ function onBrowserConsoleOpen(hud) "'exception' filter is enabled (web console)"); hud.setFilterState("exception", true); - - executeSoon(finishTest); -} +}); diff --git a/browser/devtools/webconsole/test/browser_console_iframe_messages.js b/browser/devtools/webconsole/test/browser_console_iframe_messages.js index dfda0981a5f4..f8e32b23a309 100644 --- a/browser/devtools/webconsole/test/browser_console_iframe_messages.js +++ b/browser/devtools/webconsole/test/browser_console_iframe_messages.js @@ -8,7 +8,7 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-consoleiframes.html"; -let expectedMessages = [ +const expectedMessages = [ { text: "main file", category: CATEGORY_WEBDEV, @@ -35,7 +35,7 @@ let expectedMessages = [ // other in the sequence of messages (depending on timing). If they do not, then // they will be displayed in the console output independently, as separate // messages. This is why we need to match any of the following two rules. -let expectedMessagesAny = [ +const expectedMessagesAny = [ { name: "iframe 1 (count: 2)", text: "iframe 1", @@ -55,12 +55,9 @@ let expectedMessagesAny = [ function test() { expectUncaughtException(); - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - info("open web console"); - openConsole(null, consoleOpened); - }, true); + loadTab(TEST_URI).then(() => { + openConsole().then(consoleOpened); + }); } function consoleOpened(hud) @@ -77,7 +74,7 @@ function consoleOpened(hud) messages: expectedMessagesAny, matchCondition: "any", }).then(() => { - closeConsole(null, onWebConsoleClose); + closeConsole().then(onWebConsoleClose); }); }); } @@ -101,7 +98,7 @@ function onBrowserConsoleOpen(hud) messages: expectedMessagesAny, matchCondition: "any", }).then(() => { - closeConsole(null, finishTest); + closeConsole().then(finishTest); }); }); } diff --git a/browser/devtools/webconsole/test/browser_console_keyboard_accessibility.js b/browser/devtools/webconsole/test/browser_console_keyboard_accessibility.js index 83b99dd355c4..bbf767314f8a 100644 --- a/browser/devtools/webconsole/test/browser_console_keyboard_accessibility.js +++ b/browser/devtools/webconsole/test/browser_console_keyboard_accessibility.js @@ -5,86 +5,75 @@ // Check that basic keyboard shortcuts work in the web console. -function test() -{ +"use strict"; + +let test = asyncTest(function*() { const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; - let hud = null; - addTab(TEST_URI); + yield loadTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + let hud = yield openConsole(); + ok(hud, "Web Console opened"); - function consoleOpened(aHud) - { - hud = aHud; - ok(hud, "Web Console opened"); + info("dump some spew into the console for scrolling"); + hud.jsterm.execute("(function() { for (var i = 0; i < 100; i++) { " + + "console.log('foobarz' + i);" + + "}})();"); - info("dump some spew into the console for scrolling"); - for (let i = 0; i < 100; i++) - content.console.log("foobarz" + i); - waitForMessages({ - webconsole: hud, - messages: [{ - text: "foobarz99", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - }], - }).then(onConsoleMessage); + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "foobarz99", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }], + }); + + let currentPosition = hud.outputNode.parentNode.scrollTop; + let bottom = currentPosition; + + EventUtils.synthesizeKey("VK_PAGE_UP", {}); + isnot(hud.outputNode.parentNode.scrollTop, currentPosition, "scroll position changed after page up"); + + currentPosition = hud.outputNode.parentNode.scrollTop; + EventUtils.synthesizeKey("VK_PAGE_DOWN", {}); + ok(hud.outputNode.parentNode.scrollTop > currentPosition, "scroll position now at bottom"); + + EventUtils.synthesizeKey("VK_HOME", {}); + is(hud.outputNode.parentNode.scrollTop, 0, "scroll position now at top"); + + EventUtils.synthesizeKey("VK_END", {}); + + let scrollTop = hud.outputNode.parentNode.scrollTop; + ok(scrollTop > 0 && Math.abs(scrollTop - bottom) <= 5, + "scroll position now at bottom"); + + info("try ctrl-l to clear output"); + executeSoon(() => { EventUtils.synthesizeKey("l", { ctrlKey: true }); }); + yield hud.jsterm.once("messages-cleared"); + + is(hud.outputNode.textContent.indexOf("foobarz1"), -1, "output cleared"); + is(hud.jsterm.inputNode.getAttribute("focused"), "true", + "jsterm input is focused"); + + info("try ctrl-f to focus filter"); + EventUtils.synthesizeKey("F", { accelKey: true }); + ok(!hud.jsterm.inputNode.getAttribute("focused"), + "jsterm input is not focused"); + is(hud.ui.filterBox.getAttribute("focused"), "true", + "filter input is focused"); + + if (Services.appinfo.OS == "Darwin") { + ok(hud.ui.getFilterState("network"), "network category is enabled"); + EventUtils.synthesizeKey("t", { ctrlKey: true }); + ok(!hud.ui.getFilterState("network"), "accesskey for Network works"); + EventUtils.synthesizeKey("t", { ctrlKey: true }); + ok(hud.ui.getFilterState("network"), "accesskey for Network works (again)"); } - - function onConsoleMessage() - { - let currentPosition = hud.outputNode.parentNode.scrollTop; - let bottom = currentPosition; - - EventUtils.synthesizeKey("VK_PAGE_UP", {}); - isnot(hud.outputNode.parentNode.scrollTop, currentPosition, "scroll position changed after page up"); - - currentPosition = hud.outputNode.parentNode.scrollTop; - EventUtils.synthesizeKey("VK_PAGE_DOWN", {}); - ok(hud.outputNode.parentNode.scrollTop > currentPosition, "scroll position now at bottom"); - - EventUtils.synthesizeKey("VK_HOME", {}); - is(hud.outputNode.parentNode.scrollTop, 0, "scroll position now at top"); - - EventUtils.synthesizeKey("VK_END", {}); - is(hud.outputNode.parentNode.scrollTop, bottom, "scroll position now at bottom"); - - hud.jsterm.once("messages-cleared", onClear); - info("try ctrl-l to clear output"); - EventUtils.synthesizeKey("l", { ctrlKey: true }); + else { + EventUtils.synthesizeKey("N", { altKey: true }); + let net = hud.ui.document.querySelector("toolbarbutton[category=net]"); + is(hud.ui.document.activeElement, net, + "accesskey for Network category focuses the Net button"); } - - function onClear() - { - is(hud.outputNode.textContent.indexOf("foobarz1"), -1, "output cleared"); - is(hud.jsterm.inputNode.getAttribute("focused"), "true", - "jsterm input is focused"); - - info("try ctrl-f to focus filter"); - EventUtils.synthesizeKey("F", { accelKey: true }); - ok(!hud.jsterm.inputNode.getAttribute("focused"), - "jsterm input is not focused"); - is(hud.ui.filterBox.getAttribute("focused"), "true", - "filter input is focused"); - - if (Services.appinfo.OS == "Darwin") { - ok(hud.ui.getFilterState("network"), "network category is enabled"); - EventUtils.synthesizeKey("t", { ctrlKey: true }); - ok(!hud.ui.getFilterState("network"), "accesskey for Network works"); - EventUtils.synthesizeKey("t", { ctrlKey: true }); - ok(hud.ui.getFilterState("network"), "accesskey for Network works (again)"); - } - else { - EventUtils.synthesizeKey("N", { altKey: true }); - let net = hud.ui.document.querySelector("toolbarbutton[category=net]"); - is(hud.ui.document.activeElement, net, - "accesskey for Network category focuses the Net button"); - } - - finishTest(); - } -} +}); diff --git a/browser/devtools/webconsole/test/browser_console_log_inspectable_object.js b/browser/devtools/webconsole/test/browser_console_log_inspectable_object.js index 6f575e04eb00..075f2fb70b6a 100644 --- a/browser/devtools/webconsole/test/browser_console_log_inspectable_object.js +++ b/browser/devtools/webconsole/test/browser_console_log_inspectable_object.js @@ -4,26 +4,18 @@ // Test that objects given to console.log() are inspectable. -function test() -{ - waitForExplicitFinish(); +"use strict"; - addTab("data:text/html;charset=utf8,test for bug 676722 - inspectable objects for window.console"); +let test = asyncTest(function*() { + yield loadTab("data:text/html;charset=utf8,test for bug 676722 - inspectable objects for window.console"); - gBrowser.selectedBrowser.addEventListener("load", function onLoad() { - gBrowser.selectedBrowser.removeEventListener("load", onLoad, true); - openConsole(null, performTest); - }, true); -} - -function performTest(hud) -{ + let hud = yield openConsole(); hud.jsterm.clearOutput(true); hud.jsterm.execute("myObj = {abba: 'omgBug676722'}"); hud.jsterm.execute("console.log('fooBug676722', myObj)"); - waitForMessages({ + let [result] = yield waitForMessages({ webconsole: hud, messages: [{ text: "fooBug676722", @@ -31,28 +23,28 @@ function performTest(hud) severity: SEVERITY_LOG, objects: true, }], - }).then(([result]) => { - let msg = [...result.matched][0]; - ok(msg, "message element"); - let body = msg.querySelector(".message-body"); - ok(body, "message body"); - let clickable = result.clickableElements[0]; - ok(clickable, "the console.log() object anchor was found"); - ok(body.textContent.contains('{ abba: "omgBug676722" }'), - "clickable node content is correct"); - - hud.jsterm.once("variablesview-fetched", - (aEvent, aVar) => { - ok(aVar, "object inspector opened on click"); - - findVariableViewProperties(aVar, [{ - name: "abba", - value: "omgBug676722", - }], { webconsole: hud }).then(finishTest); - }); - - executeSoon(function() { - EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow); - }); }); -} + + let msg = [...result.matched][0]; + ok(msg, "message element"); + + let body = msg.querySelector(".message-body"); + ok(body, "message body"); + + let clickable = result.clickableElements[0]; + ok(clickable, "the console.log() object anchor was found"); + ok(body.textContent.contains('{ abba: "omgBug676722" }'), + "clickable node content is correct"); + + executeSoon(() => { + EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow); + }); + + let varView = yield hud.jsterm.once("variablesview-fetched"); + ok(varView, "object inspector opened on click"); + + yield findVariableViewProperties(varView, [{ + name: "abba", + value: "omgBug676722", + }], { webconsole: hud }); +}); diff --git a/browser/devtools/webconsole/test/browser_console_native_getters.js b/browser/devtools/webconsole/test/browser_console_native_getters.js index 1d6e6c5bbb86..8213108ab286 100644 --- a/browser/devtools/webconsole/test/browser_console_native_getters.js +++ b/browser/devtools/webconsole/test/browser_console_native_getters.js @@ -6,116 +6,94 @@ // Check that native getters and setters for DOM elements work as expected in // variables view - bug 870220. +"use strict"; + const TEST_URI = "data:text/html;charset=utf8,bug870220\n" + "

hello world\n

native getters!"; -let gWebConsole, gJSTerm, gVariablesView; +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); + let jsterm = hud.jsterm; -function test() -{ - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} + jsterm.execute("document"); -function consoleOpened(hud) -{ - gWebConsole = hud; - gJSTerm = hud.jsterm; - - gJSTerm.execute("document"); - - waitForMessages({ + let [result] = yield waitForMessages({ webconsole: hud, messages: [{ text: "HTMLDocument \u2192 data:text/html;charset=utf8", category: CATEGORY_OUTPUT, objects: true, }], - }).then(onEvalResult); -} + }); -function onEvalResult(aResults) -{ - let clickable = aResults[0].clickableElements[0]; + let clickable = result.clickableElements[0]; ok(clickable, "clickable object found"); - gJSTerm.once("variablesview-fetched", onDocumentFetch); - EventUtils.synthesizeMouse(clickable, 2, 2, {}, gWebConsole.iframeWindow) -} + executeSoon(() => { + EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow); + }); -function onDocumentFetch(aEvent, aVar) -{ - gVariablesView = aVar._variablesView; - ok(gVariablesView, "variables view object"); + let fetchedVar = yield jsterm.once("variablesview-fetched"); - findVariableViewProperties(aVar, [ + let variablesView = fetchedVar._variablesView; + ok(variablesView, "variables view object"); + + let results = yield findVariableViewProperties(fetchedVar, [ { name: "title", value: "bug870220" }, { name: "bgColor" }, - ], { webconsole: gWebConsole }).then(onDocumentPropsFound); -} + ], { webconsole: hud }); -function onDocumentPropsFound(aResults) -{ - let prop = aResults[1].matchedProp; + let prop = results[1].matchedProp; ok(prop, "matched the |bgColor| property in the variables view"); // Check that property value updates work. - updateVariablesViewProperty({ + let updatedVar = yield updateVariablesViewProperty({ property: prop, field: "value", string: "'red'", - webconsole: gWebConsole, - callback: onFetchAfterBackgroundUpdate, + webconsole: hud, }); -} -function onFetchAfterBackgroundUpdate(aEvent, aVar) -{ - info("onFetchAfterBackgroundUpdate"); + info("on fetch after background update"); - is(content.document.bgColor, "red", "document background color changed"); + jsterm.clearOutput(true); + jsterm.execute("document.bgColor"); - findVariableViewProperties(aVar, [ + [result] = yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "red", + category: CATEGORY_OUTPUT, + }], + }); + + yield findVariableViewProperties(updatedVar, [ { name: "bgColor", value: "red" }, - ], { webconsole: gWebConsole }).then(testParagraphs); -} + ], { webconsole: hud }); -function testParagraphs() -{ - gJSTerm.execute("$$('p')"); + jsterm.execute("$$('p')"); - waitForMessages({ - webconsole: gWebConsole, + [result] = yield waitForMessages({ + webconsole: hud, messages: [{ text: "NodeList [", category: CATEGORY_OUTPUT, objects: true, }], - }).then(onEvalNodeList); -} + }); -function onEvalNodeList(aResults) -{ - let clickable = aResults[0].clickableElements[0]; + clickable = result.clickableElements[0]; ok(clickable, "clickable object found"); - gJSTerm.once("variablesview-fetched", onNodeListFetch); - EventUtils.synthesizeMouse(clickable, 2, 2, {}, gWebConsole.iframeWindow) -} + executeSoon(() => { + EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow); + }); -function onNodeListFetch(aEvent, aVar) -{ - gVariablesView = aVar._variablesView; - ok(gVariablesView, "variables view object"); + fetchedVar = yield jsterm.once("variablesview-fetched"); - findVariableViewProperties(aVar, [ + yield findVariableViewProperties(fetchedVar, [ { name: "0.textContent", value: /hello world/ }, { name: "1.textContent", value: /native getters/ }, - ], { webconsole: gWebConsole }).then(() => { - gWebConsole = gJSTerm = gVariablesView = null; - finishTest(); - }); -} + ], { webconsole: hud }); +}); diff --git a/browser/devtools/webconsole/test/browser_console_navigation_marker.js b/browser/devtools/webconsole/test/browser_console_navigation_marker.js index 6ec9d3432719..280c525ae444 100644 --- a/browser/devtools/webconsole/test/browser_console_navigation_marker.js +++ b/browser/devtools/webconsole/test/browser_console_navigation_marker.js @@ -5,77 +5,71 @@ // Check that the navigation marker shows on page reload - bug 793996. -function test() -{ - const PREF = "devtools.webconsole.persistlog"; - const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; - let hud = null; - let Messages = require("devtools/webconsole/console-output").Messages; +const PREF = "devtools.webconsole.persistlog"; +const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; +let hud; + +let test = asyncTest(function* () { Services.prefs.setBoolPref(PREF, true); - registerCleanupFunction(() => Services.prefs.clearUserPref(PREF)); - addTab(TEST_URI); + let { browser } = yield loadTab(TEST_URI); + hud = yield openConsole(); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + yield consoleOpened(); - function consoleOpened(aHud) - { - hud = aHud; - ok(hud, "Web Console opened"); + let loaded = loadBrowser(browser); + BrowserReload(); + yield loaded; - hud.jsterm.clearOutput(); - content.console.log("foobarz1"); - waitForMessages({ - webconsole: hud, - messages: [{ - text: "foobarz1", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - }], - }).then(onConsoleMessage); - } + yield onReload(); - function onConsoleMessage() - { - browser.addEventListener("load", onReload, true); - content.location.reload(); - } + isnot(hud.outputNode.textContent.indexOf("foobarz1"), -1, + "foobarz1 is still in the output"); - function onReload() - { - browser.removeEventListener("load", onReload, true); + Services.prefs.clearUserPref(PREF); - content.console.log("foobarz2"); + hud = null; +}); - waitForMessages({ - webconsole: hud, - messages: [{ - name: "page reload", - text: "test-console.html", - category: CATEGORY_NETWORK, - severity: SEVERITY_LOG, - }, - { - text: "foobarz2", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - }, - { - name: "navigation marker", - text: "test-console.html", - type: Messages.NavigationMarker, - }], - }).then(onConsoleMessageAfterReload); - } +function consoleOpened() +{ + ok(hud, "Web Console opened"); - function onConsoleMessageAfterReload() - { - isnot(hud.outputNode.textContent.indexOf("foobarz1"), -1, - "foobarz1 is still in the output"); - finishTest(); - } + hud.jsterm.clearOutput(); + content.console.log("foobarz1"); + return waitForMessages({ + webconsole: hud, + messages: [{ + text: "foobarz1", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }], + }); } + +function onReload() +{ + content.console.log("foobarz2"); + + return waitForMessages({ + webconsole: hud, + messages: [{ + name: "page reload", + text: "test-console.html", + category: CATEGORY_NETWORK, + severity: SEVERITY_LOG, + }, + { + text: "foobarz2", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }, + { + name: "navigation marker", + text: "test-console.html", + type: Messages.NavigationMarker, + }], + }); +} + diff --git a/browser/devtools/webconsole/test/browser_console_private_browsing.js b/browser/devtools/webconsole/test/browser_console_private_browsing.js index 7173e928d8dc..f517fdd2ce38 100644 --- a/browser/devtools/webconsole/test/browser_console_private_browsing.js +++ b/browser/devtools/webconsole/test/browser_console_private_browsing.js @@ -66,7 +66,7 @@ function test() privateBrowser.selectedBrowser.removeEventListener("load", onLoad, true); privateContent = privateBrowser.selectedBrowser.contentWindow; ok(PrivateBrowsingUtils.isBrowserPrivate(privateBrowser.selectedBrowser), "tab window is private"); - openConsole(privateTab, consoleOpened); + openConsole(privateTab).then(consoleOpened); }, true); } @@ -109,9 +109,9 @@ function test() function testCachedMessages() { info("testCachedMessages()"); - closeConsole(privateTab, () => { + closeConsole(privateTab).then(() => { info("web console closed"); - openConsole(privateTab, consoleReopened); + openConsole(privateTab).then(consoleReopened); }); } @@ -131,7 +131,7 @@ function test() function testBrowserConsole() { info("testBrowserConsole()"); - closeConsole(privateTab, () => { + closeConsole(privateTab).then(() => { info("web console closed"); privateWindow.HUDService.toggleBrowserConsole().then(onBrowserConsoleOpen); }); diff --git a/browser/devtools/webconsole/test/browser_console_variables_view.js b/browser/devtools/webconsole/test/browser_console_variables_view.js index 78887d0748a3..071e7c2c7c4f 100644 --- a/browser/devtools/webconsole/test/browser_console_variables_view.js +++ b/browser/devtools/webconsole/test/browser_console_variables_view.js @@ -9,45 +9,57 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/te let gWebConsole, gJSTerm, gVariablesView; -function test() -{ - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} +let hud; + +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + hud = yield openConsole(); -function consoleOpened(hud) -{ gWebConsole = hud; gJSTerm = hud.jsterm; - gJSTerm.execute("fooObj", onExecuteFooObj); -} + let msg = yield execute(hud, "fooObj"); -function onExecuteFooObj(msg) -{ ok(msg, "output message found"); ok(msg.textContent.contains('{ testProp: "testValue" }'), "message text check"); let anchor = msg.querySelector("a"); ok(anchor, "object link found"); - gJSTerm.once("variablesview-fetched", onFooObjFetch); + let fetched = gJSTerm.once("variablesview-fetched"); - executeSoon(() => - EventUtils.synthesizeMouse(anchor, 2, 2, {}, gWebConsole.iframeWindow) - ); -} + // executeSoon + EventUtils.synthesizeMouse(anchor, 2, 2, {}, gWebConsole.iframeWindow); -function onFooObjFetch(aEvent, aVar) + let view = yield fetched; + + let results = yield onFooObjFetch(view); + + let vView = yield onTestPropFound(results); + let results2 = yield onFooObjFetchAfterUpdate(vView); + + let vView2 = yield onUpdatedTestPropFound(results2); + let results3 = yield onFooObjFetchAfterPropRename(vView2); + + let vView3 = yield onRenamedTestPropFound(results3); + let results4 = yield onPropUpdateError(vView3); + + yield onRenamedTestPropFoundAgain(results4); + + let prop = results4[0].matchedProp; + yield testPropDelete(prop); + + gWebConsole = gJSTerm = gVariablesView = null; +}); + +function onFooObjFetch(aVar) { gVariablesView = aVar._variablesView; ok(gVariablesView, "variables view object"); - findVariableViewProperties(aVar, [ + return findVariableViewProperties(aVar, [ { name: "testProp", value: "testValue" }, - ], { webconsole: gWebConsole }).then(onTestPropFound); + ], { webconsole: gWebConsole }); } function onTestPropFound(aResults) @@ -55,29 +67,28 @@ function onTestPropFound(aResults) let prop = aResults[0].matchedProp; ok(prop, "matched the |testProp| property in the variables view"); - is(content.wrappedJSObject.fooObj.testProp, aResults[0].value, + is("testValue", aResults[0].value, "|fooObj.testProp| value is correct"); // Check that property value updates work and that jsterm functions can be // used. - updateVariablesViewProperty({ + return updateVariablesViewProperty({ property: prop, field: "value", string: "document.title + window.location + $('p')", - webconsole: gWebConsole, - callback: onFooObjFetchAfterUpdate, + webconsole: gWebConsole }); } -function onFooObjFetchAfterUpdate(aEvent, aVar) +function onFooObjFetchAfterUpdate(aVar) { info("onFooObjFetchAfterUpdate"); - let para = content.wrappedJSObject.document.querySelector("p"); - let expectedValue = content.document.title + content.location + para; + let expectedValue = content.document.title + content.location + + '[object HTMLParagraphElement]'; - findVariableViewProperties(aVar, [ + return findVariableViewProperties(aVar, [ { name: "testProp", value: expectedValue }, - ], { webconsole: gWebConsole }).then(onUpdatedTestPropFound); + ], { webconsole: gWebConsole }); } function onUpdatedTestPropFound(aResults) @@ -89,16 +100,15 @@ function onUpdatedTestPropFound(aResults) "|fooObj.testProp| value has been updated"); // Check that property name updates work. - updateVariablesViewProperty({ + return updateVariablesViewProperty({ property: prop, field: "name", string: "testUpdatedProp", - webconsole: gWebConsole, - callback: onFooObjFetchAfterPropRename, + webconsole: gWebConsole }); } -function onFooObjFetchAfterPropRename(aEvent, aVar) +function onFooObjFetchAfterPropRename(aVar) { info("onFooObjFetchAfterPropRename"); @@ -106,9 +116,9 @@ function onFooObjFetchAfterPropRename(aEvent, aVar) let expectedValue = content.document.title + content.location + para; // Check that the new value is in the variables view. - findVariableViewProperties(aVar, [ + return findVariableViewProperties(aVar, [ { name: "testUpdatedProp", value: expectedValue }, - ], { webconsole: gWebConsole }).then(onRenamedTestPropFound); + ], { webconsole: gWebConsole }); } function onRenamedTestPropFound(aResults) @@ -123,16 +133,15 @@ function onRenamedTestPropFound(aResults) // Check that property value updates that cause exceptions are reported in // the web console output. - updateVariablesViewProperty({ + return updateVariablesViewProperty({ property: prop, field: "value", string: "foobarzFailure()", - webconsole: gWebConsole, - callback: onPropUpdateError, + webconsole: gWebConsole }); } -function onPropUpdateError(aEvent, aVar) +function onPropUpdateError(aVar) { info("onPropUpdateError"); @@ -140,9 +149,9 @@ function onPropUpdateError(aEvent, aVar) let expectedValue = content.document.title + content.location + para; // Make sure the property did not change. - findVariableViewProperties(aVar, [ + return findVariableViewProperties(aVar, [ { name: "testUpdatedProp", value: expectedValue }, - ], { webconsole: gWebConsole }).then(onRenamedTestPropFoundAgain); + ], { webconsole: gWebConsole }); } function onRenamedTestPropFoundAgain(aResults) @@ -152,7 +161,7 @@ function onRenamedTestPropFoundAgain(aResults) let outputNode = gWebConsole.outputNode; - waitForMessages({ + return waitForMessages({ webconsole: gWebConsole, messages: [{ name: "exception in property update reported in the web console output", @@ -160,7 +169,7 @@ function onRenamedTestPropFoundAgain(aResults) category: CATEGORY_OUTPUT, severity: SEVERITY_ERROR, }], - }).then(testPropDelete.bind(null, prop)); + }); } function testPropDelete(aProp) @@ -170,14 +179,17 @@ function testPropDelete(aProp) executeSoon(() => { EventUtils.synthesizeKey("VK_DELETE", {}, gVariablesView.window); - gWebConsole = gJSTerm = gVariablesView = null; }); - waitForSuccess({ + return waitForSuccess({ name: "property deleted", timeout: 60000, - validatorFn: () => !("testUpdatedProp" in content.wrappedJSObject.fooObj), - successFn: finishTest, - failureFn: finishTest, + validator: () => !("testUpdatedProp" in content.wrappedJSObject.fooObj) }); } + +function execute(hud, str) { + let deferred = promise.defer(); + hud.jsterm.execute(str, deferred.resolve); + return deferred.promise; +} diff --git a/browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js b/browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js index 263ddd9b81e3..2e65f1bab58e 100644 --- a/browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js +++ b/browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js @@ -12,11 +12,11 @@ let gWebConsole, gJSTerm, gVariablesView, gToolbox; function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + loadTab(TEST_URI).then(() => { + openConsole().then(hud => { + consoleOpened(hud); + }) + }); } function consoleOpened(hud) diff --git a/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging.js b/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging.js index e8576bbf1f61..46e3118939f2 100644 --- a/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging.js +++ b/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging.js @@ -14,11 +14,9 @@ let gWebConsole, gJSTerm, gDebuggerWin, gThread, gDebuggerController, function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + loadTab(TEST_URI).then(() => { + openConsole().then(consoleOpened); + }); } function consoleOpened(hud) @@ -52,7 +50,7 @@ function onFramesAdded() info("onFramesAdded"); executeSoon(() => - openConsole(null, () => + openConsole().then(() => gJSTerm.execute("fooObj", onExecuteFooObj) ) ); @@ -95,12 +93,11 @@ function onTestPropFound(aResults) property: prop, field: "value", string: "document.title + foo2 + $('p')", - webconsole: gWebConsole, - callback: onFooObjFetchAfterUpdate, - }); + webconsole: gWebConsole + }).then(onFooObjFetchAfterUpdate); } -function onFooObjFetchAfterUpdate(aEvent, aVar) +function onFooObjFetchAfterUpdate(aVar) { info("onFooObjFetchAfterUpdate"); let para = content.wrappedJSObject.document.querySelector("p"); diff --git a/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging_and_inspecting.js b/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging_and_inspecting.js index 15ea85f797ff..75b8cbf1000a 100644 --- a/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging_and_inspecting.js +++ b/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging_and_inspecting.js @@ -13,10 +13,8 @@ let gWebConsole, gJSTerm, gDebuggerWin, gThread, gDebuggerController, function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); + loadTab(TEST_URI).then(() => { + openConsole().then(consoleOpened); }, true); } @@ -31,16 +29,18 @@ function consoleOpened(hud) function debuggerOpened(aResult) { + info("debugger opened"); gDebuggerWin = aResult.panelWin; gDebuggerController = gDebuggerWin.DebuggerController; gThread = gDebuggerController.activeThread; gStackframes = gDebuggerController.StackFrames; - openInspector(inspectorOpened); + openInspector().then(inspectorOpened); } function inspectorOpened(aPanel) { + info("inspector opened"); gThread.addOneTimeListener("framesadded", onFramesAdded); info("firstCall()"); @@ -51,7 +51,7 @@ function onFramesAdded() { info("onFramesAdded"); - openConsole(null, () => gJSTerm.execute("fooObj", onExecuteFooObj)); + openConsole().then(() => gJSTerm.execute("fooObj", onExecuteFooObj)); } function onExecuteFooObj(msg) @@ -90,12 +90,11 @@ function onTestPropFound(aResults) property: prop, field: "value", string: "document.title + foo2 + $('p')", - webconsole: gWebConsole, - callback: onFooObjFetchAfterUpdate, - }); + webconsole: gWebConsole + }).then(onFooObjFetchAfterUpdate); } -function onFooObjFetchAfterUpdate(aEvent, aVar) +function onFooObjFetchAfterUpdate(aVar) { info("onFooObjFetchAfterUpdate"); let para = content.wrappedJSObject.document.querySelector("p"); diff --git a/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe.js b/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe.js index 9e385c257f1c..79086afaeed3 100644 --- a/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe.js +++ b/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe.js @@ -12,11 +12,9 @@ let gWebConsole, gJSTerm, gDebuggerWin, gThread, gDebuggerController, gStackfram function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + loadTab(TEST_URI).then(() => { + openConsole().then(consoleOpened); + }); } function consoleOpened(hud) @@ -63,7 +61,7 @@ function debuggerOpened(aResult) info("openConsole"); executeSoon(() => - openConsole(null, () => + openConsole().then(() => gJSTerm.execute("foo + foo2", onExecuteFooAndFoo2) ) ); @@ -92,7 +90,7 @@ function onFramesAdded() { info("onFramesAdded, openConsole() now"); executeSoon(() => - openConsole(null, () => + openConsole().then(() => gJSTerm.execute("foo + foo2", onExecuteFooAndFoo2InSecondCall) ) ); @@ -114,7 +112,7 @@ function onExecuteFooAndFoo2InSecondCall() info("openConsole"); executeSoon(() => - openConsole(null, () => + openConsole().then(() => gJSTerm.execute("foo + foo2 + foo3", onExecuteFoo23InFirstCall) ) ); diff --git a/browser/devtools/webconsole/test/browser_jsterm_inspect.js b/browser/devtools/webconsole/test/browser_jsterm_inspect.js index fccf9059a861..6bc5f55592f5 100644 --- a/browser/devtools/webconsole/test/browser_jsterm_inspect.js +++ b/browser/devtools/webconsole/test/browser_jsterm_inspect.js @@ -5,31 +5,24 @@ // Check that the inspect() jsterm helper function works. -function test() -{ - const TEST_URI = "data:text/html;charset=utf8,

hello bug 869981"; +const TEST_URI = "data:text/html;charset=utf8,

hello bug 869981"; - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); +let test = asyncTest(function* () { + yield loadTab(TEST_URI); - function consoleOpened(hud) - { - content.wrappedJSObject.testProp = "testValue"; + let hud = yield openConsole(); + let jsterm = hud.jsterm; - hud.jsterm.once("variablesview-fetched", onObjFetch); - hud.jsterm.execute("inspect(window)"); - } + jsterm.execute("testProp = 'testValue'"); - function onObjFetch(aEvent, aVar) - { - ok(aVar._variablesView, "variables view object"); + let fetched = jsterm.once("variablesview-fetched"); + jsterm.execute("inspect(window)"); + let variable = yield fetched; - findVariableViewProperties(aVar, [ - { name: "testProp", value: "testValue" }, - { name: "document", value: /HTMLDocument \u2192 data:/ }, - ], { webconsole: hud }).then(finishTest); - } -} + ok(variable._variablesView, "variables view object"); + + yield findVariableViewProperties(variable, [ + { name: "testProp", value: "testValue" }, + { name: "document", value: /HTMLDocument \u2192 data:/ }, + ], { webconsole: hud }); +}); diff --git a/browser/devtools/webconsole/test/browser_longstring_hang.js b/browser/devtools/webconsole/test/browser_longstring_hang.js index 900a2fe3070c..5d8dc04cc7dd 100644 --- a/browser/devtools/webconsole/test/browser_longstring_hang.js +++ b/browser/devtools/webconsole/test/browser_longstring_hang.js @@ -4,61 +4,50 @@ // Test that very long strings do not hang the browser. -function test() -{ - addTab("http://example.com/browser/browser/devtools/webconsole/test/test-bug-859170-longstring-hang.html"); +const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-859170-longstring-hang.html"; - let hud = null; +let test = asyncTest(function* () { + yield loadTab(TEST_URI); - gBrowser.selectedBrowser.addEventListener("load", function onLoad() { - gBrowser.selectedBrowser.removeEventListener("load", onLoad, true); - openConsole(null, performTest); - }, true); + let hud = yield openConsole(); - function performTest(aHud) - { - hud = aHud; - info("wait for the initial long string"); + info("wait for the initial long string"); - waitForMessages({ - webconsole: hud, - messages: [ - { - name: "find 'foobar', no 'foobaz', in long string output", - text: "foobar", - noText: "foobaz", - category: CATEGORY_WEBDEV, - longString: true, - }, - ], - }).then(onInitialString); - } + let results = yield waitForMessages({ + webconsole: hud, + messages: [ + { + name: "find 'foobar', no 'foobaz', in long string output", + text: "foobar", + noText: "foobaz", + category: CATEGORY_WEBDEV, + longString: true, + }, + ], + }); - function onInitialString(aResults) - { - let clickable = aResults[0].longStrings[0]; - ok(clickable, "long string ellipsis is shown"); - clickable.scrollIntoView(false); + let clickable = results[0].longStrings[0]; + ok(clickable, "long string ellipsis is shown"); + clickable.scrollIntoView(false); - EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow); + EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow); - info("wait for long string expansion"); + info("wait for long string expansion"); - waitForMessages({ - webconsole: hud, - messages: [ - { - name: "find 'foobaz' after expand, but no 'boom!' at the end", - text: "foobaz", - noText: "boom!", - category: CATEGORY_WEBDEV, - longString: false, - }, - { - text: "too long to be displayed", - longString: false, - }, - ], - }).then(finishTest); - } -} + yield waitForMessages({ + webconsole: hud, + messages: [ + { + name: "find 'foobaz' after expand, but no 'boom!' at the end", + text: "foobaz", + noText: "boom!", + category: CATEGORY_WEBDEV, + longString: false, + }, + { + text: "too long to be displayed", + longString: false, + }, + ], + }); +}); diff --git a/browser/devtools/webconsole/test/browser_netpanel_longstring_expand.js b/browser/devtools/webconsole/test/browser_netpanel_longstring_expand.js index bbe554d1eb8e..d19c393a7a45 100644 --- a/browser/devtools/webconsole/test/browser_netpanel_longstring_expand.js +++ b/browser/devtools/webconsole/test/browser_netpanel_longstring_expand.js @@ -21,11 +21,9 @@ const TEST_IMG_BASE64 = let testDriver; function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testNetworkPanel); - }, true); + loadTab(TEST_URI).then(() => { + openConsole().then(testNetworkPanel); + }); } function testNetworkPanel() { diff --git a/browser/devtools/webconsole/test/browser_output_breaks_after_console_dir_uninspectable.js b/browser/devtools/webconsole/test/browser_output_breaks_after_console_dir_uninspectable.js index 27bb03399afb..b7e86b94c021 100644 --- a/browser/devtools/webconsole/test/browser_output_breaks_after_console_dir_uninspectable.js +++ b/browser/devtools/webconsole/test/browser_output_breaks_after_console_dir_uninspectable.js @@ -5,27 +5,20 @@ // Make sure that the Web Console output does not break after we try to call // console.dir() for objects that are not inspectable. -function test() -{ - waitForExplicitFinish(); +const TEST_URI = "data:text/html;charset=utf8,test for bug 773466"; - addTab("data:text/html;charset=utf8,test for bug 773466"); +let test = asyncTest(function* () { + yield loadTab(TEST_URI); - gBrowser.selectedBrowser.addEventListener("load", function onLoad() { - gBrowser.selectedBrowser.removeEventListener("load", onLoad, true); - openConsole(null, performTest); - }, true); -} + let hud = yield openConsole(); -function performTest(hud) -{ hud.jsterm.clearOutput(true); hud.jsterm.execute("console.log('fooBug773466a')"); hud.jsterm.execute("myObj = Object.create(null)"); hud.jsterm.execute("console.dir(myObj)"); - waitForMessages({ + yield waitForMessages({ webconsole: hud, messages: [{ text: "fooBug773466a", @@ -36,15 +29,16 @@ function performTest(hud) name: "console.dir output", consoleDir: "[object Object]", }], - }).then(() => { - content.console.log("fooBug773466b"); - waitForMessages({ - webconsole: hud, - messages: [{ - text: "fooBug773466b", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - }], - }).then(finishTest); + }) + + content.console.log("fooBug773466b"); + + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "fooBug773466b", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }], }); -} +}); diff --git a/browser/devtools/webconsole/test/browser_output_longstring_expand.js b/browser/devtools/webconsole/test/browser_output_longstring_expand.js index 1b8225808b76..7d5d785c3e95 100644 --- a/browser/devtools/webconsole/test/browser_output_longstring_expand.js +++ b/browser/devtools/webconsole/test/browser_output_longstring_expand.js @@ -4,10 +4,9 @@ // Test that long strings can be expanded in the console output. -function test() -{ - waitForExplicitFinish(); +const TEST_URI = "data:text/html;charset=utf8,test for bug 787981 - check that long strings can be expanded in the output."; +let test = asyncTest(function* () { let tempScope = {}; Cu.import("resource://gre/modules/devtools/dbg-server.jsm", tempScope); let DebuggerServer = tempScope.DebuggerServer; @@ -17,77 +16,68 @@ function test() let initialString = longString.substring(0, DebuggerServer.LONG_STRING_INITIAL_LENGTH); - addTab("data:text/html;charset=utf8,test for bug 787981 - check that long strings can be expanded in the output."); + yield loadTab(TEST_URI); - let hud = null; + let hud = yield openConsole(); - gBrowser.selectedBrowser.addEventListener("load", function onLoad() { - gBrowser.selectedBrowser.removeEventListener("load", onLoad, true); - openConsole(null, performTest); - }, true); + hud.jsterm.clearOutput(true); + hud.jsterm.execute("console.log('bazbaz', '" + longString +"', 'boom')"); - function performTest(aHud) - { - hud = aHud; - hud.jsterm.clearOutput(true); - hud.jsterm.execute("console.log('bazbaz', '" + longString +"', 'boom')"); + let [result] = yield waitForMessages({ + webconsole: hud, + messages: [{ + name: "console.log output", + text: ["bazbaz", "boom", initialString], + noText: "foobar", + longString: true, + }], + }); - waitForMessages({ - webconsole: hud, - messages: [{ - name: "console.log output", - text: ["bazbaz", "boom", initialString], - noText: "foobar", - longString: true, - }], - }).then(onConsoleMessage); - } + let clickable = result.longStrings[0]; + ok(clickable, "long string ellipsis is shown"); - function onConsoleMessage([result]) - { - let clickable = result.longStrings[0]; - ok(clickable, "long string ellipsis is shown"); + clickable.scrollIntoView(false); - clickable.scrollIntoView(false); + EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow); - EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow); + yield waitForMessages({ + webconsole: hud, + messages: [{ + name: "full string", + text: ["bazbaz", "boom", longString], + category: CATEGORY_WEBDEV, + longString: false, + }], + }); - waitForMessages({ - webconsole: hud, - messages: [{ - name: "full string", - text: ["bazbaz", "boom", longString], - category: CATEGORY_WEBDEV, - longString: false, - }], - }).then(() => { - hud.jsterm.clearOutput(true); - hud.jsterm.execute("'" + longString +"'", onExecute); - }); - } + hud.jsterm.clearOutput(true); + let msg = yield execute(hud, "'" + longString +"'"); - function onExecute(msg) - { - isnot(msg.textContent.indexOf(initialString), -1, - "initial string is shown"); - is(msg.textContent.indexOf(longString), -1, - "full string is not shown"); + isnot(msg.textContent.indexOf(initialString), -1, + "initial string is shown"); + is(msg.textContent.indexOf(longString), -1, + "full string is not shown"); - let clickable = msg.querySelector(".longStringEllipsis"); - ok(clickable, "long string ellipsis is shown"); + clickable = msg.querySelector(".longStringEllipsis"); + ok(clickable, "long string ellipsis is shown"); - clickable.scrollIntoView(false); + clickable.scrollIntoView(false); - EventUtils.synthesizeMouse(clickable, 3, 4, {}, hud.iframeWindow); + EventUtils.synthesizeMouse(clickable, 3, 4, {}, hud.iframeWindow); - waitForMessages({ - webconsole: hud, - messages: [{ - name: "full string", - text: longString, - category: CATEGORY_OUTPUT, - longString: false, - }], - }).then(finishTest); - } + yield waitForMessages({ + webconsole: hud, + messages: [{ + name: "full string", + text: longString, + category: CATEGORY_OUTPUT, + longString: false, + }], + }) +}); + +function execute(hud, str) { + let deferred = promise.defer(); + hud.jsterm.execute(str, deferred.resolve); + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_repeated_messages_accuracy.js b/browser/devtools/webconsole/test/browser_repeated_messages_accuracy.js index 153b5e475025..bd092bbc2003 100644 --- a/browser/devtools/webconsole/test/browser_repeated_messages_accuracy.js +++ b/browser/devtools/webconsole/test/browser_repeated_messages_accuracy.js @@ -8,25 +8,36 @@ // different lines of code, or from different severities, etc. // See bugs 720180 and 800510. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-repeated-messages.html"; +const PREF = "devtools.webconsole.persistlog"; -function test() { - const PREF = "devtools.webconsole.persistlog"; +let test = asyncTest(function* () { Services.prefs.setBoolPref(PREF, true); - registerCleanupFunction(() => Services.prefs.clearUserPref(PREF)); - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} + let { browser } = yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + yield consoleOpened(hud); + + let loaded = loadBrowser(browser); + BrowserReload(); + yield loaded; + + yield testCSSRepeats(hud); + yield testCSSRepeatsAfterReload(hud); + yield testConsoleRepeats(hud); + + Services.prefs.clearUserPref(PREF); +}); function consoleOpened(hud) { // Check that css warnings are not coalesced if they come from different lines. info("waiting for 2 css warnings"); - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [{ name: "two css warnings", @@ -34,35 +45,30 @@ function consoleOpened(hud) { count: 2, repeats: 1, }], - }).then(testCSSRepeats.bind(null, hud)); + }); } function testCSSRepeats(hud) { - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); + info("wait for repeats after page reload"); - info("wait for repeats after page reload"); - - waitForMessages({ - webconsole: hud, - messages: [{ - name: "two css warnings, repeated twice", - category: CATEGORY_CSS, - repeats: 2, - count: 2, - }], - }).then(testCSSRepeatsAfterReload.bind(null, hud)); - }, true); - content.location.reload(); + return waitForMessages({ + webconsole: hud, + messages: [{ + name: "two css warnings, repeated twice", + category: CATEGORY_CSS, + repeats: 2, + count: 2, + }], + }); } function testCSSRepeatsAfterReload(hud) { hud.jsterm.clearOutput(true); - content.wrappedJSObject.testConsole(); + hud.jsterm.execute("testConsole()"); info("wait for repeats with the console API"); - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [ { @@ -84,17 +90,18 @@ function testCSSRepeatsAfterReload(hud) { repeats: 1, }, ], - }).then(testConsoleRepeats.bind(null, hud)); + }) } function testConsoleRepeats(hud) { hud.jsterm.clearOutput(true); hud.jsterm.execute("undefined"); + content.console.log("undefined"); info("make sure console API messages are not coalesced with jsterm output"); - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [ { @@ -114,5 +121,5 @@ function testConsoleRepeats(hud) { repeats: 1, }, ], - }).then(finishTest); + }); } diff --git a/browser/devtools/webconsole/test/browser_result_format_as_string.js b/browser/devtools/webconsole/test/browser_result_format_as_string.js index 0e4b66e4587f..70c3cc61ade7 100644 --- a/browser/devtools/webconsole/test/browser_result_format_as_string.js +++ b/browser/devtools/webconsole/test/browser_result_format_as_string.js @@ -5,7 +5,7 @@ /////////////////// // // Whitelisting this test. -// As part of bug 1077403, the leaking uncaught rejection should be fixed. +// As part of bug 1077403, the leaking uncaught rejection should be fixed. // thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Connection closed"); @@ -13,36 +13,31 @@ thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Connection closed"); const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-result-format-as-string.html"; -function test() -{ - waitForExplicitFinish(); +let test = asyncTest(function* () { + yield loadTab(TEST_URI); - addTab(TEST_URI); + let hud = yield openConsole(); - gBrowser.selectedBrowser.addEventListener("load", function onLoad() { - gBrowser.selectedBrowser.removeEventListener("load", onLoad, true); - openConsole(null, performTest); - }, true); -} - -function performTest(hud) -{ hud.jsterm.clearOutput(true); - hud.jsterm.execute("document.querySelector('p')", (msg) => { - is(hud.outputNode.textContent.indexOf("bug772506_content"), -1, - "no content element found"); - ok(!hud.outputNode.querySelector("#foobar"), "no #foobar element found"); + let msg = yield execute(hud, "document.querySelector('p')"); - ok(msg, "eval output node found"); - is(msg.textContent.indexOf("

"), -1, - "
string is not displayed"); - isnot(msg.textContent.indexOf("

"), -1, - "

string is displayed"); + is(hud.outputNode.textContent.indexOf("bug772506_content"), -1, + "no content element found"); + ok(!hud.outputNode.querySelector("#foobar"), "no #foobar element found"); - EventUtils.synthesizeMouseAtCenter(msg, {type: "mousemove"}); - ok(!gBrowser._bug772506, "no content variable"); + ok(msg, "eval output node found"); + is(msg.textContent.indexOf("

"), -1, + "
string is not displayed"); + isnot(msg.textContent.indexOf("

"), -1, + "

string is displayed"); - finishTest(); - }); -} + EventUtils.synthesizeMouseAtCenter(msg, {type: "mousemove"}); + ok(!gBrowser._bug772506, "no content variable"); +}); + +function execute(hud, str) { + let deferred = promise.defer(); + hud.jsterm.execute(str, deferred.resolve); + return deferred.promise; +} \ No newline at end of file diff --git a/browser/devtools/webconsole/test/browser_warn_user_about_replaced_api.js b/browser/devtools/webconsole/test/browser_warn_user_about_replaced_api.js index 42e011339f99..adef430ada2f 100644 --- a/browser/devtools/webconsole/test/browser_warn_user_about_replaced_api.js +++ b/browser/devtools/webconsole/test/browser_warn_user_about_replaced_api.js @@ -5,75 +5,77 @@ const TEST_REPLACED_API_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-replaced-api.html"; const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/testscript.js"; +const PREF = "devtools.webconsole.persistlog"; -function test() { - waitForExplicitFinish(); - - const PREF = "devtools.webconsole.persistlog"; +let test = asyncTest(function* () { Services.prefs.setBoolPref(PREF, true); - registerCleanupFunction(() => Services.prefs.clearUserPref(PREF)); - // First test that the warning does not appear on a page that doesn't override - // the window.console object. - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testWarningNotPresent); - }, true); + let { browser } = yield loadTab(TEST_URI); + let hud = yield openConsole(); - function testWarningNotPresent(hud) - { + yield testWarningNotPresent(hud); + + let loaded = loadBrowser(browser); + content.location = TEST_REPLACED_API_URI; + yield loaded; + + let hud2 = yield openConsole(); + + yield testWarningPresent(hud2); + + Services.prefs.clearUserPref(PREF); +}); + +function testWarningNotPresent(hud) +{ + let deferred = promise.defer(); + + is(hud.outputNode.textContent.indexOf("logging API"), -1, + "no warning displayed"); + + // Bug 862024: make sure the warning doesn't show after page reload. + info("reload " + TEST_URI); + executeSoon(() => content.location.reload()); + + waitForMessages({ + webconsole: hud, + messages: [{ + text: "testscript.js", + category: CATEGORY_NETWORK, + }], + }).then(() => executeSoon(() => { is(hud.outputNode.textContent.indexOf("logging API"), -1, "no warning displayed"); + closeConsole().then(deferred.resolve); + })); - // Bug 862024: make sure the warning doesn't show after page reload. - info("reload " + TEST_URI); - executeSoon(() => content.location.reload()); - - waitForMessages({ - webconsole: hud, - messages: [{ - text: "testscript.js", - category: CATEGORY_NETWORK, - }], - }).then(() => executeSoon(() => { - is(hud.outputNode.textContent.indexOf("logging API"), -1, - "no warning displayed"); - - closeConsole(null, loadTestPage); - })); - } - - function loadTestPage() - { - info("load test " + TEST_REPLACED_API_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testWarningPresent); - }, true); - content.location = TEST_REPLACED_API_URI; - } - - function testWarningPresent(hud) - { - info("wait for the warning to show"); - let warning = { - webconsole: hud, - messages: [{ - text: /logging API .+ disabled by a script/, - category: CATEGORY_JS, - severity: SEVERITY_WARNING, - }], - }; - - waitForMessages(warning).then(() => { - hud.jsterm.clearOutput(); - - executeSoon(() => { - info("reload the test page and wait for the warning to show"); - waitForMessages(warning).then(finishTest); - content.location.reload(); - }); - }); - } + return deferred.promise; } + +function testWarningPresent(hud) +{ + info("wait for the warning to show"); + let deferred = promise.defer(); + + let warning = { + webconsole: hud, + messages: [{ + text: /logging API .+ disabled by a script/, + category: CATEGORY_JS, + severity: SEVERITY_WARNING, + }], + }; + + waitForMessages(warning).then(() => { + hud.jsterm.clearOutput(); + + executeSoon(() => { + info("reload the test page and wait for the warning to show"); + waitForMessages(warning).then(deferred.resolve); + content.location.reload(); + }); + }); + + return deferred.promise; +} + diff --git a/browser/devtools/webconsole/test/browser_webconsole_allow_mixedcontent_securityerrors.js b/browser/devtools/webconsole/test/browser_webconsole_allow_mixedcontent_securityerrors.js index 27189cdb67e0..6de4425e66cd 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_allow_mixedcontent_securityerrors.js +++ b/browser/devtools/webconsole/test/browser_webconsole_allow_mixedcontent_securityerrors.js @@ -12,41 +12,45 @@ const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-mixedcontent-securityerrors.html"; const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Security/MixedContent"; -function test() +let test = asyncTest(function* () { + yield pushPrefEnv(); + + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + let results = yield waitForMessages({ + webconsole: hud, + messages: [ + { + name: "Logged mixed active content", + text: "Loading mixed (insecure) active content on a secure page \"http://example.com/\"", + category: CATEGORY_SECURITY, + severity: SEVERITY_WARNING, + objects: true, + }, + { + name: "Logged mixed passive content - image", + text: "Loading mixed (insecure) display content on a secure page \"http://example.com/tests/image/test/mochitest/blue.png\"", + category: CATEGORY_SECURITY, + severity: SEVERITY_WARNING, + objects: true, + }, + ], + }); + + testClickOpenNewTab(hud, results); +}); + +function pushPrefEnv() { - SpecialPowers.pushPrefEnv({"set": + let deferred = promise.defer(); + let options = {"set": [["security.mixed_content.block_active_content", false], ["security.mixed_content.block_display_content", false] - ]}, loadingMixedContentTest); -} - -function loadingMixedContentTest() -{ - addTab(TEST_URI); - browser.addEventListener("load", function onLoad(aEvent) { - browser.removeEventListener(aEvent.type, onLoad, true); - openConsole(null, function testSecurityErrorLogged (hud) { - waitForMessages({ - webconsole: hud, - messages: [ - { - name: "Logged mixed active content", - text: "Loading mixed (insecure) active content on a secure page \"http://example.com/\"", - category: CATEGORY_SECURITY, - severity: SEVERITY_WARNING, - objects: true, - }, - { - name: "Logged mixed passive content - image", - text: "Loading mixed (insecure) display content on a secure page \"http://example.com/tests/image/test/mochitest/blue.png\"", - category: CATEGORY_SECURITY, - severity: SEVERITY_WARNING, - objects: true, - }, - ], - }).then((results) => testClickOpenNewTab(hud, results)); - }); - }, true); + ]}; + SpecialPowers.pushPrefEnv(options, deferred.resolve); + return deferred.promise; } function testClickOpenNewTab(hud, results) { @@ -67,6 +71,4 @@ function testClickOpenNewTab(hud, results) { warningNode.ownerDocument.defaultView); ok(linkOpened, "Clicking the Learn More Warning node opens the desired page"); window.openUILinkIn = oldOpenUILinkIn; - - finishTest(); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_assert.js b/browser/devtools/webconsole/test/browser_webconsole_assert.js index 6dce90a75059..c33f121f1058 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_assert.js +++ b/browser/devtools/webconsole/test/browser_webconsole_assert.js @@ -7,16 +7,17 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-assert.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + yield consoleOpened(hud); +}); function consoleOpened(hud) { - waitForMessages({ + hud.jsterm.execute("test()"); + + return waitForMessages({ webconsole: hud, messages: [{ text: "start", @@ -40,11 +41,6 @@ function consoleOpened(hud) { }], }).then(() => { let nodes = hud.outputNode.querySelectorAll(".message"); - is(nodes.length, 4, "only four messages are displayed, no output from the true assert"); - finishTest(); + is(nodes.length, 6, "only six messages are displayed, no output from the true assert"); }); - - let button = content.document.querySelector("button"); - ok(button, "we have the button"); - EventUtils.sendMouseEvent({ type: "click" }, button, content); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js b/browser/devtools/webconsole/test/browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js index a304db1dc1cc..907941ba9911 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js +++ b/browser/devtools/webconsole/test/browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js @@ -9,34 +9,32 @@ // Test that properties starting with underscores or dollars can be // autocompleted (bug 967468). -function test() { + +let test = asyncTest(function*() { const TEST_URI = "data:text/html;charset=utf8,test autocompletion with $ or _"; - Task.spawn(runner).then(finishTest); + yield loadTab(TEST_URI); - function* runner() { - function autocomplete(term) { - let deferred = promise.defer(); + function autocomplete(term) { + let deferred = promise.defer(); - jsterm.setInputValue(term); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, deferred.resolve); + jsterm.setInputValue(term); + jsterm.complete(jsterm.COMPLETE_HINT_ONLY, deferred.resolve); - yield deferred.promise; + yield deferred.promise; - ok(popup.itemCount > 0, "There's suggestions for '" + term + "'"); - } - - yield addTab(TEST_URI); - let { jsterm } = yield openConsole(tab); - let popup = jsterm.autocompletePopup; - - jsterm.execute("let testObject = {$$aaab: '', $$aaac: ''}"); - - // Should work with bug 967468. - yield autocomplete("Object.__d"); - yield autocomplete("testObject.$$a"); - - // Here's when things go wrong in bug 967468. - yield autocomplete("Object.__de"); - yield autocomplete("testObject.$$aa"); + ok(popup.itemCount > 0, "There's suggestions for '" + term + "'"); } -} + + let { jsterm } = yield openConsole(); + let popup = jsterm.autocompletePopup; + + jsterm.execute("let testObject = {$$aaab: '', $$aaac: ''}"); + + // Should work with bug 967468. + yield autocomplete("Object.__d"); + yield autocomplete("testObject.$$a"); + + // Here's when things go wrong in bug 967468. + yield autocomplete("Object.__de"); + yield autocomplete("testObject.$$aa"); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_autocomplete_and_selfxss.js b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_and_selfxss.js index 4a2699751026..69ccb443e36b 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_autocomplete_and_selfxss.js +++ b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_and_selfxss.js @@ -9,7 +9,17 @@ XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper", "nsIClipboardHelper"); let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils; +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + yield consoleOpened(hud); +}); + function consoleOpened(HUD) { + let deferred = promise.defer(); + let jsterm = HUD.jsterm; let stringToCopy = "foobazbarBug642615"; @@ -99,7 +109,7 @@ function consoleOpened(HUD) { ok(!jsterm.completeNode.value, "no completion value after paste (ctrl-v)"); // using executeSoon() to get out of the webconsole event loop. - executeSoon(finishTest); + executeSoon(deferred.resolve); }); // Get out of the webconsole event loop. @@ -112,12 +122,6 @@ function consoleOpened(HUD) { jsterm.once("autocomplete-updated", onCompletionValue); EventUtils.synthesizeKey("u", {}); -} -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_autocomplete_in_debugger_stackframe.js b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_in_debugger_stackframe.js index 194170aa9ce7..c3c838cb1003 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_autocomplete_in_debugger_stackframe.js +++ b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_in_debugger_stackframe.js @@ -13,14 +13,12 @@ let testDriver, gStackframes; function test() { requestLongerTimeout(2); - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, function(hud) { + loadTab(TEST_URI).then(() => { + openConsole().then((hud) => { testDriver = testCompletion(hud); testDriver.next(); }); - }, true); + }); } function testNext() { @@ -140,7 +138,7 @@ function testCompletion(hud) { gStackframes.selectFrame(1); info("openConsole"); - executeSoon(() => openConsole(null, () => testDriver.next())); + executeSoon(() => openConsole().then(() => testDriver.next())); }); yield undefined; @@ -235,7 +233,7 @@ function debuggerOpened(aResult) function onFramesAdded() { info("onFramesAdded, openConsole() now"); - executeSoon(() => openConsole(null, testNext)); + executeSoon(() => openConsole().then(testNext)); } function finishUp() { diff --git a/browser/devtools/webconsole/test/browser_webconsole_autocomplete_popup_close_on_tab_switch.js b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_popup_close_on_tab_switch.js index 5283f9feaa8e..19c3ceb49204 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_autocomplete_popup_close_on_tab_switch.js +++ b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_popup_close_on_tab_switch.js @@ -7,36 +7,27 @@ const TEST_URI = "data:text/html;charset=utf-8,

bug 900448 - autocomplete popup closes on tab switch"; -let popup = null; +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); + let popup = hud.jsterm.autocompletePopup; + let popupShown = onPopupShown(popup._panel); -registerCleanupFunction(function() { - popup = null; + hud.jsterm.setInputValue("sc"); + EventUtils.synthesizeKey("r", {}); + + yield popupShown; + + ok(!popup.isOpen, "Popup closes on tab switch"); }); -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} +function onPopupShown(panel) { + let finished = promise.defer(); -function consoleOpened(HUD) { - popup = HUD.jsterm.autocompletePopup; - - popup._panel.addEventListener("popupshown", function popupOpened() { - popup._panel.removeEventListener("popupshown", popupOpened, false); - addTab("data:text/html;charset=utf-8,

testing autocomplete closes"); - gBrowser.selectedBrowser.addEventListener("load", tab2Loaded, true); + panel.addEventListener("popupshown", function popupOpened() { + panel.removeEventListener("popupshown", popupOpened, false); + loadTab("data:text/html;charset=utf-8,

testing autocomplete closes").then(finished.resolve); }, false); - HUD.jsterm.setInputValue("sc"); - EventUtils.synthesizeKey("r", {}); -} - -function tab2Loaded() { - gBrowser.selectedBrowser.removeEventListener("load", tab2Loaded, true); - ok(!popup.isOpen, "Popup closes on tab switch"); - gBrowser.removeCurrentTab(); - finishTest(); + return finished.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_basic_net_logging.js b/browser/devtools/webconsole/test/browser_webconsole_basic_net_logging.js index 2bc7269b82da..c3c8005d4af8 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_basic_net_logging.js +++ b/browser/devtools/webconsole/test/browser_webconsole_basic_net_logging.js @@ -6,39 +6,37 @@ // Tests that the page's resources are displayed in the console as they're // loaded +"use strict"; + const TEST_NETWORK_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-network.html" + "?_date=" + Date.now(); -function test() { - addTab("data:text/html;charset=utf-8,Web Console basic network logging test"); - browser.addEventListener("load", onLoad, true); +let test = asyncTest(function* () { + yield loadTab("data:text/html;charset=utf-8,Web Console basic network logging test"); + let hud = yield openConsole(); - function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, function(hud) { - content.location = TEST_NETWORK_URI; - waitForMessages({ - webconsole: hud, - messages: [{ - text: "running network console", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - }, - { - text: "test-network.html", - category: CATEGORY_NETWORK, - severity: SEVERITY_LOG, - }, - { - text: "testscript.js", - category: CATEGORY_NETWORK, - severity: SEVERITY_LOG, - }, - { - text: "test-image.png", - category: CATEGORY_NETWORK, - severity: SEVERITY_LOG, - }], - }).then(finishTest); - }); - } -} + content.location = TEST_NETWORK_URI; + + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "running network console", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }, + { + text: "test-network.html", + category: CATEGORY_NETWORK, + severity: SEVERITY_LOG, + }, + { + text: "testscript.js", + category: CATEGORY_NETWORK, + severity: SEVERITY_LOG, + }, + { + text: "test-image.png", + category: CATEGORY_NETWORK, + severity: SEVERITY_LOG, + }], + }); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_block_mixedcontent_securityerrors.js b/browser/devtools/webconsole/test/browser_webconsole_block_mixedcontent_securityerrors.js index fe6de9a9bc23..dd295d1699f6 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_block_mixedcontent_securityerrors.js +++ b/browser/devtools/webconsole/test/browser_webconsole_block_mixedcontent_securityerrors.js @@ -15,46 +15,51 @@ const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-mixedcontent-securityerrors.html"; const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Security/MixedContent"; -function test() + +let test = asyncTest(function* () { + yield pushPrefEnv(); + + let { browser } = yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + let results = yield waitForMessages({ + webconsole: hud, + messages: [ + { + name: "Logged blocking mixed active content", + text: "Blocked loading mixed active content \"http://example.com/\"", + category: CATEGORY_SECURITY, + severity: SEVERITY_ERROR, + objects: true, + }, + { + name: "Logged blocking mixed passive content - image", + text: "Blocked loading mixed active content \"http://example.com/\"", + category: CATEGORY_SECURITY, + severity: SEVERITY_ERROR, + objects: true, + }, + ], + }); + + testClickOpenNewTab(hud, results[0]); + + let results2 = yield mixedContentOverrideTest2(hud, browser); + + testClickOpenNewTab(hud, results2[0]); +}); + +function pushPrefEnv() { - SpecialPowers.pushPrefEnv({"set": [["security.mixed_content.block_active_content", true], - ["security.mixed_content.block_display_content", true]]}, blockMixedContentTest1); + let deferred = promise.defer(); + let options = {"set": [["security.mixed_content.block_active_content", true], + ["security.mixed_content.block_display_content", true]]}; + SpecialPowers.pushPrefEnv(options, deferred.resolve); + return deferred.promise; } -function blockMixedContentTest1() -{ - addTab(TEST_URI); - browser.addEventListener("load", function onLoad(aEvent) { - browser.removeEventListener(aEvent.type, onLoad, true); - openConsole(null, function testSecurityErrorLogged (hud) { - waitForMessages({ - webconsole: hud, - messages: [ - { - name: "Logged blocking mixed active content", - text: "Blocked loading mixed active content \"http://example.com/\"", - category: CATEGORY_SECURITY, - severity: SEVERITY_ERROR, - objects: true, - }, - { - name: "Logged blocking mixed passive content - image", - text: "Blocked loading mixed active content \"http://example.com/\"", - category: CATEGORY_SECURITY, - severity: SEVERITY_ERROR, - objects: true, - }, - ], - }).then(([result]) => { - testClickOpenNewTab(hud, result); - // Call the second (MCB override) test. - mixedContentOverrideTest2(hud); - }); - }); - }, true); -} - -function mixedContentOverrideTest2(hud) +function mixedContentOverrideTest2(hud, browser) { var notification = PopupNotifications.getNotification("bad-content", browser); ok(notification, "Mixed Content Doorhanger did appear"); @@ -64,7 +69,7 @@ function mixedContentOverrideTest2(hud) PopupNotifications.panel.firstChild.disableMixedContentProtection(); notification.remove(); - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [ { @@ -84,9 +89,6 @@ function mixedContentOverrideTest2(hud) objects: true, }, ], - }).then(([result]) => { - testClickOpenNewTab(hud, result); - finishTest(); }); } @@ -109,5 +111,4 @@ function testClickOpenNewTab(hud, match) { warningNode.ownerDocument.defaultView); ok(linkOpened, "Clicking the Learn More Warning node opens the desired page"); window.openUILinkIn = oldOpenUILinkIn; - } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_1006027_message_timestamps_incorrect.js b/browser/devtools/webconsole/test/browser_webconsole_bug_1006027_message_timestamps_incorrect.js index 1329e2c5cce9..6dd85e9399d6 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_1006027_message_timestamps_incorrect.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_1006027_message_timestamps_incorrect.js @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + function test() { Task.spawn(runner).then(finishTest); @@ -37,4 +39,3 @@ function test() { ok(Math.abs(maxTimestamp - minTimestamp) < 1000, "console.log message timestamp spread < 1000ms confirmed"); } } - diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_1010953_cspro.js b/browser/devtools/webconsole/test/browser_webconsole_bug_1010953_cspro.js index ddb09510a3de..078f44b74451 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_1010953_cspro.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_1010953_cspro.js @@ -14,46 +14,34 @@ So we expect a warning (image has been blocked) and a report The expected console messages in the constants CSP_VIOLATION_MSG and CSP_REPORT_MSG are confirmed to be found in the console messages. */ +"use strict"; + +const TEST_URI = "data:text/html;charset=utf8,Web Console CSP report only test (bug 1010953)"; const TEST_VIOLATION = "http://example.com/browser/browser/devtools/webconsole/test/test_bug_1010953_cspro.html"; const CSP_VIOLATION_MSG = 'Content Security Policy: The page\'s settings blocked the loading of a resource at http://some.example.com/test.png ("img-src http://example.com").'; const CSP_REPORT_MSG = 'Content Security Policy: The page\'s settings observed the loading of a resource at http://some.example.com/test_bug_1010953_cspro.js ("script-src http://example.com"). A CSP report is being sent.'; +let test = asyncTest(function* () { + let { browser } = yield loadTab(TEST_URI); -let hud = undefined; + let hud = yield openConsole(); -function test() { - addTab("data:text/html;charset=utf8,Web Console CSP report only test (bug 1010953)"); - browser.addEventListener("load", function _onLoad() { - browser.removeEventListener("load", _onLoad, true); - openConsole(null, loadDocument); - }, true); -} + hud.jsterm.clearOutput(); -function loadDocument(theHud){ - hud = theHud; - hud.jsterm.clearOutput() - browser.addEventListener("load", onLoad, true); + let loaded = loadBrowser(browser); content.location = TEST_VIOLATION; -} + yield loaded; -function onLoad(aEvent) { - browser.removeEventListener("load", onLoad, true); - testViolationMessage(); -} - -function testViolationMessage(){ let aOutputNode = hud.outputNode; - waitForSuccess({ - name: "Confirmed that CSP and CSP-Report-Only log different messages to the console.", - validatorFn: function() { - console.log(hud.outputNode.textContent); - let success = false; - success = hud.outputNode.textContent.indexOf(CSP_VIOLATION_MSG) > -1 && - hud.outputNode.textContent.indexOf(CSP_REPORT_MSG) > -1; - return success; - }, - successFn: finishTest, - failureFn: finishTest, - }); -} + yield waitForSuccess({ + name: "Confirmed that CSP and CSP-Report-Only log different messages to the console.", + validator: function() { + console.log(hud.outputNode.textContent); + let success = false; + success = hud.outputNode.textContent.indexOf(CSP_VIOLATION_MSG) > -1 && + hud.outputNode.textContent.indexOf(CSP_REPORT_MSG) > -1; + return success; + } + }); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_578437_page_reload.js b/browser/devtools/webconsole/test/browser_webconsole_bug_578437_page_reload.js index 2c6e294fd074..f396259a5af0 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_578437_page_reload.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_578437_page_reload.js @@ -6,20 +6,20 @@ // Tests that the console object still exists after a page reload. const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; +let browser; + function test() { - addTab(TEST_URI); + loadTab(TEST_URI).then({ + openConsole().then((tab) => { + browser = tab.browser; + + browser.addEventListener("DOMContentLoaded", testPageReload, false); + content.location.reload(); + }); + }); browser.addEventListener("DOMContentLoaded", onLoad, false); } -function onLoad() { - browser.removeEventListener("DOMContentLoaded", onLoad, false); - - openConsole(); - - browser.addEventListener("DOMContentLoaded", testPageReload, false); - content.location.reload(); -} - function testPageReload() { browser.removeEventListener("DOMContentLoaded", testPageReload, false); @@ -33,6 +33,7 @@ function testPageReload() { is(typeof console.error, "function", "console.error is a function"); is(typeof console.exception, "function", "console.exception is a function"); + browser = null; finishTest(); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_579412_input_focus.js b/browser/devtools/webconsole/test/browser_webconsole_bug_579412_input_focus.js index d13a97fe0b1b..e726a0595845 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_579412_input_focus.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_579412_input_focus.js @@ -5,21 +5,15 @@ // Tests that the input field is focused when the console is opened. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("DOMContentLoaded", testInputFocus, false); -} - -function testInputFocus() { - browser.removeEventListener("DOMContentLoaded", testInputFocus, false); - - openConsole(null, function(hud) { - let inputNode = hud.jsterm.inputNode; - ok(inputNode.getAttribute("focused"), "input node is focused"); - - finishTest(); - }); -} +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); + hud.jsterm.clearOutput(); + let inputNode = hud.jsterm.inputNode; + ok(inputNode.getAttribute("focused"), "input node is focused"); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_580001_closing_after_completion.js b/browser/devtools/webconsole/test/browser_webconsole_bug_580001_closing_after_completion.js index ed9c9f990d8e..b71d83bd4dda 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_580001_closing_after_completion.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_580001_closing_after_completion.js @@ -8,15 +8,17 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testClosingAfterCompletion); - }, true); -} -function testClosingAfterCompletion(hud) { +let test = asyncTest(function* () { + let { browser } = yield loadTab(TEST_URI); + + let hud = yield openConsole(); + yield testClosingAfterCompletion(hud, browser); +}); + +function testClosingAfterCompletion(hud, browser) { + let deferred = promise.defer(); + let inputNode = hud.jsterm.inputNode; let errorWhileClosing = false; @@ -32,7 +34,7 @@ function testClosingAfterCompletion(hud) { gDevTools.once("toolbox-destroyed", function() { browser.removeEventListener("error", errorListener, false); is(errorWhileClosing, false, "no error while closing the WebConsole"); - finishTest(); + deferred.resolve(); }); if (Services.appinfo.OS == "Darwin") { @@ -40,5 +42,7 @@ function testClosingAfterCompletion(hud) { } else { EventUtils.synthesizeKey("i", { accelKey: true, shiftKey: true }); } + + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_580454_timestamp_l10n.js b/browser/devtools/webconsole/test/browser_webconsole_bug_580454_timestamp_l10n.js index d1c9487c31b1..b2887ddae2e8 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_580454_timestamp_l10n.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_580454_timestamp_l10n.js @@ -10,27 +10,21 @@ // Tests that appropriately-localized timestamps are printed. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("DOMContentLoaded", testTimestamp, false); - - function testTimestamp() - { - browser.removeEventListener("DOMContentLoaded", testTimestamp, false); - const TEST_TIMESTAMP = 12345678; - let date = new Date(TEST_TIMESTAMP); - let localizedString = WCU_l10n.timestampString(TEST_TIMESTAMP); - isnot(localizedString.indexOf(date.getHours()), -1, "the localized " + - "timestamp contains the hours"); - isnot(localizedString.indexOf(date.getMinutes()), -1, "the localized " + - "timestamp contains the minutes"); - isnot(localizedString.indexOf(date.getSeconds()), -1, "the localized " + - "timestamp contains the seconds"); - isnot(localizedString.indexOf(date.getMilliseconds()), -1, "the localized " + - "timestamp contains the milliseconds"); - finishTest(); - } -} - +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + const TEST_TIMESTAMP = 12345678; + let date = new Date(TEST_TIMESTAMP); + let localizedString = WCU_l10n.timestampString(TEST_TIMESTAMP); + isnot(localizedString.indexOf(date.getHours()), -1, "the localized " + + "timestamp contains the hours"); + isnot(localizedString.indexOf(date.getMinutes()), -1, "the localized " + + "timestamp contains the minutes"); + isnot(localizedString.indexOf(date.getSeconds()), -1, "the localized " + + "timestamp contains the seconds"); + isnot(localizedString.indexOf(date.getMilliseconds()), -1, "the localized " + + "timestamp contains the milliseconds"); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_582201_duplicate_errors.js b/browser/devtools/webconsole/test/browser_webconsole_bug_582201_duplicate_errors.js index 0425711a1111..6032cb761e64 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_582201_duplicate_errors.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_582201_duplicate_errors.js @@ -6,42 +6,39 @@ // Tests that exceptions thrown by content don't show up twice in the Web // Console. -const TEST_DUPLICATE_ERROR_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-duplicate-error.html"; +"use strict"; -function test() { - addTab("data:text/html;charset=utf8,hello world"); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); +const INIT_URI = "data:text/html;charset=utf8,hello world"; +const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-duplicate-error.html"; - function consoleOpened(hud) - { - expectUncaughtException(); - content.location = TEST_DUPLICATE_ERROR_URI; +let test = asyncTest(function* () { + yield loadTab(INIT_URI); - waitForMessages({ - webconsole: hud, - messages: [{ - text: "fooDuplicateError1", - category: CATEGORY_JS, - severity: SEVERITY_ERROR, - }, - { - text: "test-duplicate-error.html", - category: CATEGORY_NETWORK, - severity: SEVERITY_LOG, - }], - }).then(() => { - let text = hud.outputNode.textContent; - let error1pos = text.indexOf("fooDuplicateError1"); - ok(error1pos > -1, "found fooDuplicateError1"); - if (error1pos > -1) { - ok(text.indexOf("fooDuplicateError1", error1pos + 1) == -1, - "no duplicate for fooDuplicateError1"); - } + let hud = yield openConsole(); - finishTest(); - }); + expectUncaughtException(); + + content.location = TEST_URI; + + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "fooDuplicateError1", + category: CATEGORY_JS, + severity: SEVERITY_ERROR, + }, + { + text: "test-duplicate-error.html", + category: CATEGORY_NETWORK, + severity: SEVERITY_LOG, + }], + }); + + let text = hud.outputNode.textContent; + let error1pos = text.indexOf("fooDuplicateError1"); + ok(error1pos > -1, "found fooDuplicateError1"); + if (error1pos > -1) { + ok(text.indexOf("fooDuplicateError1", error1pos + 1) == -1, + "no duplicate for fooDuplicateError1"); } -} +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js b/browser/devtools/webconsole/test/browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js index ceeac816d0f2..1f089ad2ea47 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js @@ -5,13 +5,12 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/browser/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testCompletion); - }, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + testCompletion(hud); +}); function testCompletion(hud) { var jsterm = hud.jsterm; @@ -29,7 +28,4 @@ function testCompletion(hud) { is(jsterm.completeNode.value, " <- no result", "completenode content - matched"); is(input.value, "window.Bug583816", "inputnode content - matched"); is(input.getAttribute("focused"), "true", "input is still focused"); - - jsterm = input = null; - finishTest(); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_585237_line_limit.js b/browser/devtools/webconsole/test/browser_webconsole_bug_585237_line_limit.js index feb601599cfe..9ec4291e335f 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_585237_line_limit.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585237_line_limit.js @@ -13,25 +13,14 @@ // the user's preferences. const TEST_URI = "data:text/html;charset=utf8,test for bug 585237"; -let hud, testDriver; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, function(aHud) { - hud = aHud; - testDriver = testGen(); - testNext(); - }); - }, true); -} +let outputNode; -function testNext() { - testDriver.next(); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); -function testGen() { let console = content.console; outputNode = hud.outputNode; @@ -44,32 +33,28 @@ function testGen() { console.log("foo #" + i); // must change message to prevent repeats } - waitForMessages({ + yield waitForMessages({ webconsole: hud, messages: [{ text: "foo #29", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(testNext); - - yield undefined; + }); is(countMessageNodes(), 20, "there are 20 message nodes in the output " + "when the log limit is set to 20"); console.log("bar bug585237"); - waitForMessages({ + yield waitForMessages({ webconsole: hud, messages: [{ text: "bar bug585237", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(testNext); - - yield undefined; + }); is(countMessageNodes(), 20, "there are still 20 message nodes in the " + "output when adding one more"); @@ -79,26 +64,22 @@ function testGen() { console.log("boo #" + i); // must change message to prevent repeats } - waitForMessages({ + yield waitForMessages({ webconsole: hud, messages: [{ text: "boo #19", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(testNext); - - yield undefined; + }); is(countMessageNodes(), 30, "there are 30 message nodes in the output " + "when the log limit is set to 30"); prefBranch.clearUserPref("console"); - hud = testDriver = prefBranch = console = outputNode = null; - finishTest(); - yield undefined; -} + outputNode = null; +}); function countMessageNodes() { return outputNode.querySelectorAll(".message").length; diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_585956_console_trace.js b/browser/devtools/webconsole/test/browser_webconsole_bug_585956_console_trace.js index 5c3a5b047fc4..8945d2fa6c67 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_585956_console_trace.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585956_console_trace.js @@ -3,6 +3,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-585956-console-trace.html"; function test() { diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js index a5423c5e0eb9..c63ca41b48dd 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js @@ -6,15 +6,24 @@ const TEST_URI = "data:text/html;charset=utf-8,

bug 585991 - autocomplete popup keyboard usage test"; let HUD, popup, jsterm, inputNode, completeNode; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); + + yield consoleOpened(hud); + yield popupHideAfterTab(); + yield testReturnKey(); + yield dontShowArrayNumbers(); + yield testReturnWithNoSelection(); + yield popupHideAfterReturnWithNoSelection(); + yield testCompletionInText(); + yield popupHideAfterCompletionInText(); + + HUD = popup = jsterm = inputNode = completeNode = null; +}); function consoleOpened(aHud) { + let deferred = promise.defer(); HUD = aHud; info("web console opened"); @@ -26,6 +35,8 @@ function consoleOpened(aHud) { "'item2': 'value2'," + "'item3': 'value3'" + "}"); + jsterm.execute("window.testBug873250a = 'hello world';" + + "window.testBug873250b = 'hello world 2';"); popup = jsterm.autocompletePopup; completeNode = jsterm.completeNode; inputNode = jsterm.inputNode; @@ -110,20 +121,25 @@ function consoleOpened(aHud) { is(popup.selectedIndex, 0, "index is first after Home"); info("press Tab and wait for popup to hide"); - popup._panel.addEventListener("popuphidden", popupHideAfterTab, false); + popup._panel.addEventListener("popuphidden", function popupHidden() { + popup._panel.removeEventListener("popuphidden", popupHidden, false); + deferred.resolve(); + }, false); EventUtils.synthesizeKey("VK_TAB", {}); }, false); info("wait for completion: window.foobarBug585991."); jsterm.setInputValue("window.foobarBug585991"); EventUtils.synthesizeKey(".", {}); + + return deferred.promise; } function popupHideAfterTab() { - // At this point the completion suggestion should be accepted. - popup._panel.removeEventListener("popuphidden", popupHideAfterTab, false); + let deferred = promise.defer(); + // At this point the completion suggestion should be accepted. ok(!popup.isOpen, "popup is not open"); is(inputNode.value, "window.foobarBug585991.watch", @@ -158,7 +174,7 @@ function popupHideAfterTab() ok(!completeNode.value, "completeNode is empty"); - executeSoon(testReturnKey); + deferred.resolve(); }, false); info("press Escape to close the popup"); @@ -172,10 +188,14 @@ function popupHideAfterTab() jsterm.setInputValue("window.foobarBug585991"); EventUtils.synthesizeKey(".", {}); }); + + return deferred.promise; } function testReturnKey() { + let deferred = promise.defer(); + popup._panel.addEventListener("popupshown", function onShown() { popup._panel.removeEventListener("popupshown", onShown, false); @@ -210,7 +230,7 @@ function testReturnKey() ok(!completeNode.value, "completeNode is empty"); - dontShowArrayNumbers(); + deferred.resolve(); }, false); info("press Return to accept suggestion. wait for popup to hide"); @@ -225,10 +245,14 @@ function testReturnKey() EventUtils.synthesizeKey("1", {}); EventUtils.synthesizeKey(".", {}); }); + + return deferred.promise; } function dontShowArrayNumbers() { + let deferred = promise.defer(); + info("dontShowArrayNumbers"); content.wrappedJSObject.foobarBug585991 = ["Sherlock Holmes"]; @@ -243,7 +267,10 @@ function dontShowArrayNumbers() ok(!sameItems.some(function(prop, index) { prop === "0"; }), "Completing on an array doesn't show numbers."); - popup._panel.addEventListener("popuphidden", testReturnWithNoSelection, false); + popup._panel.addEventListener("popuphidden", function popupHidden() { + popup._panel.removeEventListener("popuphidden", popupHidden, false); + deferred.resolve(); + }, false); info("wait for popup to hide"); executeSoon(() => EventUtils.synthesizeKey("VK_ESCAPE", {})); @@ -254,15 +281,15 @@ function dontShowArrayNumbers() jsterm.setInputValue("window.foobarBug585991"); EventUtils.synthesizeKey(".", {}); }); + + return deferred.promise; } function testReturnWithNoSelection() { - popup._panel.removeEventListener("popuphidden", testReturnWithNoSelection, false); + let deferred = promise.defer(); info("test pressing return with open popup, but no selection, see bug 873250"); - content.wrappedJSObject.testBug873250a = "hello world"; - content.wrappedJSObject.testBug873250b = "hello world 2"; popup._panel.addEventListener("popupshown", function onShown() { popup._panel.removeEventListener("popupshown", onShown); @@ -272,7 +299,10 @@ function testReturnWithNoSelection() isnot(popup.selectedIndex, -1, "popup.selectedIndex is correct"); info("press Return and wait for popup to hide"); - popup._panel.addEventListener("popuphidden", popupHideAfterReturnWithNoSelection); + popup._panel.addEventListener("popuphidden", function popupHidden() { + popup._panel.removeEventListener("popuphidden", popupHidden); + deferred.resolve(); + }); executeSoon(() => EventUtils.synthesizeKey("VK_RETURN", {})); }); @@ -281,12 +311,12 @@ function testReturnWithNoSelection() jsterm.setInputValue("window.testBu"); EventUtils.synthesizeKey("g", {}); }); + + return deferred.promise; } function popupHideAfterReturnWithNoSelection() { - popup._panel.removeEventListener("popuphidden", popupHideAfterReturnWithNoSelection); - ok(!popup.isOpen, "popup is not open after VK_RETURN"); is(inputNode.value, "", "inputNode is empty after VK_RETURN"); @@ -294,13 +324,15 @@ function popupHideAfterReturnWithNoSelection() is(jsterm.history[jsterm.history.length-1], "window.testBug", "jsterm history is correct"); - executeSoon(testCompletionInText); + return promise.resolve(); } function testCompletionInText() { info("test that completion works inside text, see bug 812618"); + let deferred = promise.defer(); + popup._panel.addEventListener("popupshown", function onShown() { popup._panel.removeEventListener("popupshown", onShown); @@ -317,20 +349,22 @@ function testCompletionInText() ok(sameItems, "getItems returns the items we expect"); info("press Tab and wait for popup to hide"); - popup._panel.addEventListener("popuphidden", popupHideAfterCompletionInText); + popup._panel.addEventListener("popuphidden", function popupHidden() { + popup._panel.removeEventListener("popuphidden", popupHidden); + deferred.resolve(); + }); EventUtils.synthesizeKey("VK_TAB", {}); }); jsterm.setInputValue("dump(window.testBu)"); inputNode.selectionStart = inputNode.selectionEnd = 18; EventUtils.synthesizeKey("g", {}); + return deferred.promise; } function popupHideAfterCompletionInText() { // At this point the completion suggestion should be accepted. - popup._panel.removeEventListener("popuphidden", popupHideAfterCompletionInText); - ok(!popup.isOpen, "popup is not open"); is(inputNode.value, "dump(window.testBug873250b)", "completion was successful after VK_TAB"); @@ -338,10 +372,5 @@ function popupHideAfterCompletionInText() is(inputNode.selectionStart, inputNode.selectionEnd, "cursor location (confirmed)"); ok(!completeNode.value, "completeNode is empty"); - finishUp(); -} - -function finishUp() { - HUD = popup = jsterm = inputNode = completeNode = null; - finishTest(); + return promise.resolve(); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_popup.js b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_popup.js index 0dc9141b18cf..76fc5d324c7f 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_popup.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_popup.js @@ -5,15 +5,18 @@ const TEST_URI = "data:text/html;charset=utf-8,

bug 585991 - autocomplete popup test"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} +"use strict"; + +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); + + yield consoleOpened(hud); +}); function consoleOpened(HUD) { + let deferred = promise.defer(); + let items = [ {label: "item0", value: "value0"}, {label: "item1", value: "value1"}, @@ -106,9 +109,11 @@ function consoleOpened(HUD) { "no aria-activedescendant"); popup.hidePopup(); - finishTest(); + deferred.resolve(); }, false); popup.openPopup(); + + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js b/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js index ec30d62bc6a5..112cd582379f 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js @@ -10,83 +10,82 @@ const TEST_URI = "http://example.com/"; -function test() { - let hud; +"use strict"; - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testSelectionWhenMovingBetweenBoxes); - }, true); +let test = asyncTest(function* () { + yield loadTab(TEST_URI); - function testSelectionWhenMovingBetweenBoxes(aHud) { - hud = aHud; - let jsterm = hud.jsterm; + let hud = yield openConsole(); + yield testSelectionWhenMovingBetweenBoxes(hud); + performTestsAfterOutput(hud); +}) - // Fill the console with some output. - jsterm.clearOutput(); - jsterm.execute("1 + 2"); - jsterm.execute("3 + 4"); - jsterm.execute("5 + 6"); +function testSelectionWhenMovingBetweenBoxes(aHud) { + let hud = aHud; + let jsterm = hud.jsterm; - waitForMessages({ - webconsole: hud, - messages: [{ - text: "3", - category: CATEGORY_OUTPUT, - }, - { - text: "7", - category: CATEGORY_OUTPUT, - }, - { - text: "11", - category: CATEGORY_OUTPUT, - }], - }).then(performTestsAfterOutput); - } + // Fill the console with some output. + jsterm.clearOutput(); + jsterm.execute("1 + 2"); + jsterm.execute("3 + 4"); + jsterm.execute("5 + 6"); - function performTestsAfterOutput() { - let outputNode = hud.outputNode; - - ok(outputNode.childNodes.length >= 3, "the output node has children after " + - "executing some JavaScript"); - - // Test that the global Firefox "Select All" functionality (e.g. Edit > - // Select All) works properly in the Web Console. - let commandController = hud.ui._commandController; - ok(commandController != null, "the window has a command controller object"); - - commandController.selectAll(); - - let selectedCount = hud.ui.output.getSelectedMessages().length; - is(selectedCount, outputNode.childNodes.length, - "all console messages are selected after performing a regular browser " + - "select-all operation"); - - hud.iframeWindow.getSelection().removeAllRanges(); - - // Test the context menu "Select All" (which has a different code path) works - // properly as well. - let contextMenuId = outputNode.parentNode.getAttribute("context"); - let contextMenu = hud.ui.document.getElementById(contextMenuId); - ok(contextMenu != null, "the output node has a context menu"); - - let selectAllItem = contextMenu.querySelector("*[command='cmd_selectAll']"); - ok(selectAllItem != null, - "the context menu on the output node has a \"Select All\" item"); - - outputNode.focus(); - - selectAllItem.doCommand(); - - selectedCount = hud.ui.output.getSelectedMessages().length; - is(selectedCount, outputNode.childNodes.length, - "all console messages are selected after performing a select-all " + - "operation from the context menu"); - - hud.iframeWindow.getSelection().removeAllRanges(); - - finishTest(); - } + return waitForMessages({ + webconsole: hud, + messages: [{ + text: "3", + category: CATEGORY_OUTPUT, + }, + { + text: "7", + category: CATEGORY_OUTPUT, + }, + { + text: "11", + category: CATEGORY_OUTPUT, + }], + }); +} + +function performTestsAfterOutput(aHud) { + let hud = aHud; + let outputNode = hud.outputNode; + + ok(outputNode.childNodes.length >= 3, "the output node has children after " + + "executing some JavaScript"); + + // Test that the global Firefox "Select All" functionality (e.g. Edit > + // Select All) works properly in the Web Console. + let commandController = hud.ui._commandController; + ok(commandController != null, "the window has a command controller object"); + + commandController.selectAll(); + + let selectedCount = hud.ui.output.getSelectedMessages().length; + is(selectedCount, outputNode.childNodes.length, + "all console messages are selected after performing a regular browser " + + "select-all operation"); + + hud.iframeWindow.getSelection().removeAllRanges(); + + // Test the context menu "Select All" (which has a different code path) works + // properly as well. + let contextMenuId = outputNode.parentNode.getAttribute("context"); + let contextMenu = hud.ui.document.getElementById(contextMenuId); + ok(contextMenu != null, "the output node has a context menu"); + + let selectAllItem = contextMenu.querySelector("*[command='cmd_selectAll']"); + ok(selectAllItem != null, + "the context menu on the output node has a \"Select All\" item"); + + outputNode.focus(); + + selectAllItem.doCommand(); + + selectedCount = hud.ui.output.getSelectedMessages().length; + is(selectedCount, outputNode.childNodes.length, + "all console messages are selected after performing a select-all " + + "operation from the context menu"); + + hud.iframeWindow.getSelection().removeAllRanges(); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_587617_output_copy.js b/browser/devtools/webconsole/test/browser_webconsole_bug_587617_output_copy.js index 454fe22d3ef0..e3b0d21d1e5c 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_587617_output_copy.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_587617_output_copy.js @@ -12,17 +12,23 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/te let HUD, outputNode; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} +"use strict"; + +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + yield consoleOpened(hud); + yield testContextMenuCopy(); + + HUD = outputNode = null; +}); function consoleOpened(aHud) { HUD = aHud; + let deferred = promise.defer(); + // See bugs 574036, 586386 and 587617. outputNode = HUD.outputNode; @@ -57,13 +63,16 @@ function consoleOpened(aHud) { waitForClipboard((str) => { return selection.trim() == str.trim(); }, () => { goDoCommand("cmd_copy") }, - testContextMenuCopy, testContextMenuCopy); + deferred.resolve, deferred.resolve); }); + return deferred.promise; } // Test that the context menu "Copy" (which has a different code path) works // properly as well. function testContextMenuCopy() { + let deferred = promise.defer(); + let contextMenuId = outputNode.parentNode.getAttribute("context"); let contextMenu = HUD.ui.document.getElementById(contextMenuId); ok(contextMenu, "the output node has a context menu"); @@ -77,7 +86,9 @@ function testContextMenuCopy() { waitForClipboard((str) => { return selection.trim() == str.trim(); }, () => { goDoCommand("cmd_copy") }, - finishTest, finishTest); + deferred.resolve, deferred.resolve); HUD = outputNode = null; + + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_588342_document_focus.js b/browser/devtools/webconsole/test/browser_webconsole_bug_588342_document_focus.js index a27c64b024e4..6e7fcc1f6ce0 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_588342_document_focus.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_588342_document_focus.js @@ -9,31 +9,31 @@ * ***** END LICENSE BLOCK ***** */ const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 588342"; -let fm; -function test() { - fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} +let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); -function consoleOpened(hud) { - waitForFocus(function() { - is(hud.jsterm.inputNode.getAttribute("focused"), "true", - "jsterm input is focused on web console open"); - isnot(fm.focusedWindow, content, "content document has no focus"); - closeConsole(null, consoleClosed); - }, hud.iframeWindow); -} +"use strict"; + +let test = asyncTest(function* () { + let { browser } = yield loadTab(TEST_URI); + + let hud = yield openConsole(); + yield consoleOpened(hud); -function consoleClosed() { is(fm.focusedWindow, browser.contentWindow, "content document has focus"); fm = null; - finishTest(); -} +}); +function consoleOpened(hud) { + let deferred = promise.defer(); + waitForFocus(function() { + is(hud.jsterm.inputNode.getAttribute("focused"), "true", + "jsterm input is focused on web console open"); + isnot(fm.focusedWindow, content, "content document has no focus"); + closeConsole(null).then(deferred.resolve); + }, hud.iframeWindow); + + return deferred.promise; +} diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_588730_text_node_insertion.js b/browser/devtools/webconsole/test/browser_webconsole_bug_588730_text_node_insertion.js index 74f56aa77440..ef1c3e5a2d32 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_588730_text_node_insertion.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_588730_text_node_insertion.js @@ -7,17 +7,20 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testTextNodeInsertion); - }, true); -} +"use strict"; + +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + yield testTextNodeInsertion(hud); +}); // Test for bug 588730: Adding a text node to an existing label element causes // warnings function testTextNodeInsertion(hud) { + let deferred = promise.defer(); let outputNode = hud.outputNode; let label = document.createElementNS( @@ -43,7 +46,8 @@ function testTextNodeInsertion(hud) { Services.console.unregisterListener(listener); ok(!error, "no error when adding text nodes as children of labels"); - finishTest(); + return deferred.resolve(); }); + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_588967_input_expansion.js b/browser/devtools/webconsole/test/browser_webconsole_bug_588967_input_expansion.js index c22894924fd1..9b9fb3168177 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_588967_input_expansion.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_588967_input_expansion.js @@ -5,13 +5,16 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testInputExpansion); - }, true); -} +"use strict"; + +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + testInputExpansion(hud); +}); + function testInputExpansion(hud) { let input = hud.jsterm.inputNode; @@ -38,7 +41,5 @@ function testInputExpansion(hud) { is(input.clientHeight, ordinaryHeight, "the input's height is normal again"); input = length = null; - - finishTest(); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_589162_css_filter.js b/browser/devtools/webconsole/test/browser_webconsole_bug_589162_css_filter.js index 261c25a6e326..72fd295eb83f 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_589162_css_filter.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_589162_css_filter.js @@ -9,6 +9,8 @@ * * ***** END LICENSE BLOCK ***** */ +"use strict" + const TEST_URI = "data:text/html;charset=utf-8,

test CSS parser filter
"; diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_592442_closing_brackets.js b/browser/devtools/webconsole/test/browser_webconsole_bug_592442_closing_brackets.js index fbea54e9d2a4..c29e61b26ebb 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_592442_closing_brackets.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_592442_closing_brackets.js @@ -13,15 +13,14 @@ // Tests that, when the user types an extraneous closing bracket, no error // appears. -function test() { - addTab("data:text/html;charset=utf-8,test for bug 592442"); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testExtraneousClosingBrackets); - }, true); -} +"use strict"; -function testExtraneousClosingBrackets(hud) { +const TEST_URI = "data:text/html;charset=utf-8,test for bug 592442"; + +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); + hud.jsterm.clearOutput(); let jsterm = hud.jsterm; jsterm.setInputValue("document.getElementById)"); @@ -35,7 +34,4 @@ function testExtraneousClosingBrackets(hud) { } ok(!error, "no error was thrown when an extraneous bracket was inserted"); - - finishTest(); -} - +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_593003_iframe_wrong_hud.js b/browser/devtools/webconsole/test/browser_webconsole_bug_593003_iframe_wrong_hud.js index 44e12dc36be2..ac526b502820 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_593003_iframe_wrong_hud.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_593003_iframe_wrong_hud.js @@ -12,25 +12,22 @@ const TEST_DUMMY_URI = "http://example.com/browser/browser/devtools/webconsole/t let tab1, tab2; function test() { - addTab(TEST_URI); - tab1 = tab; - browser.addEventListener("load", tab1Loaded, true); -} + loadTab(TEST_URI).then(({tab}) => { + tab1 = tab; -function tab1Loaded(aEvent) { - browser.removeEventListener(aEvent.type, tab1Loaded, true); - content.console.log("FOO"); - openConsole(null, function() { - tab2 = gBrowser.addTab(TEST_DUMMY_URI); - gBrowser.selectedTab = tab2; - gBrowser.selectedBrowser.addEventListener("load", tab2Loaded, true); + content.console.log("FOO"); + openConsole().then(() => { + tab2 = gBrowser.addTab(TEST_DUMMY_URI); + gBrowser.selectedTab = tab2; + gBrowser.selectedBrowser.addEventListener("load", tab2Loaded, true); + }); }); } function tab2Loaded(aEvent) { tab2.linkedBrowser.removeEventListener(aEvent.type, tab2Loaded, true); - openConsole(gBrowser.selectedTab, function() { + openConsole(gBrowser.selectedTab).then(() => { tab1.linkedBrowser.addEventListener("load", tab1Reloaded, true); tab1.linkedBrowser.contentWindow.location.reload(); }); @@ -59,7 +56,7 @@ function tab1Reloaded(aEvent) { let msg = "Didn't find the iframe network request in tab2"; testLogEntry(outputNode2, TEST_IFRAME_URI, msg, true, true); - closeConsole(tab2, function() { + closeConsole(tab2).then(() => { gBrowser.removeTab(tab2); tab1 = tab2 = null; executeSoon(finishTest); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js b/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js index 1036ca1ca2f8..3a31b650eb88 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js @@ -10,22 +10,30 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; let HUD; - let outputItem; +let outputNode; -function consoleOpened(aHud) { - HUD = aHud; +"use strict"; +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + HUD = yield openConsole(); outputNode = HUD.outputNode; - browser.addEventListener("load", tabLoad2, true); + // reload the tab + BrowserReload(); + yield loadBrowser(gBrowser.selectedBrowser); - // Reload so we get some output in the console. - browser.contentWindow.location.reload(); -} + let event = yield clickEvents(); + yield testClickAgain(event); + yield networkPanelHidden(); -function tabLoad2(aEvent) { - browser.removeEventListener(aEvent.type, tabLoad2, true); + HUD = outputItem = outputNode = null; +}); + +function clickEvents() { + let deferred = promise.defer(); waitForMessages({ webconsole: HUD, @@ -38,18 +46,23 @@ function tabLoad2(aEvent) { let msg = [...result.matched][0]; outputItem = msg.querySelector(".message-body .url"); ok(outputItem, "found a network message"); - document.addEventListener("popupshown", networkPanelShown, false); + document.addEventListener("popupshown", function onPanelShown(event) { + document.removeEventListener("popupshown", onPanelShown, false); + deferred.resolve(event); + }, false); // Send the mousedown and click events such that the network panel opens. EventUtils.sendMouseEvent({type: "mousedown"}, outputItem); EventUtils.sendMouseEvent({type: "click"}, outputItem); }); + + return deferred.promise; } -function networkPanelShown(aEvent) { - document.removeEventListener(aEvent.type, networkPanelShown, false); +function testClickAgain(event) { + info("testClickAgain"); - info("networkPanelShown"); + let deferred = promise.defer(); document.addEventListener("popupshown", networkPanelShowFailure, false); @@ -58,19 +71,22 @@ function networkPanelShown(aEvent) { EventUtils.sendMouseEvent({type: "click"}, outputItem); executeSoon(function() { - aEvent.target.addEventListener("popuphidden", networkPanelHidden, false); - aEvent.target.hidePopup(); + document.addEventListener("popuphidden", function onHidden() { + document.removeEventListener("popuphidden", onHidden, false); + deferred.resolve(); + }, false); + event.target.hidePopup(); }); + + return deferred.promise; } -function networkPanelShowFailure(aEvent) { - document.removeEventListener(aEvent.type, networkPanelShowFailure, false); - +function networkPanelShowFailure() { ok(false, "the network panel should not show"); } -function networkPanelHidden(aEvent) { - this.removeEventListener(aEvent.type, networkPanelHidden, false); +function networkPanelHidden() { + let deferred = promise.defer(); info("networkPanelHidden"); @@ -101,7 +117,7 @@ function networkPanelHidden(aEvent) { HUD.jsterm.execute("document", (msg) => { info("jsterm execute 'document' callback"); - HUD.jsterm.once("variablesview-open", onVariablesViewOpen); + HUD.jsterm.once("variablesview-open", deferred.resolve); let outputItem = msg.querySelector(".message-body a"); ok(outputItem, "jsterm output message found"); @@ -110,22 +126,6 @@ function networkPanelHidden(aEvent) { EventUtils.sendMouseEvent({type: "click"}, outputItem); }); }); + + return deferred.promise; } - -function onVariablesViewOpen() { - info("onVariablesViewOpen"); - - executeSoon(function() { - HUD = outputItem = null; - executeSoon(finishTest); - }); -} - -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} - diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_594497_history_arrow_keys.js b/browser/devtools/webconsole/test/browser_webconsole_bug_594497_history_arrow_keys.js index 2cdf52bc937a..38210ebfbce9 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_594497_history_arrow_keys.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_594497_history_arrow_keys.js @@ -10,27 +10,35 @@ let inputNode, values; -function tabLoad(aEvent) { - browser.removeEventListener(aEvent.type, tabLoad, true); +let TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 594497 and bug 619598"; +"use strict"; - openConsole(null, function(HUD) { - inputNode = HUD.jsterm.inputNode; +let test = asyncTest(function* () { + yield loadTab(TEST_URI); - inputNode.focus(); + let hud = yield openConsole(); - ok(!inputNode.value, "inputNode.value is empty"); + setup(hud); + performTests(); - values = ["document", "window", "document.body"]; - values.push(values.join(";\n"), "document.location"); + inputNode = values = null; +}); - // Execute each of the values; - for (let i = 0; i < values.length; i++) { - HUD.jsterm.setInputValue(values[i]); - HUD.jsterm.execute(); - } +function setup(HUD) { + inputNode = HUD.jsterm.inputNode; - performTests(); - }); + inputNode.focus(); + + ok(!inputNode.value, "inputNode.value is empty"); + + values = ["document", "window", "document.body"]; + values.push(values.join(";\n"), "document.location"); + + // Execute each of the values; + for (let i = 0; i < values.length; i++) { + HUD.jsterm.setInputValue(values[i]); + HUD.jsterm.execute(); + } } function performTests() { @@ -145,13 +153,4 @@ function performTests() { ok(!inputNode.value, "VK_DOWN: inputNode.value is empty"); - - inputNode = values = null; - executeSoon(finishTest); } - -function test() { - addTab("data:text/html;charset=utf-8,Web Console test for bug 594497 and bug 619598"); - browser.addEventListener("load", tabLoad, true); -} - diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_595223_file_uri.js b/browser/devtools/webconsole/test/browser_webconsole_bug_595223_file_uri.js index fc0ee3f1f7f6..fe8ff7b2cbc6 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_595223_file_uri.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_595223_file_uri.js @@ -3,12 +3,42 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + +const PREF = "devtools.webconsole.persistlog"; const TEST_FILE = "test-network.html"; +const TEST_URI = "data:text/html;charset=utf8,

test file URI"; -function tabReload(aEvent) { - browser.removeEventListener(aEvent.type, tabReload, true); +let hud; - waitForMessages({ +let test = asyncTest(function* () { + Services.prefs.setBoolPref(PREF, true); + + let jar = getJar(getRootDirectory(gTestPath)); + let dir = jar ? + extractJarToTmp(jar) : + getChromeDir(getResolvedURI(gTestPath)); + + dir.append(TEST_FILE); + let uri = Services.io.newFileURI(dir); + + let { browser } = yield loadTab(TEST_URI); + + hud = yield openConsole(); + hud.jsterm.clearOutput(); + + let loaded = loadBrowser(browser); + content.location = uri.spec; + yield loaded; + + yield testMessages(); + + Services.prefs.clearUserPref(PREF); + hud = null; +}); + +function testMessages() { + return waitForMessages({ webconsole: hud, messages: [{ text: "running network console logging tests", @@ -30,30 +60,5 @@ function tabReload(aEvent) { category: CATEGORY_NETWORK, severity: SEVERITY_LOG, }], - }).then(finishTest); -} - -function test() { - let jar = getJar(getRootDirectory(gTestPath)); - let dir = jar ? - extractJarToTmp(jar) : - getChromeDir(getResolvedURI(gTestPath)); - dir.append(TEST_FILE); - - let uri = Services.io.newFileURI(dir); - - const PREF = "devtools.webconsole.persistlog"; - Services.prefs.setBoolPref(PREF, true); - registerCleanupFunction(() => Services.prefs.clearUserPref(PREF)); - - addTab("data:text/html;charset=utf8,

test file URI"); - browser.addEventListener("load", function tabLoad() { - browser.removeEventListener("load", tabLoad, true); - openConsole(null, function(aHud) { - hud = aHud; - hud.jsterm.clearOutput(); - browser.addEventListener("load", tabReload, true); - content.location = uri.spec; - }); - }, true); + }) } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_595350_multiple_windows_and_tabs.js b/browser/devtools/webconsole/test/browser_webconsole_bug_595350_multiple_windows_and_tabs.js index a1c96b9c17e1..cefb3e37790e 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_595350_multiple_windows_and_tabs.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_595350_multiple_windows_and_tabs.js @@ -58,7 +58,7 @@ function openConsoles() { let consolesOpen = 0; for (let i = 0; i < openTabs.length; i++) { let tab = openTabs[i]; - openConsole(tab, function(index, hud) { + openConsole(tab).then(function(index, hud) { ok(hud, "HUD is open for tab " + index); let window = hud.target.tab.linkedBrowser.contentWindow; window.console.log("message for tab " + index); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js b/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js index 6c476074e39d..bfafa4423e78 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js @@ -8,6 +8,7 @@ * * ***** END LICENSE BLOCK ***** */ +const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 595934 - message categories coverage."; const TESTS_PATH = "http://example.com/browser/browser/devtools/webconsole/test/"; const TESTS = [ { // #0 @@ -195,10 +196,8 @@ function startNextTest() { function test() { requestLongerTimeout(2); - addTab("data:text/html;charset=utf-8,Web Console test for bug 595934 - message categories coverage."); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + loadTab(TEST_URI).then(() => { + openConsole().then(consoleOpened); + }); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js b/browser/devtools/webconsole/test/browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js index b077d293241e..6bc20ba1c875 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js @@ -13,9 +13,7 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/te let tab1, tab2, win1, win2; let noErrors = true; -function tab1Loaded(aEvent) { - browser.removeEventListener(aEvent.type, tab1Loaded, true); - +function tab1Loaded() { win2 = OpenBrowserWindow(); whenDelayedStartupFinished(win2, win2Loaded); } @@ -97,9 +95,10 @@ function tab2Loaded(aEvent) { } function test() { - addTab(TEST_URI); - browser.addEventListener("load", tab1Loaded, true); - tab1 = gBrowser.selectedTab; - win1 = window; + loadTab(TEST_URI).then(() => { + tab1 = gBrowser.selectedTab; + win1 = window; + tab1Loaded(); + }); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_597136_network_requests_from_chrome.js b/browser/devtools/webconsole/test/browser_webconsole_bug_597136_network_requests_from_chrome.js index 3aa0f5399817..5f4f66f23d52 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_597136_network_requests_from_chrome.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_597136_network_requests_from_chrome.js @@ -40,7 +40,7 @@ function checkForException() { "chrome window"); Services.console.unregisterListener(listener); - listener = null; + listener = xhr = null; finishTest(); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_597460_filter_scroll.js b/browser/devtools/webconsole/test/browser_webconsole_bug_597460_filter_scroll.js index 140a1c9af8b3..f8fc821eb7da 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_597460_filter_scroll.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_597460_filter_scroll.js @@ -9,9 +9,23 @@ * ***** END LICENSE BLOCK ***** */ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-network.html"; +const PREF = "devtools.webconsole.persistlog"; -function consoleOpened(aHud) { - hud = aHud; +let test = asyncTest(function* () { + Services.prefs.setBoolPref(PREF, true); + + yield loadTab(TEST_URI); + let hud = yield openConsole(); + + let results = yield consoleOpened(hud); + + testScroll(results, hud); + + Services.prefs.clearUserPref(PREF); +}); + +function consoleOpened(hud) { + let deferred = promise.defer(); for (let i = 0; i < 200; i++) { content.console.log("test message " + i); @@ -39,12 +53,15 @@ function consoleOpened(aHud) { category: CATEGORY_NETWORK, severity: SEVERITY_LOG, }], - }).then(testScroll); + }).then(deferred.resolve); + content.location.reload(); }); + + return deferred.promise; } -function testScroll([result]) { +function testScroll([result], hud) { let scrollNode = hud.outputNode.parentNode; let msgNode = [...result.matched][0]; ok(msgNode.classList.contains("filtered-by-type"), @@ -62,18 +79,4 @@ function testScroll([result]) { hud.setFilterState("network", true); hud.setFilterState("networkinfo", true); - - executeSoon(finishTest); -} - -function test() { - const PREF = "devtools.webconsole.persistlog"; - Services.prefs.setBoolPref(PREF, true); - registerCleanupFunction(() => Services.prefs.clearUserPref(PREF)); - - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_597756_reopen_closed_tab.js b/browser/devtools/webconsole/test/browser_webconsole_bug_597756_reopen_closed_tab.js index 2842f066e320..ccaedc98e311 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_597756_reopen_closed_tab.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_597756_reopen_closed_tab.js @@ -10,25 +10,47 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-597756-reopen-closed-tab.html"; -let newTabIsOpen = false; +let HUD; -function tabLoaded(aEvent) { - gBrowser.selectedBrowser.removeEventListener(aEvent.type, tabLoaded, true); +let test = asyncTest(function* () { + expectUncaughtException(); - openConsole(gBrowser.selectedTab, function() { - gBrowser.selectedBrowser.addEventListener("load", tabReloaded, true); - expectUncaughtException(); - content.location.reload(); - }); + let { browser } = yield loadTab(TEST_URI); + HUD = yield openConsole(); + + expectUncaughtException(); + + yield reload(browser); + + yield testMessages(); + + yield closeConsole(); + + // Close and reopen + gBrowser.removeCurrentTab(); + + expectUncaughtException(); + + let tab = yield loadTab(TEST_URI); + HUD = yield openConsole(); + + expectUncaughtException(); + + yield reload(tab.browser); + + yield testMessages(); + + HUD = null; +}); + +function reload(browser) { + let loaded = loadBrowser(browser); + content.location.reload(); + return loaded; } -function tabReloaded(aEvent) { - gBrowser.selectedBrowser.removeEventListener(aEvent.type, tabReloaded, true); - - let HUD = HUDService.getHudByWindow(content); - ok(HUD, "Web Console is open"); - - waitForMessages({ +function testMessages() { + return waitForMessages({ webconsole: HUD, messages: [{ name: "error message displayed", @@ -36,29 +58,5 @@ function tabReloaded(aEvent) { category: CATEGORY_JS, severity: SEVERITY_ERROR, }], - }).then(() => { - if (newTabIsOpen) { - finishTest(); - return; - } - - closeConsole(gBrowser.selectedTab, () => { - gBrowser.removeCurrentTab(); - - let newTab = gBrowser.addTab(); - gBrowser.selectedTab = newTab; - - newTabIsOpen = true; - gBrowser.selectedBrowser.addEventListener("load", tabLoaded, true); - expectUncaughtException(); - content.location = TEST_URI; - }); }); } - -function test() { - expectUncaughtException(); - addTab(TEST_URI); - browser.addEventListener("load", tabLoaded, true); -} - diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_599725_response_headers.js b/browser/devtools/webconsole/test/browser_webconsole_bug_599725_response_headers.js index 1c589f3f6233..550a0c613e17 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_599725_response_headers.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_599725_response_headers.js @@ -8,11 +8,14 @@ * * ***** END LICENSE BLOCK ***** */ +const INIT_URI = "data:text/plain;charset=utf8,hello world"; const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-599725-response-headers.sjs"; let loads = 0; function performTest(aRequest, aConsole) { + let deferred = promise.defer(); + loads++; ok(aRequest, "page load was logged"); if (loads != 2) { @@ -50,27 +53,36 @@ function performTest(aRequest, aConsole) "response headers", headers); } - executeSoon(finishTest); + executeSoon(deferred.resolve); }); HUDService.lastFinishedRequest.callback = null; + + return deferred.promise; } -function test() -{ - addTab("data:text/plain;charset=utf8,hello world"); - - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, () => { - HUDService.lastFinishedRequest.callback = performTest; - - browser.addEventListener("load", function onReload() { - browser.removeEventListener("load", onReload, true); - executeSoon(() => content.location.reload()); - }, true); - - executeSoon(() => content.location = TEST_URI); - }); - }, true); +function waitForRequest() { + let deferred = promise.defer(); + HUDService.lastFinishedRequest.callback = (req, console) => { + performTest(req, console).then(deferred.resolve); + }; + return deferred.promise; } + +let test = asyncTest(function* () { + let { browser } = yield loadTab(INIT_URI); + + let hud = yield openConsole(); + + let gotLastRequest = waitForRequest(); + + let loaded = loadBrowser(browser); + content.location = TEST_URI; + yield loaded; + + let reloaded = loadBrowser(browser); + content.location.reload(); + yield reloaded; + + yield gotLastRequest; +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js b/browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js index ef825dfa310b..bd224375fd7d 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js @@ -8,10 +8,13 @@ * * ***** END LICENSE BLOCK ***** */ +const INIT_URI = "data:text/html;charset=utf-8,Web Console - bug 600183 test"; const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-600183-charset.html"; function performTest(lastFinishedRequest, aConsole) { + let deferred = promise.defer(); + ok(lastFinishedRequest, "charset test page was loaded and logged"); HUDService.lastFinishedRequest.callback = null; @@ -28,26 +31,36 @@ function performTest(lastFinishedRequest, aConsole) "found the chinese simplified string"); HUDService.lastFinishedRequest.callback = null; - executeSoon(finishTest); + executeSoon(deferred.resolve); }); }); + + return deferred.promise; } -function test() -{ - addTab("data:text/html;charset=utf-8,Web Console - bug 600183 test"); - - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - - openConsole(null, function(hud) { - hud.ui.setSaveRequestAndResponseBodies(true).then(() => { - ok(hud.ui._saveRequestAndResponseBodies, - "The saveRequestAndResponseBodies property was successfully set."); - - HUDService.lastFinishedRequest.callback = performTest; - content.location = TEST_URI; - }); - }); - }, true); +function waitForRequest() { + let deferred = promise.defer(); + HUDService.lastFinishedRequest.callback = (req, console) => { + performTest(req, console).then(deferred.resolve); + }; + return deferred.promise; } + +let test = asyncTest(function* () { + let { browser } = yield loadTab(INIT_URI); + + let hud = yield openConsole(); + + yield hud.ui.setSaveRequestAndResponseBodies(true); + + ok(hud.ui._saveRequestAndResponseBodies, + "The saveRequestAndResponseBodies property was successfully set."); + + let gotLastRequest = waitForRequest(); + + let loaded = loadBrowser(browser); + content.location = TEST_URI; + yield loaded; + + yield gotLastRequest; +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_601177_log_levels.js b/browser/devtools/webconsole/test/browser_webconsole_bug_601177_log_levels.js index 45dbc66c7d56..dbe21f32da01 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_601177_log_levels.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_601177_log_levels.js @@ -8,70 +8,66 @@ * * ***** END LICENSE BLOCK ***** */ -const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-601177-log-levels.html"; +const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 601177: log levels"; +const TEST_URI2 = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-601177-log-levels.html"; -function test() -{ - //requestLongerTimeout(20); - //FIXME +let test = asyncTest(function* () { Services.prefs.setBoolPref("javascript.options.strict", true); - registerCleanupFunction(function() { - Services.prefs.clearUserPref("javascript.options.strict"); + + let { browser } = yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + expectUncaughtException(); + + yield testLogLevels(hud); + + Services.prefs.clearUserPref("javascript.options.strict"); +}); + +function testLogLevels(hud) { + content.location = TEST_URI2; + + info("waiting for messages"); + + return waitForMessages({ + webconsole: hud, + messages: [ + { + text: "test-bug-601177-log-levels.html", + category: CATEGORY_NETWORK, + severity: SEVERITY_LOG, + }, + { + text: "test-bug-601177-log-levels.js", + category: CATEGORY_NETWORK, + severity: SEVERITY_LOG, + }, + { + text: "test-image.png", + category: CATEGORY_NETWORK, + severity: SEVERITY_LOG, + }, + { + text: "foobar-known-to-fail.png", + category: CATEGORY_NETWORK, + severity: SEVERITY_ERROR, + }, + { + text: "foobarBug601177exception", + category: CATEGORY_JS, + severity: SEVERITY_ERROR, + }, + { + text: "undefinedPropertyBug601177", + category: CATEGORY_JS, + severity: SEVERITY_WARNING, + }, + { + text: "foobarBug601177strictError", + category: CATEGORY_JS, + severity: SEVERITY_WARNING, + }, + ], }); - - addTab("data:text/html;charset=utf-8,Web Console test for bug 601177: log levels"); - - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); - - function consoleOpened(hud) - { - expectUncaughtException(); - content.location = TEST_URI; - - info("waiting for messages"); - - waitForMessages({ - webconsole: hud, - messages: [ - { - text: "test-bug-601177-log-levels.html", - category: CATEGORY_NETWORK, - severity: SEVERITY_LOG, - }, - { - text: "test-bug-601177-log-levels.js", - category: CATEGORY_NETWORK, - severity: SEVERITY_LOG, - }, - { - text: "test-image.png", - category: CATEGORY_NETWORK, - severity: SEVERITY_LOG, - }, - { - text: "foobar-known-to-fail.png", - category: CATEGORY_NETWORK, - severity: SEVERITY_ERROR, - }, - { - text: "foobarBug601177exception", - category: CATEGORY_JS, - severity: SEVERITY_ERROR, - }, - { - text: "undefinedPropertyBug601177", - category: CATEGORY_JS, - severity: SEVERITY_WARNING, - }, - { - text: "foobarBug601177strictError", - category: CATEGORY_JS, - severity: SEVERITY_WARNING, - }, - ], - }).then(finishTest); - } } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_601667_filter_buttons.js b/browser/devtools/webconsole/test/browser_webconsole_bug_601667_filter_buttons.js index 6bdc45ed5416..d00f2d2d93d4 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_601667_filter_buttons.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_601667_filter_buttons.js @@ -5,19 +5,21 @@ const TEST_URI = "http://example.com/"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testFilterButtons); - }, true); -} +let hud, hudId, hudBox; -function testFilterButtons(aHud) { - hud = aHud; +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + hud = yield openConsole(); hudId = hud.hudId; hudBox = hud.ui.rootElement; + testFilterButtons(); + + hud = hudId = hudBox = null; +}); + +function testFilterButtons() { testMenuFilterButton("net"); testMenuFilterButton("css"); testMenuFilterButton("js"); @@ -29,8 +31,6 @@ function testFilterButtons(aHud) { testIsolateFilterButton("js"); testIsolateFilterButton("logging"); testIsolateFilterButton("security"); - - finishTest(); } function testMenuFilterButton(aCategory) { diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js b/browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js index f9a5fa8fa747..ae68ecda85bb 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js @@ -10,6 +10,9 @@ let menuitems = [], menupopups = [], huds = [], tabs = [], runCount = 0; +const TEST_URI1 = "data:text/html;charset=utf-8,Web Console test for bug 602572: log bodies checkbox. tab 1"; +const TEST_URI2 = "data:text/html;charset=utf-8,Web Console test for bug 602572: log bodies checkbox. tab 2"; + function test() { if (runCount == 0) { @@ -17,26 +20,20 @@ function test() } // open tab 1 - addTab("data:text/html;charset=utf-8,Web Console test for bug 602572: log bodies checkbox. tab 1"); - tabs.push(tab); + loadTab(TEST_URI1).then((tab) => { + tabs.push(tab.tab); + openConsole().then((hud) => { + hud.iframeWindow.mozRequestAnimationFrame(() => { + info("iframe1 root height " + hud.ui.rootElement.clientHeight); - browser.addEventListener("load", function onLoad1(aEvent) { - browser.removeEventListener(aEvent.type, onLoad1, true); - - openConsole(null, (hud) => hud.iframeWindow.mozRequestAnimationFrame(() => { - info("iframe1 root height " + hud.ui.rootElement.clientHeight); - - // open tab 2 - addTab("data:text/html;charset=utf-8,Web Console test for bug 602572: log bodies checkbox. tab 2"); - tabs.push(tab); - - browser.addEventListener("load", function onLoad2(aEvent) { - browser.removeEventListener(aEvent.type, onLoad2, true); - - openConsole(null, (hud) => hud.iframeWindow.mozRequestAnimationFrame(startTest)); - }, true); - })); - }, true); + // open tab 2 + loadTab(TEST_URI2).then((tab) => { + tabs.push(tab.tab); + openConsole().then((hud) => hud.iframeWindow.mozRequestAnimationFrame(startTest)); + }); + }); + }); + }); } function startTest() @@ -154,7 +151,7 @@ function testpopup2c(aEvent) { info("menupopups[1] hidden"); // Done if on second run - closeConsole(gBrowser.selectedTab, function() { + closeConsole(gBrowser.selectedTab).then(function() { if (runCount == 0) { runCount++; info("start second run"); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_603750_websocket.js b/browser/devtools/webconsole/test/browser_webconsole_bug_603750_websocket.js index 323340f7a6c1..5bc9c3a12605 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_603750_websocket.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_603750_websocket.js @@ -9,31 +9,29 @@ * ***** END LICENSE BLOCK ***** */ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-603750-websocket.html"; +const TEST_URI2 = "data:text/html;charset=utf-8,Web Console test for bug 603750: Web Socket errors"; -function test() { - addTab("data:text/html;charset=utf-8,Web Console test for bug 603750: Web Socket errors"); - browser.addEventListener("load", function tabLoad() { - browser.removeEventListener("load", tabLoad, true); - openConsole(null, (hud) => { - content.location = TEST_URI; - info("waiting for websocket errors"); - waitForMessages({ - webconsole: hud, - messages: [ - { - text: "ws://0.0.0.0:81", - source: { url: "test-bug-603750-websocket.js" }, - category: CATEGORY_JS, - severity: SEVERITY_ERROR, - }, - { - text: "ws://0.0.0.0:82", - source: { url: "test-bug-603750-websocket.js" }, - category: CATEGORY_JS, - severity: SEVERITY_ERROR, - }, - ]}).then(finishTest); - }); - }, true); -} +let test = asyncTest(function* () { + let { browser } = yield loadTab(TEST_URI2); + let hud = yield openConsole(); + + content.location = TEST_URI; + + yield waitForMessages({ + webconsole: hud, + messages: [ + { + text: "ws://0.0.0.0:81", + source: { url: "test-bug-603750-websocket.js" }, + category: CATEGORY_JS, + severity: SEVERITY_ERROR, + }, + { + text: "ws://0.0.0.0:82", + source: { url: "test-bug-603750-websocket.js" }, + category: CATEGORY_JS, + severity: SEVERITY_ERROR, + }, + ]}); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_611795.js b/browser/devtools/webconsole/test/browser_webconsole_bug_611795.js index aab1e361f196..cfc1c8c378e8 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_611795.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_611795.js @@ -4,61 +4,61 @@ const TEST_URI = 'data:text/html;charset=utf-8,

test repeated' + ' css warnings

hi

'; +let hud; + +"use strict"; + +/** + * Unit test for bug 611795: + * Repeated CSS messages get collapsed into one. + */ + +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + hud = yield openConsole(); + hud.jsterm.clearOutput(true); + + BrowserReload(); + yield loadBrowser(gBrowser.selectedBrowser); + + yield onContentLoaded(); + yield testConsoleLogRepeats(); + + hud = null; +}); function onContentLoaded() { - browser.removeEventListener("load", onContentLoaded, true); - - let HUD = HUDService.getHudByWindow(content); - let cssWarning = "Unknown property '-moz-opacity'. Declaration dropped."; - waitForMessages({ - webconsole: HUD, + return waitForMessages({ + webconsole: hud, messages: [{ text: cssWarning, category: CATEGORY_CSS, severity: SEVERITY_WARNING, repeats: 2, }], - }).then(testConsoleLogRepeats); + }); } function testConsoleLogRepeats() { - let HUD = HUDService.getHudByWindow(content); - let jsterm = HUD.jsterm; + let jsterm = hud.jsterm; jsterm.clearOutput(); jsterm.setInputValue("for (let i = 0; i < 10; ++i) console.log('this is a line of reasonably long text that I will use to verify that the repeated text node is of an appropriate size.');"); jsterm.execute(); - waitForMessages({ - webconsole: HUD, + return waitForMessages({ + webconsole: hud, messages: [{ text: "this is a line of reasonably long text", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, repeats: 10, }], - }).then(finishTest); -} - -/** - * Unit test for bug 611795: - * Repeated CSS messages get collapsed into one. - */ -function test() -{ - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, function(aHud) { - // Clear cached messages that are shown once the Web Console opens. - aHud.jsterm.clearOutput(true); - browser.addEventListener("load", onContentLoaded, true); - content.location.reload(); - }); - }, true); + }); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_613013_console_api_iframe.js b/browser/devtools/webconsole/test/browser_webconsole_bug_613013_console_api_iframe.js index 7e0fe28e1d6a..13a1057ecf07 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_613013_console_api_iframe.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_613013_console_api_iframe.js @@ -10,43 +10,20 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-613013-console-api-iframe.html"; -let TestObserver = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]), - observe: function test_observe(aMessage, aTopic, aData) - { - if (aTopic == "console-api-log-event") { - executeSoon(performTest); - } - } -}; +let test = asyncTest(function* () { + yield loadTab(TEST_URI); -function tabLoad(aEvent) { - browser.removeEventListener(aEvent.type, tabLoad, true); + let hud = yield openConsole(); - openConsole(null, function(aHud) { - hud = aHud; - Services.obs.addObserver(TestObserver, "console-api-log-event", false); - content.location.reload(); - }); -} + BrowserReload(); -function performTest() { - Services.obs.removeObserver(TestObserver, "console-api-log-event"); - TestObserver = null; - - waitForMessages({ + yield waitForMessages({ webconsole: hud, messages: [{ text: "foobarBug613013", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(finishTest); -} - -function test() { - addTab(TEST_URI); - browser.addEventListener("load", tabLoad, true); -} - + }); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_613280_jsterm_copy.js b/browser/devtools/webconsole/test/browser_webconsole_bug_613280_jsterm_copy.js index 1e03ac0c3adc..e5d77b1e3029 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_613280_jsterm_copy.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_613280_jsterm_copy.js @@ -9,10 +9,8 @@ const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 613280"; function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, function(HUD) { + loadTab(TEST_URI).then(() => { + openConsole().then((HUD) => { content.console.log("foobarBazBug613280"); waitForMessages({ webconsole: HUD, @@ -22,8 +20,8 @@ function test() { severity: SEVERITY_LOG, }], }).then(performTest.bind(null, HUD)); - }); - }, true); + }) + }); } function performTest(HUD, [result]) { diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_613642_maintain_scroll.js b/browser/devtools/webconsole/test/browser_webconsole_bug_613642_maintain_scroll.js index 804e071fbf77..c747ca0a8379 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_613642_maintain_scroll.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_613642_maintain_scroll.js @@ -7,13 +7,13 @@ * Mihai Șucan */ -let hud, testDriver; +let TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 613642: remember scroll location"; -function testNext() { - testDriver.next(); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); -function testGen() { hud.jsterm.clearOutput(); let outputNode = hud.outputNode; let scrollBox = outputNode.parentNode; @@ -22,22 +22,22 @@ function testGen() { content.console.log("test message " + i); } - waitForMessages({ + yield waitForMessages({ webconsole: hud, messages: [{ text: "test message 149", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(testNext); - - yield undefined; + }); ok(scrollBox.scrollTop > 0, "scroll location is not at the top"); // scroll to the first node outputNode.focus(); + let scrolled = promise.defer(); + scrollBox.onscroll = () => { info("onscroll top " + scrollBox.scrollTop); if (scrollBox.scrollTop != 0) { @@ -46,26 +46,26 @@ function testGen() { } scrollBox.onscroll = null; is(scrollBox.scrollTop, 0, "scroll location updated (moved to top)"); - testNext(); + scrolled.resolve(); }; EventUtils.synthesizeKey("VK_HOME", {}, hud.iframeWindow); - yield undefined; + yield scrolled.promise; + // add a message and make sure scroll doesn't change content.console.log("test message 150"); - waitForMessages({ + yield waitForMessages({ webconsole: hud, messages: [{ text: "test message 150", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(testNext); - - yield undefined; + }); + scrolled = promise.defer(); scrollBox.onscroll = () => { if (scrollBox.scrollTop != 0) { // Wait for scroll to stabilize at the top. @@ -73,18 +73,19 @@ function testGen() { } scrollBox.onscroll = null; is(scrollBox.scrollTop, 0, "scroll location is still at the top"); - testNext(); + scrolled.resolve(); }; // Make sure that scroll stabilizes at the top. executeSoon() is needed for // the yield to work. executeSoon(scrollBox.onscroll); - yield undefined; + yield scrolled.promise; // scroll back to the bottom outputNode.lastChild.focus(); + scrolled = promise.defer(); scrollBox.onscroll = () => { if (scrollBox.scrollTop == 0) { // Wait for scroll to bottom. @@ -92,15 +93,16 @@ function testGen() { } scrollBox.onscroll = null; isnot(scrollBox.scrollTop, 0, "scroll location updated (moved to bottom)"); - testNext(); + scrolled.resolve(); }; EventUtils.synthesizeKey("VK_END", {}); - yield undefined; + yield scrolled.promise; let oldScrollTop = scrollBox.scrollTop; content.console.log("test message 151"); + scrolled = promise.defer(); scrollBox.onscroll = () => { if (scrollBox.scrollTop == oldScrollTop) { // Wait for scroll to change. @@ -108,21 +110,7 @@ function testGen() { } scrollBox.onscroll = null; isnot(scrollBox.scrollTop, oldScrollTop, "scroll location updated (moved to bottom again)"); - hud = testDriver = null; - finishTest(); + scrolled.resolve(); }; - - yield undefined; -} - -function test() { - addTab("data:text/html;charset=utf-8,Web Console test for bug 613642: remember scroll location"); - browser.addEventListener("load", function tabLoad(aEvent) { - browser.removeEventListener(aEvent.type, tabLoad, true); - openConsole(null, function(aHud) { - hud = aHud; - testDriver = testGen(); - testDriver.next(); - }); - }, true); -} + yield scrolled.promise; +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_613642_prune_scroll.js b/browser/devtools/webconsole/test/browser_webconsole_bug_613642_prune_scroll.js index f0cd21741d7c..c11ca88786cc 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_613642_prune_scroll.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_613642_prune_scroll.js @@ -7,13 +7,17 @@ * Mihai Șucan */ -let hud, testDriver; +"use strict"; -function testNext() { - testDriver.next(); -} +const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 613642: maintain scroll with pruning of old messages"; + +let hud; + +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); -function testGen() { hud.jsterm.clearOutput(); let outputNode = hud.outputNode; @@ -25,16 +29,14 @@ function testGen() { content.console.log("test message " + i); } - waitForMessages({ + yield waitForMessages({ webconsole: hud, messages: [{ text: "test message 149", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(testNext); - - yield undefined; + }); let oldScrollTop = scrollBoxElement.scrollTop; isnot(oldScrollTop, 0, "scroll location is not at the top"); @@ -56,16 +58,14 @@ function testGen() { // add a message content.console.log("hello world"); - waitForMessages({ + yield waitForMessages({ webconsole: hud, messages: [{ text: "hello world", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(testNext); - - yield undefined; + }); // Scroll location needs to change, because one message is also removed, and // we need to scroll a bit towards the top, to keep the current view in sync. @@ -77,21 +77,5 @@ function testGen() { Services.prefs.clearUserPref("devtools.hud.loglimit.console"); - hud = testDriver = null; - finishTest(); - - yield undefined; -} - -function test() { - addTab("data:text/html;charset=utf-8,Web Console test for bug 613642: maintain scroll with pruning of old messages"); - browser.addEventListener("load", function tabLoad(aEvent) { - browser.removeEventListener(aEvent.type, tabLoad, true); - - openConsole(null, function(aHud) { - hud = aHud; - testDriver = testGen(); - testDriver.next(); - }); - }, true); -} + hud = null; +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_614793_jsterm_scroll.js b/browser/devtools/webconsole/test/browser_webconsole_bug_614793_jsterm_scroll.js index 5ec3ff4c4734..20decb266db5 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_614793_jsterm_scroll.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_614793_jsterm_scroll.js @@ -7,7 +7,21 @@ * Mihai Șucan */ +const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 614793: jsterm result scroll"; + +"use strict"; + +let test = asyncTest(function* () { + let { browser } = yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + yield consoleOpened(hud); +}); + function consoleOpened(hud) { + let deferred = promise.defer(); + hud.jsterm.clearOutput(); let scrollNode = hud.outputNode.parentNode; @@ -42,15 +56,8 @@ function consoleOpened(hud) { is(scrollNode.scrollTop, oldScrollTop, "scroll location is the same"); - finishTest(); + deferred.resolve(); } -} -function test() { - addTab("data:text/html;charset=utf-8,Web Console test for bug 614793: jsterm result scroll"); - browser.addEventListener("load", function onLoad(aEvent) { - browser.removeEventListener(aEvent.type, onLoad, true); - openConsole(null, consoleOpened); - }, true); + return deferred.promise; } - diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_618078_network_exceptions.js b/browser/devtools/webconsole/test/browser_webconsole_bug_618078_network_exceptions.js index cdd616c72eae..cb98e2c0dc62 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_618078_network_exceptions.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_618078_network_exceptions.js @@ -6,26 +6,24 @@ // Tests that we report JS exceptions in event handlers coming from // network requests, like onreadystate for XHR. See bug 618078. -const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-618078-network-exceptions.html"; +const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 618078"; +const TEST_URI2 = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-618078-network-exceptions.html"; -function test() -{ - addTab("data:text/html;charset=utf-8,Web Console test for bug 618078"); +let test = asyncTest(function* () { + yield loadTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, function(hud) { - expectUncaughtException(); - content.location = TEST_URI; + let hud = yield openConsole(); - waitForMessages({ - webconsole: hud, - messages: [{ - text: "bug618078exception", - category: CATEGORY_JS, - severity: SEVERITY_ERROR, - }], - }).then(finishTest); - }); - }, true); -} + expectUncaughtException(); + + content.location = TEST_URI2; + + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "bug618078exception", + category: CATEGORY_JS, + severity: SEVERITY_ERROR, + }], + }); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_618311_close_panels.js b/browser/devtools/webconsole/test/browser_webconsole_bug_618311_close_panels.js index 461d2f10e9f4..6d3c9e4e5610 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_618311_close_panels.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_618311_close_panels.js @@ -5,28 +5,28 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); +let test = asyncTest(function* () { + yield loadTab(TEST_URI); - openConsole(null, function(hud) { - content.location.reload(); + let hud = yield openConsole(); - waitForMessages({ - webconsole: hud, - messages: [{ - text: "test-console.html", - category: CATEGORY_NETWORK, - severity: SEVERITY_LOG, - }], - }).then(performTest); - }); - }, true); -} + BrowserReload(); -function performTest(results) { - let HUD = HUDService.getHudByWindow(content); + let results = yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "test-console.html", + category: CATEGORY_NETWORK, + severity: SEVERITY_LOG, + }], + }) + + yield performTest(hud, results); +}); + + +function performTest(HUD, results) { + let deferred = promise.defer(); let networkMessage = [...results[0].matched][0]; ok(networkMessage, "network message element"); @@ -69,7 +69,7 @@ function performTest(results) { let popups = popupset.querySelectorAll("panel[hudId=" + HUD.hudId + "]"); is(popups.length, 0, "no popups found"); - executeSoon(finishTest); + executeSoon(deferred.resolve); }); }; @@ -85,4 +85,6 @@ function performTest(results) { EventUtils.sendMouseEvent({ type: "mousedown" }, networkLink, HUD.iframeWindow); EventUtils.sendMouseEvent({ type: "mouseup" }, networkLink, HUD.iframeWindow); EventUtils.sendMouseEvent({ type: "click" }, networkLink, HUD.iframeWindow); + + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_621644_jsterm_dollar.js b/browser/devtools/webconsole/test/browser_webconsole_bug_621644_jsterm_dollar.js index 3c7f8d95d615..085887e699ac 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_621644_jsterm_dollar.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_621644_jsterm_dollar.js @@ -9,32 +9,41 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-621644-jsterm-dollar.html"; -function test$(HUD) { +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + yield test$(hud); + yield test$$(hud); +}); + + +function* test$(HUD) { + let deferred = promise.defer(); + HUD.jsterm.clearOutput(); HUD.jsterm.execute("$(document.body)", (msg) => { ok(msg.textContent.indexOf("

") > -1, "jsterm output is correct for $()"); - - test$$(HUD); + deferred.resolve(); }); + + return deferred.promise; } function test$$(HUD) { + let deferred = promise.defer(); + HUD.jsterm.clearOutput(); HUD.jsterm.setInputValue(); HUD.jsterm.execute("$$(document)", (msg) => { ok(msg.textContent.indexOf("621644") > -1, "jsterm output is correct for $$()"); - finishTest(); + deferred.resolve(); }); -} -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, test$); - }, true); + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_622303_persistent_filters.js b/browser/devtools/webconsole/test/browser_webconsole_bug_622303_persistent_filters.js index 39d075a560b1..15c603475858 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_622303_persistent_filters.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_622303_persistent_filters.js @@ -1,7 +1,7 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -let prefs = { +const prefs = { "net": [ "network", "netwarn", @@ -25,7 +25,7 @@ let prefs = { ] }; -function test() { +let test = asyncTest(function* () { // Set all prefs to true for (let category in prefs) { prefs[category].forEach(function(pref) { @@ -33,11 +33,25 @@ function test() { }); } - addTab("about:blank"); - openConsole(null, onConsoleOpen); -} + yield loadTab("about:blank"); + + let hud = yield openConsole(); + + let hud2 = yield onConsoleOpen(hud); + let hud3 = yield onConsoleReopen1(hud2); + yield onConsoleReopen2(hud3); + + // Clear prefs + for (let category in prefs) { + prefs[category].forEach(function(pref) { + Services.prefs.clearUserPref("devtools.webconsole.filter." + pref); + }); + } +}); function onConsoleOpen(hud) { + let deferred = promise.defer(); + let hudBox = hud.ui.rootElement; // Check if the filters menuitems exists and are checked @@ -60,12 +74,17 @@ function onConsoleOpen(hud) { } //Re-init the console - closeConsole(null, function() { - openConsole(null, onConsoleReopen1); + closeConsole().then(() => { + openConsole().then(deferred.resolve); }); + + return deferred.promise; } function onConsoleReopen1(hud) { + info("testing after reopening once"); + let deferred = promise.defer(); + let hudBox = hud.ui.rootElement; // Check if the filter button and menuitems are unchecked @@ -86,12 +105,16 @@ function onConsoleReopen1(hud) { } // Re-init the console - closeConsole(null, function() { - openConsole(null, onConsoleReopen2); + closeConsole().then(() => { + openConsole().then(deferred.resolve); }); + + return deferred.promise; } function onConsoleReopen2(hud) { + info("testing after reopening again"); + let hudBox = hud.ui.rootElement; // Check the main category button is checked and first menuitem is checked @@ -104,16 +127,6 @@ function onConsoleReopen2(hud) { let menuitem = hudBox.querySelector("menuitem[prefKey=" + pref + "]"); ok(isChecked(menuitem), "first " + category + " menuitem is checked"); } - - // Clear prefs - for (let category in prefs) { - prefs[category].forEach(function(pref) { - Services.prefs.clearUserPref("devtools.webconsole.filter." + pref); - }); - } - - prefs = null; - finishTest(); } function isChecked(aNode) { diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js b/browser/devtools/webconsole/test/browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js index 6e93ce523479..84cd52c4a0ac 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js @@ -4,16 +4,14 @@ // Test for https://bugzilla.mozilla.org/show_bug.cgi?id=623749 // Map Control + A to Select All, In the web console input, on Windows -function test() { - addTab("data:text/html;charset=utf-8,Test console for bug 623749"); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, runTest); - }, true); -} +const TEST_URI = "data:text/html;charset=utf-8,Test console for bug 623749"; -function runTest(HUD) { - let jsterm = HUD.jsterm; +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + let jsterm = hud.jsterm; jsterm.setInputValue("Ignore These Four Words"); let inputNode = jsterm.inputNode; @@ -27,6 +25,4 @@ function runTest(HUD) { inputNode.selectionStart = 0; EventUtils.synthesizeKey("e", { ctrlKey: true }); is(inputNode.selectionStart, 0, "Control + E does not move to end of input"); - - executeSoon(finishTest); -} +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js b/browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js index dba3f760589f..88f77127558d 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js @@ -7,35 +7,51 @@ * Mihai Sucan */ -const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-630733-response-redirect-headers.sjs"; +const TEST_URI = "data:text/html;charset=utf-8,

Web Console test for bug 630733"; +const TEST_URI2 = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-630733-response-redirect-headers.sjs"; let lastFinishedRequests = {}; let webConsoleClient; +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + yield consoleOpened(hud); + yield getHeaders(); + yield getContent(); + + performTest(); +}); + function consoleOpened(hud) { + let deferred = promise.defer(); + webConsoleClient = hud.ui.webConsoleClient; hud.ui.setSaveRequestAndResponseBodies(true).then(() => { ok(hud.ui._saveRequestAndResponseBodies, "The saveRequestAndResponseBodies property was successfully set."); - HUDService.lastFinishedRequest.callback = requestDoneCallback; - content.location = TEST_URI; + HUDService.lastFinishedRequest.callback = (aHttpRequest) => { + let status = aHttpRequest.response.status; + lastFinishedRequests[status] = aHttpRequest; + if ("301" in lastFinishedRequests && + "404" in lastFinishedRequests) { + deferred.resolve(); + } + } + content.location = TEST_URI2; }); -} -function requestDoneCallback(aHttpRequest) -{ - let status = aHttpRequest.response.status; - lastFinishedRequests[status] = aHttpRequest; - if ("301" in lastFinishedRequests && - "404" in lastFinishedRequests) { - getHeaders(); - } + return deferred.promise; } function getHeaders() { + let deferred = promise.defer(); + HUDService.lastFinishedRequest.callback = null; ok("301" in lastFinishedRequests, "request 1: 301 Moved Permanently"); @@ -48,13 +64,16 @@ function getHeaders() webConsoleClient.getResponseHeaders(lastFinishedRequests["404"].actor, function (aResponse) { lastFinishedRequests["404"].response.headers = aResponse.headers; - executeSoon(getContent); + executeSoon(deferred.resolve); }); }); + return deferred.promise; } function getContent() { + let deferred = promise.defer(); + webConsoleClient.getResponseContent(lastFinishedRequests["301"].actor, function (aResponse) { lastFinishedRequests["301"].response.content = aResponse.content; @@ -67,9 +86,10 @@ function getContent() aResponse.contentDiscarded; webConsoleClient = null; - executeSoon(performTest); + executeSoon(deferred.resolve); }); }); + return deferred.promise; } function performTest() @@ -106,16 +126,5 @@ function performTest() isnot(body.indexOf("404"), -1, "body is correct for request 2"); - lastFinishedRequests = null; - executeSoon(finishTest); -} - -function test() -{ - addTab("data:text/html;charset=utf-8,

Web Console test for bug 630733"); - - browser.addEventListener("load", function onLoad(aEvent) { - browser.removeEventListener(aEvent.type, onLoad, true); - openConsole(null, consoleOpened); - }, true); + lastFinishedRequests = webConsoleClient = null; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_632275_getters_document_width.js b/browser/devtools/webconsole/test/browser_webconsole_bug_632275_getters_document_width.js index 756cb3e7dcd8..6b0a3d09700f 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_632275_getters_document_width.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_632275_getters_document_width.js @@ -13,11 +13,9 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/te let getterValue = null; function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + loadTab(TEST_URI).then(() => { + openConsole().then(consoleOpened); + }); } function consoleOpened(hud) { @@ -46,6 +44,7 @@ function onViewOpened(hud, event, view) is(textContent.indexOf("document.body.client"), -1, "no document.width/height warning displayed"); + getterValue = null; finishTest(); }); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js b/browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js index be5e2d81a4c9..0410a6968a0a 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js @@ -8,11 +8,9 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/te function test() { requestLongerTimeout(6); - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + loadTab(TEST_URI).then(() => { + openConsole().then(consoleOpened); + }); } function consoleOpened(HUD) { diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_632817.js b/browser/devtools/webconsole/test/browser_webconsole_bug_632817.js index e77d7be45b79..c42ff615e9ff 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_632817.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_632817.js @@ -11,8 +11,11 @@ const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/test/te const TEST_DATA_JSON_CONTENT = '{ id: "test JSON data", myArray: [ "foo", "bar", "baz", "biff" ] }'; +const TEST_URI = "data:text/html;charset=utf-8,Web Console network logging tests"; + let lastRequest = null; let requestCallback = null; +let hud, browser; function test() { @@ -25,12 +28,9 @@ function test() Services.prefs.clearUserPref(PREF); }); - addTab("data:text/html;charset=utf-8,Web Console network logging tests"); - - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - - openConsole(null, function(aHud) { + loadTab(TEST_URI).then((tab) => { + browser = tab.browser; + openConsole().then((aHud) => { hud = aHud; HUDService.lastFinishedRequest.callback = function(aRequest) { @@ -41,8 +41,8 @@ function test() }; executeSoon(testPageLoad); - }); - }, true); + }) + }); } function testPageLoad() @@ -186,6 +186,7 @@ function testLiveFilteringOnSearchStrings() { HUDService.lastFinishedRequest.callback = null; lastRequest = null; requestCallback = null; + hud = browser = null; finishTest(); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_644419_log_limits.js b/browser/devtools/webconsole/test/browser_webconsole_bug_644419_log_limits.js index 2f3a0127db18..ac489ee42981 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_644419_log_limits.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_644419_log_limits.js @@ -7,44 +7,54 @@ // Tests that the Web Console limits the number of lines displayed according to // the limit set for each category. +const INIT_URI = "data:text/html;charset=utf-8,Web Console test for bug 644419: Console should " + + "have user-settable log limits for each message category"; + const TEST_URI = "http://example.com/browser/browser/devtools/" + "webconsole/test/test-bug-644419-log-limits.html"; let hud, outputNode; -function test() { - addTab("data:text/html;charset=utf-8,Web Console test for bug 644419: Console should " + - "have user-settable log limits for each message category"); - browser.addEventListener("load", onLoad, true); -} +let test = asyncTest(function* () { + let { browser } = yield loadTab(INIT_URI); -function onLoad(aEvent) { - browser.removeEventListener(aEvent.type, onLoad, true); + hud = yield openConsole(); - openConsole(null, function(aHud) { - aHud.jsterm.clearOutput(); - hud = aHud; - outputNode = aHud.outputNode; + hud.jsterm.clearOutput(); + outputNode = hud.outputNode; - browser.addEventListener("load", testWebDevLimits, true); - expectUncaughtException(); - content.location = TEST_URI; - }); -} + let loaded = loadBrowser(browser); -function testWebDevLimits(aEvent) { - browser.removeEventListener(aEvent.type, testWebDevLimits, true); + expectUncaughtException(); + + content.location = TEST_URI; + yield loaded; + + yield testWebDevLimits(); + yield testWebDevLimits2(); + yield testJsLimits(); + yield testJsLimits2(); + + yield testNetLimits(); + yield loadImage(); + yield testCssLimits(); + yield testCssLimits2(); + + hud = outputNode = null; +}); + +function testWebDevLimits() { Services.prefs.setIntPref("devtools.hud.loglimit.console", 10); // Find the sentinel entry. - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [{ text: "bar is not defined", category: CATEGORY_JS, severity: SEVERITY_ERROR, }], - }).then(testWebDevLimits2); + }) } function testWebDevLimits2() { @@ -53,7 +63,7 @@ function testWebDevLimits2() { content.console.log("test message " + i); } - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [{ text: "test message 10", @@ -67,7 +77,6 @@ function testWebDevLimits2() { findLogEntry("bar is not defined"); Services.prefs.clearUserPref("devtools.hud.loglimit.console"); - testJsLimits(); }); } @@ -78,14 +87,14 @@ function testJsLimits() { content.console.log("testing JS limits"); // Find the sentinel entry. - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [{ text: "testing JS limits", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(testJsLimits2); + }); } function testJsLimits2() { @@ -94,11 +103,12 @@ function testJsLimits2() { for (let i = 0; i < 11; i++) { var script = content.document.createElement("script"); script.text = "fubar" + i + ".bogus(6);"; + expectUncaughtException(); head.insertBefore(script, head.firstChild); } - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [{ text: "fubar10 is not defined", @@ -112,7 +122,6 @@ function testJsLimits2() { findLogEntry("testing JS limits"); Services.prefs.clearUserPref("devtools.hud.loglimit.exception"); - testNetLimits(); }); } @@ -125,7 +134,7 @@ function testNetLimits() { content.console.log("testing Net limits"); // Find the sentinel entry. - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [{ text: "testing Net limits", @@ -135,7 +144,6 @@ function testNetLimits() { }).then(() => { // Fill the log with network messages. gCounter = 0; - loadImage(); }); } @@ -153,7 +161,7 @@ function loadImage() { is(gCounter, 11, "loaded 11 files"); - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [{ text: "test-image.png", @@ -169,7 +177,6 @@ function loadImage() { findLogEntry("testing Net limits"); Services.prefs.clearUserPref("devtools.hud.loglimit.network"); - testCssLimits(); }); } @@ -180,14 +187,14 @@ function testCssLimits() { content.console.log("testing CSS limits"); // Find the sentinel entry. - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [{ text: "testing CSS limits", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(testCssLimits2); + }); } function testCssLimits2() { @@ -199,7 +206,7 @@ function testCssLimits2() { body.insertBefore(div, body.firstChild); } - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [{ text: "-moz-foobar10", @@ -214,6 +221,5 @@ function testCssLimits2() { findLogEntry("testing CSS limits"); Services.prefs.clearUserPref("devtools.hud.loglimit.cssparser"); - finishTest(); }); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_646025_console_file_location.js b/browser/devtools/webconsole/test/browser_webconsole_bug_646025_console_file_location.js index aeca2751a18e..39be46e41aee 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_646025_console_file_location.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_646025_console_file_location.js @@ -6,51 +6,49 @@ // Tests that console logging methods display the method location along with // the output in the console. -const TEST_URI = "http://example.com/browser/browser/devtools/" + +const TEST_URI = "data:text/html;charset=utf-8,Web Console file location display test"; +const TEST_URI2 = "http://example.com/browser/browser/devtools/" + "webconsole/test/" + "test-bug-646025-console-file-location.html"; -function test() { - addTab("data:text/html;charset=utf-8,Web Console file location display test"); - browser.addEventListener("load", onLoad, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); -function onLoad(aEvent) { - browser.removeEventListener(aEvent.type, onLoad, true); - openConsole(null, function(hud) { - content.location = TEST_URI; - waitForMessages({ - webconsole: hud, - messages: [{ - text: "message for level log", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - source: { url: "test-file-location.js", line: 5 }, - }, - { - text: "message for level info", - category: CATEGORY_WEBDEV, - severity: SEVERITY_INFO, - source: { url: "test-file-location.js", line: 6 }, - }, - { - text: "message for level warn", - category: CATEGORY_WEBDEV, - severity: SEVERITY_WARNING, - source: { url: "test-file-location.js", line: 7 }, - }, - { - text: "message for level error", - category: CATEGORY_WEBDEV, - severity: SEVERITY_ERROR, - source: { url: "test-file-location.js", line: 8 }, - }, - { - text: "message for level debug", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - source: { url: "test-file-location.js", line: 9 }, - }], - }).then(finishTest); + let hud = yield openConsole(); + + content.location = TEST_URI2; + + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "message for level log", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + source: { url: "test-file-location.js", line: 5 }, + }, + { + text: "message for level info", + category: CATEGORY_WEBDEV, + severity: SEVERITY_INFO, + source: { url: "test-file-location.js", line: 6 }, + }, + { + text: "message for level warn", + category: CATEGORY_WEBDEV, + severity: SEVERITY_WARNING, + source: { url: "test-file-location.js", line: 7 }, + }, + { + text: "message for level error", + category: CATEGORY_WEBDEV, + severity: SEVERITY_ERROR, + source: { url: "test-file-location.js", line: 8 }, + }, + { + text: "message for level debug", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + source: { url: "test-file-location.js", line: 9 }, + }], }); -} +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js b/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js index 50c885c57738..9f2969214e8d 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js @@ -5,19 +5,28 @@ */ // Tests that document.body autocompletes in the web console. +const TEST_URI = "data:text/html;charset=utf-8,Web Console autocompletion bug in document.body"; -function test() { - addTab("data:text/html;charset=utf-8,Web Console autocompletion bug in document.body"); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} +"use strict"; let gHUD; +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + gHUD = yield openConsole(); + + yield consoleOpened(); + yield autocompletePopupHidden(); + let view = yield testPropertyPanel(); + yield onVariablesViewReady(view); + + gHUD = null; +}); + function consoleOpened(aHud) { - gHUD = aHud; + let deferred = promise.defer(); + let jsterm = gHUD.jsterm; let popup = jsterm.autocompletePopup; let completeNode = jsterm.completeNode; @@ -38,17 +47,21 @@ function consoleOpened(aHud) { isnot(jsterm._autocompleteCache.indexOf("ATTRIBUTE_NODE"), -1, "ATTRIBUTE_NODE is in the list of suggestions"); - popup._panel.addEventListener("popuphidden", autocompletePopupHidden, false); + popup._panel.addEventListener("popuphidden", deferred.resolve, false); EventUtils.synthesizeKey("VK_ESCAPE", {}); }, false); jsterm.setInputValue("document.body"); EventUtils.synthesizeKey(".", {}); + + return deferred.promise; } function autocompletePopupHidden() { + let deferred = promise.defer(); + let jsterm = gHUD.jsterm; let popup = jsterm.autocompletePopup; let completeNode = jsterm.completeNode; @@ -60,34 +73,37 @@ function autocompletePopupHidden() jsterm.once("autocomplete-updated", function() { is(completeNode.value, testStr + "dy", "autocomplete shows document.body"); - testPropertyPanel(); + deferred.resolve(); }); let inputStr = "document.b"; jsterm.setInputValue(inputStr); EventUtils.synthesizeKey("o", {}); let testStr = inputStr.replace(/./g, " ") + " "; + + return deferred.promise; } function testPropertyPanel() { + let deferred = promise.defer(); + let jsterm = gHUD.jsterm; jsterm.clearOutput(); jsterm.execute("document", (msg) => { - jsterm.once("variablesview-fetched", onVariablesViewReady); + jsterm.once("variablesview-fetched", (aEvent, aView) => { + deferred.resolve(aView); + }); let anchor = msg.querySelector(".message-body a"); EventUtils.synthesizeMouse(anchor, 2, 2, {}, gHUD.iframeWindow); }); + + return deferred.promise; } -function onVariablesViewReady(aEvent, aView) +function onVariablesViewReady(aView) { - findVariableViewProperties(aView, [ + return findVariableViewProperties(aView, [ { name: "body", value: "" }, - ], { webconsole: gHUD }).then(finishUp); -} - -function finishUp() { - gHUD = null; - finishTest(); + ], { webconsole: gHUD }); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js b/browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js index 8874cb11e441..85d2a0466815 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js @@ -6,13 +6,13 @@ /////////////////// // // Whitelisting this test. -// As part of bug 1077403, the leaking uncaught rejection should be fixed. +// As part of bug 1077403, the leaking uncaught rejection should be fixed. // thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Protocol error (unknownError): TypeError: this.conn.getActor(...) is null"); // Tests that the $0 console helper works as intended. -let inspector, h1; +let inspector, h1, outputNode; function createDocument() { let doc = content.document; @@ -50,7 +50,7 @@ function createDocument() { function setupHighlighterTests() { ok(h1, "we have the header node"); - openInspector(runSelectionTests); + openInspector().then(runSelectionTests); } let runSelectionTests = Task.async(function*(aInspector) { @@ -95,7 +95,7 @@ function performWebConsoleTests(hud) { is(inspector.selection.node.textContent, "bug653531", "node successfully updated"); - inspector = h1 = null; + inspector = h1 = outputNode = null; gBrowser.removeCurrentTab(); finishTest(); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_658368_time_methods.js b/browser/devtools/webconsole/test/browser_webconsole_bug_658368_time_methods.js index b45f5ac15f63..8cb87324e51c 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_658368_time_methods.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_658368_time_methods.js @@ -6,82 +6,61 @@ // Tests that the Console API implements the time() and timeEnd() methods. -function test() { - addTab("http://example.com/browser/browser/devtools/webconsole/" + - "test/test-bug-658368-time-methods.html"); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - Task.spawn(runner); - }, true); +const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" + + "test/test-bug-658368-time-methods.html"; - function* runner() { - let hud1 = yield openConsole(); +const TEST_URI2 = "data:text/html;charset=utf-8,"; - yield waitForMessages({ - webconsole: hud1, - messages: [{ - name: "aTimer started", - consoleTime: "aTimer", - }, { - name: "aTimer end", - consoleTimeEnd: "aTimer", - }], - }); - - let deferred = promise.defer(); - - // The next test makes sure that timers with the same name but in separate - // tabs, do not contain the same value. - addTab("data:text/html;charset=utf-8,"); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole().then((hud) => { - deferred.resolve(hud); - }); - }, true); - - let hud2 = yield deferred.promise; - - testLogEntry(hud2.outputNode, "bTimer: timer started", - "bTimer was not started", false, true); - - // The next test makes sure that timers with the same name but in separate - // pages, do not contain the same value. - content.location = "data:text/html;charset=utf-8,"; - yield waitForMessages({ - webconsole: hud2, - messages: [{ - name: "bTimer started", - consoleTime: "bTimer", - }], - }); - - hud2.jsterm.clearOutput(); - - deferred = promise.defer(); - - // Now the following console.timeEnd() call shouldn't display anything, - // if the timers in different pages are not related. - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - deferred.resolve(null); - }, true); - - content.location = "data:text/html;charset=utf-8," + +const TEST_URI4 = "data:text/html;charset=utf-8," + ""; - yield deferred.promise; +let test = asyncTest(function* () { + yield loadTab(TEST_URI); - testLogEntry(hud2.outputNode, "bTimer: timer started", - "bTimer was not started", false, true); + let hud1 = yield openConsole(); - yield closeConsole(gBrowser.selectedTab); + yield waitForMessages({ + webconsole: hud1, + messages: [{ + name: "aTimer started", + consoleTime: "aTimer", + }, { + name: "aTimer end", + consoleTimeEnd: "aTimer", + }], + }); - gBrowser.removeCurrentTab(); + // The next test makes sure that timers with the same name but in separate + // tabs, do not contain the same value. + let { browser } = yield loadTab(TEST_URI2); + let hud2 = yield openConsole(); - executeSoon(finishTest); - } -} + testLogEntry(hud2.outputNode, "bTimer: timer started", + "bTimer was not started", false, true); + + // The next test makes sure that timers with the same name but in separate + // pages, do not contain the same value. + content.location = TEST_URI3; + + yield waitForMessages({ + webconsole: hud2, + messages: [{ + name: "bTimer started", + consoleTime: "bTimer", + }], + }); + + hud2.jsterm.clearOutput(); + + // Now the following console.timeEnd() call shouldn't display anything, + // if the timers in different pages are not related. + content.location = TEST_URI4; + yield loadBrowser(browser); + + testLogEntry(hud2.outputNode, "bTimer: timer started", + "bTimer was not started", false, true); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_659907_console_dir.js b/browser/devtools/webconsole/test/browser_webconsole_bug_659907_console_dir.js index 431b55981275..1569899a139d 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_659907_console_dir.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_659907_console_dir.js @@ -6,24 +6,23 @@ // Tests that console.dir works as intended. -function test() { - addTab("data:text/html;charset=utf-8,Web Console test for bug 659907: Expand console " + - "object with a dir method"); - browser.addEventListener("load", function onLoad(aEvent) { - browser.removeEventListener(aEvent.type, onLoad, true); - openConsole(null, consoleOpened); - }, true); -} +"use strict"; + +const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 659907: " + + "Expand console object with a dir method" + +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); + hud.jsterm.clearOutput(); -function consoleOpened(hud) { hud.jsterm.execute("console.dir(document)"); - hud.jsterm.once("variablesview-fetched", testConsoleDir.bind(null, hud)); -} -function testConsoleDir(hud, ev, view) { - findVariableViewProperties(view, [ + let varView = yield hud.jsterm.once("variablesview-fetched"); + + yield findVariableViewProperties(varView, [ { name: "__proto__.__proto__.querySelectorAll", value: "querySelectorAll()" }, { name: "location", value: /Location \u2192 data:Web/ }, { name: "__proto__.write", value: "write()" }, - ], { webconsole: hud }).then(finishTest); -} + ], { webconsole: hud }); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_660806_history_nav.js b/browser/devtools/webconsole/test/browser_webconsole_bug_660806_history_nav.js index ade0c09363ae..2f057e4ca0c6 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_660806_history_nav.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_660806_history_nav.js @@ -4,20 +4,17 @@ const TEST_URI = "data:text/html;charset=utf-8,

bug 660806 - history navigation must not show the autocomplete popup"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + yield consoleOpened(hud); +}); function consoleOpened(HUD) { - content.wrappedJSObject.foobarBug660806 = { - "location": "value0", - "locationbar": "value1", - }; + let deferred = promise.defer(); let jsterm = HUD.jsterm; let popup = jsterm.autocompletePopup; @@ -25,6 +22,11 @@ function consoleOpened(HUD) ok(false, "popup shown"); }; + jsterm.execute("window.foobarBug660806 = {\ + 'location': 'value0',\ + 'locationbar': 'value1'\ + }"); + popup._panel.addEventListener("popupshown", onShown, false); ok(!popup.isOpen, "popup is not open"); @@ -43,6 +45,7 @@ function consoleOpened(HUD) executeSoon(function() { ok(!popup.isOpen, "popup is not open"); popup._panel.removeEventListener("popupshown", onShown, false); - executeSoon(finishTest); + executeSoon(deferred.resolve); }); + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_664131_console_group.js b/browser/devtools/webconsole/test/browser_webconsole_bug_664131_console_group.js index faaa53cb0f4e..792490245117 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_664131_console_group.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_664131_console_group.js @@ -7,73 +7,71 @@ // Tests that console.group/groupEnd works as intended. const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 664131: Expand console object with group methods"; -function test() { - Task.spawn(runner).then(finishTest); +let test = asyncTest(function* () { + yield loadTab(TEST_URI); - function* runner() { - let {tab} = yield loadTab(TEST_URI); - let hud = yield openConsole(tab); - let outputNode = hud.outputNode; + let hud = yield openConsole(); + let jsterm = hud.jsterm; + let outputNode = hud.outputNode; - hud.jsterm.clearOutput(); + hud.jsterm.clearOutput(); - content.console.group("bug664131a"); + jsterm.execute("console.group('bug664131a')") - yield waitForMessages({ - webconsole: hud, - messages: [{ - text: "bug664131a", - consoleGroup: 1, - }], - }); + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "bug664131a", + consoleGroup: 1, + }], + }); - content.console.log("bug664131a-inside"); + jsterm.execute("console.log('bug664131a-inside')") - yield waitForMessages({ - webconsole: hud, - messages: [{ - text: "bug664131a-inside", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - groupDepth: 1, - }], - }); + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "bug664131a-inside", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + groupDepth: 1, + }], + }); - content.console.groupEnd("bug664131a"); - content.console.log("bug664131-outside"); + jsterm.execute('console.groupEnd("bug664131a")'); + jsterm.execute('console.log("bug664131-outside")'); - yield waitForMessages({ - webconsole: hud, - messages: [{ - text: "bug664131-outside", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - groupDepth: 0, - }], - }); + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "bug664131-outside", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + groupDepth: 0, + }], + }); - content.console.groupCollapsed("bug664131b"); + jsterm.execute('console.groupCollapsed("bug664131b")'); - yield waitForMessages({ - webconsole: hud, - messages: [{ - text: "bug664131b", - consoleGroup: 1, - }], - }); + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "bug664131b", + consoleGroup: 1, + }], + }); - // Test that clearing the console removes the indentation. - hud.jsterm.clearOutput(); - content.console.log("bug664131-cleared"); + // Test that clearing the console removes the indentation. + hud.jsterm.clearOutput(); + jsterm.execute('console.log("bug664131-cleared")'); - yield waitForMessages({ - webconsole: hud, - messages: [{ - text: "bug664131-cleared", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - groupDepth: 0, - }], - }); - } -} + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "bug664131-cleared", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + groupDepth: 0, + }], + }); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_686937_autocomplete_JSTerm_helpers.js b/browser/devtools/webconsole/test/browser_webconsole_bug_686937_autocomplete_JSTerm_helpers.js index c5fe935622dd..d2e45489dad5 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_686937_autocomplete_JSTerm_helpers.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_686937_autocomplete_JSTerm_helpers.js @@ -7,68 +7,54 @@ const TEST_URI = "data:text/html;charset=utf8,

test JSTerm Helpers autocomplete"; -let testDriver; +let jsterm; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, function(hud) { - testDriver = testCompletion(hud); - testDriver.next(); - }); - }, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); -function testNext() { - executeSoon(function() { - testDriver.next(); - }); -} + let hud = yield openConsole(); -function testCompletion(hud) { - let jsterm = hud.jsterm; + jsterm = hud.jsterm; let input = jsterm.inputNode; let popup = jsterm.autocompletePopup; // Test if 'i' gives 'inspect' input.value = "i"; input.setSelectionRange(1, 1); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield; + yield complete(jsterm.COMPLETE_HINT_ONLY); let newItems = popup.getItems().map(function(e) {return e.label;}); ok(newItems.indexOf("inspect") > -1, "autocomplete results contain helper 'inspect'"); - + // Test if 'window.' does not give 'inspect'. input.value = "window."; input.setSelectionRange(7, 7); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield; + yield complete(jsterm.COMPLETE_HINT_ONLY); newItems = popup.getItems().map(function(e) {return e.label;}); is(newItems.indexOf("inspect"), -1, "autocomplete results do not contain helper 'inspect'"); - -// Test if 'dump(i' gives 'inspect' + // Test if 'dump(i' gives 'inspect' input.value = "dump(i"; input.setSelectionRange(6, 6); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield; + yield complete(jsterm.COMPLETE_HINT_ONLY); newItems = popup.getItems().map(function(e) {return e.label;}); ok(newItems.indexOf("inspect") > -1, "autocomplete results contain helper 'inspect'"); -// Test if 'window.dump(i' gives 'inspect' + // Test if 'window.dump(i' gives 'inspect' input.value = "window.dump(i"; input.setSelectionRange(13, 13); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield; + yield complete(jsterm.COMPLETE_HINT_ONLY); newItems = popup.getItems().map(function(e) {return e.label;}); ok(newItems.indexOf("inspect") > -1, "autocomplete results contain helper 'inspect'"); - testDriver = jsterm = input = popup = newItems = null; - executeSoon(finishTest); - yield; -} + jsterm = null; +}); + +function complete(type) { + let updated = jsterm.once("autocomplete-updated"); + jsterm.complete(type); + return updated; +} \ No newline at end of file diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_704295.js b/browser/devtools/webconsole/test/browser_webconsole_bug_704295.js index 043e11c3803e..14d4aeeabcfc 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_704295.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_704295.js @@ -7,13 +7,13 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testCompletion); - }, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + testCompletion(hud); +}); function testCompletion(hud) { var jsterm = hud.jsterm; @@ -27,7 +27,7 @@ function testCompletion(hud) { is(jsterm.completeNode.value, "", "no completion"); EventUtils.synthesizeKey("VK_RETURN", {}); is(jsterm.completeNode.value, "", "clear completion on execute()"); - + // Test typing 'var a = d' and press RETURN jsterm.setInputValue("var a = "); EventUtils.synthesizeKey("d", {}); @@ -35,8 +35,5 @@ function testCompletion(hud) { is(jsterm.completeNode.value, "", "no completion"); EventUtils.synthesizeKey("VK_RETURN", {}); is(jsterm.completeNode.value, "", "clear completion on execute()"); - - jsterm = input = null; - finishTest(); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_734061_No_input_change_and_Tab_key_pressed.js b/browser/devtools/webconsole/test/browser_webconsole_bug_734061_No_input_change_and_Tab_key_pressed.js index 6433e0f717c3..9aff77a44c1e 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_734061_No_input_change_and_Tab_key_pressed.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_734061_No_input_change_and_Tab_key_pressed.js @@ -5,15 +5,11 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/browser/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testInputChange); - }, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); -function testInputChange(hud) { var jsterm = hud.jsterm; var input = jsterm.inputNode; @@ -33,7 +29,4 @@ function testInputChange(hud) { EventUtils.synthesizeKey("VK_RIGHT", {}); EventUtils.synthesizeKey("VK_TAB", {}); is(input.getAttribute("focused"), "", "input moved away"); - - jsterm = input = null; - finishTest(); -} +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js b/browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js index 87d0776bab7c..761645ccde92 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js @@ -10,24 +10,27 @@ // Tests that the Web Console Mixed Content messages are displayed +const TEST_URI = "data:text/html;charset=utf8,Web Console mixed content test"; const TEST_HTTPS_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html"; -function test() { - addTab("data:text/html;charset=utf8,Web Console mixed content test"); - browser.addEventListener("load", onLoad, true); -} - -function onLoad(aEvent) { - browser.removeEventListener("load", onLoad, true); +let test = asyncTest(function* () { Services.prefs.setBoolPref("security.mixed_content.block_display_content", false); Services.prefs.setBoolPref("security.mixed_content.block_active_content", false); - openConsole(null, testMixedContent); -} + + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + yield testMixedContent(hud); + + Services.prefs.clearUserPref("security.mixed_content.block_display_content"); + Services.prefs.clearUserPref("security.mixed_content.block_active_content"); +}); function testMixedContent(hud) { content.location = TEST_HTTPS_URI; - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [{ text: "example.com", @@ -64,10 +67,5 @@ function testMixedContent(hud) { ok(msg.classList.contains("filtered-by-type"), "message is filtered"); hud.setFilterState("netwarn", true); - - Services.prefs.clearUserPref("security.mixed_content.block_display_content"); - Services.prefs.clearUserPref("security.mixed_content.block_active_content"); - - finishTest(); }); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_752559_ineffective_iframe_sandbox_warning.js b/browser/devtools/webconsole/test/browser_webconsole_bug_752559_ineffective_iframe_sandbox_warning.js index d745593f9f38..fac6f2cc2cdd 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_752559_ineffective_iframe_sandbox_warning.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_752559_ineffective_iframe_sandbox_warning.js @@ -18,10 +18,8 @@ const SENTINEL_MSG = "testing ineffective sandboxing message"; function test() { - addTab(TEST_URI_WARNING); - browser.addEventListener("load", function onLoad(aEvent) { - browser.removeEventListener(aEvent.type, onLoad, true); - openConsole(null, function testIneffectiveIframeSandboxingLogged (hud) { + loadTab(TEST_URI_WARNING).then(() => { + openConsole().then((hud) => { content.console.log(SENTINEL_MSG) waitForMessages({ webconsole: hud, @@ -42,16 +40,14 @@ function test() is(msgs.length, 1, "one security message"); testNoWarning(0); }); - }); - }, true); + }) + }); } function testNoWarning(id) { - addTab(TEST_URI_NOWARNING[id]); - browser.addEventListener("load", function onLoad(aEvent) { - browser.removeEventListener(aEvent.type, onLoad, true); - openConsole(null, function testIneffectiveIframeSandboxingNotLogged (hud) { + loadTab(TEST_URI_NOWARNING[id]).then(() => { + openConsole().then((hud) => { content.console.log(SENTINEL_MSG) waitForMessages({ webconsole: hud, @@ -72,6 +68,6 @@ function testNoWarning(id) finishTest(); } }); - }); - }, true); + }) + }); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_about_blank_web_console_warning.js b/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_about_blank_web_console_warning.js index 3f4f4abaf8f7..d0322f6e9068 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_about_blank_web_console_warning.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_about_blank_web_console_warning.js @@ -8,22 +8,21 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-762593-insecure-passwords-about-blank-web-console-warning.html"; const INSECURE_PASSWORD_MSG = "Password fields present on an insecure (http://) page. This is a security risk that allows user login credentials to be stolen."; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad(aEvent) { - browser.removeEventListener(aEvent.type, onLoad, true); - openConsole(null, function testInsecurePasswordErrorLogged (hud) { - waitForMessages({ - webconsole: hud, - messages: [ - { - name: "Insecure password error displayed successfully", - text: INSECURE_PASSWORD_MSG, - category: CATEGORY_SECURITY, - severity: SEVERITY_WARNING - }, - ], - }).then(finishTest); - }); - }, true); -} + +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + yield waitForMessages({ + webconsole: hud, + messages: [ + { + name: "Insecure password error displayed successfully", + text: INSECURE_PASSWORD_MSG, + category: CATEGORY_SECURITY, + severity: SEVERITY_WARNING + }, + ], + }); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_web_console_warning.js b/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_web_console_warning.js index ff95dda9cd45..f4aa7d617849 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_web_console_warning.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_762593_insecure_passwords_web_console_warning.js @@ -11,37 +11,37 @@ const INSECURE_FORM_ACTION_MSG = "Password fields present in a form with an inse const INSECURE_IFRAME_MSG = "Password fields present on an insecure (http://) iframe. This is a security risk that allows user login credentials to be stolen."; const INSECURE_PASSWORDS_URI = "https://developer.mozilla.org/docs/Security/InsecurePasswords"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad(aEvent) { - browser.removeEventListener(aEvent.type, onLoad, true); - openConsole(null, function testInsecurePasswordErrorLogged (hud) { - waitForMessages({ - webconsole: hud, - messages: [ - { - name: "Insecure password error displayed successfully", - text: INSECURE_PASSWORD_MSG, - category: CATEGORY_SECURITY, - severity: SEVERITY_WARNING - }, - { - name: "Insecure iframe error displayed successfully", - text: INSECURE_IFRAME_MSG, - category: CATEGORY_SECURITY, - severity: SEVERITY_WARNING - }, - { - name: "Insecure form action error displayed successfully", - text: INSECURE_FORM_ACTION_MSG, - category: CATEGORY_SECURITY, - severity: SEVERITY_WARNING - }, - ], - }).then(testClickOpenNewTab.bind(null, hud)); - }); - }, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + let result = yield waitForMessages({ + webconsole: hud, + messages: [ + { + name: "Insecure password error displayed successfully", + text: INSECURE_PASSWORD_MSG, + category: CATEGORY_SECURITY, + severity: SEVERITY_WARNING + }, + { + name: "Insecure iframe error displayed successfully", + text: INSECURE_IFRAME_MSG, + category: CATEGORY_SECURITY, + severity: SEVERITY_WARNING + }, + { + name: "Insecure form action error displayed successfully", + text: INSECURE_FORM_ACTION_MSG, + category: CATEGORY_SECURITY, + severity: SEVERITY_WARNING + }, + ], + }); + + testClickOpenNewTab(hud, result); +}); function testClickOpenNewTab(hud, [result]) { let msg = [...result.matched][0]; @@ -62,6 +62,4 @@ function testClickOpenNewTab(hud, [result]) { warningNode.ownerDocument.defaultView); ok(linkOpened, "Clicking the Insecure Passwords Warning node opens the desired page"); window.openUILinkIn = oldOpenUILinkIn; - - finishTest(); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_764572_output_open_url.js b/browser/devtools/webconsole/test/browser_webconsole_bug_764572_output_open_url.js index 3b936a37cf12..2517c8e94759 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_764572_output_open_url.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_764572_output_open_url.js @@ -10,40 +10,41 @@ const CONTEXT_MENU_ID = "#menu_openURL"; let HUD = null, outputNode = null, contextMenu = null; -function test() { - let original = Services.prefs.getBoolPref("devtools.webconsole.filter.networkinfo"); +let test = asyncTest(function* () { Services.prefs.setBoolPref("devtools.webconsole.filter.networkinfo", true); - registerCleanupFunction(() => { - Services.prefs.setBoolPref("devtools.webconsole.filter.networkinfo", original); - }); - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} -function consoleOpened(aHud) { - HUD = aHud; - outputNode = aHud.outputNode; + yield loadTab(TEST_URI); + HUD = yield openConsole(); + + let results = yield consoleOpened(); + yield onConsoleMessage(results); + + let results2 = yield testOnNetActivity(); + let msg = yield onNetworkMessage(results2); + + yield testOnNetActivity_contextmenu(msg); + + Services.prefs.clearUserPref("devtools.webconsole.filter.networkinfo"); + + HUD = null, outputNode = null, contextMenu = null; +}); + +function consoleOpened() { + outputNode = HUD.outputNode; contextMenu = HUD.iframeWindow.document.getElementById("output-contextmenu"); - registerCleanupFunction(() => { - HUD = outputNode = contextMenu = null; - }); - HUD.jsterm.clearOutput(); content.console.log("bug 764572"); - waitForMessages({ + return waitForMessages({ webconsole: HUD, messages: [{ text: "bug 764572", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(onConsoleMessage); + }); } function onConsoleMessage(aResults) { @@ -59,10 +60,10 @@ function onConsoleMessage(aResults) { ok(isDisabled, COMMAND_NAME + " should be disabled."); outputNode.selectedItem.scrollIntoView(); - waitForContextMenu(contextMenu, outputNode.selectedItem, () => { + return waitForContextMenu(contextMenu, outputNode.selectedItem, () => { let isHidden = contextMenu.querySelector(CONTEXT_MENU_ID).hidden; ok(isHidden, CONTEXT_MENU_ID + " should be hidden."); - }, testOnNetActivity); + }); } function testOnNetActivity() { @@ -71,17 +72,19 @@ function testOnNetActivity() { // Reload the url to show net activity in console. content.location.reload(); - waitForMessages({ + return waitForMessages({ webconsole: HUD, messages: [{ text: "test-console.html", category: CATEGORY_NETWORK, severity: SEVERITY_LOG, }], - }).then(onNetworkMessage); + }); } function onNetworkMessage(aResults) { + let deferred = promise.defer(); + outputNode.focus(); let msg = [...aResults[0].matched][0]; ok(msg, "network message"); @@ -100,7 +103,7 @@ function onNetworkMessage(aResults) { newTab.linkedBrowser.removeEventListener("load", onTabLoaded, true); gBrowser.removeTab(newTab); gBrowser.selectedTab = currentTab; - executeSoon(testOnNetActivity_contextmenu.bind(null, msg)); + executeSoon(deferred.resolve.bind(null, msg)); } // Check if the command is enabled for a network message. @@ -112,15 +115,23 @@ function onNetworkMessage(aResults) { // Try to open the URL. goDoCommand(COMMAND_NAME); + + return deferred.promise; } function testOnNetActivity_contextmenu(msg) { + let deferred = promise.defer(); + outputNode.focus(); HUD.ui.output.selectMessage(msg); - msg.scrollIntoView(); + + info("net activity context menu"); + waitForContextMenu(contextMenu, msg, () => { let isShown = !contextMenu.querySelector(CONTEXT_MENU_ID).hidden; ok(isShown, CONTEXT_MENU_ID + " should be shown."); - }, finishTest); + }).then(deferred.resolve); + + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_766001_JS_Console_in_Debugger.js b/browser/devtools/webconsole/test/browser_webconsole_bug_766001_JS_Console_in_Debugger.js index 2f2b10947328..05580a7c3a9b 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_766001_JS_Console_in_Debugger.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_766001_JS_Console_in_Debugger.js @@ -19,6 +19,7 @@ function test() { function* runner() { expectUncaughtException(); + let {tab} = yield loadTab(TEST_URI); hud = yield openConsole(tab); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js b/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js index 79dde9c4e402..6c0400492fb8 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js @@ -7,40 +7,25 @@ // Tests that the Web Console CSP messages are displayed +const TEST_URI = "data:text/html;charset=utf8,Web Console CSP violation test"; const TEST_VIOLATION = "https://example.com/browser/browser/devtools/webconsole/test/test_bug_770099_violation.html"; const CSP_VIOLATION_MSG = 'Content Security Policy: The page\'s settings blocked the loading of a resource at http://some.example.com/test.png ("default-src https://example.com").' -let hud = undefined; +let test = asyncTest(function* () { + let { browser } = yield loadTab(TEST_URI); -function test() { - addTab("data:text/html;charset=utf8,Web Console CSP violation test"); - browser.addEventListener("load", function _onLoad() { - browser.removeEventListener("load", _onLoad, true); - openConsole(null, loadDocument); - }, true); -} + let hud = yield openConsole(); -function loadDocument(theHud){ - hud = theHud; - hud.jsterm.clearOutput() - browser.addEventListener("load", onLoad, true); + hud.jsterm.clearOutput(); + + let loaded = loadBrowser(browser); content.location = TEST_VIOLATION; -} + yield loaded; -function onLoad(aEvent) { - browser.removeEventListener("load", onLoad, true); - testViolationMessage(); -} - -function testViolationMessage(){ - let aOutputNode = hud.outputNode; - - waitForSuccess({ - name: "CSP policy URI warning displayed successfully", - validatorFn: function() { - return hud.outputNode.textContent.indexOf(CSP_VIOLATION_MSG) > -1; - }, - successFn: finishTest, - failureFn: finishTest, - }); -} + yield waitForSuccess({ + name: "CSP policy URI warning displayed successfully", + validator: function() { + return hud.outputNode.textContent.indexOf(CSP_VIOLATION_MSG) > -1; + } + }); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js b/browser/devtools/webconsole/test/browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js index 25d87f28117c..6cc5172c58ef 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js @@ -9,22 +9,20 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test" + let nodes, hud, StyleEditorUI; -function test() -{ - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testViewSource); - }, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); -function testViewSource(aHud) -{ - hud = aHud; + hud = yield openConsole(); - registerCleanupFunction(function() { - nodes = hud = StyleEditorUI = null; - }); + let styleEditor = yield testViewSource(); + yield onStyleEditorReady(styleEditor); + + nodes = hud = StyleEditorUI = null; +}); + +function testViewSource() +{ + let deferred = promise.defer(); waitForMessages({ webconsole: hud, @@ -54,17 +52,21 @@ function testViewSource(aHud) let count = 0; StyleEditorUI.on("editor-added", function() { if (++count == 2) { - onStyleEditorReady(panel); + deferred.resolve(panel); } }); }); EventUtils.sendMouseEvent({ type: "click" }, nodes[0]); }); + + return deferred.promise; } function onStyleEditorReady(aPanel) { + let deferred = promise.defer(); + let win = aPanel.panelWindow; ok(win, "Style Editor Window is defined"); ok(StyleEditorUI, "Style Editor UI is defined"); @@ -76,7 +78,7 @@ function onStyleEditorReady(aPanel) let line = nodes[0].sourceLine; ok(line, "found source line"); - checkStyleEditorForSheetAndLine(href, line - 1, function() { + checkStyleEditorForSheetAndLine(href, line - 1).then(function() { info("first check done"); let target = TargetFactory.forTab(gBrowser.selectedTab); @@ -92,19 +94,18 @@ function onStyleEditorReady(aPanel) toolbox.once("styleeditor-selected", function(aEvent) { info(aEvent + " event fired"); - checkStyleEditorForSheetAndLine(href, line - 1, function() { - info("second check done"); - finishTest(); - }); + checkStyleEditorForSheetAndLine(href, line - 1).then(deferred.resolve); }); EventUtils.sendMouseEvent({ type: "click" }, nodes[1]); }); }); }, win); + + return deferred.promise; } -function checkStyleEditorForSheetAndLine(aHref, aLine, aCallback) +function checkStyleEditorForSheetAndLine(aHref, aLine) { let foundEditor = null; for (let editor of StyleEditorUI.editors) { @@ -115,11 +116,13 @@ function checkStyleEditorForSheetAndLine(aHref, aLine, aCallback) } ok(foundEditor, "found style editor for " + aHref); - performLineCheck(foundEditor, aLine, aCallback); + return performLineCheck(foundEditor, aLine); } -function performLineCheck(aEditor, aLine, aCallback) +function performLineCheck(aEditor, aLine) { + let deferred = promise.defer(); + function checkForCorrectState() { is(aEditor.sourceEditor.getCursor().line, aLine, @@ -127,7 +130,7 @@ function performLineCheck(aEditor, aLine, aCallback) is(StyleEditorUI.selectedStyleSheetIndex, aEditor.styleSheet.styleSheetIndex, "correct stylesheet is selected in the editor"); - aCallback && executeSoon(aCallback); + executeSoon(deferred.resolve); } info("wait for source editor to load"); @@ -139,4 +142,6 @@ function performLineCheck(aEditor, aLine, aCallback) executeSoon(checkForCorrectState); }); }); + + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_804845_ctrl_key_nav.js b/browser/devtools/webconsole/test/browser_webconsole_bug_804845_ctrl_key_nav.js index 7fbe22e41df8..f6a66572f4bb 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_804845_ctrl_key_nav.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_804845_ctrl_key_nav.js @@ -11,15 +11,21 @@ // Test navigation of webconsole contents via ctrl-a, ctrl-e, ctrl-p, ctrl-n // see https://bugzilla.mozilla.org/show_bug.cgi?id=804845 +"use strict"; + +const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 804845 and bug 619598"; let jsterm, inputNode; -function test() { - addTab("data:text/html;charset=utf-8,Web Console test for bug 804845 and bug 619598"); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, doTests); - }, true); -} + +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + doTests(hud); + + jsterm = inputNode = null; +}); function doTests(HUD) { jsterm = HUD.jsterm; @@ -31,9 +37,6 @@ function doTests(HUD) { testSingleLineInputNavNoHistory(); testMultiLineInputNavNoHistory(); testNavWithHistory(); - - jsterm = inputNode = null; - executeSoon(finishTest); } function testSingleLineInputNavNoHistory() { diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_817834_add_edited_input_to_history.js b/browser/devtools/webconsole/test/browser_webconsole_bug_817834_add_edited_input_to_history.js index 7600103a6b01..98633c327f98 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_817834_add_edited_input_to_history.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_817834_add_edited_input_to_history.js @@ -13,13 +13,17 @@ // lost after navigating in history. // See https://bugzilla.mozilla.org/show_bug.cgi?id=817834 -function test() { - addTab("data:text/html;charset=utf-8,Web Console test for bug 817834"); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testEditedInputHistory); - }, true); -} +"use strict"; + +const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 817834"; + +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + testEditedInputHistory(hud); +}); function testEditedInputHistory(HUD) { let jsterm = HUD.jsterm; @@ -56,6 +60,4 @@ function testEditedInputHistory(HUD) { EventUtils.synthesizeKey("VK_DOWN", {}); is(inputNode.value, '"editing input 2"', "test history down restores new in-progress input again"); - - executeSoon(finishTest); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_837351_securityerrors.js b/browser/devtools/webconsole/test/browser_webconsole_bug_837351_securityerrors.js index 19705326d761..c5d8b22fbf2e 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_837351_securityerrors.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_837351_securityerrors.js @@ -3,32 +3,34 @@ const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-bug-837351-security-errors.html"; -function run_test() -{ - addTab(TEST_URI); - browser.addEventListener("load", function onLoad(aEvent) { - browser.removeEventListener(aEvent.type, onLoad, true); - openConsole(null, function testSecurityErrorLogged (hud) { - let button = hud.ui.rootElement.querySelector(".webconsole-filter-button[category=\"security\"]"); - ok(button, "Found security button in the web console"); +let test = asyncTest(function* () { + yield pushPrefEnv(); - waitForMessages({ - webconsole: hud, - messages: [ - { - name: "Logged blocking mixed active content", - text: "Blocked loading mixed active content \"http://example.com/\"", - category: CATEGORY_SECURITY, - severity: SEVERITY_ERROR - }, - ], - }).then(finishTest); - }); - }, true); -} - -function test() -{ - SpecialPowers.pushPrefEnv({'set': [["security.mixed_content.block_active_content", true]]}, run_test); + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + + let button = hud.ui.rootElement.querySelector(".webconsole-filter-button[category=\"security\"]"); + ok(button, "Found security button in the web console"); + + yield waitForMessages({ + webconsole: hud, + messages: [ + { + name: "Logged blocking mixed active content", + text: "Blocked loading mixed active content \"http://example.com/\"", + category: CATEGORY_SECURITY, + severity: SEVERITY_ERROR + }, + ], + }); +}); + +function pushPrefEnv() +{ + let deferred = promise.defer(); + let options = {'set': [["security.mixed_content.block_active_content", true]]}; + SpecialPowers.pushPrefEnv(options, deferred.resolve); + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_846918_hsts_invalid-headers.js b/browser/devtools/webconsole/test/browser_webconsole_bug_846918_hsts_invalid-headers.js index 33c214cdca57..c101962c75f0 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_846918_hsts_invalid-headers.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_846918_hsts_invalid-headers.js @@ -8,10 +8,8 @@ const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Security/HTTP_Strict_ function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad(aEvent) { - browser.removeEventListener(aEvent.type, onLoad, true); - openConsole(null, function testHSTSErrorLogged (hud) { + loadTab(TEST_URI).then(() => { + openConsole().then((hud) => { waitForMessages({ webconsole: hud, messages: [ @@ -24,8 +22,8 @@ function test() }, ], }).then((results) => testClickOpenNewTab(hud, results)); - }); - }, true); + }) + }); } function testClickOpenNewTab(hud, results) { diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js b/browser/devtools/webconsole/test/browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js index d2b7037e9083..56b566654949 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js @@ -65,6 +65,7 @@ function test() { "Console net menu: 'log responses' is NOT checked after menuitem was selected with keyboard."); is(hud.ui._saveRequestAndResponseBodies, false, "Responses are NOT saved after menuitem was selected with keyboard."); + hud = null; }) .then(finishTest); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_cached_autocomplete.js b/browser/devtools/webconsole/test/browser_webconsole_cached_autocomplete.js index cb5aff2dcd67..d38e0b866a7d 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_cached_autocomplete.js +++ b/browser/devtools/webconsole/test/browser_webconsole_cached_autocomplete.js @@ -8,36 +8,21 @@ const TEST_URI = "data:text/html;charset=utf8,

test cached autocompletion results"; -let testDriver; +let jsterm; -function test() { - requestLongerTimeout(2); - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, function(hud) { - testDriver = testCompletion(hud); - testDriver.next(); - }); - }, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); -function testNext() { - executeSoon(function() { - testDriver.next(); - }); -} + let hud = yield openConsole(); -function testCompletion(hud) { - let jsterm = hud.jsterm; + jsterm = hud.jsterm; let input = jsterm.inputNode; let popup = jsterm.autocompletePopup; // Test if 'doc' gives 'document' input.value = "doc"; input.setSelectionRange(3, 3); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); is(input.value, "doc", "'docu' completion (input.value)"); is(jsterm.completeNode.value, " ument", "'docu' completion (completeNode)"); @@ -45,18 +30,16 @@ function testCompletion(hud) { // Test typing 'window.'. input.value = "window."; input.setSelectionRange(7, 7); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); ok(popup.getItems().length > 0, "'window.' gave a list of suggestions") - content.wrappedJSObject.docfoobar = true; + jsterm.execute("window.docfoobar = true"); // Test typing 'window.doc'. input.value = "window.doc"; input.setSelectionRange(10, 10); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); let newItems = popup.getItems(); ok(newItems.every(function(item) { @@ -66,25 +49,24 @@ function testCompletion(hud) { // Test that backspace does not cause a request to the server input.value = "window.do"; input.setSelectionRange(9, 9); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); newItems = popup.getItems(); ok(newItems.every(function(item) { return item.label != "docfoobar"; }), "autocomplete cached results do not contain docfoobar. list has not been updated"); - delete content.wrappedJSObject.docfoobar; + jsterm.execute("delete window.docfoobar"); // Test if 'window.getC' gives 'getComputedStyle' input.value = "window." input.setSelectionRange(7, 7); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); + input.value = "window.getC"; input.setSelectionRange(11, 11); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); + newItems = popup.getItems(); ok(!newItems.every(function(item) { return item.label != "getComputedStyle"; @@ -93,33 +75,34 @@ function testCompletion(hud) { // Test if 'dump(d' gives non-zero results input.value = "dump(d"; input.setSelectionRange(6, 6); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); ok(popup.getItems().length > 0, "'dump(d' gives non-zero results"); // Test that 'dump(window.)' works. input.value = "dump(window.)"; input.setSelectionRange(12, 12); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); - content.wrappedJSObject.docfoobar = true; + jsterm.execute("window.docfoobar = true"); // Make sure 'dump(window.doc)' does not contain 'docfoobar'. input.value = "dump(window.doc)"; input.setSelectionRange(15, 15); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); newItems = popup.getItems(); ok(newItems.every(function(item) { return item.label != "docfoobar"; }), "autocomplete cached results do not contain docfoobar. list has not been updated"); - delete content.wrappedJSObject.docfoobar; + jsterm.execute("delete window.docfoobar"); - testDriver = null; - executeSoon(finishTest); - yield undefined; + jsterm = null; +}); + +function complete(type) { + let updated = jsterm.once("autocomplete-updated"); + jsterm.complete(type); + return updated; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_certificate_messages.js b/browser/devtools/webconsole/test/browser_webconsole_certificate_messages.js index 8f41d13222fa..e6efc7dad11a 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_certificate_messages.js +++ b/browser/devtools/webconsole/test/browser_webconsole_certificate_messages.js @@ -4,7 +4,9 @@ // Tests that the Web Console shows weak crypto warnings (SHA-1 Certificate, SSLv3, and RC4) +const TEST_URI = "data:text/html;charset=utf8,Web Console weak crypto warnings test"; const TEST_URI_PATH = "/browser/browser/devtools/webconsole/test/test-certificate-messages.html"; + let gWebconsoleTests = [ {url: "https://sha1ee.example.com" + TEST_URI_PATH, name: "SHA1 warning displayed successfully", @@ -26,31 +28,31 @@ let gWebconsoleTests = [ ]; const TRIGGER_MSG = "If you haven't seen ssl warnings yet, you won't"; -let gHud = undefined; +let gHud = undefined, gContentBrowser; let gCurrentTest; function test() { registerCleanupFunction(function () { - gHud = null; + gHud = gContentBrowser = null; }); - addTab("data:text/html;charset=utf8,Web Console weak crypto warnings test"); - browser.addEventListener("load", function _onLoad() { - browser.removeEventListener("load", _onLoad, true); - openConsole(null, runTestLoop); - }, true); + loadTab(TEST_URI).then(({browser}) => { + gContentBrowser = browser; + openConsole().then(runTestLoop); + }); } function runTestLoop(theHud) { gCurrentTest = gWebconsoleTests.shift(); if (!gCurrentTest) { finishTest(); + return; } if (!gHud) { gHud = theHud; } gHud.jsterm.clearOutput(); - browser.addEventListener("load", onLoad, true); + gContentBrowser.addEventListener("load", onLoad, true); if (gCurrentTest.pref) { SpecialPowers.pushPrefEnv({"set": gCurrentTest.pref}, function() { @@ -62,12 +64,12 @@ function runTestLoop(theHud) { } function onLoad(aEvent) { - browser.removeEventListener("load", onLoad, true); + gContentBrowser.removeEventListener("load", onLoad, true); let aOutputNode = gHud.outputNode; waitForSuccess({ name: gCurrentTest.name, - validatorFn: function() { + validator: function() { if (gHud.outputNode.textContent.indexOf(TRIGGER_MSG) >= 0) { for (let warning of gCurrentTest.warning) { if (gHud.outputNode.textContent.indexOf(warning) < 0) { @@ -81,8 +83,6 @@ function onLoad(aEvent) { } return true; } - }, - successFn: runTestLoop, - failureFn: finishTest, - }); + } + }).then(runTestLoop); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_change_font_size.js b/browser/devtools/webconsole/test/browser_webconsole_change_font_size.js index 1769cdcc61e9..ab86bb49e6bf 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_change_font_size.js +++ b/browser/devtools/webconsole/test/browser_webconsole_change_font_size.js @@ -8,18 +8,15 @@ * * ***** END LICENSE BLOCK ***** */ +"use strict"; + const TEST_URI = "http://example.com/"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - Services.prefs.setIntPref("devtools.webconsole.fontSize", 10); - HUDService.toggleBrowserConsole().then(testFontSizeChange); - }, true); -} +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + Services.prefs.setIntPref("devtools.webconsole.fontSize", 10); + let hud = yield HUDService.toggleBrowserConsole(); -function testFontSizeChange(hud) { let inputNode = hud.jsterm.inputNode; let outputNode = hud.jsterm.outputNode; outputNode.focus(); @@ -39,6 +36,4 @@ function testFontSizeChange(hud) { EventUtils.synthesizeKey("0", { accelKey: true }, hud.iframeWindow); is(inputNode.style.fontSize, "", "font reset with ctrl+0"); is(outputNode.style.fontSize, inputNode.style.fontSize, "output font stays at same size with ctrl+0"); - - finishTest(); -} +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_chrome.js b/browser/devtools/webconsole/test/browser_webconsole_chrome.js index e6ac01f2cf66..f7f3cd0e328e 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_chrome.js +++ b/browser/devtools/webconsole/test/browser_webconsole_chrome.js @@ -5,6 +5,8 @@ // Tests that code completion works properly in chrome tabs, like about:credits. +"use strict"; + function test() { Task.spawn(function*() { const {tab} = yield loadTab("about:config"); diff --git a/browser/devtools/webconsole/test/browser_webconsole_clickable_urls.js b/browser/devtools/webconsole/test/browser_webconsole_clickable_urls.js index ebfbe5329d28..05f1ee2c9e84 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_clickable_urls.js +++ b/browser/devtools/webconsole/test/browser_webconsole_clickable_urls.js @@ -6,6 +6,8 @@ // When strings containing URLs are entered into the webconsole, // check its output and ensure that the output can be clicked to open those URLs. +"use strict"; + const TEST_URI = "data:text/html;charset=utf8,Bug 1005909 - Clickable URLS"; let inputTests = [ diff --git a/browser/devtools/webconsole/test/browser_webconsole_closure_inspection.js b/browser/devtools/webconsole/test/browser_webconsole_closure_inspection.js index f0b0f839e583..537ef1a72e2e 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_closure_inspection.js +++ b/browser/devtools/webconsole/test/browser_webconsole_closure_inspection.js @@ -16,10 +16,8 @@ function test() gWebConsole = gJSTerm = gVariablesView = null; }); - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, (hud) => { + loadTab(TEST_URI).then(() => { + openConsole().then((hud) => { openDebugger().then(({ toolbox, panelWin }) => { let deferred = promise.defer(); panelWin.gThreadClient.addOneTimeListener("resumed", (aEvent, aPacket) => { @@ -41,8 +39,8 @@ function test() return deferred.promise; }); - }); - }, true); + }) + }); } function consoleOpened(hud) diff --git a/browser/devtools/webconsole/test/browser_webconsole_column_numbers.js b/browser/devtools/webconsole/test/browser_webconsole_column_numbers.js index c255893d5936..bbc5dde8134d 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_column_numbers.js +++ b/browser/devtools/webconsole/test/browser_webconsole_column_numbers.js @@ -10,11 +10,9 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/te let hud; function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + loadTab(TEST_URI).then(() => { + openConsole().then(consoleOpened); + }); } function consoleOpened(aHud) { diff --git a/browser/devtools/webconsole/test/browser_webconsole_completion.js b/browser/devtools/webconsole/test/browser_webconsole_completion.js index df7a8ca9558a..7e384b346698 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_completion.js +++ b/browser/devtools/webconsole/test/browser_webconsole_completion.js @@ -7,34 +7,20 @@ const TEST_URI = "data:text/html;charset=utf8,

test code completion"; -let testDriver; +let jsterm; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, function(hud) { - testDriver = testCompletion(hud); - testDriver.next(); - }); - }, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); -function testNext() { - executeSoon(function() { - testDriver.next(); - }); -} + let hud = yield openConsole(); -function testCompletion(hud) { - let jsterm = hud.jsterm; + jsterm = hud.jsterm; let input = jsterm.inputNode; // Test typing 'docu'. input.value = "docu"; input.setSelectionRange(4, 4); - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); is(input.value, "docu", "'docu' completion (input.value)"); is(jsterm.completeNode.value, " ment", "'docu' completion (completeNode)"); @@ -42,8 +28,7 @@ function testCompletion(hud) { // Test typing 'docu' and press tab. input.value = "docu"; input.setSelectionRange(4, 4); - jsterm.complete(jsterm.COMPLETE_FORWARD, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_FORWARD); is(input.value, "document", "'docu' tab completion"); is(input.selectionStart, 8, "start selection is alright"); @@ -54,30 +39,26 @@ function testCompletion(hud) { // ambiguous: could be window.Object, window.Option, etc. input.value = "window.Ob"; input.setSelectionRange(9, 9); - jsterm.complete(jsterm.COMPLETE_FORWARD, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_FORWARD); is(input.value, "window.Object", "'window.Ob' tab completion"); // Test typing 'document.getElem'. input.value = "document.getElem"; input.setSelectionRange(16, 16); - jsterm.complete(jsterm.COMPLETE_FORWARD, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_FORWARD); is(input.value, "document.getElem", "'document.getElem' completion"); is(jsterm.completeNode.value, " entsByTagNameNS", "'document.getElem' completion"); // Test pressing tab another time. - jsterm.complete(jsterm.COMPLETE_FORWARD, testNext); - yield undefined; + yield jsterm.complete(jsterm.COMPLETE_FORWARD); is(input.value, "document.getElem", "'document.getElem' completion"); is(jsterm.completeNode.value, " entsByTagName", "'document.getElem' another tab completion"); // Test pressing shift_tab. - jsterm.complete(jsterm.COMPLETE_BACKWARD, testNext); - yield undefined; + complete(jsterm.COMPLETE_BACKWARD); is(input.value, "document.getElem", "'document.getElem' untab completion"); is(jsterm.completeNode.value, " entsByTagNameNS", "'document.getElem' completion"); @@ -85,8 +66,7 @@ function testCompletion(hud) { jsterm.clearOutput(); input.value = "docu"; - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); is(jsterm.completeNode.value, " ment", "'docu' completion"); jsterm.execute(); @@ -94,27 +74,28 @@ function testCompletion(hud) { // Test multi-line completion works input.value = "console.log('one');\nconsol"; - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); is(jsterm.completeNode.value, " \n e", "multi-line completion"); // Test non-object autocompletion. input.value = "Object.name.sl"; - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); is(jsterm.completeNode.value, " ice", "non-object completion"); // Test string literal autocompletion. input.value = "'Asimov'.sl"; - jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext); - yield undefined; + yield complete(jsterm.COMPLETE_HINT_ONLY); is(jsterm.completeNode.value, " ice", "string literal completion"); - testDriver = jsterm = input = null; - executeSoon(finishTest); - yield undefined; -} + jsterm = null; +}); + +function complete(type) { + let updated = jsterm.once("autocomplete-updated"); + jsterm.complete(type); + return updated; +} diff --git a/browser/devtools/webconsole/test/browser_webconsole_console_extras.js b/browser/devtools/webconsole/test/browser_webconsole_console_extras.js index dfb8d6ac08b5..b424374926ae 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_console_extras.js +++ b/browser/devtools/webconsole/test/browser_webconsole_console_extras.js @@ -10,11 +10,9 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-extras.html"; function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + loadTab(TEST_URI).then(() => { + openConsole().then(consoleOpened); + }); } function consoleOpened(hud) { diff --git a/browser/devtools/webconsole/test/browser_webconsole_console_logging_api.js b/browser/devtools/webconsole/test/browser_webconsole_console_logging_api.js index 9425f1266c06..aeb73c58eed9 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_console_logging_api.js +++ b/browser/devtools/webconsole/test/browser_webconsole_console_logging_api.js @@ -5,40 +5,33 @@ // Tests that the basic console.log()-style APIs and filtering work. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -let hud, outputNode; +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); + hud.jsterm.clearOutput(); -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - Task.spawn(runner); - }, true); + let outputNode = hud.outputNode; - function* runner() { - hud = yield openConsole(); - outputNode = hud.outputNode; - - let methods = ["log", "info", "warn", "error", "exception", "debug"]; - for (let method of methods) { - yield testMethod(method); - } - - executeSoon(finishTest); + let methods = ["log", "info", "warn", "error", "exception", "debug"]; + for (let method of methods) { + yield testMethod(method, hud, outputNode); } -} +}); -function* testMethod(aMethod) { +function* testMethod(aMethod, aHud, aOutputNode) { let console = content.console; - hud.jsterm.clearOutput(); + aHud.jsterm.clearOutput(); console[aMethod]("foo-bar-baz"); console[aMethod]("baar-baz"); yield waitForMessages({ - webconsole: hud, + webconsole: aHud, messages: [{ text: "foo-bar-baz", }, { @@ -46,25 +39,25 @@ function* testMethod(aMethod) { }], }); - setStringFilter("foo"); + setStringFilter("foo", aHud); - is(outputNode.querySelectorAll(".filtered-by-string").length, 1, + is(aOutputNode.querySelectorAll(".filtered-by-string").length, 1, "1 hidden " + aMethod + " node via string filtering") - hud.jsterm.clearOutput(); + aHud.jsterm.clearOutput(); // now toggle the current method off - make sure no visible message // TODO: move all filtering tests into a separate test file: see bug 608135 console[aMethod]("foo-bar-baz"); yield waitForMessages({ - webconsole: hud, + webconsole: aHud, messages: [{ text: "foo-bar-baz", }], }); - setStringFilter(""); + setStringFilter("", aHud); let filter; switch(aMethod) { case "debug": @@ -78,23 +71,23 @@ function* testMethod(aMethod) { break; } - hud.setFilterState(filter, false); + aHud.setFilterState(filter, false); - is(outputNode.querySelectorAll(".filtered-by-type").length, 1, + is(aOutputNode.querySelectorAll(".filtered-by-type").length, 1, "1 message hidden for " + aMethod + " (logging turned off)") - hud.setFilterState(filter, true); + aHud.setFilterState(filter, true); - is(outputNode.querySelectorAll(".message:not(.filtered-by-type)").length, 1, + is(aOutputNode.querySelectorAll(".message:not(.filtered-by-type)").length, 1, "1 message shown for " + aMethod + " (logging turned on)") - hud.jsterm.clearOutput(); + aHud.jsterm.clearOutput(); // test for multiple arguments. console[aMethod]("foo", "bar"); yield waitForMessages({ - webconsole: hud, + webconsole: aHud, messages: [{ text: '"foo" "bar"', category: CATEGORY_WEBDEV, @@ -102,8 +95,7 @@ function* testMethod(aMethod) { }) } -function setStringFilter(aValue) { - hud.ui.filterBox.value = aValue; - hud.ui.adjustVisibilityOnSearchStringChange(); +function setStringFilter(aValue, aHud) { + aHud.ui.filterBox.value = aValue; + aHud.ui.adjustVisibilityOnSearchStringChange(); } - diff --git a/browser/devtools/webconsole/test/browser_webconsole_dont_navigate_on_doubleclick.js b/browser/devtools/webconsole/test/browser_webconsole_dont_navigate_on_doubleclick.js index f1a03da7c83c..34eb87b00653 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_dont_navigate_on_doubleclick.js +++ b/browser/devtools/webconsole/test/browser_webconsole_dont_navigate_on_doubleclick.js @@ -5,6 +5,8 @@ // Tests that if a link in console is double clicked, the console frame doesn't // navigate to that destination (bug 975707). +"use strict"; + function test() { let originalNetPref = Services.prefs.getBoolPref("devtools.webconsole.filter.networkinfo"); registerCleanupFunction(() => { diff --git a/browser/devtools/webconsole/test/browser_webconsole_execution_scope.js b/browser/devtools/webconsole/test/browser_webconsole_execution_scope.js index f29c907b3eaf..338b17e16d57 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_execution_scope.js +++ b/browser/devtools/webconsole/test/browser_webconsole_execution_scope.js @@ -5,22 +5,17 @@ // Tests that commands run by the user are executed in content space. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testExecutionScope); - }, true); -} +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); + hud.jsterm.clearOutput(); + hud.jsterm.execute("window.location.href;"); -function testExecutionScope(hud) { - let jsterm = hud.jsterm; - - jsterm.clearOutput(); - jsterm.execute("window.location.href;"); - waitForMessages({ + let [input, output] = yield waitForMessages({ webconsole: hud, messages: [{ text: "window.location.href;", @@ -30,12 +25,10 @@ function testExecutionScope(hud) { text: TEST_URI, category: CATEGORY_OUTPUT, }], - }).then(([input, output]) => { - let inputNode = [...input.matched][0]; - let outputNode = [...output.matched][0]; - is(inputNode.getAttribute("category"), "input", "input node category is correct"); - is(outputNode.getAttribute("category"), "output", "output node category is correct"); - finishTest(); }); -} + let inputNode = [...input.matched][0]; + let outputNode = [...output.matched][0]; + is(inputNode.getAttribute("category"), "input", "input node category is correct"); + is(outputNode.getAttribute("category"), "output", "output node category is correct"); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_expandable_timestamps.js b/browser/devtools/webconsole/test/browser_webconsole_expandable_timestamps.js index 1818fecfe890..efcdaa63ca2b 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_expandable_timestamps.js +++ b/browser/devtools/webconsole/test/browser_webconsole_expandable_timestamps.js @@ -4,54 +4,53 @@ // Test for the message timestamps option: check if the preference toggles the // display of messages in the console output. See bug 722267. -function test() +const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 722267 - " + + "preference for toggling timestamps in messages"; +const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages"; +let hud; + +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + hud = yield openConsole(); + let panel = yield consoleOpened(); + + yield onOptionsPanelSelected(panel); + onPrefChanged(); + + Services.prefs.clearUserPref(PREF_MESSAGE_TIMESTAMP); + hud = null; +}); + +function consoleOpened() { - const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages"; - let hud; + info("console opened"); + let prefValue = Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP); + ok(!prefValue, "messages have no timestamp by default (pref check)"); + ok(hud.outputNode.classList.contains("hideTimestamps"), + "messages have no timestamp (class name check)"); - registerCleanupFunction(() => { - Services.prefs.clearUserPref(PREF_MESSAGE_TIMESTAMP); - }); - - addTab("data:text/html;charset=utf-8,Web Console test for bug 722267 - " + - "preference for toggling timestamps in messages"); - - browser.addEventListener("load", function tabLoad() { - browser.removeEventListener("load", tabLoad, true); - openConsole(null, consoleOpened); - }, true); - - function consoleOpened(aHud) - { - hud = aHud; - - info("console opened"); - let prefValue = Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP); - ok(!prefValue, "messages have no timestamp by default (pref check)"); - ok(hud.outputNode.classList.contains("hideTimestamps"), - "messages have no timestamp (class name check)"); - - let toolbox = gDevTools.getToolbox(hud.target); - toolbox.selectTool("options").then(onOptionsPanelSelected); - } - - function onOptionsPanelSelected(panel) - { - info("options panel opened"); - - gDevTools.once("pref-changed", onPrefChanged); - - let checkbox = panel.panelDoc.getElementById("webconsole-timestamp-messages"); - checkbox.click(); - } - - function onPrefChanged() - { - info("pref changed"); - let prefValue = Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP); - ok(prefValue, "messages have timestamps (pref check)"); - ok(!hud.outputNode.classList.contains("hideTimestamps"), - "messages have timestamps (class name check)"); - finishTest(); - } + let toolbox = gDevTools.getToolbox(hud.target); + return toolbox.selectTool("options"); +} + +function onOptionsPanelSelected(panel) +{ + info("options panel opened"); + + let prefChanged = gDevTools.once("pref-changed", onPrefChanged); + + let checkbox = panel.panelDoc.getElementById("webconsole-timestamp-messages"); + checkbox.click(); + + return prefChanged; +} + +function onPrefChanged() +{ + info("pref changed"); + let prefValue = Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP); + ok(prefValue, "messages have timestamps (pref check)"); + ok(!hud.outputNode.classList.contains("hideTimestamps"), + "messages have timestamps (class name check)"); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_filter_buttons_contextmenu.js b/browser/devtools/webconsole/test/browser_webconsole_filter_buttons_contextmenu.js index 6b18bd7c0bd2..058b52afa6ae 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_filter_buttons_contextmenu.js +++ b/browser/devtools/webconsole/test/browser_webconsole_filter_buttons_contextmenu.js @@ -6,11 +6,9 @@ const TEST_URI = "http://example.com/"; function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testFilterButtons); - }, true); + loadTab(TEST_URI).then(() => { + openConsole().then(testFilterButtons); + }) } function testFilterButtons(aHud) { diff --git a/browser/devtools/webconsole/test/browser_webconsole_for_of.js b/browser/devtools/webconsole/test/browser_webconsole_for_of.js index cfae6f2ea736..b5b6304f6ece 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_for_of.js +++ b/browser/devtools/webconsole/test/browser_webconsole_for_of.js @@ -5,20 +5,23 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-for-of.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testForOf); - }, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + let hud = yield openConsole(); + yield testForOf(hud); +}); function testForOf(hud) { + let deferred = promise.defer(); + var jsterm = hud.jsterm; jsterm.execute("{ [x.tagName for (x of document.body.childNodes) if (x.nodeType === 1)].join(' '); }", (node) => { ok(/H1 DIV H2 P/.test(node.textContent), "for-of loop should find all top-level nodes"); - finishTest(); + deferred.resolve(); }); + + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_history.js b/browser/devtools/webconsole/test/browser_webconsole_history.js index bb39cd60fff3..0da0b1d6ee3d 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_history.js +++ b/browser/devtools/webconsole/test/browser_webconsole_history.js @@ -5,21 +5,19 @@ // Tests the console history feature accessed via the up and down arrow keys. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; // Constants used for defining the direction of JSTerm input history navigation. const HISTORY_BACK = -1; const HISTORY_FORWARD = 1; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testHistory); - }, true); -} +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); + hud.jsterm.clearOutput(); -function testHistory(hud) { let jsterm = hud.jsterm; let input = jsterm.inputNode; @@ -60,7 +58,4 @@ function testHistory(hud) { let idxLast = executeList.length - 1; jsterm.historyPeruse(HISTORY_BACK); is (input.value, executeList[idxLast], "check history next idx:" + idxLast); - - executeSoon(finishTest); -} - +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_input_field_focus_on_panel_select.js b/browser/devtools/webconsole/test/browser_webconsole_input_field_focus_on_panel_select.js index 02dc2274096d..192fc55950a4 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_input_field_focus_on_panel_select.js +++ b/browser/devtools/webconsole/test/browser_webconsole_input_field_focus_on_panel_select.js @@ -5,19 +5,15 @@ // Test that the JS input field is focused when the user switches back to the // web console from other tools, see bug 891581. +"use strict"; + const TEST_URI = "data:text/html;charset=utf8,

hello"; -function test() -{ - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); + hud.jsterm.clearOutput(); -function consoleOpened(hud) -{ is(hud.jsterm.inputNode.hasAttribute("focused"), true, "inputNode should be focused"); @@ -29,18 +25,9 @@ function consoleOpened(hud) is(hud.jsterm.inputNode.hasAttribute("focused"), false, "inputNode shouldn't be focused"); - openDebugger().then(debuggerOpened); -} + yield openDebugger(); + hud = yield openConsole(); -function debuggerOpened() -{ - openConsole(null, consoleReopened); -} - -function consoleReopened(hud) -{ is(hud.jsterm.inputNode.hasAttribute("focused"), true, "inputNode should be focused"); - - finishTest(); -} +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_inspect-parsed-documents.js b/browser/devtools/webconsole/test/browser_webconsole_inspect-parsed-documents.js index 0d00ded90a12..e55e021c25f9 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_inspect-parsed-documents.js +++ b/browser/devtools/webconsole/test/browser_webconsole_inspect-parsed-documents.js @@ -1,11 +1,12 @@ /* vim: set ft=javascript ts=2 et sw=2 tw=80: */ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; // Test that dynamically created (HTML|XML|SVG)Documents can be inspected by // clicking on the object in console (bug 1035198). +"use strict;" + const TEST_CASES = [ { input: '(new DOMParser()).parseFromString("", "text/html")', diff --git a/browser/devtools/webconsole/test/browser_webconsole_js_input_expansion.js b/browser/devtools/webconsole/test/browser_webconsole_js_input_expansion.js index 2dce912932ef..fe048323302c 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_js_input_expansion.js +++ b/browser/devtools/webconsole/test/browser_webconsole_js_input_expansion.js @@ -5,19 +5,16 @@ // Tests that the input box expands as the user types long lines. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testJSInputExpansion); - }, true); -} +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); + hud.jsterm.clearOutput(); -function testJSInputExpansion(hud) { - let jsterm = hud.jsterm; - let input = jsterm.inputNode; + let input = hud.jsterm.inputNode; input.focus(); is(input.getAttribute("multiline"), "true", "multiline is enabled"); @@ -55,6 +52,4 @@ function testJSInputExpansion(hud) { info("initialHeight: " + initialHeight); let finalHeightDifference = Math.abs(initialHeight - height); ok(finalHeightDifference <= 1, "height shrank to original size within 1px"); - - finishTest(); -} +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_jsterm.js b/browser/devtools/webconsole/test/browser_webconsole_jsterm.js index 2c81dc24d44e..e4118a577cee 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_jsterm.js +++ b/browser/devtools/webconsole/test/browser_webconsole_jsterm.js @@ -8,14 +8,12 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/te let jsterm, testDriver; function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, function(hud) { + loadTab(TEST_URI).then(() => { + openConsole().then((hud) => { testDriver = testJSTerm(hud); testDriver.next(); - }); - }, true); + }) + }); } function nextTest() { @@ -68,13 +66,11 @@ function testJSTerm(hud) waitForSuccess({ name: "clear() worked", - validatorFn: function() + validator: function() { return jsterm.outputNode.childNodes.length == 0; - }, - successFn: nextTest, - failureFn: nextTest, - }); + } + }).then(nextTest); yield undefined; diff --git a/browser/devtools/webconsole/test/browser_webconsole_live_filtering_of_message_types.js b/browser/devtools/webconsole/test/browser_webconsole_live_filtering_of_message_types.js index d05ee988d2e8..02b79b6e954f 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_live_filtering_of_message_types.js +++ b/browser/devtools/webconsole/test/browser_webconsole_live_filtering_of_message_types.js @@ -5,20 +5,13 @@ // Tests that the message type filter checkboxes work. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -let hud; - -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} - -function consoleOpened(aHud) { - hud = aHud; +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); hud.jsterm.clearOutput(); let console = content.console; @@ -27,31 +20,27 @@ function consoleOpened(aHud) { console.log("foobarz #" + i); } - waitForMessages({ + yield waitForMessages({ webconsole: hud, messages: [{ text: "foobarz #49", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(testLiveFilteringOfMessageTypes); -} + }); -function testLiveFilteringOfMessageTypes() { is(hud.outputNode.children.length, 50, "number of messages"); hud.setFilterState("log", false); - is(countMessageNodes(), 0, "the log nodes are hidden when the " + + is(countMessageNodes(hud), 0, "the log nodes are hidden when the " + "corresponding filter is switched off"); hud.setFilterState("log", true); - is(countMessageNodes(), 50, "the log nodes reappear when the " + + is(countMessageNodes(hud), 50, "the log nodes reappear when the " + "corresponding filter is switched on"); +}); - finishTest(); -} - -function countMessageNodes() { +function countMessageNodes(hud) { let messageNodes = hud.outputNode.querySelectorAll(".message"); let displayedMessageNodes = 0; let view = hud.iframeWindow; diff --git a/browser/devtools/webconsole/test/browser_webconsole_live_filtering_on_search_strings.js b/browser/devtools/webconsole/test/browser_webconsole_live_filtering_on_search_strings.js index 6a1e21e6d173..fb229075a123 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_live_filtering_on_search_strings.js +++ b/browser/devtools/webconsole/test/browser_webconsole_live_filtering_on_search_strings.js @@ -5,84 +5,74 @@ // Tests that the text filter box works. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -let hud; - -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} - -function consoleOpened(aHud) { - hud = aHud; +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); hud.jsterm.clearOutput(); + let console = content.console; for (let i = 0; i < 50; i++) { console.log("http://www.example.com/ " + i); } - waitForMessages({ + yield waitForMessages({ webconsole: hud, messages: [{ text: "http://www.example.com/ 49", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(testLiveFilteringOnSearchStrings); -} + }) -function testLiveFilteringOnSearchStrings() { is(hud.outputNode.children.length, 50, "number of messages"); - setStringFilter("http"); - isnot(countMessageNodes(), 0, "the log nodes are not hidden when the " + + setStringFilter(hud, "http"); + isnot(countMessageNodes(hud), 0, "the log nodes are not hidden when the " + "search string is set to \"http\""); - setStringFilter("hxxp"); - is(countMessageNodes(), 0, "the log nodes are hidden when the search " + + setStringFilter(hud, "hxxp"); + is(countMessageNodes(hud), 0, "the log nodes are hidden when the search " + "string is set to \"hxxp\""); - setStringFilter("ht tp"); - isnot(countMessageNodes(), 0, "the log nodes are not hidden when the " + + setStringFilter(hud, "ht tp"); + isnot(countMessageNodes(hud), 0, "the log nodes are not hidden when the " + "search string is set to \"ht tp\""); - setStringFilter(" zzzz zzzz "); - is(countMessageNodes(), 0, "the log nodes are hidden when the search " + + setStringFilter(hud, " zzzz zzzz "); + is(countMessageNodes(hud), 0, "the log nodes are hidden when the search " + "string is set to \" zzzz zzzz \""); - setStringFilter(""); - isnot(countMessageNodes(), 0, "the log nodes are not hidden when the " + + setStringFilter(hud, ""); + isnot(countMessageNodes(hud), 0, "the log nodes are not hidden when the " + "search string is removed"); - setStringFilter("\u9f2c"); - is(countMessageNodes(), 0, "the log nodes are hidden when searching " + + setStringFilter(hud, "\u9f2c"); + is(countMessageNodes(hud), 0, "the log nodes are hidden when searching " + "for weasels"); - setStringFilter("\u0007"); - is(countMessageNodes(), 0, "the log nodes are hidden when searching for " + + setStringFilter(hud, "\u0007"); + is(countMessageNodes(hud), 0, "the log nodes are hidden when searching for " + "the bell character"); - setStringFilter('"foo"'); - is(countMessageNodes(), 0, "the log nodes are hidden when searching for " + + setStringFilter(hud, '"foo"'); + is(countMessageNodes(hud), 0, "the log nodes are hidden when searching for " + 'the string "foo"'); - setStringFilter("'foo'"); - is(countMessageNodes(), 0, "the log nodes are hidden when searching for " + + setStringFilter(hud, "'foo'"); + is(countMessageNodes(hud), 0, "the log nodes are hidden when searching for " + "the string 'foo'"); - setStringFilter("foo\"bar'baz\"boo'"); - is(countMessageNodes(), 0, "the log nodes are hidden when searching for " + + setStringFilter(hud, "foo\"bar'baz\"boo'"); + is(countMessageNodes(hud), 0, "the log nodes are hidden when searching for " + "the string \"foo\"bar'baz\"boo'\""); +}); - finishTest(); -} - -function countMessageNodes() { +function countMessageNodes(hud) { let outputNode = hud.outputNode; let messageNodes = outputNode.querySelectorAll(".message"); @@ -98,7 +88,7 @@ function countMessageNodes() { return displayedMessageNodes; } -function setStringFilter(aValue) +function setStringFilter(hud, aValue) { hud.ui.filterBox.value = aValue; hud.ui.adjustVisibilityOnSearchStringChange(); diff --git a/browser/devtools/webconsole/test/browser_webconsole_log_file_filter.js b/browser/devtools/webconsole/test/browser_webconsole_log_file_filter.js index fcb31780382d..906bb2b4883e 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_log_file_filter.js +++ b/browser/devtools/webconsole/test/browser_webconsole_log_file_filter.js @@ -9,26 +9,30 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/te let hud; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} +"use strict"; -function consoleOpened(aHud) { - hud = aHud; +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + + hud = yield openConsole(); + yield consoleOpened(); + + testLiveFilteringOnSearchStrings(); + + hud = null; +}); + +function consoleOpened() { let console = content.console; console.log("sentinel log"); - waitForMessages({ + return waitForMessages({ webconsole: hud, messages: [{ text: "sentinel log", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG }], - }).then(testLiveFilteringOnSearchStrings); + }) } function testLiveFilteringOnSearchStrings() { @@ -51,8 +55,6 @@ function testLiveFilteringOnSearchStrings() { setStringFilter(""); is(countMessageNodes(), 4, "show all log nodes on setting filter string " + "as \"\"."); - - finishTest(); } function countMessageNodes() { diff --git a/browser/devtools/webconsole/test/browser_webconsole_message_node_id.js b/browser/devtools/webconsole/test/browser_webconsole_message_node_id.js index 825fd5d631c8..0a94538e6a85 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_message_node_id.js +++ b/browser/devtools/webconsole/test/browser_webconsole_message_node_id.js @@ -3,29 +3,25 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("DOMContentLoaded", onLoad, false); -} +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); -function onLoad() { - browser.removeEventListener("DOMContentLoaded", onLoad, false); - openConsole(null, function(hud) { - content.console.log("a log message"); + hud.jsterm.execute("console.log('a log message')"); - waitForMessages({ + let [result] = yield waitForMessages({ webconsole: hud, messages: [{ text: "a log message", category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(([result]) => { - let msg = [...result.matched][0]; - ok(msg.getAttribute("id"), "log message has an ID"); - finishTest(); - }); }); -} + + let msg = [...result.matched][0]; + ok(msg.getAttribute("id"), "log message has an ID"); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_netlogging.js b/browser/devtools/webconsole/test/browser_webconsole_netlogging.js index 8d55ccf80a35..7cf95822ef65 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_netlogging.js +++ b/browser/devtools/webconsole/test/browser_webconsole_netlogging.js @@ -12,6 +12,8 @@ // Tests that network log messages bring up the network panel. +const TEST_URI = "data:text/html;charset=utf-8,Web Console network logging tests"; + const TEST_NETWORK_REQUEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-network-request.html"; const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/test/test-image.png"; @@ -21,22 +23,21 @@ const TEST_DATA_JSON_CONTENT = let lastRequest = null; let requestCallback = null; +let browser, hud; function test() { - addTab("data:text/html;charset=utf-8,Web Console network logging tests"); + loadTab(TEST_URI).then((tab) => { + browser = tab.browser; - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - - openConsole(null, function(aHud) { + openConsole().then((aHud) => { hud = aHud; HUDService.lastFinishedRequest.callback = requestCallbackWrapper; executeSoon(testPageLoad); }); - }, true); + }); } function requestCallbackWrapper(aRequest) @@ -205,6 +206,7 @@ function testNetworkPanel() networkPanel.panel.hidePopup(); lastRequest = null; HUDService.lastFinishedRequest.callback = null; + browser = requestCallback = hud = null; executeSoon(finishTest); }, true); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_network_panel.js b/browser/devtools/webconsole/test/browser_webconsole_network_panel.js index 82f9d1ef9763..0cea84fea650 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_network_panel.js +++ b/browser/devtools/webconsole/test/browser_webconsole_network_panel.js @@ -19,17 +19,16 @@ const TEST_IMG_BASE64 = "A16/JvfiigMSYyzqJXlw/XKUyOORMUaBor6YavgdjKa8xGOnidadmwtwsnMu18q83/kHSou+bFND" + "Dr4AAAAASUVORK5CYII="; -let testDriver; +let testDriver, hud; function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testNetworkPanel); - }, true); + loadTab(TEST_URI).then(() => { + openConsole().then(testNetworkPanel); + }); } -function testNetworkPanel() { +function testNetworkPanel(aHud) { + hud = aHud; testDriver = testGen(); testDriver.next(); } @@ -71,7 +70,6 @@ function checkNodeKeyValue(aPanel, aId, aKey, aValue) { } function testGen() { - let hud = HUDService.getHudByWindow(content); let filterBox = hud.ui.filterBox; let httpActivity = { @@ -536,7 +534,7 @@ function testGen() { networkPanel.panel.hidePopup(); */ // All done! - testDriver = null; + testDriver = hud = null; executeSoon(finishTest); yield undefined; diff --git a/browser/devtools/webconsole/test/browser_webconsole_notifications.js b/browser/devtools/webconsole/test/browser_webconsole_notifications.js index 1c7f34fe2337..bc0ca015cf14 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_notifications.js +++ b/browser/devtools/webconsole/test/browser_webconsole_notifications.js @@ -5,66 +5,73 @@ const TEST_URI = "data:text/html;charset=utf-8,

Web Console test for notifications"; -function test() { - observer.init(); - addTab(TEST_URI); - browser.addEventListener("load", onLoad, true); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); -function webConsoleCreated(aID) -{ - Services.obs.removeObserver(observer, "web-console-created"); - ok(HUDService.getHudReferenceById(aID), "We have a hud reference"); - content.wrappedJSObject.console.log("adding a log message"); -} + let gotEvents = waitForEvents(); -function webConsoleDestroyed(aID) -{ - Services.obs.removeObserver(observer, "web-console-destroyed"); - ok(!HUDService.getHudReferenceById(aID), "We do not have a hud reference"); - executeSoon(finishTest); -} + let hud = yield openConsole(); -function webConsoleMessage(aID, aNodeID) -{ - Services.obs.removeObserver(observer, "web-console-message-created"); - ok(aID, "we have a console ID"); - is(typeof aNodeID, "string", "message node id is a string"); - executeSoon(closeConsole); -} + yield gotEvents; +}); -let observer = { +function waitForEvents() { + let deferred = promise.defer(); - QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]), - - observe: function observe(aSubject, aTopic, aData) + function webConsoleCreated(aID) { - aSubject = aSubject.QueryInterface(Ci.nsISupportsString); - - switch(aTopic) { - case "web-console-created": - webConsoleCreated(aSubject.data); - break; - case "web-console-destroyed": - webConsoleDestroyed(aSubject.data); - break; - case "web-console-message-created": - webConsoleMessage(aSubject, aData); - break; - default: - break; - } - }, - - init: function init() - { - Services.obs.addObserver(this, "web-console-created", false); - Services.obs.addObserver(this, "web-console-destroyed", false); - Services.obs.addObserver(this, "web-console-message-created", false); + Services.obs.removeObserver(observer, "web-console-created"); + ok(HUDService.getHudReferenceById(aID), "We have a hud reference"); + content.wrappedJSObject.console.log("adding a log message"); } -}; -function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(); + function webConsoleDestroyed(aID) + { + Services.obs.removeObserver(observer, "web-console-destroyed"); + ok(!HUDService.getHudReferenceById(aID), "We do not have a hud reference"); + executeSoon(deferred.resolve); + } + + function webConsoleMessage(aID, aNodeID) + { + Services.obs.removeObserver(observer, "web-console-message-created"); + ok(aID, "we have a console ID"); + is(typeof aNodeID, "string", "message node id is a string"); + executeSoon(closeConsole); + } + + let observer = { + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]), + + observe: function observe(aSubject, aTopic, aData) + { + aSubject = aSubject.QueryInterface(Ci.nsISupportsString); + + switch(aTopic) { + case "web-console-created": + webConsoleCreated(aSubject.data); + break; + case "web-console-destroyed": + webConsoleDestroyed(aSubject.data); + break; + case "web-console-message-created": + webConsoleMessage(aSubject, aData); + break; + default: + break; + } + }, + + init: function init() + { + Services.obs.addObserver(this, "web-console-created", false); + Services.obs.addObserver(this, "web-console-destroyed", false); + Services.obs.addObserver(this, "web-console-message-created", false); + } + } + + observer.init(); + + return deferred.promise; } diff --git a/browser/devtools/webconsole/test/browser_webconsole_open-links-without-callback.js b/browser/devtools/webconsole/test/browser_webconsole_open-links-without-callback.js index 8f1eb758ae3f..225a340ef5a5 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_open-links-without-callback.js +++ b/browser/devtools/webconsole/test/browser_webconsole_open-links-without-callback.js @@ -5,6 +5,8 @@ // Tests that if a link without an onclick callback is clicked the link is // opened in a new tab and no exception occurs (bug 999236). +"use strict"; + function test() { function* runner() { const TEST_EVAL_STRING = "document"; diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_01.js b/browser/devtools/webconsole/test/browser_webconsole_output_01.js index c5c5df79f2e6..12e96a992b92 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_output_01.js +++ b/browser/devtools/webconsole/test/browser_webconsole_output_01.js @@ -108,6 +108,8 @@ if (typeof Symbol !== "undefined") { longString = initialString = null; function test() { + requestLongerTimeout(2); + registerCleanupFunction(() => { DebuggerServer.LONG_STRING_LENGTH = LONG_STRING_LENGTH; DebuggerServer.LONG_STRING_INITIAL_LENGTH = LONG_STRING_INITIAL_LENGTH; @@ -121,6 +123,6 @@ function test() { } function finishUp() { - inputTests = null; + longString = initialString = inputTests = null; finishTest(); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_04.js b/browser/devtools/webconsole/test/browser_webconsole_output_04.js index cd24521273a9..f50f4d073085 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_output_04.js +++ b/browser/devtools/webconsole/test/browser_webconsole_output_04.js @@ -117,6 +117,7 @@ let inputTests = [ ]; function test() { + requestLongerTimeout(2); Task.spawn(function*() { const {tab} = yield loadTab(TEST_URI); const hud = yield openConsole(tab); diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_05.js b/browser/devtools/webconsole/test/browser_webconsole_output_05.js index 9dc6618363fc..43c0dae16814 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_output_05.js +++ b/browser/devtools/webconsole/test/browser_webconsole_output_05.js @@ -107,6 +107,7 @@ let inputTests = [ ]; function test() { + requestLongerTimeout(2); Task.spawn(function*() { let {tab} = yield loadTab(TEST_URI); let hud = yield openConsole(tab); @@ -115,6 +116,6 @@ function test() { } function finishUp() { - inputTests = null; + inputTests = dateNow = null; finishTest(); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_06.js b/browser/devtools/webconsole/test/browser_webconsole_output_06.js index ebe9d8760e76..1925acd5678e 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_output_06.js +++ b/browser/devtools/webconsole/test/browser_webconsole_output_06.js @@ -101,6 +101,7 @@ let inputTests = [ ]; function test() { + requestLongerTimeout(2); Task.spawn(function*() { let {tab} = yield loadTab(TEST_URI); let hud = yield openConsole(tab); diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_copy_newlines.js b/browser/devtools/webconsole/test/browser_webconsole_output_copy_newlines.js index ff2cf2506a72..3760996611a5 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_output_copy_newlines.js +++ b/browser/devtools/webconsole/test/browser_webconsole_output_copy_newlines.js @@ -4,74 +4,64 @@ // Test that multiple messages are copied into the clipboard and that they are // separated by new lines. See bug 916997. -function test() -{ +"use strict"; + +let test = asyncTest(function*() { const TEST_URI = "data:text/html;charset=utf8,

hello world, bug 916997"; let clipboardValue = ""; - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); + yield loadTab(TEST_URI); + let hud = yield openConsole(); + hud.jsterm.clearOutput(); - function consoleOpened(hud) - { - hud.jsterm.clearOutput(); + let controller = top.document.commandDispatcher. + getControllerForCommand("cmd_copy"); + is(controller.isCommandEnabled("cmd_copy"), false, "cmd_copy is disabled"); - let controller = top.document.commandDispatcher. - getControllerForCommand("cmd_copy"); - is(controller.isCommandEnabled("cmd_copy"), false, "cmd_copy is disabled"); + content.console.log("Hello world! bug916997a"); + content.console.log("Hello world 2! bug916997b"); - content.console.log("Hello world! bug916997a"); - content.console.log("Hello world 2! bug916997b"); + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: "Hello world! bug916997a", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }, { + text: "Hello world 2! bug916997b", + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }], + }); - waitForMessages({ - webconsole: hud, - messages: [{ - text: "Hello world! bug916997a", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - }, { - text: "Hello world 2! bug916997b", - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - }], - }).then(() => { - hud.ui.output.selectAllMessages(); - hud.outputNode.focus(); + hud.ui.output.selectAllMessages(); + hud.outputNode.focus(); - goUpdateCommand("cmd_copy"); - controller = top.document.commandDispatcher.getControllerForCommand("cmd_copy"); - is(controller.isCommandEnabled("cmd_copy"), true, "cmd_copy is enabled"); + goUpdateCommand("cmd_copy"); + controller = top.document.commandDispatcher.getControllerForCommand("cmd_copy"); + is(controller.isCommandEnabled("cmd_copy"), true, "cmd_copy is enabled"); - let selection = hud.iframeWindow.getSelection() + ""; - info("selection '" + selection + "'"); - waitForClipboard((str) => { - clipboardValue = str; - return str.indexOf("bug916997a") > -1 && str.indexOf("bug916997b") > -1; - }, - () => { goDoCommand("cmd_copy"); }, - checkClipboard.bind(null, hud), - () => { - info("last clipboard value: '" + clipboardValue + "'"); - finishTest(); - }); + let selection = hud.iframeWindow.getSelection() + ""; + info("selection '" + selection + "'"); + + waitForClipboard((str) => { + clipboardValue = str; + return str.indexOf("bug916997a") > -1 && str.indexOf("bug916997b") > -1; + }, + () => { goDoCommand("cmd_copy"); }, + () => { + info("clipboard value '" + clipboardValue + "'"); + let lines = clipboardValue.trim().split("\n"); + is(hud.outputNode.children.length, 2, "number of messages"); + is(lines.length, hud.outputNode.children.length, "number of lines"); + isnot(lines[0].indexOf("bug916997a"), -1, + "first message text includes 'bug916997a'"); + isnot(lines[1].indexOf("bug916997b"), -1, + "second message text includes 'bug916997b'"); + is(lines[0].indexOf("bug916997b"), -1, + "first message text does not include 'bug916997b'"); + }, + () => { + info("last clipboard value: '" + clipboardValue + "'"); }); - } - - function checkClipboard(hud) - { - info("clipboard value '" + clipboardValue + "'"); - let lines = clipboardValue.trim().split("\n"); - is(hud.outputNode.children.length, 2, "number of messages"); - is(lines.length, hud.outputNode.children.length, "number of lines"); - isnot(lines[0].indexOf("bug916997a"), -1, - "first message text includes 'bug916997a'"); - isnot(lines[1].indexOf("bug916997b"), -1, - "second message text includes 'bug916997b'"); - is(lines[0].indexOf("bug916997b"), -1, - "first message text does not include 'bug916997b'"); - finishTest(); - } -} +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_01.js b/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_01.js index a61c478891e6..e7cc49369693 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_01.js +++ b/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_01.js @@ -99,6 +99,7 @@ let inputTests = [ ]; function test() { + requestLongerTimeout(2); Task.spawn(function*() { let {tab} = yield loadTab(TEST_URI); let hud = yield openConsole(tab); diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_02.js b/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_02.js index 4dbd900710a0..d6db04ea161f 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_02.js +++ b/browser/devtools/webconsole/test/browser_webconsole_output_dom_elements_02.js @@ -14,19 +14,27 @@ const TEST_DATA = [ // default selected node, so re-selecting it won't fire the inspector-updated // event input: "testNode()", - output: '

' + output: '

', + tagName: 'P', + attrs: [{name: "some-attribute", value: "some-value"}] }, { input: "testBodyNode()", - output: '' + output: '', + tagName: 'BODY', + attrs: [{name: "id", value: "body-id"}, {name: "class", value: "body-class"}] }, { input: "testNodeInIframe()", - output: '

' + output: '

', + tagName: 'P', + attrs: [] }, { input: "testDocumentElement()", - output: '' + output: '', + tagName: 'HTML', + attrs: [{name: "lang", value: "en-US"}, {name: "dir", value: "ltr"}] } ]; @@ -53,18 +61,23 @@ function test() { info("Clicking on the inspector icon and waiting for the inspector to be selected"); let onInspectorSelected = toolbox.once("inspector-selected"); let onInspectorUpdated = inspector.once("inspector-updated"); - let onNewNode = toolbox.selection.once("new-node"); + let onNewNode = toolbox.selection.once("new-node-front"); EventUtils.synthesizeMouseAtCenter(inspectorIcon, {}, inspectorIcon.ownerDocument.defaultView); yield onInspectorSelected; yield onInspectorUpdated; - yield onNewNode; + let nodeFront = yield onNewNode; + ok(true, "Inspector selected and new node got selected"); - let rawNode = content.wrappedJSObject[data.input.replace(/\(\)/g, "")](); - is(inspector.selection.node.wrappedJSObject, rawNode, - "The current inspector selection is correct"); + is(nodeFront.tagName, data.tagName, "The correct node was highlighted"); + + let attrs = nodeFront.attributes; + for (let i in data.attrs) { + is(attrs[i].name, data.attrs[i].name, "The correct node was highlighted"); + is(attrs[i].value, data.attrs[i].value, "The correct node was highlighted"); + } info("Switching back to the console"); yield toolbox.selectTool("webconsole"); diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_events.js b/browser/devtools/webconsole/test/browser_webconsole_output_events.js index 079abaa23c92..72b2ec93d46a 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_output_events.js +++ b/browser/devtools/webconsole/test/browser_webconsole_output_events.js @@ -14,54 +14,40 @@ thisTestLeaksUncaughtRejectionsAndShouldBeFixed("null"); const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-events.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - Task.spawn(runner); - }, true); +let test = asyncTest(function* () { + yield loadTab(TEST_URI); - function* runner() - { - let hud = yield openConsole(); + let hud = yield openConsole(); - hud.jsterm.clearOutput(); - hud.jsterm.execute("testDOMEvents()"); + hud.jsterm.clearOutput(); + hud.jsterm.execute("testDOMEvents()"); - yield waitForMessages({ - webconsole: hud, - messages: [{ - name: "testDOMEvents() output", - text: "undefined", - category: CATEGORY_OUTPUT, - }], - }); + yield waitForMessages({ + webconsole: hud, + messages: [{ + name: "testDOMEvents() output", + text: "undefined", + category: CATEGORY_OUTPUT, + }], + }); - EventUtils.synthesizeMouse(content.document.body, 2, 2, {type: "mousemove"}, content); + yield waitForMessages({ + webconsole: hud, + messages: [{ + name: "console.log() output for mousemove", + text: /"eventLogger" mousemove { target: .+, buttons: 0, clientX: \d+, clientY: \d+, layerX: \d+, layerY: \d+ }/, + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }], + }); - yield waitForMessages({ - webconsole: hud, - messages: [{ - name: "console.log() output for mousemove", - text: /"eventLogger" mousemove { target: .+, buttons: 1, clientX: \d+, clientY: \d+, layerX: \d+, layerY: \d+ }/, - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - }], - }); - - content.focus(); - EventUtils.synthesizeKey("a", {shiftKey: true}, content); - - yield waitForMessages({ - webconsole: hud, - messages: [{ - name: "console.log() output for keypress", - text: /"eventLogger" keypress Shift { target: .+, key: .+, charCode: \d+, keyCode: \d+ }/, - category: CATEGORY_WEBDEV, - severity: SEVERITY_LOG, - }], - }); - - finishTest(); - } -} + yield waitForMessages({ + webconsole: hud, + messages: [{ + name: "console.log() output for keypress", + text: /"eventLogger" keypress Shift { target: .+, key: .+, charCode: \d+, keyCode: \d+ }/, + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }], + }); +}); \ No newline at end of file diff --git a/browser/devtools/webconsole/test/browser_webconsole_output_order.js b/browser/devtools/webconsole/test/browser_webconsole_output_order.js index 4712be52de29..4a2a9f6be537 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_output_order.js +++ b/browser/devtools/webconsole/test/browser_webconsole_output_order.js @@ -6,24 +6,21 @@ // Tests that any output created from calls to the console API comes after the // echoed JavaScript. +"use strict"; + const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testOutputOrder); - }, true); -} +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + let hud = yield openConsole(); -function testOutputOrder(hud) { let jsterm = hud.jsterm; let outputNode = jsterm.outputNode; jsterm.clearOutput(); jsterm.execute("console.log('foo', 'bar');"); - waitForMessages({ + let [function_call, result, console_message] = yield waitForMessages({ webconsole: hud, messages: [{ text: "console.log('foo', 'bar');", @@ -38,14 +35,13 @@ function testOutputOrder(hud) { category: CATEGORY_WEBDEV, severity: SEVERITY_LOG, }], - }).then(([function_call, result, console_message]) => { - let fncall_node = [...function_call.matched][0]; - let result_node = [...result.matched][0]; - let console_message_node = [...console_message.matched][0]; - is(fncall_node.nextElementSibling, result_node, - "console.log() is followed by undefined"); - is(result_node.nextElementSibling, console_message_node, - "undefined is followed by 'foo' 'bar'"); - finishTest(); }); -} + + let fncall_node = [...function_call.matched][0]; + let result_node = [...result.matched][0]; + let console_message_node = [...console_message.matched][0]; + is(fncall_node.nextElementSibling, result_node, + "console.log() is followed by undefined"); + is(result_node.nextElementSibling, console_message_node, + "undefined is followed by 'foo' 'bar'"); +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_property_provider.js b/browser/devtools/webconsole/test/browser_webconsole_property_provider.js index 2ca742d48178..14c054d36cc5 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_property_provider.js +++ b/browser/devtools/webconsole/test/browser_webconsole_property_provider.js @@ -9,11 +9,10 @@ const TEST_URI = "data:text/html;charset=utf8,

test the JS property provider"; function test() { - addTab(TEST_URI); - browser.addEventListener("load", testPropertyProvider, true); + loadTab(TEST_URI).then(testPropertyProvider); } -function testPropertyProvider() { +function testPropertyProvider({browser}) { browser.removeEventListener("load", testPropertyProvider, true); let tools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools; let JSPropertyProvider = tools.require("devtools/toolkit/webconsole/utils").JSPropertyProvider; diff --git a/browser/devtools/webconsole/test/browser_webconsole_reflow.js b/browser/devtools/webconsole/test/browser_webconsole_reflow.js index a357c8b581d4..328b296de37d 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_reflow.js +++ b/browser/devtools/webconsole/test/browser_webconsole_reflow.js @@ -3,33 +3,30 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -function test() -{ - addTab("data:text/html;charset=utf-8,Web Console test for reflow activity"); +"use strict"; - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(gBrowser.selectedTab, function(hud) { +const TEST_URI = "data:text/html;charset=utf-8,Web Console test for reflow activity"; - function onReflowListenersReady(aType, aPacket) { - browser.contentDocument.body.style.display = "none"; - browser.contentDocument.body.clientTop; - } +let test = asyncTest(function* () { + let { browser } = yield loadTab(TEST_URI); - Services.prefs.setBoolPref("devtools.webconsole.filter.csslog", true); - hud.ui._updateReflowActivityListener(onReflowListenersReady); - Services.prefs.clearUserPref("devtools.webconsole.filter.csslog"); + let hud = yield openConsole(); - waitForMessages({ - webconsole: hud, - messages: [{ - text: /reflow: /, - category: CATEGORY_CSS, - severity: SEVERITY_LOG, - }], - }).then(() => { - finishTest(); - }); - }); - }, true); -} + function onReflowListenersReady(aType, aPacket) { + browser.contentDocument.body.style.display = "none"; + browser.contentDocument.body.clientTop; + } + + Services.prefs.setBoolPref("devtools.webconsole.filter.csslog", true); + hud.ui._updateReflowActivityListener(onReflowListenersReady); + Services.prefs.clearUserPref("devtools.webconsole.filter.csslog"); + + yield waitForMessages({ + webconsole: hud, + messages: [{ + text: /reflow: /, + category: CATEGORY_CSS, + severity: SEVERITY_LOG, + }], + }) +}); diff --git a/browser/devtools/webconsole/test/browser_webconsole_scratchpad_panel_link.js b/browser/devtools/webconsole/test/browser_webconsole_scratchpad_panel_link.js index 04077cdafe75..0d1db73c5828 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_scratchpad_panel_link.js +++ b/browser/devtools/webconsole/test/browser_webconsole_scratchpad_panel_link.js @@ -15,14 +15,12 @@ function test() { waitForExplicitFinish(); - addTab(TEST_URI); - gBrowser.selectedBrowser.addEventListener("load", function onTabLoad() { - gBrowser.selectedBrowser.removeEventListener("load", onTabLoad, true); + loadTab(TEST_URI).then(() => { info("Opening toolbox with Scratchpad panel"); let target = TargetFactory.forTab(gBrowser.selectedTab); gDevTools.showToolbox(target, "scratchpad", "window").then(runTests); - }, true); + }); } function runTests(aToolbox) diff --git a/browser/devtools/webconsole/test/browser_webconsole_split.js b/browser/devtools/webconsole/test/browser_webconsole_split.js index 30ae9ce70852..9501cd238e0f 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_split.js +++ b/browser/devtools/webconsole/test/browser_webconsole_split.js @@ -3,6 +3,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +const TEST_URI = "data:text/html;charset=utf-8,Web Console test for splitting"; + function test() { // Test is slow on Linux EC2 instances - Bug 962931 @@ -13,11 +15,7 @@ function test() let Toolbox = devtools.Toolbox; let toolbox; - addTab("data:text/html;charset=utf-8,Web Console test for splitting"); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - testConsoleLoadOnDifferentPanel() - }, true); + loadTab(TEST_URI).then(testConsoleLoadOnDifferentPanel); function testConsoleLoadOnDifferentPanel() { diff --git a/browser/devtools/webconsole/test/browser_webconsole_view_source.js b/browser/devtools/webconsole/test/browser_webconsole_view_source.js index 33d364166aa3..ad008478df71 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_view_source.js +++ b/browser/devtools/webconsole/test/browser_webconsole_view_source.js @@ -11,11 +11,9 @@ let Sources; let getItemInvoked = false; function test() { - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, testViewSource); - }, true); + loadTab(TEST_URI).then(() => { + openConsole(null).then(testViewSource); + }); } function testViewSource(hud) { @@ -30,7 +28,7 @@ function testViewSource(hud) { openDebugger().then(({panelWin: { DebuggerView }}) => { info("debugger opened"); Sources = DebuggerView.Sources; - openConsole(null, (hud) => { + openConsole().then((hud) => { info("console opened again"); waitForMessages({ diff --git a/browser/devtools/webconsole/test/head.js b/browser/devtools/webconsole/test/head.js index cdf81ee3069c..e842f3ad93de 100644 --- a/browser/devtools/webconsole/test/head.js +++ b/browser/devtools/webconsole/test/head.js @@ -15,6 +15,7 @@ let {Utils: WebConsoleUtils} = require("devtools/toolkit/webconsole/utils"); let {Messages} = require("devtools/webconsole/console-output"); // promise._reportErrors = true; // please never leave me. +//Services.prefs.setBoolPref("devtools.debugger.log", true); let gPendingOutputTest = 0; @@ -40,35 +41,13 @@ const WEBCONSOLE_STRINGS_URI = "chrome://browser/locale/devtools/webconsole.prop let WCU_l10n = new WebConsoleUtils.l10n(WEBCONSOLE_STRINGS_URI); gDevTools.testing = true; -SimpleTest.registerCleanupFunction(() => { - gDevTools.testing = false; -}); -function log(aMsg) -{ - dump("*** WebConsoleTest: " + aMsg + "\n"); +function asyncTest(generator) { + return () => { + Task.spawn(generator).then(finishTest); + }; } -function pprint(aObj) -{ - for (let prop in aObj) { - if (typeof aObj[prop] == "function") { - log("function " + prop); - } - else { - log(prop + ": " + aObj[prop]); - } - } -} - -let tab, browser, hudId, hud, hudBox, filterBox, outputNode, cs; - -function addTab(aURL) -{ - gBrowser.selectedTab = gBrowser.addTab(aURL); - tab = gBrowser.selectedTab; - browser = gBrowser.getBrowserForTab(tab); -} function loadTab(url) { let deferred = promise.defer(); @@ -89,7 +68,7 @@ function loadBrowser(browser) { browser.addEventListener("load", function onLoad() { browser.removeEventListener("load", onLoad, true); - deferred.resolve(null) + deferred.resolve(null); }, true); return deferred.promise; @@ -198,18 +177,16 @@ function findLogEntry(aString) * @return object * A promise that is resolved once the web console is open. */ -function openConsole(aTab, aCallback = function() { }) -{ - let deferred = promise.defer(); - let target = TargetFactory.forTab(aTab || tab); - gDevTools.showToolbox(target, "webconsole").then(function(toolbox) { +let openConsole = function(aTab) { + let webconsoleOpened = promise.defer(); + let target = TargetFactory.forTab(aTab || gBrowser.selectedTab); + gDevTools.showToolbox(target, "webconsole").then(toolbox => { let hud = toolbox.getCurrentPanel().hud; hud.jsterm._lazyVariablesView = false; - aCallback(hud); - deferred.resolve(hud); + webconsoleOpened.resolve(hud); }); - return deferred.promise; -} + return webconsoleOpened.promise; +}; /** * Close the Web Console for the given tab. @@ -223,22 +200,13 @@ function openConsole(aTab, aCallback = function() { }) * @return object * A promise that is resolved once the web console is closed. */ -function closeConsole(aTab, aCallback = function() { }) -{ - let target = TargetFactory.forTab(aTab || tab); +let closeConsole = Task.async(function* (aTab) { + let target = TargetFactory.forTab(aTab || gBrowser.selectedTab); let toolbox = gDevTools.getToolbox(target); if (toolbox) { - let panel = toolbox.getPanel("webconsole"); - if (panel) { - let hudId = panel.hud.hudId; - return toolbox.destroy().then(aCallback.bind(null, hudId)).then(null, console.debug); - } - return toolbox.destroy().then(aCallback.bind(null)); + yield toolbox.destroy(); } - - aCallback(); - return promise.resolve(null); -} +}); /** * Wait for a context menu popup to open. @@ -252,6 +220,9 @@ function closeConsole(aTab, aCallback = function() { }) * Function to invoke on popupshown event. * @param function aOnHidden * Function to invoke on popuphidden event. + * @return object + * A Promise object that is resolved after the popuphidden event + * callback is invoked. */ function waitForContextMenu(aPopup, aButton, aOnShown, aOnHidden) { @@ -259,7 +230,7 @@ function waitForContextMenu(aPopup, aButton, aOnShown, aOnHidden) info("onPopupShown"); aPopup.removeEventListener("popupshown", onPopupShown); - aOnShown(); + aOnShown && aOnShown(); // Use executeSoon() to get out of the popupshown event. aPopup.addEventListener("popuphidden", onPopupHidden); @@ -268,15 +239,20 @@ function waitForContextMenu(aPopup, aButton, aOnShown, aOnHidden) function onPopupHidden() { info("onPopupHidden"); aPopup.removeEventListener("popuphidden", onPopupHidden); - aOnHidden(); + + aOnHidden && aOnHidden(); + + deferred.resolve(aPopup); } + let deferred = promise.defer(); aPopup.addEventListener("popupshown", onPopupShown); info("wait for the context menu to open"); let eventDetails = { type: "contextmenu", button: 2}; EventUtils.synthesizeMouse(aButton, 2, 2, eventDetails, aButton.ownerDocument.defaultView); + return deferred.promise; } /** @@ -326,10 +302,7 @@ function dumpMessageElement(aMessage) "text", text); } -function finishTest() -{ - browser = hudId = hud = filterBox = outputNode = cs = hudBox = null; - +let finishTest = Task.async(function* () { dumpConsoles(); let browserConsole = HUDService.getBrowserConsole(); @@ -337,27 +310,19 @@ function finishTest() if (browserConsole.jsterm) { browserConsole.jsterm.clearOutput(true); } - HUDService.toggleBrowserConsole().then(finishTest); - return; + yield HUDService.toggleBrowserConsole(); } - let contentHud = HUDService.getHudByWindow(content); - if (!contentHud) { - finish(); - return; - } + let target = TargetFactory.forTab(gBrowser.selectedTab); + yield gDevTools.closeToolbox(target); - if (contentHud.jsterm) { - contentHud.jsterm.clearOutput(true); - } - - closeConsole(contentHud.target.tab, finish); - - contentHud = null; -} + finish(); +}); function tearDown() { + gDevTools.testing = false; + dumpConsoles(); if (HUDService.getBrowserConsole()) { @@ -366,10 +331,10 @@ function tearDown() let target = TargetFactory.forTab(gBrowser.selectedTab); gDevTools.closeToolbox(target); + while (gBrowser.tabs.length > 1) { gBrowser.removeCurrentTab(); } - WCU_l10n = tab = browser = hudId = hud = filterBox = outputNode = cs = null; } registerCleanupFunction(tearDown); @@ -381,55 +346,56 @@ waitForExplicitFinish(); * * @param object aOptions * Options object with the following properties: - * - validatorFn + * - validator * A validator function that returns a boolean. This is called every few - * milliseconds to check if the result is true. When it is true, succesFn - * is called and polling stops. If validatorFn never returns true, then - * polling timeouts after several tries and a failure is recorded. - * - successFn - * A function called when the validator function returns true. - * - failureFn - * A function called if the validator function timeouts - fails to return - * true in the given time. + * milliseconds to check if the result is true. When it is true, the + * promise is resolved and polling stops. If validator never returns + * true, then polling timeouts after several tries and the promise is + * rejected. * - name * Name of test. This is used to generate the success and failure * messages. * - timeout * Timeout for validator function, in milliseconds. Default is 5000. + * @return object + * A Promise object that is resolved based on the validator function. */ function waitForSuccess(aOptions) { + let deferred = promise.defer(); let start = Date.now(); let timeout = aOptions.timeout || 5000; + let {validator} = aOptions; - function wait(validatorFn, successFn, failureFn) + + function wait() { if ((Date.now() - start) > timeout) { // Log the failure. ok(false, "Timed out while waiting for: " + aOptions.name); - failureFn(aOptions); + deferred.reject(null); return; } - if (validatorFn(aOptions)) { + if (validator(aOptions)) { ok(true, aOptions.name); - successFn(); + deferred.resolve(null); } else { - setTimeout(function() wait(validatorFn, successFn, failureFn), 100); + setTimeout(wait, 100); } } - wait(aOptions.validatorFn, aOptions.successFn, aOptions.failureFn); + setTimeout(wait, 100); + + return deferred.promise; } -function openInspector(aCallback, aTab = gBrowser.selectedTab) -{ +let openInspector = Task.async(function* (aTab = gBrowser.selectedTab) { let target = TargetFactory.forTab(aTab); - gDevTools.showToolbox(target, "inspector").then(function(toolbox) { - aCallback(toolbox.getCurrentPanel()); - }); -} + let toolbox = yield gDevTools.showToolbox(target, "inspector"); + return toolbox.getCurrentPanel(); +}); /** * Find variables or properties in a VariablesView instance. @@ -773,10 +739,10 @@ function variablesViewExpandTo(aOptions) * - or "value" to change the property value. * - string: the new string to write into the field. * - webconsole: reference to the Web Console instance we work with. - * - callback: function to invoke after the property is updated. + * @return object + * A Promise object that is resolved once the property is updated. */ -function updateVariablesViewProperty(aOptions) -{ +let updateVariablesViewProperty = Task.async(function* (aOptions) { let view = aOptions.property._variablesView; view.window.focus(); aOptions.property.focus(); @@ -790,27 +756,34 @@ function updateVariablesViewProperty(aOptions) break; default: throw new Error("options.field is incorrect"); - return; } + let deferred = promise.defer(); + executeSoon(() => { EventUtils.synthesizeKey("A", { accelKey: true }, view.window); for (let c of aOptions.string) { - EventUtils.synthesizeKey(c, {}, gVariablesView.window); + EventUtils.synthesizeKey(c, {}, view.window); } if (aOptions.webconsole) { - aOptions.webconsole.jsterm.once("variablesview-fetched", aOptions.callback); + aOptions.webconsole.jsterm.once("variablesview-fetched").then((varView) => { + deferred.resolve(varView); + }); } EventUtils.synthesizeKey("VK_RETURN", {}, view.window); if (!aOptions.webconsole) { - executeSoon(aOptions.callback); + executeSoon(() => { + deferred.resolve(null); + }); } }); -} + + return deferred.promise; +}); /** * Open the JavaScript debugger. diff --git a/browser/devtools/webconsole/test/test-console-assert.html b/browser/devtools/webconsole/test/test-console-assert.html index 5358eb31f092..b104d72d4350 100644 --- a/browser/devtools/webconsole/test/test-console-assert.html +++ b/browser/devtools/webconsole/test/test-console-assert.html @@ -19,6 +19,5 @@

test console.assert()

- diff --git a/browser/devtools/webconsole/test/test-console-output-events.html b/browser/devtools/webconsole/test/test-console-output-events.html index 921c1002949e..908a86fabde1 100644 --- a/browser/devtools/webconsole/test/test-console-output-events.html +++ b/browser/devtools/webconsole/test/test-console-output-events.html @@ -10,6 +10,7 @@

hello world!

+ From e32e63d0a33af5408dc044a2e1d46fcc4eea6663 Mon Sep 17 00:00:00 2001 From: Shubham Jindal Date: Mon, 15 Dec 2014 09:38:00 +0100 Subject: [PATCH 003/130] Bug 1073857 - Allow app names without ASCII characters when creating new app/handle non-ASCII characters like umlauts more gracefully (repeatedly asking for folder). r=jryans --- browser/devtools/webide/content/newapp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/devtools/webide/content/newapp.js b/browser/devtools/webide/content/newapp.js index 83f5ea18a0f6..60151c0e8911 100644 --- a/browser/devtools/webide/content/newapp.js +++ b/browser/devtools/webide/content/newapp.js @@ -127,7 +127,7 @@ function doOK() { } // Create subfolder with fs-friendly name of project - let subfolder = projectName.replace(/\W/g, '').toLowerCase(); + let subfolder = projectName.replace(/[\\/:*?"<>|]/g, '').toLowerCase(); folder.append(subfolder); try { From 0582a88359ca748d987a913810c35ffd260535ed Mon Sep 17 00:00:00 2001 From: Brian Grinstead Date: Mon, 15 Dec 2014 15:06:00 +0100 Subject: [PATCH 004/130] Bug 1100578 - DevEdition theme: remove 2px gap to the left of the first tab. r=Gijs --- browser/themes/shared/devedition.inc.css | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/browser/themes/shared/devedition.inc.css b/browser/themes/shared/devedition.inc.css index e6dcb824e61e..7e2fc7f02d64 100644 --- a/browser/themes/shared/devedition.inc.css +++ b/browser/themes/shared/devedition.inc.css @@ -127,20 +127,20 @@ /* Override @tabCurveHalfWidth@ and @tabCurveWidth@. XXX: Switch to a CSS variable once the perf is sorted out - bug 1088771 */ .tab-background-middle { - border-left: 2px solid transparent; - border-right: 2px solid transparent; - margin: 0 -2px; + border-left-width: 0; + border-right-width: 0; + margin: 0; } .tab-background, .tabs-newtab-button { - -moz-margin-end: -2px; - -moz-margin-start: -2px; + -moz-margin-end: 0; + -moz-margin-start: 0; } .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox { - -moz-padding-end: 2px; - -moz-padding-start: 2px; + -moz-padding-end: 0; + -moz-padding-start: 0; } .tab-background-start[selected=true]::after, @@ -149,12 +149,12 @@ .tab-background-end, .tab-background-end[selected=true]::after, .tab-background-end[selected=true]::before { - width: 4px; + width: 0; } .tab-background-start[selected=true]::after, .tab-background-end[selected=true]::after { - -moz-margin-start: -4px; + -moz-margin-start: 0; } /* End override @tabCurveHalfWidth@ and @tabCurveWidth@ */ From a6f00268e42643142cf55608da3aa4ad2e730d3c Mon Sep 17 00:00:00 2001 From: vivek Date: Sat, 6 Dec 2014 13:33:34 -0800 Subject: [PATCH 005/130] Bug 732752 - Restore a closed tab with previous session history r=bnicholson. --- mobile/android/base/BrowserApp.java | 13 ---- mobile/android/base/home/HomePager.java | 4 - mobile/android/base/home/RecentTabsPanel.java | 77 +++++++++---------- mobile/android/components/SessionStore.js | 27 ++++++- 4 files changed, 62 insertions(+), 59 deletions(-) diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java index f89be2a67085..e9f9abb0d6be 100644 --- a/mobile/android/base/BrowserApp.java +++ b/mobile/android/base/BrowserApp.java @@ -148,7 +148,6 @@ public class BrowserApp extends GeckoApp LayerView.OnMetricsChangedListener, BrowserSearch.OnSearchListener, BrowserSearch.OnEditSuggestionListener, - HomePager.OnNewTabsListener, OnUrlOpenListener, OnUrlOpenInBackgroundListener, ActionModeCompat.Presenter, @@ -3158,18 +3157,6 @@ public class BrowserApp extends GeckoApp }).execute(); } - // HomePager.OnNewTabsListener - @Override - public void onNewTabs(List urls) { - final EnumSet flags = EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB); - - for (String url : urls) { - if (!maybeSwitchToTab(url, flags)) { - openUrlAndStopEditing(url, true); - } - } - } - // HomePager.OnUrlOpenListener @Override public void onUrlOpen(String url, EnumSet flags) { diff --git a/mobile/android/base/home/HomePager.java b/mobile/android/base/home/HomePager.java index 5d16c8f05c16..f826a7d4d1e0 100644 --- a/mobile/android/base/home/HomePager.java +++ b/mobile/android/base/home/HomePager.java @@ -102,10 +102,6 @@ public class HomePager extends ViewPager { public void onUrlOpenInBackground(String url, EnumSet flags); } - public interface OnNewTabsListener { - public void onNewTabs(List urls); - } - /** * Interface for listening into ViewPager panel changes */ diff --git a/mobile/android/base/home/RecentTabsPanel.java b/mobile/android/base/home/RecentTabsPanel.java index 9e55ccd2fe37..7485d4169aa1 100644 --- a/mobile/android/base/home/RecentTabsPanel.java +++ b/mobile/android/base/home/RecentTabsPanel.java @@ -8,6 +8,9 @@ package org.mozilla.gecko.home; import java.util.ArrayList; import java.util.List; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.mozilla.gecko.AboutPages; import org.mozilla.gecko.EventDispatcher; import org.mozilla.gecko.GeckoAppShell; @@ -19,8 +22,8 @@ import org.mozilla.gecko.Telemetry; import org.mozilla.gecko.TelemetryContract; import org.mozilla.gecko.db.BrowserContract.CommonColumns; import org.mozilla.gecko.db.BrowserContract.URLColumns; -import org.mozilla.gecko.home.HomePager.OnNewTabsListener; import org.mozilla.gecko.util.EventCallback; +import org.mozilla.gecko.util.GeckoRequest; import org.mozilla.gecko.util.NativeEventListener; import org.mozilla.gecko.util.NativeJSObject; import org.mozilla.gecko.util.ThreadUtils; @@ -33,6 +36,7 @@ import android.database.MatrixCursor.RowBuilder; import android.os.Bundle; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -65,24 +69,35 @@ public class RecentTabsPanel extends HomeFragment // Callbacks used for the search and favicon cursor loaders private CursorLoaderCallbacks mCursorLoaderCallbacks; - // On new tabs listener - private OnNewTabsListener mNewTabsListener; - // Recently closed tabs from gecko private ClosedTab[] mClosedTabs; + private void restoreSessionWithHistory(List dataList) { + JSONObject json = new JSONObject(); + try { + json.put("tabs", new JSONArray(dataList)); + } catch (JSONException e) { + Log.e(LOGTAG, "JSON error", e); + } + + GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Session:RestoreRecentTabs", json.toString())); + } + private static final class ClosedTab { public final String url; public final String title; + public final String data; - public ClosedTab(String url, String title) { + public ClosedTab(String url, String title, String data) { this.url = url; this.title = title; + this.data = data; } } public static final class RecentTabs implements URLColumns, CommonColumns { public static final String TYPE = "type"; + public static final String DATA = "data"; public static final int TYPE_HEADER = 0; public static final int TYPE_LAST_TIME = 1; @@ -91,25 +106,6 @@ public class RecentTabsPanel extends HomeFragment public static final int TYPE_OPEN_ALL_CLOSED = 4; } - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - - try { - mNewTabsListener = (OnNewTabsListener) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() - + " must implement HomePager.OnNewTabsListener"); - } - } - - @Override - public void onDetach() { - super.onDetach(); - - mNewTabsListener = null; - } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.home_recent_tabs_panel, container, false); @@ -142,10 +138,9 @@ public class RecentTabsPanel extends HomeFragment Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.LIST_ITEM); - final ArrayList urls = new ArrayList(); - urls.add(c.getString(c.getColumnIndexOrThrow(RecentTabs.URL))); - - mNewTabsListener.onNewTabs(urls); + final List dataList = new ArrayList<>(); + dataList.add(c.getString(c.getColumnIndexOrThrow(RecentTabs.DATA))); + restoreSessionWithHistory(dataList); } }); @@ -227,7 +222,7 @@ public class RecentTabsPanel extends HomeFragment final ClosedTab[] closedTabs = new ClosedTab[length]; for (int i = 0; i < length; i++) { final NativeJSObject tab = tabs[i]; - closedTabs[i] = new ClosedTab(tab.getString("url"), tab.getString("title")); + closedTabs[i] = new ClosedTab(tab.getString("url"), tab.getString("title"), tab.getObject("data").toString()); } // Only modify mClosedTabs on the UI thread @@ -252,16 +247,16 @@ public class RecentTabsPanel extends HomeFragment return; } - final List urls = new ArrayList(); + final List dataList = new ArrayList(); do { if (c.getInt(c.getColumnIndexOrThrow(RecentTabs.TYPE)) == type) { - urls.add(c.getString(c.getColumnIndexOrThrow(RecentTabs.URL))); + dataList.add(c.getString(c.getColumnIndexOrThrow(RecentTabs.DATA))); } } while (c.moveToNext()); Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.BUTTON); - mNewTabsListener.onNewTabs(urls); + restoreSessionWithHistory(dataList); } private static class RecentTabsCursorLoader extends SimpleCursorLoader { @@ -272,12 +267,13 @@ public class RecentTabsPanel extends HomeFragment this.closedTabs = closedTabs; } - private void addRow(MatrixCursor c, String url, String title, int type) { + private void addRow(MatrixCursor c, String url, String title, int type, String data) { final RowBuilder row = c.newRow(); row.add(-1); row.add(url); row.add(title); row.add(type); + row.add(data); } @Override @@ -287,7 +283,8 @@ public class RecentTabsPanel extends HomeFragment final MatrixCursor c = new MatrixCursor(new String[] { RecentTabs._ID, RecentTabs.URL, RecentTabs.TITLE, - RecentTabs.TYPE }); + RecentTabs.TYPE, + RecentTabs.DATA}); if (closedTabs != null && closedTabs.length > 0) { // How many closed tabs are actually displayed. @@ -301,16 +298,16 @@ public class RecentTabsPanel extends HomeFragment if (!AboutPages.isTitlelessAboutPage(url)) { // If this is the first closed tab we're adding, add a header for the section. if (visibleClosedTabs == 0) { - addRow(c, null, context.getString(R.string.home_closed_tabs_title), RecentTabs.TYPE_HEADER); + addRow(c, null, context.getString(R.string.home_closed_tabs_title), RecentTabs.TYPE_HEADER, null); } - addRow(c, url, closedTabs[i].title, RecentTabs.TYPE_CLOSED); + addRow(c, url, closedTabs[i].title, RecentTabs.TYPE_CLOSED, closedTabs[i].data); visibleClosedTabs++; } } // Add an "Open all" button if more than 2 tabs were added to the list. if (visibleClosedTabs > 1) { - addRow(c, null, null, RecentTabs.TYPE_OPEN_ALL_CLOSED); + addRow(c, null, null, RecentTabs.TYPE_OPEN_ALL_CLOSED, null); } } @@ -334,16 +331,16 @@ public class RecentTabsPanel extends HomeFragment // If this is the first tab we're reading, add a header. if (c.getCount() == count) { - addRow(c, null, context.getString(R.string.home_last_tabs_title), RecentTabs.TYPE_HEADER); + addRow(c, null, context.getString(R.string.home_last_tabs_title), RecentTabs.TYPE_HEADER, null); } - addRow(c, url, tab.getTitle(), RecentTabs.TYPE_LAST_TIME); + addRow(c, url, tab.getTitle(), RecentTabs.TYPE_LAST_TIME, tab.getTabObject().toString()); } }.parse(jsonString); // Add an "Open all" button if more than 2 tabs were added to the list (account for the header) if (c.getCount() - count > 2) { - addRow(c, null, null, RecentTabs.TYPE_OPEN_ALL_LAST_TIME); + addRow(c, null, null, RecentTabs.TYPE_OPEN_ALL_LAST_TIME, null); } return c; diff --git a/mobile/android/components/SessionStore.js b/mobile/android/components/SessionStore.js index 30a016976d5a..34cc208b6b0c 100644 --- a/mobile/android/components/SessionStore.js +++ b/mobile/android/components/SessionStore.js @@ -86,6 +86,7 @@ SessionStore.prototype = { observerService.addObserver(this, "ClosedTabs:StartNotifications", true); observerService.addObserver(this, "ClosedTabs:StopNotifications", true); observerService.addObserver(this, "last-pb-context-exited", true); + observerService.addObserver(this, "Session:RestoreRecentTabs", true); break; case "final-ui-startup": observerService.removeObserver(this, "final-ui-startup"); @@ -176,6 +177,11 @@ SessionStore.prototype = { } this._lastClosedTabIndex = -1; break; + case "Session:RestoreRecentTabs": { + let data = JSON.parse(aData); + this._restoreTabsWithHistory(data); + break; + } } }, @@ -758,7 +764,23 @@ SessionStore.prototype = { return shEntry; }, - _restoreHistory: function _restoreHistory(aTabData, aHistory) { + // This function iterates through a list of tab data restoring history for each of them. + _restoreTabsWithHistory: function ss_restoreTabsWithHistory(data) { + let window = Services.wm.getMostRecentWindow("navigator:browser"); + for (let i = 0; i < data.tabs.length; i++) { + let tabData = JSON.parse(data.tabs[i]); + let params = { + selected: (i == data.tabs.length - 1), + isPrivate: tabData.isPrivate, + desktopMode: tabData.desktopMode, + }; + + let tab = window.BrowserApp.addTab(tabData.entries[tabData.index - 1].url, params); + this._restoreHistory(tabData, tab.browser.sessionHistory); + } + }, + + _restoreHistory: function ss_restoreHistory(aTabData, aHistory) { if (aHistory.count > 0) aHistory.PurgeHistory(aHistory.count); aHistory.QueryInterface(Ci.nsISHistoryInternal); @@ -934,7 +956,8 @@ SessionStore.prototype = { let lastEntry = tab.entries[tab.entries.length - 1]; return { url: lastEntry.url, - title: lastEntry.title || "" + title: lastEntry.title || "", + data: tab }; }); From c673460607cd2597a6b17f64339844d7d1b32148 Mon Sep 17 00:00:00 2001 From: Matthew Noorenberghe Date: Tue, 16 Dec 2014 01:26:24 -0800 Subject: [PATCH 006/130] Bug 1111013 - Add aOpenParams.ignoreQueryString to switchToTabHavingURI to ignore query params without replacing. r=dolske --HG-- rename : browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_ignoreFragment.js => browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_aOpenParams.js extra : rebase_source : 201b4ff0e007045d73884de51a8f6574a82c1e64 --- browser/base/content/browser.js | 14 +++- browser/base/content/test/general/browser.ini | 2 +- ...025195_switchToTabHavingURI_aOpenParams.js | 83 +++++++++++++++++++ ...195_switchToTabHavingURI_ignoreFragment.js | 62 -------------- 4 files changed, 94 insertions(+), 67 deletions(-) create mode 100644 browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_aOpenParams.js delete mode 100644 browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_ignoreFragment.js diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 20de9f3d42c8..d06eed3cad4f 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -7492,8 +7492,10 @@ let gRemoteTabsUI = { * This object also allows: * - 'ignoreFragment' property to be set to true to exclude fragment-portion * matching when comparing URIs. + * - 'ignoreQueryString' property to be set to true to exclude query string + * matching when comparing URIs. * - 'replaceQueryString' property to be set to true to exclude query string - * matching when comparing URIs and ovewrite the initial query string with + * matching when comparing URIs and overwrite the initial query string with * the one from the new URI. * @return True if an existing tab was found, false otherwise */ @@ -7505,11 +7507,13 @@ function switchToTabHavingURI(aURI, aOpenNew, aOpenParams={}) { ]); let ignoreFragment = aOpenParams.ignoreFragment; + let ignoreQueryString = aOpenParams.ignoreQueryString; let replaceQueryString = aOpenParams.replaceQueryString; - // This property is only used by switchToTabHavingURI and should + // These properties are only used by switchToTabHavingURI and should // not be used as a parameter for the new load. delete aOpenParams.ignoreFragment; + delete aOpenParams.ignoreQueryString; // This will switch to the tab in aWindow having aURI, if present. function switchIfURIInWindow(aWindow) { @@ -7538,12 +7542,14 @@ function switchToTabHavingURI(aURI, aOpenNew, aOpenParams={}) { } return true; } - if (replaceQueryString) { + if (ignoreQueryString || replaceQueryString) { if (browser.currentURI.spec.split("?")[0] == aURI.spec.split("?")[0]) { // Focus the matching window & tab aWindow.focus(); aWindow.gBrowser.tabContainer.selectedIndex = i; - browser.loadURI(aURI.spec); + if (replaceQueryString) { + browser.loadURI(aURI.spec); + } return true; } } diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index c68a60463052..5f5b5bb9febb 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -482,7 +482,7 @@ skip-if = e10s # Bug 940206 - nsIWebContentHandlerRegistrar::registerProtocolHan skip-if = e10s [browser_bug1024133-switchtab-override-keynav.js] skip-if = e10s -[browser_bug1025195_switchToTabHavingURI_ignoreFragment.js] +[browser_bug1025195_switchToTabHavingURI_aOpenParams.js] [browser_addCertException.js] skip-if = e10s # Bug 1100687 - test directly manipulates content (content.document.getElementById) [browser_bug1045809.js] diff --git a/browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_aOpenParams.js b/browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_aOpenParams.js new file mode 100644 index 000000000000..0ff2e8dc26da --- /dev/null +++ b/browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_aOpenParams.js @@ -0,0 +1,83 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +add_task(function test_ignoreFragment() { + let tabRefAboutHome = gBrowser.addTab("about:home#1"); + yield promiseTabLoaded(tabRefAboutHome); + let tabRefAboutMozilla = gBrowser.addTab("about:mozilla"); + yield promiseTabLoaded(tabRefAboutMozilla); + + gBrowser.selectedTab = tabRefAboutMozilla; + let numTabsAtStart = gBrowser.tabs.length; + + switchTab("about:home#1", true); + switchTab("about:mozilla", true); + switchTab("about:home#2", true, { ignoreFragment: true }); + is(tabRefAboutHome, gBrowser.selectedTab, "The same about:home tab should be switched to"); + is(gBrowser.currentURI.ref, "2", "The ref should be updated to the new ref"); + switchTab("about:mozilla", true); + switchTab("about:home#1", false); + isnot(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should not be initial about:blank tab"); + is(gBrowser.tabs.length, numTabsAtStart + 1, "Should have one new tab opened"); + switchTab("about:about", false, { ignoreFragment: true }); + cleanupTestTabs(); +}); + +add_task(function test_ignoreQueryString() { + let tabRefAboutHome = gBrowser.addTab("about:home?hello=firefox"); + yield promiseTabLoaded(tabRefAboutHome); + let tabRefAboutMozilla = gBrowser.addTab("about:mozilla"); + yield promiseTabLoaded(tabRefAboutMozilla); + gBrowser.selectedTab = tabRefAboutMozilla; + + switchTab("about:home?hello=firefox", true); + switchTab("about:home?hello=firefoxos", false); + // Remove the last opened tab to test ignoreQueryString option. + gBrowser.removeCurrentTab(); + switchTab("about:home?hello=firefoxos", true, { ignoreQueryString: true }); + is(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should be the initial about:home tab"); + is(gBrowser.currentURI.spec, "about:home?hello=firefox", "The spec should NOT be updated to the new query string"); + cleanupTestTabs(); +}); + +add_task(function test_replaceQueryString() { + let tabRefAboutHome = gBrowser.addTab("about:home?hello=firefox"); + yield promiseTabLoaded(tabRefAboutHome); + let tabRefAboutMozilla = gBrowser.addTab("about:mozilla"); + yield promiseTabLoaded(tabRefAboutMozilla); + gBrowser.selectedTab = tabRefAboutMozilla; + + switchTab("about:home", false); + switchTab("about:home?hello=firefox", true); + switchTab("about:home?hello=firefoxos", false); + // Remove the last opened tab to test replaceQueryString option. + gBrowser.removeCurrentTab(); + switchTab("about:home?hello=firefoxos", true, { replaceQueryString: true }); + is(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should be the initial about:home tab"); + // Wait for the tab to load the new URI spec. + yield promiseTabLoaded(tabRefAboutHome); + is(gBrowser.currentURI.spec, "about:home?hello=firefoxos", "The spec should be updated to the new spec"); + cleanupTestTabs(); +}); + +// Begin helpers + +function cleanupTestTabs() { + while (gBrowser.tabs.length > 1) + gBrowser.removeCurrentTab(); +} + +function switchTab(aURI, aShouldFindExistingTab, aOpenParams = {}) { + // Build the description before switchToTabHavingURI deletes the object properties. + let msg = "Should switch to existing " + aURI + " tab if one existed, " + + (aOpenParams.ignoreFragment ? "ignoring" : "including") + " fragment portion, " + + (aOpenParams.ignoreQueryString || aOpenParams.replaceQueryString ? + (aOpenParams.replaceQueryString ? "replacing" : "ignoring") : + "including" + ) + " query string."; + let tabFound = switchToTabHavingURI(aURI, true, aOpenParams); + is(tabFound, aShouldFindExistingTab, msg); +} + +registerCleanupFunction(cleanupTestTabs); diff --git a/browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_ignoreFragment.js b/browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_ignoreFragment.js deleted file mode 100644 index fef091b8b771..000000000000 --- a/browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_ignoreFragment.js +++ /dev/null @@ -1,62 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -add_task(function() { - registerCleanupFunction(function() { - while (gBrowser.tabs.length > 1) - gBrowser.removeCurrentTab(); - }); - let tabRefAboutHome = gBrowser.addTab("about:home#1"); - yield promiseTabLoaded(tabRefAboutHome); - let tabRefAboutMozilla = gBrowser.addTab("about:mozilla"); - yield promiseTabLoaded(tabRefAboutMozilla); - - gBrowser.selectedTab = tabRefAboutMozilla; - let numTabsAtStart = gBrowser.tabs.length; - - switchTab("about:home#1", false, false, true); - switchTab("about:mozilla", false, false, true); - switchTab("about:home#2", true, false, true); - is(tabRefAboutHome, gBrowser.selectedTab, "The same about:home tab should be switched to"); - is(gBrowser.currentURI.ref, "2", "The ref should be updated to the new ref"); - switchTab("about:mozilla", false, false, true); - switchTab("about:home#1", false, false, false); - isnot(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should not be initial about:blank tab"); - is(gBrowser.tabs.length, numTabsAtStart + 1, "Should have one new tab opened"); - switchTab("about:about", true, false, false); -}); - - -// Test for replaceQueryString option. -add_task(function() { - registerCleanupFunction(function() { - while (gBrowser.tabs.length > 1) - gBrowser.removeCurrentTab(); - }); - - let tabRefAboutHome = gBrowser.addTab("about:home?hello=firefox"); - yield promiseTabLoaded(tabRefAboutHome); - - switchTab("about:home", false, false, false); - switchTab("about:home?hello=firefox", false, false, true); - switchTab("about:home?hello=firefoxos", false, false, false); - // Remove the last opened tab to test replaceQueryString option. - gBrowser.removeCurrentTab(); - switchTab("about:home?hello=firefoxos", false, true, true); - is(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should be the initial about:home tab"); - // Wait for the tab to load the new URI spec. - yield promiseTabLoaded(tabRefAboutHome); - is(gBrowser.currentURI.spec, "about:home?hello=firefoxos", "The spec should be updated to the new spec"); -}); - -function switchTab(aURI, aIgnoreFragment, aReplaceQueryString, aShouldFindExistingTab) { - let tabFound = switchToTabHavingURI(aURI, true, { - ignoreFragment: aIgnoreFragment, - replaceQueryString: aReplaceQueryString - }); - is(tabFound, aShouldFindExistingTab, - "Should switch to existing " + aURI + " tab if one existed, " + - (aIgnoreFragment ? "ignoring" : "including") + " fragment portion, " + - (aReplaceQueryString ? "ignoring" : "replacing") + " query string."); -} From 84fd03cdab480aebd06617a7276c0503dc2580d2 Mon Sep 17 00:00:00 2001 From: Tim Nguyen Date: Tue, 16 Dec 2014 01:29:50 -0800 Subject: [PATCH 007/130] Bug 1111332 - In-Content Prefs: Remove border from help button. r=jaws --HG-- extra : rebase_source : a84acadf1c4c0864b31dc61884f0a1373e348c10 --- toolkit/themes/shared/in-content/common.inc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolkit/themes/shared/in-content/common.inc.css b/toolkit/themes/shared/in-content/common.inc.css index 256eccff04f8..d3a7ad44f0fd 100644 --- a/toolkit/themes/shared/in-content/common.inc.css +++ b/toolkit/themes/shared/in-content/common.inc.css @@ -212,7 +212,7 @@ xul|button[type="menu"] > xul|*.button-box > xul|*.button-menu-dropmarker { xul|*.help-button { min-width: 30px; border-radius: 2px; - border: 1px solid #c1c1c1; + border-width: 0; background-color: #ffcb00; background-image: none; box-shadow: none; From 4c223e8cb966a99e6707cf4b3540e52b4b632e36 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Thu, 11 Dec 2014 19:06:14 +0100 Subject: [PATCH 008/130] Bug 1073339 - Enable autocomplete tests for Linux and e10s r=Unfocused --- browser/base/content/test/general/browser.ini | 8 --- .../test/general/browser_action_keyword.js | 5 +- .../general/browser_action_searchengine.js | 28 +++----- .../browser_action_searchengine_alias.js | 14 ++-- .../browser_autocomplete_a11y_label.js | 19 ++---- .../browser_autocomplete_autoselect.js | 12 ++-- .../general/browser_autocomplete_no_title.js | 20 +++--- .../browser_autocomplete_oldschool_wrap.js | 14 ++-- .../test/general/browser_bug1070778.js | 12 ++-- .../test/general/browser_search_favicon.js | 18 ++--- ...wser_tabMatchesInAwesomebar_perwindowpb.js | 65 +++++++------------ browser/base/content/test/general/head.js | 38 +++++------ 12 files changed, 89 insertions(+), 164 deletions(-) diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 5f5b5bb9febb..2e672e45032f 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -111,23 +111,16 @@ skip-if = os == "linux" # Bug 924307 skip-if = e10s # Bug 1093153 - no about:home support yet [browser_aboutSyncProgress.js] [browser_action_keyword.js] -skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s [browser_action_searchengine.js] -skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s [browser_action_searchengine_alias.js] -skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s [browser_addKeywordSearch.js] [browser_search_favicon.js] -skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s [browser_alltabslistener.js] [browser_autocomplete_a11y_label.js] skip-if = e10s # Bug 1101993 - times out for unknown reasons when run in the dir (works on its own) [browser_autocomplete_no_title.js] -skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s [browser_autocomplete_autoselect.js] -skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s [browser_autocomplete_oldschool_wrap.js] -skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s [browser_backButtonFitts.js] skip-if = os != "win" || e10s # The Fitts Law back button is only supported on Windows (bug 571454) / e10s - Bug 1099154: test touches content (attempts to add an event listener directly to the contentWindow) [browser_blob-channelname.js] @@ -293,7 +286,6 @@ skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and skip-if = os == 'win' || e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s [browser_bug1064280_changeUrlInPinnedTab.js] [browser_bug1070778.js] -skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s [browser_canonizeURL.js] skip-if = e10s # Bug 1094510 - test hits the network in e10s mode only [browser_contentAreaClick.js] diff --git a/browser/base/content/test/general/browser_action_keyword.js b/browser/base/content/test/general/browser_action_keyword.js index 6aee5b3c4cfd..9f5c654bf8b3 100644 --- a/browser/base/content/test/general/browser_action_keyword.js +++ b/browser/base/content/test/general/browser_action_keyword.js @@ -4,10 +4,7 @@ let gOnSearchComplete = null; function* promise_first_result(inputText) { - gURLBar.focus(); - gURLBar.value = inputText.slice(0, -1); - EventUtils.synthesizeKey(inputText.slice(-1) , {}); - yield promiseSearchComplete(); + yield promiseAutocompleteResultPopup(inputText); let firstResult = gURLBar.popup.richlistbox.firstChild; return firstResult; diff --git a/browser/base/content/test/general/browser_action_searchengine.js b/browser/base/content/test/general/browser_action_searchengine.js index 3582b500e7b7..8ba9077ebb1d 100644 --- a/browser/base/content/test/general/browser_action_searchengine.js +++ b/browser/base/content/test/general/browser_action_searchengine.js @@ -1,21 +1,6 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -let gOriginalEngine; - -function* promise_first_result(inputText) { - gURLBar.focus(); - gURLBar.value = inputText.slice(0, -1); - EventUtils.synthesizeKey(inputText.slice(-1) , {}); - yield promiseSearchComplete(); - // On Linux, the popup may or may not be open at this stage. So we need - // additional checks to ensure we wait long enough. - yield promisePopupShown(gURLBar.popup); - - let firstResult = gURLBar.popup.richlistbox.firstChild; - return firstResult; -} - add_task(function* () { // This test is only relevant if UnifiedComplete is enabled. if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { @@ -26,13 +11,14 @@ add_task(function* () { Services.search.addEngineWithDetails("MozSearch", "", "", "", "GET", "http://example.com/?q={searchTerms}"); let engine = Services.search.getEngineByName("MozSearch"); - gOriginalEngine = Services.search.currentEngine; + let originalEngine = Services.search.currentEngine; Services.search.currentEngine = engine; - let tab = gBrowser.selectedTab = gBrowser.addTab(); + let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); + yield promiseTabLoaded(gBrowser.selectedTab); registerCleanupFunction(() => { - Services.search.currentEngine = gOriginalEngine; + Services.search.currentEngine = originalEngine; let engine = Services.search.getEngineByName("MozSearch"); Services.search.removeEngine(engine); @@ -43,7 +29,9 @@ add_task(function* () { return promiseClearHistory(); }); - let result = yield promise_first_result("open a search"); + yield promiseAutocompleteResultPopup("open a search"); + let result = gURLBar.popup.richlistbox.firstChild; + isnot(result, null, "Should have a result"); is(result.getAttribute("url"), `moz-action:searchengine,{"engineName":"MozSearch","input":"open a search","searchQuery":"open a search"}`, @@ -51,7 +39,7 @@ add_task(function* () { is(result.hasAttribute("image"), false, "Result shouldn't have an image attribute"); let tabPromise = promiseTabLoaded(gBrowser.selectedTab); - EventUtils.synthesizeMouseAtCenter(result, {}); + result.click(); yield tabPromise; is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search", "Correct URL should be loaded"); diff --git a/browser/base/content/test/general/browser_action_searchengine_alias.js b/browser/base/content/test/general/browser_action_searchengine_alias.js index 9b81476caeef..0dee4590f506 100644 --- a/browser/base/content/test/general/browser_action_searchengine_alias.js +++ b/browser/base/content/test/general/browser_action_searchengine_alias.js @@ -3,8 +3,6 @@ * http://creativecommons.org/publicdomain/zero/1.0/ **/ -let gOriginalEngine; - add_task(function* () { Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true); @@ -12,13 +10,14 @@ add_task(function* () { Services.search.addEngineWithDetails("MozSearch", iconURI, "moz", "", "GET", "http://example.com/?q={searchTerms}"); let engine = Services.search.getEngineByName("MozSearch"); - gOriginalEngine = Services.search.currentEngine; + let originalEngine = Services.search.currentEngine; Services.search.currentEngine = engine; - let tab = gBrowser.selectedTab = gBrowser.addTab(); + let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); + yield promiseTabLoaded(gBrowser.selectedTab); registerCleanupFunction(() => { - Services.search.currentEngine = gOriginalEngine; + Services.search.currentEngine = originalEngine; let engine = Services.search.getEngineByName("MozSearch"); Services.search.removeEngine(engine); Services.prefs.clearUserPref("browser.urlbar.unifiedcomplete"); @@ -30,10 +29,7 @@ add_task(function* () { return promiseClearHistory(); }); - gURLBar.focus(); - gURLBar.value = "moz open a searc"; - EventUtils.synthesizeKey("h" , {}); - yield promiseSearchComplete(); + yield promiseAutocompleteResultPopup("moz open a search"); let result = gURLBar.popup.richlistbox.children[0]; ok(result.hasAttribute("image"), "Result should have an image attribute"); diff --git a/browser/base/content/test/general/browser_autocomplete_a11y_label.js b/browser/base/content/test/general/browser_autocomplete_a11y_label.js index b84500cad135..5d141ef437db 100644 --- a/browser/base/content/test/general/browser_autocomplete_a11y_label.js +++ b/browser/base/content/test/general/browser_autocomplete_a11y_label.js @@ -1,18 +1,6 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -function* check_a11y_label(inputText, expectedLabel) { - gURLBar.focus(); - gURLBar.value = inputText.slice(0, -1); - EventUtils.synthesizeKey(inputText.slice(-1) , {}); - yield promiseSearchComplete(); - - ok(gURLBar.popup.richlistbox.children.length > 1, "Should get at least 2 results"); - let result = gURLBar.popup.richlistbox.children[1]; - is(result.getAttribute("type"), "action switchtab", "Expect right type attribute"); - is(result.label, expectedLabel, "Result a11y label should be as expected"); -} - add_task(function*() { // This test is only relevant if UnifiedComplete is enabled. if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { @@ -24,7 +12,12 @@ add_task(function*() { yield promiseTabLoaded(tab); let actionURL = makeActionURI("switchtab", {url: "about:about"}).spec; - yield check_a11y_label("% about", "about:about " + actionURL + " Tab"); + yield promiseAutocompleteResultPopup("% about"); + + ok(gURLBar.popup.richlistbox.children.length > 1, "Should get at least 2 results"); + let result = gURLBar.popup.richlistbox.children[1]; + is(result.getAttribute("type"), "action switchtab", "Expect right type attribute"); + is(result.label, "about:about " + actionURL + " Tab", "Result a11y label should be as expected"); gURLBar.popup.hidePopup(); yield promisePopupHidden(gURLBar.popup); diff --git a/browser/base/content/test/general/browser_autocomplete_autoselect.js b/browser/base/content/test/general/browser_autocomplete_autoselect.js index 9d767acbd70c..c85f0d96e5ee 100644 --- a/browser/base/content/test/general/browser_autocomplete_autoselect.js +++ b/browser/base/content/test/general/browser_autocomplete_autoselect.js @@ -4,13 +4,6 @@ function repeat(limit, func) { } } -function* promiseAutoComplete(inputText) { - gURLBar.focus(); - gURLBar.value = inputText.slice(0, -1); - EventUtils.synthesizeKey(inputText.slice(-1), {}); - yield promiseSearchComplete(); -} - function is_selected(index) { is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`); } @@ -32,7 +25,9 @@ add_task(function*() { }); yield PlacesTestUtils.addVisits(visits); - yield promiseAutoComplete("example.com/autocomplete"); + let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); + yield promiseTabLoaded(tab); + yield promiseAutocompleteResultPopup("example.com/autocomplete"); let popup = gURLBar.popup; let results = popup.richlistbox.children; @@ -62,4 +57,5 @@ add_task(function*() { EventUtils.synthesizeKey("VK_ESCAPE", {}); yield promisePopupHidden(gURLBar.popup); + gBrowser.removeTab(tab); }); diff --git a/browser/base/content/test/general/browser_autocomplete_no_title.js b/browser/base/content/test/general/browser_autocomplete_no_title.js index 3af3f6623cca..9b4a688694d2 100644 --- a/browser/base/content/test/general/browser_autocomplete_no_title.js +++ b/browser/base/content/test/general/browser_autocomplete_no_title.js @@ -1,17 +1,6 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -function* check_title(inputText, expectedTitle) { - gURLBar.focus(); - gURLBar.value = inputText.slice(0, -1); - EventUtils.synthesizeKey(inputText.slice(-1) , {}); - yield promiseSearchComplete(); - - ok(gURLBar.popup.richlistbox.children.length > 1, "Should get at least 2 results"); - let result = gURLBar.popup.richlistbox.children[1]; - is(result._title.textContent, expectedTitle, "Result title should be as expected"); -} - add_task(function*() { // This test is only relevant if UnifiedComplete is enabled. if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { @@ -19,11 +8,18 @@ add_task(function*() { return; } + let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); + yield promiseTabLoaded(tab); + let uri = NetUtil.newURI("http://bug1060642.example.com/beards/are/pretty/great"); yield PlacesTestUtils.addVisits([{uri: uri, title: ""}]); - yield check_title("bug1060642", "bug1060642.example.com"); + yield promiseAutocompleteResultPopup("bug1060642"); + ok(gURLBar.popup.richlistbox.children.length > 1, "Should get at least 2 results"); + let result = gURLBar.popup.richlistbox.children[1]; + is(result._title.textContent, "bug1060642.example.com", "Result title should be as expected"); gURLBar.popup.hidePopup(); yield promisePopupHidden(gURLBar.popup); + gBrowser.removeTab(tab); }); diff --git a/browser/base/content/test/general/browser_autocomplete_oldschool_wrap.js b/browser/base/content/test/general/browser_autocomplete_oldschool_wrap.js index 819c4920e08b..b60012e3a492 100644 --- a/browser/base/content/test/general/browser_autocomplete_oldschool_wrap.js +++ b/browser/base/content/test/general/browser_autocomplete_oldschool_wrap.js @@ -4,13 +4,6 @@ function repeat(limit, func) { } } -function* promiseAutoComplete(inputText) { - gURLBar.focus(); - gURLBar.value = inputText.slice(0, -1); - EventUtils.synthesizeKey(inputText.slice(-1), {}); - yield promiseSearchComplete(); -} - function is_selected(index) { is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`); } @@ -18,7 +11,7 @@ function is_selected(index) { add_task(function*() { // This test is only relevant if UnifiedComplete is *disabled*. if (Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { - todo(false, "Stop supporting old autocomplete components."); + ok(true, "Don't run this test with UnifiedComplete enabled.") return; } @@ -32,7 +25,9 @@ add_task(function*() { }); yield PlacesTestUtils.addVisits(visits); - yield promiseAutoComplete("example.com/autocomplete"); + let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); + yield promiseTabLoaded(tab); + yield promiseAutocompleteResultPopup("example.com/autocomplete"); let popup = gURLBar.popup; let results = popup.richlistbox.children; @@ -71,4 +66,5 @@ add_task(function*() { EventUtils.synthesizeKey("VK_ESCAPE", {}); yield promisePopupHidden(gURLBar.popup); + gBrowser.removeTab(tab); }); diff --git a/browser/base/content/test/general/browser_bug1070778.js b/browser/base/content/test/general/browser_bug1070778.js index a0ec32f20bd6..9ec43f04764d 100644 --- a/browser/base/content/test/general/browser_bug1070778.js +++ b/browser/base/content/test/general/browser_bug1070778.js @@ -1,13 +1,6 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -function* promiseAutoComplete(inputText) { - gURLBar.focus(); - gURLBar.value = inputText.slice(0, -1); - EventUtils.synthesizeKey(inputText.slice(-1) , {}); - yield promiseSearchComplete(); -} - function is_selected(index) { is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`); } @@ -38,7 +31,9 @@ add_task(function*() { PlacesUtils.bookmarks.DEFAULT_INDEX, "keyword abc"); - yield promiseAutoComplete("keyword a"); + let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); + yield promiseTabLoaded(tab); + yield promiseAutocompleteResultPopup("keyword a"); // First item should already be selected is_selected(0); @@ -61,4 +56,5 @@ add_task(function*() { EventUtils.synthesizeKey("VK_ESCAPE", {}); yield promisePopupHidden(gURLBar.popup); + gBrowser.removeTab(tab); }); diff --git a/browser/base/content/test/general/browser_search_favicon.js b/browser/base/content/test/general/browser_search_favicon.js index d4236d468e6d..81b329cc4be1 100644 --- a/browser/base/content/test/general/browser_search_favicon.js +++ b/browser/base/content/test/general/browser_search_favicon.js @@ -67,15 +67,6 @@ function promiseAddVisits(aPlaceInfo) { }); } -function* promiseAutocompleteResultPopup(inputText) { - gURLBar.focus(); - gURLBar.value = inputText.slice(0, -1); - EventUtils.synthesizeKey(inputText.slice(-1) , {}); - yield promiseSearchComplete(); - - return gURLBar.popup.richlistbox.children; -} - registerCleanupFunction(() => { Services.prefs.clearUserPref(gUnifiedCompletePref); Services.prefs.clearUserPref(gRestyleSearchesPref); @@ -101,10 +92,13 @@ add_task(function*() { let uri = NetUtil.newURI("http://s.example.com/search?q=foo&client=1"); yield promiseAddVisits({ uri: uri, title: "Foo - SearchEngine Search" }); + let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); + yield promiseTabLoaded(gBrowser.selectedTab); + // The first autocomplete result has the action searchengine, while // the second result is the "search favicon" element. - let result = yield promiseAutocompleteResultPopup("foo"); - result = result[1]; + yield promiseAutocompleteResultPopup("foo"); + let result = gURLBar.popup.richlistbox.children[1]; isnot(result, null, "Expect a search result"); is(result.getAttribute("type"), "search favicon", "Expect correct `type` attribute"); @@ -121,4 +115,6 @@ add_task(function*() { is_element_visible(result._url, "URL element should be visible"); is(result._url.textContent, "Search with SearchEngine"); + + gBrowser.removeCurrentTab(); }); diff --git a/browser/base/content/test/general/browser_tabMatchesInAwesomebar_perwindowpb.js b/browser/base/content/test/general/browser_tabMatchesInAwesomebar_perwindowpb.js index e63bfbe37ed9..27073c18192b 100644 --- a/browser/base/content/test/general/browser_tabMatchesInAwesomebar_perwindowpb.js +++ b/browser/base/content/test/general/browser_tabMatchesInAwesomebar_perwindowpb.js @@ -71,52 +71,35 @@ function test() { ok(!testTab.hasAttribute("busy"), "The test tab doesn't have the busy attribute"); - let urlbar = aDestWindow.gURLBar; - let controller = urlbar.controller; - - // Focus URL bar, enter value, and start searching. - urlbar.focus(); - urlbar.value = testURL; - controller.startSearch(testURL); - // Wait for the Awesomebar popup to appear. - let popup = aDestWindow.gURLBar.popup; - promisePopupShown(popup).then(() => { - function searchIsComplete() { - return controller.searchStatus == - Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH; + promiseAutocompleteResultPopup(testURL, aDestWindow).then(() => { + if (aExpectSwitch) { + // If we expect a tab switch then the current tab + // will be closed and we switch to the other tab. + let tabContainer = aDestWindow.gBrowser.tabContainer; + tabContainer.addEventListener("TabClose", function onClose(event) { + if (event.target == testTab) { + tabContainer.removeEventListener("TabClose", onClose); + executeSoon(aCallback); + } + }); + } else { + // If we don't expect a tab switch then wait for the tab to load. + testTab.addEventListener("load", function onLoad() { + testTab.removeEventListener("load", onLoad, true); + executeSoon(aCallback); + }, true); } - // Wait until the search is complete. - waitForCondition(searchIsComplete, function () { - if (aExpectSwitch) { - // If we expect a tab switch then the current tab - // will be closed and we switch to the other tab. - let tabContainer = aDestWindow.gBrowser.tabContainer; - tabContainer.addEventListener("TabClose", function onClose(event) { - if (event.target == testTab) { - tabContainer.removeEventListener("TabClose", onClose); - executeSoon(aCallback); - } - }); - } else { - // If we don't expect a tab switch then wait for the tab to load. - testTab.addEventListener("load", function onLoad() { - testTab.removeEventListener("load", onLoad, true); - executeSoon(aCallback); - }, true); - } + // Make sure the last match is selected. + let {controller, popup} = aDestWindow.gURLBar; + while (popup.selectedIndex < controller.matchCount - 1) { + controller.handleKeyNavigation(KeyEvent.DOM_VK_DOWN); + } - // Make sure the last match is selected. - while (popup.selectedIndex < controller.matchCount - 1) { - controller.handleKeyNavigation(KeyEvent.DOM_VK_DOWN); - } - - // Execute the selected action. - controller.handleEnter(true); - }); + // Execute the selected action. + controller.handleEnter(true); }); - }, aDestWindow); }, true); } diff --git a/browser/base/content/test/general/head.js b/browser/base/content/test/general/head.js index e23919b64d43..5c667ec51ccc 100644 --- a/browser/base/content/test/general/head.js +++ b/browser/base/content/test/general/head.js @@ -780,28 +780,24 @@ function promisePopupHidden(popup) { return promisePopupEvent(popup, "hidden"); } -// NOTE: If you're using this, and attempting to interact with one of the -// autocomplete results, your test is likely to be unreliable on Linux. -// See bug 1073339. -let gURLBarOnSearchComplete = null; -function promiseSearchComplete() { - info("Waiting for onSearchComplete"); - return new Promise(resolve => { - if (!gURLBarOnSearchComplete) { - gURLBarOnSearchComplete = gURLBar.onSearchComplete; - registerCleanupFunction(() => { - gURLBar.onSearchComplete = gURLBarOnSearchComplete; - }); +function promiseSearchComplete(win = window) { + return promisePopupShown(win.gURLBar.popup).then(() => { + function searchIsComplete() { + return win.gURLBar.controller.searchStatus >= + Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH; } - gURLBar.onSearchComplete = function () { - ok(gURLBar.popupOpen, "The autocomplete popup is correctly open"); - gURLBarOnSearchComplete.apply(gURLBar); - resolve(); - } - }).then(() => { - // On Linux, the popup may or may not be open at this stage. So we need - // additional checks to ensure we wait long enough. - return promisePopupShown(gURLBar.popup); + // Wait until there are at least two matches. + return new Promise(resolve => waitForCondition(searchIsComplete, resolve)); }); } + +function promiseAutocompleteResultPopup(inputText, win = window) { + waitForFocus(() => { + win.gURLBar.focus(); + win.gURLBar.value = inputText; + win.gURLBar.controller.startSearch(inputText); + }, win); + + return promiseSearchComplete(win); +} From dda74f46e495b2122d620cd95f900cf34005f3bc Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Fri, 28 Nov 2014 12:03:34 +0100 Subject: [PATCH 009/130] Bug 1073339 - Convert from CRLF to LF for autocomplete tests r=Unfocused --- .../test/general/browser_action_keyword.js | 176 +++++++++--------- .../general/browser_action_searchengine.js | 92 ++++----- .../browser_action_searchengine_alias.js | 88 ++++----- .../browser_autocomplete_a11y_label.js | 50 ++--- .../browser_autocomplete_autoselect.js | 122 ++++++------ .../test/general/browser_bug1070778.js | 120 ++++++------ 6 files changed, 324 insertions(+), 324 deletions(-) diff --git a/browser/base/content/test/general/browser_action_keyword.js b/browser/base/content/test/general/browser_action_keyword.js index 9f5c654bf8b3..7e3ef9555c2a 100644 --- a/browser/base/content/test/general/browser_action_keyword.js +++ b/browser/base/content/test/general/browser_action_keyword.js @@ -1,88 +1,88 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -let gOnSearchComplete = null; - -function* promise_first_result(inputText) { - yield promiseAutocompleteResultPopup(inputText); - - let firstResult = gURLBar.popup.richlistbox.firstChild; - return firstResult; -} - - -add_task(function*() { - // This test is only relevant if UnifiedComplete is enabled. - if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { - todo(false, "Stop supporting old autocomplete components."); - return; - } - - let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla"); - let tabs = [tab]; - registerCleanupFunction(() => { - for (let tab of tabs) - gBrowser.removeTab(tab); - PlacesUtils.bookmarks.removeItem(itemId); - }); - - yield promiseTabLoadEvent(tab); - - let itemId = - PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - NetUtil.newURI("http://example.com/?q=%s"), - PlacesUtils.bookmarks.DEFAULT_INDEX, - "test"); - PlacesUtils.bookmarks.setKeywordForBookmark(itemId, "keyword"); - - let result = yield promise_first_result("keyword something"); - isnot(result, null, "Expect a keyword result"); - - is(result.getAttribute("type"), "action keyword", "Expect correct `type` attribute"); - is(result.getAttribute("actiontype"), "keyword", "Expect correct `actiontype` attribute"); - is(result.getAttribute("title"), "test", "Expect correct title"); - - // We need to make a real URI out of this to ensure it's normalised for - // comparison. - let uri = NetUtil.newURI(result.getAttribute("url")); - is(uri.spec, makeActionURI("keyword", {url: "http://example.com/?q=something", input: "keyword something"}).spec, "Expect correct url"); - - is_element_visible(result._title, "Title element should be visible"); - is(result._title.childNodes.length, 1, "Title element should have 1 child"); - is(result._title.childNodes[0].nodeName, "#text", "That child should be a text node"); - is(result._title.childNodes[0].data, "test", "Node should contain the name of the bookmark"); - - is_element_visible(result._extra, "Extra element should be visible"); - is(result._extra.childNodes.length, 1, "Title element should have 1 child"); - is(result._extra.childNodes[0].nodeName, "span", "That child should be a span node"); - let span = result._extra.childNodes[0]; - is(span.childNodes.length, 1, "span element should have 1 child"); - is(span.childNodes[0].nodeName, "#text", "That child should be a text node"); - is(span.childNodes[0].data, "something", "Node should contain the query for the keyword"); - - is_element_hidden(result._url, "URL element should be hidden"); - - // Click on the result - info("Normal click on result"); - let tabPromise = promiseTabLoadEvent(tab); - EventUtils.synthesizeMouseAtCenter(result, {}); - let loadEvent = yield tabPromise; - is(loadEvent.target.location.href, "http://example.com/?q=something", "Tab should have loaded from clicking on result"); - - // Middle-click on the result - info("Middle-click on result"); - result = yield promise_first_result("keyword somethingmore"); - isnot(result, null, "Expect a keyword result"); - // We need to make a real URI out of this to ensure it's normalised for - // comparison. - uri = NetUtil.newURI(result.getAttribute("url")); - is(uri.spec, makeActionURI("keyword", {url: "http://example.com/?q=somethingmore", input: "keyword somethingmore"}).spec, "Expect correct url"); - - tabPromise = promiseWaitForEvent(gBrowser.tabContainer, "TabOpen"); - EventUtils.synthesizeMouseAtCenter(result, {button: 1}); - let tabOpenEvent = yield tabPromise; - let newTab = tabOpenEvent.target; - tabs.push(newTab); - loadEvent = yield promiseTabLoadEvent(newTab); - is(loadEvent.target.location.href, "http://example.com/?q=somethingmore", "Tab should have loaded from middle-clicking on result"); -}); +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +let gOnSearchComplete = null; + +function* promise_first_result(inputText) { + yield promiseAutocompleteResultPopup(inputText); + + let firstResult = gURLBar.popup.richlistbox.firstChild; + return firstResult; +} + + +add_task(function*() { + // This test is only relevant if UnifiedComplete is enabled. + if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { + todo(false, "Stop supporting old autocomplete components."); + return; + } + + let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla"); + let tabs = [tab]; + registerCleanupFunction(() => { + for (let tab of tabs) + gBrowser.removeTab(tab); + PlacesUtils.bookmarks.removeItem(itemId); + }); + + yield promiseTabLoadEvent(tab); + + let itemId = + PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, + NetUtil.newURI("http://example.com/?q=%s"), + PlacesUtils.bookmarks.DEFAULT_INDEX, + "test"); + PlacesUtils.bookmarks.setKeywordForBookmark(itemId, "keyword"); + + let result = yield promise_first_result("keyword something"); + isnot(result, null, "Expect a keyword result"); + + is(result.getAttribute("type"), "action keyword", "Expect correct `type` attribute"); + is(result.getAttribute("actiontype"), "keyword", "Expect correct `actiontype` attribute"); + is(result.getAttribute("title"), "test", "Expect correct title"); + + // We need to make a real URI out of this to ensure it's normalised for + // comparison. + let uri = NetUtil.newURI(result.getAttribute("url")); + is(uri.spec, makeActionURI("keyword", {url: "http://example.com/?q=something", input: "keyword something"}).spec, "Expect correct url"); + + is_element_visible(result._title, "Title element should be visible"); + is(result._title.childNodes.length, 1, "Title element should have 1 child"); + is(result._title.childNodes[0].nodeName, "#text", "That child should be a text node"); + is(result._title.childNodes[0].data, "test", "Node should contain the name of the bookmark"); + + is_element_visible(result._extra, "Extra element should be visible"); + is(result._extra.childNodes.length, 1, "Title element should have 1 child"); + is(result._extra.childNodes[0].nodeName, "span", "That child should be a span node"); + let span = result._extra.childNodes[0]; + is(span.childNodes.length, 1, "span element should have 1 child"); + is(span.childNodes[0].nodeName, "#text", "That child should be a text node"); + is(span.childNodes[0].data, "something", "Node should contain the query for the keyword"); + + is_element_hidden(result._url, "URL element should be hidden"); + + // Click on the result + info("Normal click on result"); + let tabPromise = promiseTabLoadEvent(tab); + EventUtils.synthesizeMouseAtCenter(result, {}); + let loadEvent = yield tabPromise; + is(loadEvent.target.location.href, "http://example.com/?q=something", "Tab should have loaded from clicking on result"); + + // Middle-click on the result + info("Middle-click on result"); + result = yield promise_first_result("keyword somethingmore"); + isnot(result, null, "Expect a keyword result"); + // We need to make a real URI out of this to ensure it's normalised for + // comparison. + uri = NetUtil.newURI(result.getAttribute("url")); + is(uri.spec, makeActionURI("keyword", {url: "http://example.com/?q=somethingmore", input: "keyword somethingmore"}).spec, "Expect correct url"); + + tabPromise = promiseWaitForEvent(gBrowser.tabContainer, "TabOpen"); + EventUtils.synthesizeMouseAtCenter(result, {button: 1}); + let tabOpenEvent = yield tabPromise; + let newTab = tabOpenEvent.target; + tabs.push(newTab); + loadEvent = yield promiseTabLoadEvent(newTab); + is(loadEvent.target.location.href, "http://example.com/?q=somethingmore", "Tab should have loaded from middle-clicking on result"); +}); diff --git a/browser/base/content/test/general/browser_action_searchengine.js b/browser/base/content/test/general/browser_action_searchengine.js index 8ba9077ebb1d..96130a3d54b5 100644 --- a/browser/base/content/test/general/browser_action_searchengine.js +++ b/browser/base/content/test/general/browser_action_searchengine.js @@ -1,46 +1,46 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -add_task(function* () { - // This test is only relevant if UnifiedComplete is enabled. - if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { - todo(false, "Stop supporting old autocomplete components."); - return; - } - - Services.search.addEngineWithDetails("MozSearch", "", "", "", "GET", - "http://example.com/?q={searchTerms}"); - let engine = Services.search.getEngineByName("MozSearch"); - let originalEngine = Services.search.currentEngine; - Services.search.currentEngine = engine; - - let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); - yield promiseTabLoaded(gBrowser.selectedTab); - - registerCleanupFunction(() => { - Services.search.currentEngine = originalEngine; - let engine = Services.search.getEngineByName("MozSearch"); - Services.search.removeEngine(engine); - - try { - gBrowser.removeTab(tab); - } catch(ex) { /* tab may have already been closed in case of failure */ } - - return promiseClearHistory(); - }); - - yield promiseAutocompleteResultPopup("open a search"); - let result = gURLBar.popup.richlistbox.firstChild; - - isnot(result, null, "Should have a result"); - is(result.getAttribute("url"), - `moz-action:searchengine,{"engineName":"MozSearch","input":"open a search","searchQuery":"open a search"}`, - "Result should be a moz-action: for the correct search engine"); - is(result.hasAttribute("image"), false, "Result shouldn't have an image attribute"); - - let tabPromise = promiseTabLoaded(gBrowser.selectedTab); - result.click(); - yield tabPromise; - - is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search", "Correct URL should be loaded"); -}); +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function* () { + // This test is only relevant if UnifiedComplete is enabled. + if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { + todo(false, "Stop supporting old autocomplete components."); + return; + } + + Services.search.addEngineWithDetails("MozSearch", "", "", "", "GET", + "http://example.com/?q={searchTerms}"); + let engine = Services.search.getEngineByName("MozSearch"); + let originalEngine = Services.search.currentEngine; + Services.search.currentEngine = engine; + + let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); + yield promiseTabLoaded(gBrowser.selectedTab); + + registerCleanupFunction(() => { + Services.search.currentEngine = originalEngine; + let engine = Services.search.getEngineByName("MozSearch"); + Services.search.removeEngine(engine); + + try { + gBrowser.removeTab(tab); + } catch(ex) { /* tab may have already been closed in case of failure */ } + + return promiseClearHistory(); + }); + + yield promiseAutocompleteResultPopup("open a search"); + let result = gURLBar.popup.richlistbox.firstChild; + + isnot(result, null, "Should have a result"); + is(result.getAttribute("url"), + `moz-action:searchengine,{"engineName":"MozSearch","input":"open a search","searchQuery":"open a search"}`, + "Result should be a moz-action: for the correct search engine"); + is(result.hasAttribute("image"), false, "Result shouldn't have an image attribute"); + + let tabPromise = promiseTabLoaded(gBrowser.selectedTab); + result.click(); + yield tabPromise; + + is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search", "Correct URL should be loaded"); +}); diff --git a/browser/base/content/test/general/browser_action_searchengine_alias.js b/browser/base/content/test/general/browser_action_searchengine_alias.js index 0dee4590f506..9a252204b369 100644 --- a/browser/base/content/test/general/browser_action_searchengine_alias.js +++ b/browser/base/content/test/general/browser_action_searchengine_alias.js @@ -1,44 +1,44 @@ -/** - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - **/ - -add_task(function* () { - Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true); - - let iconURI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC"; - Services.search.addEngineWithDetails("MozSearch", iconURI, "moz", "", "GET", - "http://example.com/?q={searchTerms}"); - let engine = Services.search.getEngineByName("MozSearch"); - let originalEngine = Services.search.currentEngine; - Services.search.currentEngine = engine; - - let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); - yield promiseTabLoaded(gBrowser.selectedTab); - - registerCleanupFunction(() => { - Services.search.currentEngine = originalEngine; - let engine = Services.search.getEngineByName("MozSearch"); - Services.search.removeEngine(engine); - Services.prefs.clearUserPref("browser.urlbar.unifiedcomplete"); - - try { - gBrowser.removeTab(tab); - } catch(ex) { /* tab may have already been closed in case of failure */ } - - return promiseClearHistory(); - }); - - yield promiseAutocompleteResultPopup("moz open a search"); - - let result = gURLBar.popup.richlistbox.children[0]; - ok(result.hasAttribute("image"), "Result should have an image attribute"); - // Image attribute gets a suffix (-moz-resolution) added in the value. - ok(result.getAttribute("image").startsWith(engine.iconURI.spec), - "Image attribute should have the search engine's icon"); - - EventUtils.synthesizeKey("VK_RETURN" , { }); - yield promiseTabLoaded(gBrowser.selectedTab); - - is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search"); -}); +/** + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + **/ + +add_task(function* () { + Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true); + + let iconURI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC"; + Services.search.addEngineWithDetails("MozSearch", iconURI, "moz", "", "GET", + "http://example.com/?q={searchTerms}"); + let engine = Services.search.getEngineByName("MozSearch"); + let originalEngine = Services.search.currentEngine; + Services.search.currentEngine = engine; + + let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); + yield promiseTabLoaded(gBrowser.selectedTab); + + registerCleanupFunction(() => { + Services.search.currentEngine = originalEngine; + let engine = Services.search.getEngineByName("MozSearch"); + Services.search.removeEngine(engine); + Services.prefs.clearUserPref("browser.urlbar.unifiedcomplete"); + + try { + gBrowser.removeTab(tab); + } catch(ex) { /* tab may have already been closed in case of failure */ } + + return promiseClearHistory(); + }); + + yield promiseAutocompleteResultPopup("moz open a search"); + + let result = gURLBar.popup.richlistbox.children[0]; + ok(result.hasAttribute("image"), "Result should have an image attribute"); + // Image attribute gets a suffix (-moz-resolution) added in the value. + ok(result.getAttribute("image").startsWith(engine.iconURI.spec), + "Image attribute should have the search engine's icon"); + + EventUtils.synthesizeKey("VK_RETURN" , { }); + yield promiseTabLoaded(gBrowser.selectedTab); + + is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search"); +}); diff --git a/browser/base/content/test/general/browser_autocomplete_a11y_label.js b/browser/base/content/test/general/browser_autocomplete_a11y_label.js index 5d141ef437db..1ecd66c6b103 100644 --- a/browser/base/content/test/general/browser_autocomplete_a11y_label.js +++ b/browser/base/content/test/general/browser_autocomplete_a11y_label.js @@ -1,25 +1,25 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -add_task(function*() { - // This test is only relevant if UnifiedComplete is enabled. - if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { - todo(false, "Stop supporting old autocomplete components."); - return; - } - - let tab = gBrowser.addTab("about:about"); - yield promiseTabLoaded(tab); - - let actionURL = makeActionURI("switchtab", {url: "about:about"}).spec; - yield promiseAutocompleteResultPopup("% about"); - - ok(gURLBar.popup.richlistbox.children.length > 1, "Should get at least 2 results"); - let result = gURLBar.popup.richlistbox.children[1]; - is(result.getAttribute("type"), "action switchtab", "Expect right type attribute"); - is(result.label, "about:about " + actionURL + " Tab", "Result a11y label should be as expected"); - - gURLBar.popup.hidePopup(); - yield promisePopupHidden(gURLBar.popup); - gBrowser.removeTab(tab); -}); +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(function*() { + // This test is only relevant if UnifiedComplete is enabled. + if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { + todo(false, "Stop supporting old autocomplete components."); + return; + } + + let tab = gBrowser.addTab("about:about"); + yield promiseTabLoaded(tab); + + let actionURL = makeActionURI("switchtab", {url: "about:about"}).spec; + yield promiseAutocompleteResultPopup("% about"); + + ok(gURLBar.popup.richlistbox.children.length > 1, "Should get at least 2 results"); + let result = gURLBar.popup.richlistbox.children[1]; + is(result.getAttribute("type"), "action switchtab", "Expect right type attribute"); + is(result.label, "about:about " + actionURL + " Tab", "Result a11y label should be as expected"); + + gURLBar.popup.hidePopup(); + yield promisePopupHidden(gURLBar.popup); + gBrowser.removeTab(tab); +}); diff --git a/browser/base/content/test/general/browser_autocomplete_autoselect.js b/browser/base/content/test/general/browser_autocomplete_autoselect.js index c85f0d96e5ee..123e97693ba9 100644 --- a/browser/base/content/test/general/browser_autocomplete_autoselect.js +++ b/browser/base/content/test/general/browser_autocomplete_autoselect.js @@ -1,61 +1,61 @@ -function repeat(limit, func) { - for (let i = 0; i < limit; i++) { - func(i); - } -} - -function is_selected(index) { - is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`); -} - -add_task(function*() { - // This test is only relevant if UnifiedComplete is enabled. - if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { - todo(false, "Stop supporting old autocomplete components."); - return; - } - - registerCleanupFunction(promiseClearHistory); - - let visits = []; - repeat(10, i => { - visits.push({ - uri: makeURI("http://example.com/autocomplete/?" + i), - }); - }); - yield PlacesTestUtils.addVisits(visits); - - let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); - yield promiseTabLoaded(tab); - yield promiseAutocompleteResultPopup("example.com/autocomplete"); - - let popup = gURLBar.popup; - let results = popup.richlistbox.children; - // 1 extra for the current search engine match - is(results.length, 11, "Should get 11 results"); - is_selected(0); - - info("Key Down to select the next item"); - EventUtils.synthesizeKey("VK_DOWN", {}); - is_selected(1); - - info("Key Down 11 times should wrap around all the way around"); - repeat(11, () => EventUtils.synthesizeKey("VK_DOWN", {})); - is_selected(1); - - info("Key Up 11 times should wrap around the other way"); - repeat(11, () => EventUtils.synthesizeKey("VK_UP", {})); - is_selected(1); - - info("Page Up will go up the list, but not wrap"); - EventUtils.synthesizeKey("VK_PAGE_UP", {}) - is_selected(0); - - info("Page Up again will wrap around to the end of the list"); - EventUtils.synthesizeKey("VK_PAGE_UP", {}) - is_selected(10); - - EventUtils.synthesizeKey("VK_ESCAPE", {}); - yield promisePopupHidden(gURLBar.popup); - gBrowser.removeTab(tab); -}); +function repeat(limit, func) { + for (let i = 0; i < limit; i++) { + func(i); + } +} + +function is_selected(index) { + is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`); +} + +add_task(function*() { + // This test is only relevant if UnifiedComplete is enabled. + if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { + todo(false, "Stop supporting old autocomplete components."); + return; + } + + registerCleanupFunction(promiseClearHistory); + + let visits = []; + repeat(10, i => { + visits.push({ + uri: makeURI("http://example.com/autocomplete/?" + i), + }); + }); + yield PlacesTestUtils.addVisits(visits); + + let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); + yield promiseTabLoaded(tab); + yield promiseAutocompleteResultPopup("example.com/autocomplete"); + + let popup = gURLBar.popup; + let results = popup.richlistbox.children; + // 1 extra for the current search engine match + is(results.length, 11, "Should get 11 results"); + is_selected(0); + + info("Key Down to select the next item"); + EventUtils.synthesizeKey("VK_DOWN", {}); + is_selected(1); + + info("Key Down 11 times should wrap around all the way around"); + repeat(11, () => EventUtils.synthesizeKey("VK_DOWN", {})); + is_selected(1); + + info("Key Up 11 times should wrap around the other way"); + repeat(11, () => EventUtils.synthesizeKey("VK_UP", {})); + is_selected(1); + + info("Page Up will go up the list, but not wrap"); + EventUtils.synthesizeKey("VK_PAGE_UP", {}) + is_selected(0); + + info("Page Up again will wrap around to the end of the list"); + EventUtils.synthesizeKey("VK_PAGE_UP", {}) + is_selected(10); + + EventUtils.synthesizeKey("VK_ESCAPE", {}); + yield promisePopupHidden(gURLBar.popup); + gBrowser.removeTab(tab); +}); diff --git a/browser/base/content/test/general/browser_bug1070778.js b/browser/base/content/test/general/browser_bug1070778.js index 9ec43f04764d..c52854763d40 100644 --- a/browser/base/content/test/general/browser_bug1070778.js +++ b/browser/base/content/test/general/browser_bug1070778.js @@ -1,60 +1,60 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -function is_selected(index) { - is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`); -} - -add_task(function*() { - // This test is only relevant if UnifiedComplete is enabled. - if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { - todo(false, "Stop supporting old autocomplete components."); - return; - } - - registerCleanupFunction(() => { - PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId); - }); - - let itemId = - PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - NetUtil.newURI("http://example.com/?q=%s"), - PlacesUtils.bookmarks.DEFAULT_INDEX, - "test"); - PlacesUtils.bookmarks.setKeywordForBookmark(itemId, "keyword"); - - // This item only needed so we can select the keyword item, select something - // else, then select the keyword item again. - itemId = - PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - NetUtil.newURI("http://example.com/keyword"), - PlacesUtils.bookmarks.DEFAULT_INDEX, - "keyword abc"); - - let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); - yield promiseTabLoaded(tab); - yield promiseAutocompleteResultPopup("keyword a"); - - // First item should already be selected - is_selected(0); - // Select next one (important!) - EventUtils.synthesizeKey("VK_DOWN", {}); - is_selected(1); - // Re-select keyword item - EventUtils.synthesizeKey("VK_UP", {}); - is_selected(0); - - EventUtils.synthesizeKey("b", {}); - yield promiseSearchComplete(); - - is(gURLBar.value, "keyword ab", "urlbar should have expected input"); - - let result = gURLBar.popup.richlistbox.firstChild; - isnot(result, null, "Should have first item"); - let uri = NetUtil.newURI(result.getAttribute("url")); - is(uri.spec, makeActionURI("keyword", {url: "http://example.com/?q=ab", input: "keyword ab"}).spec, "Expect correct url"); - - EventUtils.synthesizeKey("VK_ESCAPE", {}); - yield promisePopupHidden(gURLBar.popup); - gBrowser.removeTab(tab); -}); +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function is_selected(index) { + is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`); +} + +add_task(function*() { + // This test is only relevant if UnifiedComplete is enabled. + if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) { + todo(false, "Stop supporting old autocomplete components."); + return; + } + + registerCleanupFunction(() => { + PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId); + }); + + let itemId = + PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, + NetUtil.newURI("http://example.com/?q=%s"), + PlacesUtils.bookmarks.DEFAULT_INDEX, + "test"); + PlacesUtils.bookmarks.setKeywordForBookmark(itemId, "keyword"); + + // This item only needed so we can select the keyword item, select something + // else, then select the keyword item again. + itemId = + PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, + NetUtil.newURI("http://example.com/keyword"), + PlacesUtils.bookmarks.DEFAULT_INDEX, + "keyword abc"); + + let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); + yield promiseTabLoaded(tab); + yield promiseAutocompleteResultPopup("keyword a"); + + // First item should already be selected + is_selected(0); + // Select next one (important!) + EventUtils.synthesizeKey("VK_DOWN", {}); + is_selected(1); + // Re-select keyword item + EventUtils.synthesizeKey("VK_UP", {}); + is_selected(0); + + EventUtils.synthesizeKey("b", {}); + yield promiseSearchComplete(); + + is(gURLBar.value, "keyword ab", "urlbar should have expected input"); + + let result = gURLBar.popup.richlistbox.firstChild; + isnot(result, null, "Should have first item"); + let uri = NetUtil.newURI(result.getAttribute("url")); + is(uri.spec, makeActionURI("keyword", {url: "http://example.com/?q=ab", input: "keyword ab"}).spec, "Expect correct url"); + + EventUtils.synthesizeKey("VK_ESCAPE", {}); + yield promisePopupHidden(gURLBar.popup); + gBrowser.removeTab(tab); +}); From 8615fcb4f869b938b08cb21f99b45bed06dc8cd6 Mon Sep 17 00:00:00 2001 From: Eugen Sawin Date: Tue, 16 Dec 2014 14:06:56 +0100 Subject: [PATCH 010/130] Bug 1109940 - Fix unwrapped function call. r=glandium --- other-licenses/android/getaddrinfo.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/other-licenses/android/getaddrinfo.c b/other-licenses/android/getaddrinfo.c index 7edabbc2d057..c2267b6c0958 100644 --- a/other-licenses/android/getaddrinfo.c +++ b/other-licenses/android/getaddrinfo.c @@ -414,6 +414,14 @@ extern int __wrap_getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res); +extern const char * +__real_gai_strerror(int ecode); +extern void +__real_freeaddrinfo(struct addrinfo *ai); +extern int +__real_getaddrinfo(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res); + int android_sdk_version; #pragma GCC visibility pop @@ -434,7 +442,7 @@ const char * __wrap_gai_strerror(int ecode) { if (honeycomb_or_later()) - return gai_strerror(ecode); + return __real_gai_strerror(ecode); if (ecode < 0 || ecode > EAI_MAX) ecode = EAI_MAX; return ai_errlist[ecode]; @@ -446,7 +454,7 @@ __wrap_freeaddrinfo(struct addrinfo *ai) struct addrinfo *next; if (honeycomb_or_later()) { - freeaddrinfo(ai); + __real_freeaddrinfo(ai); return; } @@ -545,7 +553,7 @@ __wrap_getaddrinfo(const char *hostname, const char *servname, const struct explore *ex; if (honeycomb_or_later()) - return getaddrinfo(hostname, servname, hints, res); + return __real_getaddrinfo(hostname, servname, hints, res); /* hostname is allowed to be NULL */ /* servname is allowed to be NULL */ From 4a1b5156d6736fedd25c7ed817afe6d599f1a61d Mon Sep 17 00:00:00 2001 From: Gijs Kruitbosch Date: Tue, 2 Dec 2014 15:52:26 -0800 Subject: [PATCH 011/130] Bug 1043584 - fix mouseover vs. enter issue in the urlbar, r=mak --HG-- extra : rebase_source : a44d3e897a6ae930119fff45b6babc7a0ad8bcbb --- browser/base/content/test/general/browser.ini | 2 + .../browser_urlbarEnterAfterMouseOver.js | 71 ++++++++++++++ .../autocomplete/nsAutoCompleteController.cpp | 36 +++++-- .../autocomplete/nsAutoCompleteController.h | 8 ++ .../tests/unit/test_finalCompleteValue.js | 4 - .../test_finalCompleteValueSelectedIndex.js | 97 +++++++++++++++++++ .../autocomplete/tests/unit/xpcshell.ini | 1 + 7 files changed, 205 insertions(+), 14 deletions(-) create mode 100644 browser/base/content/test/general/browser_urlbarEnterAfterMouseOver.js create mode 100644 toolkit/components/autocomplete/tests/unit/test_finalCompleteValueSelectedIndex.js diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 2e672e45032f..0d6fd37aa3eb 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -442,6 +442,8 @@ skip-if = e10s # Bug 1093941 - Waits indefinitely for onSearchComplete [browser_urlbarCopying.js] [browser_urlbarEnter.js] skip-if = e10s # Bug 1093941 - used to cause obscure non-windows child process crashes on try +[browser_urlbarEnterAfterMouseOver.js] +skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s [browser_urlbarRevert.js] skip-if = e10s # Bug 1093941 - ESC reverted the location bar value - Got foobar, expected example.com [browser_urlbarSearchSingleWordNotification.js] diff --git a/browser/base/content/test/general/browser_urlbarEnterAfterMouseOver.js b/browser/base/content/test/general/browser_urlbarEnterAfterMouseOver.js new file mode 100644 index 000000000000..47f7873212d0 --- /dev/null +++ b/browser/base/content/test/general/browser_urlbarEnterAfterMouseOver.js @@ -0,0 +1,71 @@ +function repeat(limit, func) { + for (let i = 0; i < limit; i++) { + func(i); + } +} + +function* promiseAutoComplete(inputText) { + gURLBar.focus(); + gURLBar.value = inputText.slice(0, -1); + EventUtils.synthesizeKey(inputText.slice(-1), {}); + yield promiseSearchComplete(); +} + +function is_selected(index) { + is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`); +} + +add_task(function*() { + registerCleanupFunction(promiseClearHistory); + + yield promiseClearHistory(); + let tabCount = gBrowser.tabs.length; + + let visits = []; + repeat(10, i => { + visits.push({ + uri: makeURI("http://example.com/autocomplete/?" + i), + }); + }); + yield PlacesTestUtils.addVisits(visits); + + Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true); + yield* do_test(); + Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", false); + yield* do_test(); + Services.prefs.clearUserPref("browser.urlbar.unifiedcomplete"); +}); + +function* do_test() { + gBrowser.selectedTab = gBrowser.addTab("about:blank"); + yield promiseAutoComplete("http://example.com/autocomplete/"); + + let popup = gURLBar.popup; + let results = popup.richlistbox.children; + is(results.length, 11, "Should get 11 results"); + + let initiallySelected = gURLBar.popup.richlistbox.selectedIndex; + + info("Key Down to select the next item"); + EventUtils.synthesizeKey("VK_DOWN", {}); + is_selected(initiallySelected + 1); + let expectedURL = gURLBar.controller.getFinalCompleteValueAt(initiallySelected + 1); + + is(gURLBar.value, gURLBar.controller.getValueAt(initiallySelected + 1), + "Value in the URL bar should be updated by keyboard selection"); + + // Verify that what we're about to do changes the selectedIndex: + isnot(initiallySelected + 1, 3, "Shouldn't be changing the selectedIndex to the same index we keyboard-selected."); + + // Would love to use a synthetic mousemove event here, but that doesn't seem to do anything. + // EventUtils.synthesizeMouseAtCenter(results[3], {type: "mousemove"}); + gURLBar.popup.richlistbox.selectedIndex = 3; + is_selected(3); + + let autocompletePopupHidden = promisePopupHidden(gURLBar.popup); + let openedExpectedPage = waitForDocLoadAndStopIt(expectedURL); + EventUtils.synthesizeKey("VK_RETURN", {}); + yield Promise.all([autocompletePopupHidden, openedExpectedPage]); + + gBrowser.removeCurrentTab(); +} diff --git a/toolkit/components/autocomplete/nsAutoCompleteController.cpp b/toolkit/components/autocomplete/nsAutoCompleteController.cpp index 5d15421cfef9..bb0df56f5ce9 100644 --- a/toolkit/components/autocomplete/nsAutoCompleteController.cpp +++ b/toolkit/components/autocomplete/nsAutoCompleteController.cpp @@ -52,7 +52,8 @@ nsAutoCompleteController::nsAutoCompleteController() : mSearchesOngoing(0), mSearchesFailed(0), mFirstSearchResult(false), - mImmediateSearchesCount(0) + mImmediateSearchesCount(0), + mCompletedSelectionIndex(-1) { } @@ -122,6 +123,7 @@ nsAutoCompleteController::SetInput(nsIAutoCompleteInput *aInput) mSearchStatus = nsIAutoCompleteController::STATUS_NONE; mRowCount = 0; mSearchesOngoing = 0; + mCompletedSelectionIndex = -1; // Initialize our list of search objects uint32_t searchCount; @@ -421,10 +423,12 @@ nsAutoCompleteController::HandleKeyNavigation(uint32_t aKey, bool *_retval) input->SetTextValue(value); input->SelectTextRange(value.Length(), value.Length()); } + mCompletedSelectionIndex = selectedIndex; } else { // Nothing is selected, so fill in the last typed value input->SetTextValue(mSearchString); input->SelectTextRange(mSearchString.Length(), mSearchString.Length()); + mCompletedSelectionIndex = -1; } } } else { @@ -1244,17 +1248,29 @@ nsAutoCompleteController::EnterMatch(bool aIsPopupSelection) int32_t selectedIndex; popup->GetSelectedIndex(&selectedIndex); if (selectedIndex >= 0) { + nsAutoString finalValue; // If completeselectedindex is false or a row was selected from the popup, - // enter it into the textbox. If completeselectedindex is true, or - // EnterMatch was called via other means, for instance pressing Enter, - // don't fill in the value as it will have already been filled in as - // needed, unless the final complete value differs. - nsAutoString finalValue, inputValue; - GetResultValueAt(selectedIndex, true, finalValue); - input->GetTextValue(inputValue); - if (!completeSelection || aIsPopupSelection || - !finalValue.Equals(inputValue)) { + // enter it into the textbox. + if (!completeSelection || aIsPopupSelection) { + GetResultValueAt(selectedIndex, true, finalValue); value = finalValue; + } else if (mCompletedSelectionIndex != -1) { + // If completeselectedindex is true, and EnterMatch was not invoked by + // mouse-clicking a match (for example the user pressed Enter), + // don't fill in the value as it will have already been filled in as + // needed, unless the selected match has a final complete value that + // differs from the user-facing value. + GetResultValueAt(mCompletedSelectionIndex, true, finalValue); + nsAutoString inputValue; + input->GetTextValue(inputValue); + if (!finalValue.Equals(inputValue)) { + value = finalValue; + } + // Note that if the user opens the popup, mouses over entries without + // ever selecting one with the keyboard, and then hits enter, none of + // the above cases will be hitt, since mouseover doesn't activate + // completeselectedindex and thus mCompletedSelectionIndex would be + // -1. } } else if (shouldComplete) { diff --git a/toolkit/components/autocomplete/nsAutoCompleteController.h b/toolkit/components/autocomplete/nsAutoCompleteController.h index 556d5eb68cb4..f96e55f3ab6b 100644 --- a/toolkit/components/autocomplete/nsAutoCompleteController.h +++ b/toolkit/components/autocomplete/nsAutoCompleteController.h @@ -151,6 +151,14 @@ protected: uint32_t mSearchesFailed; bool mFirstSearchResult; uint32_t mImmediateSearchesCount; + // The index of the match on the popup that was selected using the keyboard, + // if the completeselectedindex attribute is set. + // This is used to distinguish that selection (which would have been put in + // the input on being selected) from a moused-over selectedIndex value. This + // distinction is used to prevent mouse moves from inadvertently changing + // what happens once the user hits Enter on the keyboard. + // See bug 1043584 for more details. + int32_t mCompletedSelectionIndex; }; #endif /* __nsAutoCompleteController__ */ diff --git a/toolkit/components/autocomplete/tests/unit/test_finalCompleteValue.js b/toolkit/components/autocomplete/tests/unit/test_finalCompleteValue.js index 8607809eb8e2..27304d03aab4 100644 --- a/toolkit/components/autocomplete/tests/unit/test_finalCompleteValue.js +++ b/toolkit/components/autocomplete/tests/unit/test_finalCompleteValue.js @@ -1,7 +1,3 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - function AutoCompleteResult(aValues, aFinalCompleteValues) { this._values = aValues; this._finalCompleteValues = aFinalCompleteValues; diff --git a/toolkit/components/autocomplete/tests/unit/test_finalCompleteValueSelectedIndex.js b/toolkit/components/autocomplete/tests/unit/test_finalCompleteValueSelectedIndex.js new file mode 100644 index 000000000000..a1fcf158f01f --- /dev/null +++ b/toolkit/components/autocomplete/tests/unit/test_finalCompleteValueSelectedIndex.js @@ -0,0 +1,97 @@ +function AutoCompleteResult(aResultValues) { + this._values = aResultValues.map(x => x[0]); + this._finalCompleteValues = aResultValues.map(x => x[1]); +} +AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype); + +let selectByWasCalled = false; +function AutoCompleteInput(aSearches) { + this.searches = aSearches; + this.popup.selectedIndex = 0; + this.popup.selectBy = function(reverse, page) { + Assert.equal(selectByWasCalled, false); + selectByWasCalled = true; + Assert.equal(reverse, false); + Assert.equal(page, false); + this.selectedIndex += (reverse ? -1 : 1) * (page ? 100 : 1); + }; + this.completeSelectedIndex = true; +} +AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype); + +function run_test() { + run_next_test(); +} + +add_test(function test_handleEnter() { + let results = [ + ["mozilla.com", "http://www.mozilla.com"], + ["mozilla.org", "http://www.mozilla.org"], + ]; + // First check the case where we do select a value with the keyboard: + doSearch("moz", results, function(aController) { + Assert.equal(aController.input.textValue, "moz"); + Assert.equal(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com"); + Assert.equal(aController.getFinalCompleteValueAt(1), "http://www.mozilla.org"); + + Assert.equal(aController.input.popup.selectedIndex, 0); + aController.handleKeyNavigation(Ci.nsIDOMKeyEvent.DOM_VK_DOWN); + Assert.equal(aController.input.popup.selectedIndex, 1); + // Simulate mouse interaction changing selectedIndex + // ie NOT keyboard interaction: + aController.input.popup.selectedIndex = 0; + + aController.handleEnter(false); + // Verify that the keyboard-selected thing got inserted, + // and not the mouse selection: + Assert.equal(aController.input.textValue, "http://www.mozilla.org"); + }); + + // Then the case where we do not: + doSearch("moz", results, function(aController) { + Assert.equal(aController.input.textValue, "moz"); + Assert.equal(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com"); + Assert.equal(aController.getFinalCompleteValueAt(1), "http://www.mozilla.org"); + + Assert.equal(aController.input.popup.selectedIndex, 0); + aController.input.popupOpen = true; + // Simulate mouse interaction changing selectedIndex + // ie NOT keyboard interaction: + aController.input.popup.selectedIndex = 1; + Assert.equal(selectByWasCalled, false); + Assert.equal(aController.input.popup.selectedIndex, 1); + + aController.handleEnter(false); + // Verify that the input stayed the same, because no selection was made + // with the keyboard: + Assert.equal(aController.input.textValue, "moz"); + }); +}); + +function doSearch(aSearchString, aResults, aOnCompleteCallback) { + selectByWasCalled = false; + let search = new AutoCompleteSearchBase( + "search", + new AutoCompleteResult(aResults) + ); + registerAutoCompleteSearch(search); + + let controller = Cc["@mozilla.org/autocomplete/controller;1"]. + getService(Ci.nsIAutoCompleteController); + + // Make an AutoCompleteInput that uses our searches and confirms results. + let input = new AutoCompleteInput([ search.name ]); + input.textValue = aSearchString; + + controller.input = input; + controller.startSearch(aSearchString); + + input.onSearchComplete = function onSearchComplete() { + aOnCompleteCallback(controller); + + // Clean up. + unregisterAutoCompleteSearch(search); + run_next_test(); + }; +} + diff --git a/toolkit/components/autocomplete/tests/unit/xpcshell.ini b/toolkit/components/autocomplete/tests/unit/xpcshell.ini index 86ac0df84f83..7f0ba577e6f3 100644 --- a/toolkit/components/autocomplete/tests/unit/xpcshell.ini +++ b/toolkit/components/autocomplete/tests/unit/xpcshell.ini @@ -14,6 +14,7 @@ skip-if = toolkit == 'gonk' [test_completeDefaultIndex_casing.js] [test_finalCompleteValue.js] [test_finalCompleteValue_forceComplete.js] +[test_finalCompleteValueSelectedIndex.js] [test_finalDefaultCompleteValue.js] [test_hiddenResult.js] [test_immediate_search.js] From 9e6206a1b510012e2a65bddc6d85f7db2cef4b0f Mon Sep 17 00:00:00 2001 From: Gijs Kruitbosch Date: Wed, 29 Oct 2014 21:42:44 +0000 Subject: [PATCH 012/130] Bug 1088588 - fix ifdef in X11TextureSourceOGL.cpp, patch by Dirk Mueller, r=nical --- gfx/layers/opengl/X11TextureSourceOGL.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gfx/layers/opengl/X11TextureSourceOGL.cpp b/gfx/layers/opengl/X11TextureSourceOGL.cpp index 7ecd4e624e89..b744e92b3761 100644 --- a/gfx/layers/opengl/X11TextureSourceOGL.cpp +++ b/gfx/layers/opengl/X11TextureSourceOGL.cpp @@ -101,7 +101,7 @@ X11TextureSourceOGL::ContentTypeToSurfaceFormat(gfxContentType aType) } } -#endif +} +} -} -} +#endif From 206a008179ff3ae3f048ffc57e38589f8c41789e Mon Sep 17 00:00:00 2001 From: Ralph Giles Date: Tue, 16 Dec 2014 10:45:48 -0500 Subject: [PATCH 013/130] Bug 1080995 - Filter out h264parse gstreamer element. r=edwin This avoids the crash but also blocks video decoding in general, at least with the fluendo decoder. The audio track still plays on valid videos. We limit the blacklist by version. Gstreamer 1.0 api calls are untested. --- dom/media/gstreamer/GStreamerFunctionList.h | 4 ++ dom/media/gstreamer/GStreamerReader.cpp | 63 ++++++++++++++++++++- dom/media/gstreamer/GStreamerReader.h | 6 +- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/dom/media/gstreamer/GStreamerFunctionList.h b/dom/media/gstreamer/GStreamerFunctionList.h index 72792949212c..5522fee373f4 100644 --- a/dom/media/gstreamer/GStreamerFunctionList.h +++ b/dom/media/gstreamer/GStreamerFunctionList.h @@ -88,7 +88,9 @@ GST_FUNC(LIBGSTREAMER, gst_pad_add_event_probe) GST_FUNC(LIBGSTREAMER, gst_pad_alloc_buffer) GST_FUNC(LIBGSTREAMER, gst_pad_get_negotiated_caps) GST_FUNC(LIBGSTREAMER, gst_pad_set_bufferalloc_function) +GST_FUNC(LIBGSTREAMER, gst_registry_find_plugin) GST_FUNC(LIBGSTREAMER, gst_registry_get_default) +GST_FUNC(LIBGSTREAMER, gst_plugin_feature_get_type) GST_FUNC(LIBGSTREAMER, gst_segment_set_newsegment) GST_FUNC(LIBGSTVIDEO, gst_video_format_get_component_height) GST_FUNC(LIBGSTVIDEO, gst_video_format_get_component_offset) @@ -130,6 +132,8 @@ GST_FUNC(LIBGSTREAMER, gst_object_get_type) GST_FUNC(LIBGSTREAMER, gst_pad_add_probe) GST_FUNC(LIBGSTREAMER, gst_pad_get_current_caps) GST_FUNC(LIBGSTREAMER, gst_pad_probe_info_get_query) +GST_FUNC(LIBGSTREAMER, gst_plugin_feature_get_plugin) +GST_FUNC(LIBGSTREAMER, gst_plugin_get_version) GST_FUNC(LIBGSTREAMER, gst_query_add_allocation_meta) GST_FUNC(LIBGSTREAMER, gst_query_add_allocation_param) GST_FUNC(LIBGSTREAMER, gst_query_add_allocation_pool) diff --git a/dom/media/gstreamer/GStreamerReader.cpp b/dom/media/gstreamer/GStreamerReader.cpp index 18d99d4cd251..c3e9814365a0 100644 --- a/dom/media/gstreamer/GStreamerReader.cpp +++ b/dom/media/gstreamer/GStreamerReader.cpp @@ -15,6 +15,7 @@ #endif #include "GStreamerFormatHelper.h" #include "VideoUtils.h" +#include "mozilla/ArrayUtils.h" #include "mozilla/dom/TimeRanges.h" #include "mozilla/Endian.h" #include "mozilla/Preferences.h" @@ -22,6 +23,10 @@ #include "GStreamerLoader.h" #include "gfx2DGlue.h" +#include +#include +#include + namespace mozilla { using namespace gfx; @@ -1168,17 +1173,71 @@ GStreamerReader::PlayElementAddedCb(GstBin *aBin, GstElement *aElement, g_free(name); } +/** + * Helper to calculate the length of a C string constant at compile time. + * Substract one from the array length for the trailing null. + */ +#define STRING_LENGTH(string) (ArrayLength(string) - 1) + +/** Check proposed element factories for acceptability. */ +bool GStreamerReader::IsFactoryBlacklisted(GstElementFactory* aFactory) +{ + // Retrieve version string for the element. +#if GST_VERSION_MAJOR >= 1 + GstPlugin* plugin = gst_plugin_feature_get_plugin(GST_PLUGIN_FEATURE(aFactory)); + const gchar* version = plugin ? gst_plugin_get_version(plugin) : "unknown"; +#else + const gchar* plugin_name = GST_PLUGIN_FEATURE(aFactory)->plugin_name; + if (!plugin_name) { + return true; + } + GstPlugin* plugin = gst_default_registry_find_plugin(plugin_name); + const gchar* version = plugin ? plugin->desc.version : "unknown"; +#endif + if (!plugin) { + return true; + } + // Retrieve the element name. + const gchar* name = gst_element_get_name(aFactory); + + // Reject h264parse <= 0.10.23. + const char badname[] = "h264parse"; + const char version_base[] = "0.10."; + // Length needed to compare with version base plus two more digits. + const size_t version_min = STRING_LENGTH(version_base) + 2; + if (strcmp(name, badname) == 0 && + strncmp(version, version_base, strlen(version_base)) == 0 && + strlen(version) >= version_min && + atoi(version + strlen(version_base)) <= 23) { + gst_object_unref(plugin); + return true; + } + + // Clean up. + gst_object_unref(plugin); + + // Factory isn't blacklisted. + return false; +} + +/** Filter elements to control autoplug selection. */ bool GStreamerReader::ShouldAutoplugFactory(GstElementFactory* aFactory, GstCaps* aCaps) { + /* Blacklist unstable elements. */ + if (IsFactoryBlacklisted(aFactory)) { + return false; + } + + /* Filter Demuxers and Decoders for supported formats. */ bool autoplug; - const gchar *klass = gst_element_factory_get_klass(aFactory); + const gchar* klass = gst_element_factory_get_klass(aFactory); if (strstr(klass, "Demuxer") && !strstr(klass, "Metadata")) { autoplug = GStreamerFormatHelper::Instance()->CanHandleContainerCaps(aCaps); } else if (strstr(klass, "Decoder") && !strstr(klass, "Generic")) { autoplug = GStreamerFormatHelper::Instance()->CanHandleCodecCaps(aCaps); } else { - /* we only filter demuxers and decoders, let everything else be autoplugged */ + /* Let everything else be autoplugged. */ autoplug = true; } diff --git a/dom/media/gstreamer/GStreamerReader.h b/dom/media/gstreamer/GStreamerReader.h index 548164df6414..5c939e3b9498 100644 --- a/dom/media/gstreamer/GStreamerReader.h +++ b/dom/media/gstreamer/GStreamerReader.h @@ -166,9 +166,11 @@ private: static void PlayElementAddedCb(GstBin *aBin, GstElement *aElement, gpointer *aUserData); - /* Called during decoding, to decide whether a (sub)stream should be decoded or - * ignored */ + /* Called during decoding, to decide whether a (sub)stream should be + * decoded or ignored. */ static bool ShouldAutoplugFactory(GstElementFactory* aFactory, GstCaps* aCaps); + /* Called from ShouldAutoplugFactory to check for blacklisted elements. */ + static bool IsFactoryBlacklisted(GstElementFactory* aFactory); /* Called by decodebin during autoplugging. We use it to apply our * container/codec whitelist. From 678d7a5647809ee40e12aedc69f7550a3013497a Mon Sep 17 00:00:00 2001 From: Dave Hunt Date: Fri, 12 Dec 2014 09:48:00 -0500 Subject: [PATCH 014/130] Bug 1110763 - Raise an exception in the Marionette test runner if no tests are selected. r=jgriffin --- testing/marionette/client/marionette/runner/base.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/testing/marionette/client/marionette/runner/base.py b/testing/marionette/client/marionette/runner/base.py index ede0e49dfda1..12ffb745095e 100644 --- a/testing/marionette/client/marionette/runner/base.py +++ b/testing/marionette/client/marionette/runner/base.py @@ -922,7 +922,9 @@ setReq.onerror = function() { break def run_test_sets(self): - if self.total_chunks > len(self.tests): + if len(self.tests) < 1: + raise Exception('There are no tests to run.') + elif self.total_chunks > len(self.tests): raise ValueError('Total number of chunks must be between 1 and %d.' % len(self.tests)) if self.total_chunks > 1: chunks = [[] for i in range(self.total_chunks)] From f2eb08851e495257f74c6de02a82596b5e3bee29 Mon Sep 17 00:00:00 2001 From: Dave Hunt Date: Thu, 11 Dec 2014 09:44:00 -0500 Subject: [PATCH 015/130] Bug 1101497 - Support connecting to a remote ADB host. r=mdas --- testing/marionette/client/marionette/marionette.py | 7 +++++-- .../marionette/client/marionette/runner/base.py | 14 ++++++++++++-- .../client/marionette/runner/mixins/b2g.py | 9 +++++---- testing/marionette/client/requirements.txt | 4 ++-- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/testing/marionette/client/marionette/marionette.py b/testing/marionette/client/marionette/marionette.py index f8a2e333df0b..160c10b2579a 100644 --- a/testing/marionette/client/marionette/marionette.py +++ b/testing/marionette/client/marionette/marionette.py @@ -471,7 +471,8 @@ class Marionette(object): emulator_binary=None, emulator_res=None, connect_to_running_emulator=False, gecko_log=None, homedir=None, baseurl=None, no_window=False, logdir=None, busybox=None, symbols_path=None, timeout=None, socket_timeout=360, - device_serial=None, adb_path=None, process_args=None): + device_serial=None, adb_path=None, process_args=None, + adb_host=None, adb_port=None): self.host = host self.port = self.local_port = port self.bin = bin @@ -488,8 +489,10 @@ class Marionette(object): self.no_window = no_window self._test_name = None self.timeout = timeout - self.socket_timeout=socket_timeout + self.socket_timeout = socket_timeout self.device_serial = device_serial + self.adb_host = adb_host + self.adb_port = adb_port if bin: port = int(self.port) diff --git a/testing/marionette/client/marionette/runner/base.py b/testing/marionette/client/marionette/runner/base.py index 12ffb745095e..6453d0a666a7 100644 --- a/testing/marionette/client/marionette/runner/base.py +++ b/testing/marionette/client/marionette/runner/base.py @@ -290,6 +290,10 @@ class BaseMarionetteOptions(OptionParser): dest='device_serial', action='store', help='serial ID of a device to use for adb / fastboot') + self.add_option('--adb-host', + help='host to use for adb connection') + self.add_option('--adb-port', + help='port to use for adb connection') self.add_option('--type', dest='type', action='store', @@ -455,7 +459,7 @@ class BaseMarionetteTestRunner(object): shuffle=False, shuffle_seed=random.randint(0, sys.maxint), sdcard=None, this_chunk=1, total_chunks=1, sources=None, server_root=None, gecko_log=None, result_callbacks=None, - **kwargs): + adb_host=None, adb_port=None, **kwargs): self.address = address self.emulator = emulator self.emulator_binary = emulator_binary @@ -495,6 +499,8 @@ class BaseMarionetteTestRunner(object): self.manifest_skipped_tests = [] self.tests = [] self.result_callbacks = result_callbacks if result_callbacks is not None else [] + self._adb_host = adb_host + self._adb_port = adb_port def gather_debug(test, status): rv = {} @@ -605,6 +611,8 @@ class BaseMarionetteTestRunner(object): 'device_serial': self.device_serial, 'symbols_path': self.symbols_path, 'timeout': self.timeout, + 'adb_host': self._adb_host, + 'adb_port': self._adb_port, } if self.bin: kwargs.update({ @@ -728,7 +736,9 @@ setReq.onerror = function() { version_info = mozversion.get_version(binary=self.bin, sources=self.sources, dm_type=os.environ.get('DM_TRANS', 'adb'), - device_serial=self.device_serial) + device_serial=self.device_serial, + adb_host=self.marionette.adb_host, + adb_port=self.marionette.adb_port) device_info = None if self.capabilities['device'] != 'desktop' and self.capabilities['browserName'] == 'B2G': diff --git a/testing/marionette/client/marionette/runner/mixins/b2g.py b/testing/marionette/client/marionette/runner/mixins/b2g.py index 438372798e27..94fe7485dd04 100644 --- a/testing/marionette/client/marionette/runner/mixins/b2g.py +++ b/testing/marionette/client/marionette/runner/mixins/b2g.py @@ -7,15 +7,16 @@ import os import re -def get_dm(marionette=None,**kwargs): +def get_dm(marionette=None, **kwargs): dm_type = os.environ.get('DM_TRANS', 'adb') if marionette and hasattr(marionette.runner, 'device'): return marionette.runner.app_ctx.dm - elif marionette and marionette.device_serial and dm_type == 'adb': - return mozdevice.DeviceManagerADB(deviceSerial=marionette.device_serial, **kwargs) else: if dm_type == 'adb': - return mozdevice.DeviceManagerADB(**kwargs) + return mozdevice.DeviceManagerADB(deviceSerial=marionette.device_serial, + serverHost=marionette.adb_host, + serverPort=marionette.adb_port, + **kwargs) elif dm_type == 'sut': host = os.environ.get('TEST_DEVICE') if not host: diff --git a/testing/marionette/client/requirements.txt b/testing/marionette/client/requirements.txt index 1d20067a1b60..6cfc18169db3 100644 --- a/testing/marionette/client/requirements.txt +++ b/testing/marionette/client/requirements.txt @@ -4,10 +4,10 @@ mozhttpd >= 0.5 mozinfo >= 0.7 mozprocess >= 0.9 mozrunner >= 6.2 -mozdevice >= 0.37 +mozdevice >= 0.44 mozlog >= 2.7 moznetwork >= 0.21 mozcrash >= 0.5 mozprofile >= 0.7 moztest >= 0.7 -mozversion >= 0.2 +mozversion >= 1.1 From 625804e99af0c2ce94e17df8a3e4dc6feaecc856 Mon Sep 17 00:00:00 2001 From: Oleksiy Avramchenko Date: Fri, 12 Dec 2014 06:18:00 -0500 Subject: [PATCH 016/130] Bug 1107923 - Use powerctl for reboot & shutdown. r=gsvelto Android KK and later supports sys.powerctl property to reboot or shutdown device via the init. This allows to: - hook up on these events from the rc scripts to perform some actions - remount all fs to ro in android_reboot() before calling the kernel --- hal/linux/LinuxPower.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/hal/linux/LinuxPower.cpp b/hal/linux/LinuxPower.cpp index 0cf87d4247c5..1b88bbc497e2 100644 --- a/hal/linux/LinuxPower.cpp +++ b/hal/linux/LinuxPower.cpp @@ -11,9 +11,28 @@ #include "mozilla/Services.h" #include "MainThreadUtils.h" +#if defined(MOZ_WIDGET_GONK) +#include "cutils/android_reboot.h" +#include "cutils/properties.h" +#endif + namespace mozilla { namespace hal_impl { +#if (defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19) +static void +PowerCtl(const char* aValue, int aCmd) +{ + // this invokes init's powerctl builtin via /init.rc + property_set("sys.powerctl", aValue); + // device should reboot in few moments, but if it doesn't - call + // android_reboot() to make sure that init isn't stuck somewhere + sleep(10); + HAL_LOG("Powerctl call takes too long, forcing %s.", aValue); + android_reboot(aCmd, 0, nullptr); +} +#endif + void Reboot() { @@ -23,8 +42,15 @@ Reboot() obsServ->NotifyObservers(nullptr, "system-reboot", nullptr); } } + +#if !defined(MOZ_WIDGET_GONK) sync(); reboot(RB_AUTOBOOT); +#elif (ANDROID_VERSION < 19) + android_reboot(ANDROID_RB_RESTART, 0, nullptr); +#else + PowerCtl("reboot", ANDROID_RB_RESTART); +#endif } void @@ -36,8 +62,15 @@ PowerOff() obsServ->NotifyObservers(nullptr, "system-power-off", nullptr); } } + +#if !defined(MOZ_WIDGET_GONK) sync(); reboot(RB_POWER_OFF); +#elif (ANDROID_VERSION < 19) + android_reboot(ANDROID_RB_POWEROFF, 0, nullptr); +#else + PowerCtl("shutdown", ANDROID_RB_POWEROFF); +#endif } // Structure to specify how watchdog pthread is going to work. From 13f89f6e4903fcb0774a08461d5e6762ff1cc089 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 08:02:27 -0800 Subject: [PATCH 017/130] Bug 1111076 - Get rid of nsIScriptContext::GC(). r=smaug --- dom/base/nsGlobalWindow.cpp | 4 ++-- dom/base/nsIScriptContext.h | 15 +++------------ dom/base/nsJSEnvironment.cpp | 6 ------ dom/base/nsJSEnvironment.h | 2 -- 4 files changed, 5 insertions(+), 22 deletions(-) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index f30a2743fee4..4cfd7329bbcd 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -2698,7 +2698,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, newInnerWindow->mChromeEventHandler = mChromeEventHandler; } - mContext->GC(JS::gcreason::SET_NEW_DOCUMENT); + nsJSContext::PokeGC(JS::gcreason::SET_NEW_DOCUMENT); mContext->DidInitializeContext(); // We wait to fire the debugger hook until the window is all set up and hooked @@ -2921,7 +2921,7 @@ nsGlobalWindow::DetachFromDocShell() mChromeEventHandler = nullptr; // force release now if (mContext) { - mContext->GC(JS::gcreason::SET_DOC_SHELL); + nsJSContext::PokeGC(JS::gcreason::SET_DOC_SHELL); mContext = nullptr; } diff --git a/dom/base/nsIScriptContext.h b/dom/base/nsIScriptContext.h index d2bad832ce64..a94acc2af07d 100644 --- a/dom/base/nsIScriptContext.h +++ b/dom/base/nsIScriptContext.h @@ -27,8 +27,8 @@ class nsIDOMWindow; class nsIURI; #define NS_ISCRIPTCONTEXT_IID \ -{ 0x274840b6, 0x7349, 0x4798, \ - { 0xbe, 0x24, 0xbd, 0x75, 0xa6, 0x46, 0x99, 0xb7 } } +{ 0x901f0d5e, 0x217a, 0x45fa, \ + { 0x9a, 0xca, 0x45, 0x0f, 0xe7, 0x2f, 0x10, 0x9a } } class nsIOffThreadScriptReceiver; @@ -67,19 +67,11 @@ public: */ virtual bool IsContextInitialized() = 0; - /** - * For garbage collected systems, do a synchronous collection pass. - * May be a no-op on other systems - * - * @return NS_OK if the method is successful - */ - virtual void GC(JS::gcreason::Reason aReason) = 0; - // SetProperty is suspect and jst believes should not be needed. Currenly // used only for "arguments". virtual nsresult SetProperty(JS::Handle aTarget, const char* aPropName, nsISupports* aVal) = 0; - /** + /** * Called to set/get information if the script context is * currently processing a script tag */ @@ -134,4 +126,3 @@ public: NS_DEFINE_STATIC_IID_ACCESSOR(nsIOffThreadScriptReceiver, NS_IOFFTHREADSCRIPTRECEIVER_IID) #endif // nsIScriptContext_h__ - diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index fafa3d332b72..e427654b22c6 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2302,12 +2302,6 @@ nsJSContext::KillICCTimer() } } -void -nsJSContext::GC(JS::gcreason::Reason aReason) -{ - PokeGC(aReason); -} - class NotifyGCEndRunnable : public nsRunnable { nsString mMessage; diff --git a/dom/base/nsJSEnvironment.h b/dom/base/nsJSEnvironment.h index d4ae7c33f051..d090549d3604 100644 --- a/dom/base/nsJSEnvironment.h +++ b/dom/base/nsJSEnvironment.h @@ -125,8 +125,6 @@ public: // Calling LikelyShortLivingObjectCreated() makes a GC more likely. static void LikelyShortLivingObjectCreated(); - virtual void GC(JS::gcreason::Reason aReason) MOZ_OVERRIDE; - static uint32_t CleanupsSinceLastGC(); nsIScriptGlobalObject* GetCachedGlobalObject() From b8abb8e65f82fe3fc5afda0a2eb668f3657d1d78 Mon Sep 17 00:00:00 2001 From: Andrew Halberstadt Date: Mon, 15 Dec 2014 16:47:13 -0500 Subject: [PATCH 018/130] Bug 1111727 - Make sure mozrunner's command line interface uses the proper profile class, r=whimboo --HG-- extra : rebase_source : 46c97f32314078f71808bd5083df159060f6f4d7 --- testing/mozbase/mozrunner/mozrunner/cli.py | 23 ++++++++-------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/testing/mozbase/mozrunner/mozrunner/cli.py b/testing/mozbase/mozrunner/mozrunner/cli.py index 5fef70a63d15..85c03d8bf596 100644 --- a/testing/mozbase/mozrunner/mozrunner/cli.py +++ b/testing/mozbase/mozrunner/mozrunner/cli.py @@ -6,21 +6,12 @@ import optparse import os import sys -from mozprofile import MozProfileCLI, Profile -from .runners import ( - FirefoxRunner, - MetroRunner, - ThunderbirdRunner, -) +from mozprofile import MozProfileCLI +from .application import get_app_context +from .runners import runners from .utils import findInPath -RUNNER_MAP = { - 'firefox': FirefoxRunner, - 'metro': MetroRunner, - 'thunderbird': ThunderbirdRunner, -} - # Map of debugging programs to information about them # from http://mxr.mozilla.org/mozilla-central/source/build/automationutils.py#59 DEBUGGERS = {'gdb': {'interactive': True, @@ -79,11 +70,13 @@ class CLI(MozProfileCLI): sys.exit(0) # choose appropriate runner and profile classes + app = self.options.app try: - self.runner_class = RUNNER_MAP[self.options.app] + self.runner_class = runners[app] + self.profile_class = get_app_context(app).profile_class except KeyError: self.parser.error('Application "%s" unknown (should be one of "%s")' % - (self.options.app, ', '.join(RUNNER_MAP.keys()))) + (app, ', '.join(runners.keys()))) def add_options(self, parser): """add options to the parser""" @@ -145,7 +138,7 @@ class CLI(MozProfileCLI): binary=self.options.binary) def create_runner(self): - profile = Profile(**self.profile_args()) + profile = self.profile_class(**self.profile_args()) return self.runner_class(profile=profile, **self.runner_args()) def run(self): From 28f79d4ae5d8fd2a04549b8dc07a0be41f6df2e4 Mon Sep 17 00:00:00 2001 From: Andrew Halberstadt Date: Tue, 16 Dec 2014 09:31:06 -0500 Subject: [PATCH 019/130] Bug 1111727 - Bump mozrunner to version 6.7, r=whimboo --HG-- extra : rebase_source : 34854203ebbc8b2339de54f83d29e381f718208a --- testing/mozbase/mozrunner/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setup.py index 3dc593648e6e..2856e74ba0c7 100644 --- a/testing/mozbase/mozrunner/setup.py +++ b/testing/mozbase/mozrunner/setup.py @@ -6,7 +6,7 @@ import sys from setuptools import setup, find_packages PACKAGE_NAME = 'mozrunner' -PACKAGE_VERSION = '6.6' +PACKAGE_VERSION = '6.7' desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)""" From b8e66b9896149c828aab935e9c9f8c4d7d68b8d6 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 16 Dec 2014 16:13:06 +0000 Subject: [PATCH 020/130] Bug 1052139 - Mark entered compartments r=terrence --- js/src/jscntxt.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 4289418a5b0c..ce80dfda395c 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -1199,6 +1199,9 @@ JSContext::mark(JSTracer *trc) MarkValueRoot(trc, &unwrappedException_, "unwrapped exception"); TraceCycleDetectionSet(trc, cycleDetectorSet); + + if (compartment_) + compartment_->mark(); } void * From 351ab4aeb79dc61c7701c8ae297a6c0dd7893a0e Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Wed, 26 Nov 2014 16:04:55 -0500 Subject: [PATCH 021/130] Bug 1052139 - Refactor global-object creation code to distinguish the unique self-hosting global from all other run-of-the-mill globals. r=till --- js/src/jsapi.cpp | 69 +----------------------------------- js/src/vm/GlobalObject.cpp | 44 ++++++++++++++++++++++- js/src/vm/GlobalObject.h | 12 ++++++- js/src/vm/Runtime.h | 3 ++ js/src/vm/SelfHosting.cpp | 72 ++++++++++++++++++++++++-------------- 5 files changed, 103 insertions(+), 97 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 517c26493a8c..10504df21ffb 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2299,39 +2299,6 @@ JS_GetConstructor(JSContext *cx, HandleObject proto) return &cval.toObject(); } -namespace { - -class AutoCompartmentRooter : private JS::CustomAutoRooter -{ - public: - explicit AutoCompartmentRooter(JSContext *cx, JSCompartment *comp - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : CustomAutoRooter(cx), compartment(comp) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - operator JSCompartment *() { - return compartment; - } - - JSCompartment *operator->() { - return compartment; - } - - protected: - virtual void trace(JSTracer *trc) - { - compartment->mark(); - } - - private: - JSCompartment *compartment; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -} /* anonymous namespace */ - bool JS::CompartmentOptions::extraWarnings(JSRuntime *rt) const { @@ -2383,42 +2350,8 @@ JS_NewGlobalObject(JSContext *cx, const JSClass *clasp, JSPrincipals *principals { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); - MOZ_ASSERT(!cx->isExceptionPending()); - JSRuntime *rt = cx->runtime(); - - Zone *zone; - if (options.zoneSpecifier() == JS::SystemZone) - zone = rt->gc.systemZone; - else if (options.zoneSpecifier() == JS::FreshZone) - zone = nullptr; - else - zone = static_cast(options.zonePointer()); - - AutoCompartmentRooter compartment(cx, NewCompartment(cx, zone, principals, options)); - if (!compartment) - return nullptr; - - // Lazily create the system zone. - if (!rt->gc.systemZone && options.zoneSpecifier() == JS::SystemZone) { - rt->gc.systemZone = compartment->zone(); - rt->gc.systemZone->isSystem = true; - } - - Rooted global(cx); - { - AutoCompartment ac(cx, compartment); - global = GlobalObject::create(cx, Valueify(clasp)); - } - - if (!global) - return nullptr; - - if (hookOption == JS::FireOnNewGlobalHook) - JS_FireOnNewGlobalObject(cx, global); - - return global; + return GlobalObject::new_(cx, Valueify(clasp), principals, hookOption, options); } JS_PUBLIC_API(void) diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 6abb4621f625..061fae830187 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -229,7 +229,7 @@ GlobalObject::initBuiltinConstructor(JSContext *cx, Handle global } GlobalObject * -GlobalObject::create(JSContext *cx, const Class *clasp) +GlobalObject::createInternal(JSContext *cx, const Class *clasp) { MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL); MOZ_ASSERT(clasp->trace == JS_GlobalObjectTraceHook); @@ -257,6 +257,48 @@ GlobalObject::create(JSContext *cx, const Class *clasp) return global; } +GlobalObject * +GlobalObject::new_(JSContext *cx, const Class *clasp, JSPrincipals *principals, + JS::OnNewGlobalHookOption hookOption, + const JS::CompartmentOptions &options) +{ + MOZ_ASSERT(!cx->isExceptionPending()); + MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); + + JSRuntime *rt = cx->runtime(); + + Zone *zone; + if (options.zoneSpecifier() == JS::SystemZone) + zone = rt->gc.systemZone; + else if (options.zoneSpecifier() == JS::FreshZone) + zone = nullptr; + else + zone = static_cast(options.zonePointer()); + + JSCompartment *compartment = NewCompartment(cx, zone, principals, options); + if (!compartment) + return nullptr; + + // Lazily create the system zone. + if (!rt->gc.systemZone && options.zoneSpecifier() == JS::SystemZone) { + rt->gc.systemZone = compartment->zone(); + rt->gc.systemZone->isSystem = true; + } + + Rooted global(cx); + { + AutoCompartment ac(cx, compartment); + global = GlobalObject::createInternal(cx, clasp); + if (!global) + return nullptr; + } + + if (hookOption == JS::FireOnNewGlobalHook) + JS_FireOnNewGlobalObject(cx, global); + + return global; +} + /* static */ bool GlobalObject::getOrCreateEval(JSContext *cx, Handle global, MutableHandleObject eval) diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index b364ccb44872..acc27cfccaf6 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -17,6 +17,7 @@ #include "js/Vector.h" #include "vm/ArrayBufferObject.h" #include "vm/ErrorObject.h" +#include "vm/Runtime.h" extern JSObject * js_InitSharedArrayBufferClass(JSContext *cx, js::HandleObject obj); @@ -259,8 +260,17 @@ class GlobalObject : public NativeObject template inline void setCreateArrayFromBuffer(Handle fun); + private: + // Disallow use of unqualified JSObject::create in GlobalObject. + static GlobalObject *create(...) MOZ_DELETE; + + friend struct ::JSRuntime; + static GlobalObject *createInternal(JSContext *cx, const Class *clasp); + public: - static GlobalObject *create(JSContext *cx, const Class *clasp); + static GlobalObject * + new_(JSContext *cx, const Class *clasp, JSPrincipals *principals, + JS::OnNewGlobalHookOption hookOption, const JS::CompartmentOptions &options); /* * Create a constructor function with the specified name and length using diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 2af4f545e2c9..c36e4c89553d 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -848,6 +848,9 @@ struct JSRuntime : public JS::shadow::Runtime, */ js::NativeObject *selfHostingGlobal_; + static js::GlobalObject * + createSelfHostingGlobal(JSContext *cx); + /* Space for interpreter frames. */ js::InterpreterStack interpreterStack_; diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 40fc4416c184..1d76a11549f7 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -49,14 +49,6 @@ selfHosting_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *rep PrintError(cx, stderr, message, report, true); } -static const JSClass self_hosting_global_class = { - "self-hosting-global", JSCLASS_GLOBAL_FLAGS, - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - JS_GlobalObjectTraceHook -}; - bool js::intrinsic_ToObject(JSContext *cx, unsigned argc, Value *vp) { @@ -1284,6 +1276,45 @@ js::FillSelfHostingCompileOptions(CompileOptions &options) #endif } +GlobalObject * +JSRuntime::createSelfHostingGlobal(JSContext *cx) +{ + MOZ_ASSERT(!cx->isExceptionPending()); + MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); + + JS::CompartmentOptions options; + options.setDiscardSource(true); + options.setZone(JS::FreshZone); + + JSCompartment *compartment = NewCompartment(cx, nullptr, nullptr, options); + if (!compartment) + return nullptr; + + static const Class shgClass = { + "self-hosting-global", JSCLASS_GLOBAL_FLAGS, + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + JS_GlobalObjectTraceHook + }; + + AutoCompartment ac(cx, compartment); + Rooted shg(cx, GlobalObject::createInternal(cx, &shgClass)); + if (!shg) + return nullptr; + + cx->runtime()->selfHostingGlobal_ = shg; + compartment->isSelfHosting = true; + compartment->isSystem = true; + + if (!GlobalObject::initSelfHostingBuiltins(cx, shg, intrinsic_functions)) + return nullptr; + + JS_FireOnNewGlobalObject(cx, shg); + + return shg; +} + bool JSRuntime::initSelfHosting(JSContext *cx) { @@ -1300,24 +1331,11 @@ JSRuntime::initSelfHosting(JSContext *cx) */ JS::AutoDisableGenerationalGC disable(cx->runtime()); - JS::CompartmentOptions compartmentOptions; - compartmentOptions.setDiscardSource(true); - if (!(selfHostingGlobal_ = MaybeNativeObject(JS_NewGlobalObject(cx, &self_hosting_global_class, - nullptr, JS::DontFireOnNewGlobalHook, - compartmentOptions)))) - { - return false; - } - - JSAutoCompartment ac(cx, selfHostingGlobal_); - Rooted shg(cx, &selfHostingGlobal_->as()); - selfHostingGlobal_->compartment()->isSelfHosting = true; - selfHostingGlobal_->compartment()->isSystem = true; - - if (!GlobalObject::initSelfHostingBuiltins(cx, shg, intrinsic_functions)) + Rooted shg(cx, JSRuntime::createSelfHostingGlobal(cx)); + if (!shg) return false; - JS_FireOnNewGlobalObject(cx, shg); + JSAutoCompartment ac(cx, shg); CompileOptions options(cx); FillSelfHostingCompileOptions(options); @@ -1329,7 +1347,7 @@ JSRuntime::initSelfHosting(JSContext *cx) */ JSErrorReporter oldReporter = JS_SetErrorReporter(cx->runtime(), selfHosting_ErrorReporter); RootedValue rv(cx); - bool ok = false; + bool ok = true; char *filename = getenv("MOZ_SELFHOSTEDJS"); if (filename) { @@ -1345,10 +1363,10 @@ JSRuntime::initSelfHosting(JSContext *cx) if (!src || !DecompressString(compressed, compressedLen, reinterpret_cast(src.get()), srcLen)) { - return false; + ok = false; } - ok = Evaluate(cx, shg, options, src, srcLen, &rv); + ok = ok && Evaluate(cx, shg, options, src, srcLen, &rv); } JS_SetErrorReporter(cx->runtime(), oldReporter); return ok; From e9df582545d1ac400e9efba956bf1e89b8b51055 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 16 Dec 2014 11:41:36 -0500 Subject: [PATCH 022/130] Backed out changeset 938abddb1a2d (bug 1080995) for Linux mochitest failures. --- dom/media/gstreamer/GStreamerFunctionList.h | 4 -- dom/media/gstreamer/GStreamerReader.cpp | 63 +-------------------- dom/media/gstreamer/GStreamerReader.h | 6 +- 3 files changed, 4 insertions(+), 69 deletions(-) diff --git a/dom/media/gstreamer/GStreamerFunctionList.h b/dom/media/gstreamer/GStreamerFunctionList.h index 5522fee373f4..72792949212c 100644 --- a/dom/media/gstreamer/GStreamerFunctionList.h +++ b/dom/media/gstreamer/GStreamerFunctionList.h @@ -88,9 +88,7 @@ GST_FUNC(LIBGSTREAMER, gst_pad_add_event_probe) GST_FUNC(LIBGSTREAMER, gst_pad_alloc_buffer) GST_FUNC(LIBGSTREAMER, gst_pad_get_negotiated_caps) GST_FUNC(LIBGSTREAMER, gst_pad_set_bufferalloc_function) -GST_FUNC(LIBGSTREAMER, gst_registry_find_plugin) GST_FUNC(LIBGSTREAMER, gst_registry_get_default) -GST_FUNC(LIBGSTREAMER, gst_plugin_feature_get_type) GST_FUNC(LIBGSTREAMER, gst_segment_set_newsegment) GST_FUNC(LIBGSTVIDEO, gst_video_format_get_component_height) GST_FUNC(LIBGSTVIDEO, gst_video_format_get_component_offset) @@ -132,8 +130,6 @@ GST_FUNC(LIBGSTREAMER, gst_object_get_type) GST_FUNC(LIBGSTREAMER, gst_pad_add_probe) GST_FUNC(LIBGSTREAMER, gst_pad_get_current_caps) GST_FUNC(LIBGSTREAMER, gst_pad_probe_info_get_query) -GST_FUNC(LIBGSTREAMER, gst_plugin_feature_get_plugin) -GST_FUNC(LIBGSTREAMER, gst_plugin_get_version) GST_FUNC(LIBGSTREAMER, gst_query_add_allocation_meta) GST_FUNC(LIBGSTREAMER, gst_query_add_allocation_param) GST_FUNC(LIBGSTREAMER, gst_query_add_allocation_pool) diff --git a/dom/media/gstreamer/GStreamerReader.cpp b/dom/media/gstreamer/GStreamerReader.cpp index c3e9814365a0..18d99d4cd251 100644 --- a/dom/media/gstreamer/GStreamerReader.cpp +++ b/dom/media/gstreamer/GStreamerReader.cpp @@ -15,7 +15,6 @@ #endif #include "GStreamerFormatHelper.h" #include "VideoUtils.h" -#include "mozilla/ArrayUtils.h" #include "mozilla/dom/TimeRanges.h" #include "mozilla/Endian.h" #include "mozilla/Preferences.h" @@ -23,10 +22,6 @@ #include "GStreamerLoader.h" #include "gfx2DGlue.h" -#include -#include -#include - namespace mozilla { using namespace gfx; @@ -1173,71 +1168,17 @@ GStreamerReader::PlayElementAddedCb(GstBin *aBin, GstElement *aElement, g_free(name); } -/** - * Helper to calculate the length of a C string constant at compile time. - * Substract one from the array length for the trailing null. - */ -#define STRING_LENGTH(string) (ArrayLength(string) - 1) - -/** Check proposed element factories for acceptability. */ -bool GStreamerReader::IsFactoryBlacklisted(GstElementFactory* aFactory) -{ - // Retrieve version string for the element. -#if GST_VERSION_MAJOR >= 1 - GstPlugin* plugin = gst_plugin_feature_get_plugin(GST_PLUGIN_FEATURE(aFactory)); - const gchar* version = plugin ? gst_plugin_get_version(plugin) : "unknown"; -#else - const gchar* plugin_name = GST_PLUGIN_FEATURE(aFactory)->plugin_name; - if (!plugin_name) { - return true; - } - GstPlugin* plugin = gst_default_registry_find_plugin(plugin_name); - const gchar* version = plugin ? plugin->desc.version : "unknown"; -#endif - if (!plugin) { - return true; - } - // Retrieve the element name. - const gchar* name = gst_element_get_name(aFactory); - - // Reject h264parse <= 0.10.23. - const char badname[] = "h264parse"; - const char version_base[] = "0.10."; - // Length needed to compare with version base plus two more digits. - const size_t version_min = STRING_LENGTH(version_base) + 2; - if (strcmp(name, badname) == 0 && - strncmp(version, version_base, strlen(version_base)) == 0 && - strlen(version) >= version_min && - atoi(version + strlen(version_base)) <= 23) { - gst_object_unref(plugin); - return true; - } - - // Clean up. - gst_object_unref(plugin); - - // Factory isn't blacklisted. - return false; -} - -/** Filter elements to control autoplug selection. */ bool GStreamerReader::ShouldAutoplugFactory(GstElementFactory* aFactory, GstCaps* aCaps) { - /* Blacklist unstable elements. */ - if (IsFactoryBlacklisted(aFactory)) { - return false; - } - - /* Filter Demuxers and Decoders for supported formats. */ bool autoplug; - const gchar* klass = gst_element_factory_get_klass(aFactory); + const gchar *klass = gst_element_factory_get_klass(aFactory); if (strstr(klass, "Demuxer") && !strstr(klass, "Metadata")) { autoplug = GStreamerFormatHelper::Instance()->CanHandleContainerCaps(aCaps); } else if (strstr(klass, "Decoder") && !strstr(klass, "Generic")) { autoplug = GStreamerFormatHelper::Instance()->CanHandleCodecCaps(aCaps); } else { - /* Let everything else be autoplugged. */ + /* we only filter demuxers and decoders, let everything else be autoplugged */ autoplug = true; } diff --git a/dom/media/gstreamer/GStreamerReader.h b/dom/media/gstreamer/GStreamerReader.h index 5c939e3b9498..548164df6414 100644 --- a/dom/media/gstreamer/GStreamerReader.h +++ b/dom/media/gstreamer/GStreamerReader.h @@ -166,11 +166,9 @@ private: static void PlayElementAddedCb(GstBin *aBin, GstElement *aElement, gpointer *aUserData); - /* Called during decoding, to decide whether a (sub)stream should be - * decoded or ignored. */ + /* Called during decoding, to decide whether a (sub)stream should be decoded or + * ignored */ static bool ShouldAutoplugFactory(GstElementFactory* aFactory, GstCaps* aCaps); - /* Called from ShouldAutoplugFactory to check for blacklisted elements. */ - static bool IsFactoryBlacklisted(GstElementFactory* aFactory); /* Called by decodebin during autoplugging. We use it to apply our * container/codec whitelist. From f18311f96bc3cf24d7b3bba5d042855e0ee49c2e Mon Sep 17 00:00:00 2001 From: Philip Chee Date: Wed, 17 Dec 2014 01:09:12 +0800 Subject: [PATCH 023/130] Bug 1110036 - "Save As" stops working from "Page Info" > "Media" pane. Progress of downloading is 0% forever r=sstamm --- toolkit/content/contentAreaUtils.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/toolkit/content/contentAreaUtils.js b/toolkit/content/contentAreaUtils.js index 3554cd60f0d8..44e635d4a4f5 100644 --- a/toolkit/content/contentAreaUtils.js +++ b/toolkit/content/contentAreaUtils.js @@ -424,7 +424,7 @@ function internalPersist(persistArgs) .QueryInterface(Components.interfaces.nsILoadContext); persist.saveURI(persistArgs.sourceURI, persistArgs.sourceCacheKey, persistArgs.sourceReferrer, - Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE, + Components.interfaces.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE, persistArgs.sourcePostData, null, targetFileURL, privacyContext); } } @@ -663,9 +663,9 @@ function DownloadURL(aURL, aFileName, aInitiatingDocument) { // For private browsing, try to get document out of the most recent browser // window, or provide our own if there's no browser window. let isPrivate = aInitiatingDocument.defaultView - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsILoadContext) + .QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIWebNavigation) + .QueryInterface(Components.interfaces.nsILoadContext) .usePrivateBrowsing; let fileInfo = new FileInfo(aFileName); From 3e7955b2538f38a9866f4fbb5c2d8f30c95db374 Mon Sep 17 00:00:00 2001 From: Georg Fritzsche Date: Tue, 16 Dec 2014 18:10:28 +0100 Subject: [PATCH 024/130] Bug 1101491 - Properly record SEARCH_DEFAULT_ENGINE on search service init and change events. r=mconley --- browser/base/content/browser.js | 29 ----------------------------- browser/components/nsBrowserGlue.js | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 20de9f3d42c8..a0d6054c9aa4 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -403,33 +403,6 @@ const gSessionHistoryObserver = { } }; -const gGatherTelemetryObserver = { - observe: function(subject, topic, data) { - if (topic != "gather-telemetry") { - return; - } - - let engine; - try { - engine = Services.search.defaultEngine; - } catch (e) {} - let name; - - if (!engine) { - name = "NONE"; - } else if (engine.identifier) { - name = engine.identifier; - } else if (engine.name) { - name = "other-" + engine.name; - } else { - name = "UNDEFINED"; - } - - let engines = Services.telemetry.getKeyedHistogramById("SEARCH_DEFAULT_ENGINE"); - engines.add(name, true) - }, -}; - /** * Given a starting docshell and a URI to look up, find the docshell the URI * is loaded in. @@ -1213,7 +1186,6 @@ var gBrowserInit = { Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false); Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false); Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false); - Services.obs.addObserver(gGatherTelemetryObserver, "gather-telemetry", false); window.messageManager.addMessageListener("Browser:URIFixup", gKeywordURIFixup); window.messageManager.addMessageListener("Browser:LoadURI", RedirectLoad); @@ -1534,7 +1506,6 @@ var gBrowserInit = { Services.obs.removeObserver(gXPInstallObserver, "addon-install-blocked"); Services.obs.removeObserver(gXPInstallObserver, "addon-install-failed"); Services.obs.removeObserver(gXPInstallObserver, "addon-install-complete"); - Services.obs.removeObserver(gGatherTelemetryObserver, "gather-telemetry"); window.messageManager.removeMessageListener("Browser:URIFixup", gKeywordURIFixup); window.messageManager.removeMessageListener("Browser:LoadURI", RedirectLoad); diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index a9f02ecda857..a89fd158a2ee 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -144,6 +144,28 @@ const BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS = 1; // days we will try to create a new one more aggressively. const BOOKMARKS_BACKUP_MAX_INTERVAL_DAYS = 3; +// Record the current default search engine in Telemetry. +function recordDefaultSearchEngine() { + let engine; + try { + engine = Services.search.defaultEngine; + } catch (e) {} + let name; + + if (!engine) { + name = "NONE"; + } else if (engine.identifier) { + name = engine.identifier; + } else if (engine.name) { + name = "other-" + engine.name; + } else { + name = "UNDEFINED"; + } + + let engines = Services.telemetry.getKeyedHistogramById("SEARCH_DEFAULT_ENGINE"); + engines.add(name, true) +} + // Factory object const BrowserGlueServiceFactory = { _instance: null, @@ -402,12 +424,14 @@ BrowserGlue.prototype = { ss.defaultEngine = ss.currentEngine; else ss.currentEngine = ss.defaultEngine; + recordDefaultSearchEngine(); break; case "browser-search-service": if (data != "init-complete") return; Services.obs.removeObserver(this, "browser-search-service"); this._syncSearchEngines(); + recordDefaultSearchEngine(); break; #ifdef NIGHTLY_BUILD case "nsPref:changed": From 81b90b829ce56dd5abc7fa07d9cec4c7076f61e9 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:01 -0800 Subject: [PATCH 025/130] Bug 1064439, part 1a - Remove trailing whitespace from nsDocShellTreeOwner. r=jst --- embedding/browser/nsDocShellTreeOwner.cpp | 90 +++++++++++------------ embedding/browser/nsDocShellTreeOwner.h | 22 ++---- 2 files changed, 50 insertions(+), 62 deletions(-) diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index 88c388a637e9..f561e6a4269a 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -103,7 +103,7 @@ GetDOMEventTarget(nsWebBrowser* inBrowser, EventTarget** aTarget) //***************************************************************************** nsDocShellTreeOwner::nsDocShellTreeOwner() : - mWebBrowser(nullptr), + mWebBrowser(nullptr), mTreeOwner(nullptr), mPrimaryContentShell(nullptr), mWebBrowserChrome(nullptr), @@ -121,7 +121,7 @@ nsDocShellTreeOwner::~nsDocShellTreeOwner() //***************************************************************************** // nsDocShellTreeOwner::nsISupports -//***************************************************************************** +//***************************************************************************** NS_IMPL_ADDREF(nsDocShellTreeOwner) NS_IMPL_RELEASE(nsDocShellTreeOwner) @@ -139,7 +139,7 @@ NS_INTERFACE_MAP_END //***************************************************************************** // nsDocShellTreeOwner::nsIInterfaceRequestor -//***************************************************************************** +//***************************************************************************** NS_IMETHODIMP nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink) @@ -188,7 +188,7 @@ nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink) //***************************************************************************** // nsDocShellTreeOwner::nsIDocShellTreeOwner -//***************************************************************************** +//***************************************************************************** NS_IMETHODIMP nsDocShellTreeOwner::FindItemWithName(const char16_t* aName, @@ -198,7 +198,7 @@ nsDocShellTreeOwner::FindItemWithName(const char16_t* aName, { NS_ENSURE_ARG(aName); NS_ENSURE_ARG_POINTER(aFoundItem); - *aFoundItem = nullptr; // if we don't find one, we return NS_OK and a null result + *aFoundItem = nullptr; // if we don't find one, we return NS_OK and a null result nsresult rv; nsAutoString name(aName); @@ -402,7 +402,7 @@ nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem, NS_ENSURE_SUCCESS(presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE), NS_ERROR_FAILURE); - + nsRect shellArea = presContext->GetVisibleArea(); int32_t browserCX = presContext->AppUnitsToDevPixels(shellArea.width); @@ -441,13 +441,13 @@ nsDocShellTreeOwner::GetTargetableShellCount(uint32_t* aResult) //***************************************************************************** // nsDocShellTreeOwner::nsIBaseWindow -//***************************************************************************** +//***************************************************************************** NS_IMETHODIMP nsDocShellTreeOwner::InitWindow(nativeWindow aParentNativeWindow, nsIWidget* aParentWidget, int32_t aX, - int32_t aY, int32_t aCX, int32_t aCY) + int32_t aY, int32_t aCX, int32_t aCY) { return NS_ERROR_NULL_POINTER; } @@ -677,14 +677,14 @@ nsDocShellTreeOwner::SetTitle(const char16_t* aTitle) //***************************************************************************** // nsDocShellTreeOwner::nsIWebProgressListener -//***************************************************************************** +//***************************************************************************** NS_IMETHODIMP nsDocShellTreeOwner::OnProgressChange(nsIWebProgress* aProgress, nsIRequest* aRequest, int32_t aCurSelfProgress, - int32_t aMaxSelfProgress, + int32_t aMaxSelfProgress, int32_t aCurTotalProgress, int32_t aMaxTotalProgress) { @@ -712,7 +712,7 @@ nsDocShellTreeOwner::OnLocationChange(nsIWebProgress* aWebProgress, return NS_OK; } -NS_IMETHODIMP +NS_IMETHODIMP nsDocShellTreeOwner::OnStatusChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest, nsresult aStatus, @@ -721,9 +721,9 @@ nsDocShellTreeOwner::OnStatusChange(nsIWebProgress* aWebProgress, return NS_OK; } -NS_IMETHODIMP -nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress *aWebProgress, - nsIRequest *aRequest, +NS_IMETHODIMP +nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, uint32_t state) { return NS_OK; @@ -732,11 +732,11 @@ nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress *aWebProgress, //***************************************************************************** // nsDocShellTreeOwner: Helpers -//***************************************************************************** +//***************************************************************************** //***************************************************************************** // nsDocShellTreeOwner: Accessors -//***************************************************************************** +//***************************************************************************** void nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser) @@ -759,7 +759,7 @@ nsDocShellTreeOwner::WebBrowser() NS_IMETHODIMP nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner) -{ +{ if(aTreeOwner) { nsCOMPtr webBrowserChrome(do_GetInterface(aTreeOwner)); NS_ENSURE_TRUE(webBrowserChrome, NS_ERROR_INVALID_ARG); @@ -819,7 +819,7 @@ nsDocShellTreeOwner::AddChromeListeners() return NS_ERROR_FAILURE; // install tooltips - if ( !mChromeTooltipListener ) { + if ( !mChromeTooltipListener ) { nsCOMPtr tooltipListener(do_QueryInterface(webBrowserChrome)); if ( tooltipListener ) { @@ -833,7 +833,7 @@ nsDocShellTreeOwner::AddChromeListeners() rv = NS_ERROR_OUT_OF_MEMORY; } } - + // install context menus if ( !mChromeContextMenuListener ) { nsCOMPtr @@ -1000,10 +1000,10 @@ NS_IMPL_ISUPPORTS(DefaultTooltipTextProvider, nsITooltipTextProvider) DefaultTooltipTextProvider::DefaultTooltipTextProvider() { // There are certain element types which we don't want to use - // as tool tip text. + // as tool tip text. mTag_dialog = do_GetAtom("dialog"); mTag_dialogheader = do_GetAtom("dialogheader"); - mTag_window = do_GetAtom("window"); + mTag_window = do_GetAtom("window"); } // @@ -1131,7 +1131,7 @@ NS_IMPL_ISUPPORTS(ChromeTooltipListener, nsIDOMEventListener) // ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* inBrowser, - nsIWebBrowserChrome* inChrome) + nsIWebBrowserChrome* inChrome) : mWebBrowser(inBrowser), mWebBrowserChrome(inChrome), mTooltipListenerInstalled(false), mMouseClientX(0), mMouseClientY(0), @@ -1224,12 +1224,12 @@ ChromeTooltipListener::RemoveChromeListeners ( ) if ( mTooltipListenerInstalled ) RemoveTooltipListener(); - + mEventTarget = nullptr; - + // it really doesn't matter if these fail... return NS_OK; - + } // RemoveChromeTooltipListeners @@ -1239,7 +1239,7 @@ ChromeTooltipListener::RemoveChromeListeners ( ) // // Unsubscribe from all the various tooltip events that we were listening to // -NS_IMETHODIMP +NS_IMETHODIMP ChromeTooltipListener::RemoveTooltipListener() { if (mEventTarget) { @@ -1299,7 +1299,7 @@ ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent) if (!mouseEvent) return NS_OK; - // stash the coordinates of the event so that we can still get back to it from within the + // stash the coordinates of the event so that we can still get back to it from within the // timer callback. On win32, we'll get a MouseMove event even when a popup goes away -- // even when the mouse doesn't change position! To get around this, we make sure the // mouse has really moved before proceeding. @@ -1361,17 +1361,17 @@ ChromeTooltipListener::ShowTooltip(int32_t inXCoords, int32_t inYCoords, const nsAString & inTipText) { nsresult rv = NS_OK; - + // do the work to call the client nsCOMPtr tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); if ( tooltipListener ) { - rv = tooltipListener->OnShowTooltip ( inXCoords, inYCoords, PromiseFlatString(inTipText).get() ); + rv = tooltipListener->OnShowTooltip ( inXCoords, inYCoords, PromiseFlatString(inTipText).get() ); if ( NS_SUCCEEDED(rv) ) mShowingTooltip = true; } return rv; - + } // ShowTooltip @@ -1385,7 +1385,7 @@ NS_IMETHODIMP ChromeTooltipListener::HideTooltip() { nsresult rv = NS_OK; - + // shut down the relevant timers if ( mTooltipTimer ) { mTooltipTimer->Cancel(); @@ -1405,14 +1405,14 @@ ChromeTooltipListener::HideTooltip() } return rv; - + } // HideTooltip // // sTooltipCallback // -// A timer callback, fired when the mouse has hovered inside of a frame for the +// A timer callback, fired when the mouse has hovered inside of a frame for the // appropriate amount of time. Getting to this point means that we should show the // tooltip, but only after we determine there is an appropriate TITLE element. // @@ -1468,7 +1468,7 @@ ChromeTooltipListener::sTooltipCallback(nsITimer *aTimer, self->mTooltipTextProvider->GetNodeText( self->mPossibleTooltipNode, getter_Copies(tooltipText), &textFound); - + if (textFound) { nsString tipText(tooltipText); nsIntPoint screenDot = widget->WidgetToScreenOffset(); @@ -1477,11 +1477,11 @@ ChromeTooltipListener::sTooltipCallback(nsITimer *aTimer, tipText); } } - + // release tooltip target if there is one, NO MATTER WHAT self->mPossibleTooltipNode = nullptr; } // if "self" data valid - + } // sTooltipCallback @@ -1491,7 +1491,7 @@ NS_IMPL_ISUPPORTS(ChromeContextMenuListener, nsIDOMEventListener) // // ChromeTooltipListener ctor // -ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) +ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) : mContextMenuListenerInstalled(false), mWebBrowser(inBrowser), mWebBrowserChrome(inChrome) @@ -1532,9 +1532,9 @@ ChromeContextMenuListener::AddContextMenuListener() // // RemoveContextMenuListener // -// Unsubscribe from all the various context menu events that we were listening to. +// Unsubscribe from all the various context menu events that we were listening to. // -NS_IMETHODIMP +NS_IMETHODIMP ChromeContextMenuListener::RemoveContextMenuListener() { if (mEventTarget) { @@ -1586,12 +1586,12 @@ ChromeContextMenuListener::RemoveChromeListeners() { if ( mContextMenuListenerInstalled ) RemoveContextMenuListener(); - + mEventTarget = nullptr; - + // it really doesn't matter if these fail... return NS_OK; - + } // RemoveChromeTooltipListeners @@ -1633,7 +1633,7 @@ ChromeContextMenuListener::HandleEvent(nsIDOMEvent* aMouseEvent) nsCOMPtr menuInfo; if (menuListener2) { menuInfoImpl = new nsContextMenuInfo; - menuInfo = menuInfoImpl; + menuInfo = menuInfoImpl; } uint32_t flags = nsIContextMenuListener::CONTEXT_NONE; @@ -1742,8 +1742,8 @@ ChromeContextMenuListener::HandleEvent(nsIDOMEvent* aMouseEvent) // and if the listener is ready for that (only nsIContextMenuListener2 and up) if (menuInfoImpl && menuInfoImpl->HasBackgroundImage(targetDOMnode)) { flags2 |= nsIContextMenuListener2::CONTEXT_BACKGROUND_IMAGE; - // For the embedder to get the correct background image - // targetDOMnode must point to the original node. + // For the embedder to get the correct background image + // targetDOMnode must point to the original node. targetDOMnode = do_QueryInterface(targetNode); } } diff --git a/embedding/browser/nsDocShellTreeOwner.h b/embedding/browser/nsDocShellTreeOwner.h index 608d0b7d173a..998d50eb58e7 100644 --- a/embedding/browser/nsDocShellTreeOwner.h +++ b/embedding/browser/nsDocShellTreeOwner.h @@ -84,7 +84,7 @@ protected: virtual ~nsDocShellTreeOwner(); void WebBrowser(nsWebBrowser* aWebBrowser); - + nsWebBrowser* WebBrowser(); NS_IMETHOD SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner); NS_IMETHOD SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome); @@ -117,7 +117,7 @@ protected: // Weak References nsWebBrowser* mWebBrowser; nsIDocShellTreeOwner* mTreeOwner; - nsIDocShellTreeItem* mPrimaryContentShell; + nsIDocShellTreeItem* mPrimaryContentShell; nsIWebBrowserChrome* mWebBrowserChrome; nsIEmbeddingSiteWindow* mOwnerWin; @@ -125,7 +125,7 @@ protected: nsWeakPtr mWebBrowserChromeWeak; // nsIWebBrowserChrome - // the objects that listen for chrome events like context menus and tooltips. + // the objects that listen for chrome events like context menus and tooltips. // They are separate objects to avoid circular references between |this| // and the DOM. These are strong, owning refs. ChromeTooltipListener* mChromeTooltipListener; @@ -151,7 +151,7 @@ protected: public: NS_DECL_ISUPPORTS - + ChromeTooltipListener ( nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) ; NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); @@ -222,7 +222,7 @@ protected: public: NS_DECL_ISUPPORTS - + ChromeContextMenuListener ( nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) ; // nsIDOMContextMenuListener @@ -249,15 +249,3 @@ private: #endif /* nsDocShellTreeOwner_h__ */ - - - - - - - - - - - - From f7c0e804bad8a915985966363e32a4a23380e7a8 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:01 -0800 Subject: [PATCH 026/130] Bug 1064439, part 1b - Get rid of if( in nsDocShellTreeOwner. r=jst --- embedding/browser/nsDocShellTreeOwner.cpp | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index f561e6a4269a..f41b3f3e4b60 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -146,7 +146,7 @@ nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink) { NS_ENSURE_ARG_POINTER(aSink); - if(NS_SUCCEEDED(QueryInterface(aIID, aSink))) + if (NS_SUCCEEDED(QueryInterface(aIID, aSink))) return NS_OK; if (aIID.Equals(NS_GET_IID(nsIWebBrowserChromeFocus))) { @@ -207,14 +207,14 @@ nsDocShellTreeOwner::FindItemWithName(const char16_t* aName, return NS_OK; // stymied /* special cases */ - if(name.IsEmpty()) + if (name.IsEmpty()) return NS_OK; - if(name.LowerCaseEqualsLiteral("_blank")) + if (name.LowerCaseEqualsLiteral("_blank")) return NS_OK; // _main is an IE target which should be case-insensitive but isn't // see bug 217886 for details // XXXbz what if our browser isn't targetable? We need to handle that somehow. - if(name.LowerCaseEqualsLiteral("_content") || name.EqualsLiteral("_main")) { + if (name.LowerCaseEqualsLiteral("_content") || name.EqualsLiteral("_main")) { *aFoundItem = mWebBrowser->mDocShell; NS_IF_ADDREF(*aFoundItem); return NS_OK; @@ -231,7 +231,7 @@ nsDocShellTreeOwner::FindItemWithName(const char16_t* aName, } // next, if we have a parent and it isn't the requestor, ask it - if(mTreeOwner) { + if (mTreeOwner) { nsCOMPtr reqAsTreeOwner(do_QueryInterface(aRequestor)); if (mTreeOwner != reqAsTreeOwner) return mTreeOwner->FindItemWithName(aName, mWebBrowser->mDocShell, @@ -326,7 +326,7 @@ nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem* aContentShell, bool aPrimary, bool aTargetable, const nsAString& aID) { - if(mTreeOwner) + if (mTreeOwner) return mTreeOwner->ContentShellAdded(aContentShell, aPrimary, aTargetable, aID); @@ -338,10 +338,10 @@ nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem* aContentShell, NS_IMETHODIMP nsDocShellTreeOwner::ContentShellRemoved(nsIDocShellTreeItem* aContentShell) { - if(mTreeOwner) + if (mTreeOwner) return mTreeOwner->ContentShellRemoved(aContentShell); - if(mPrimaryContentShell == aContentShell) + if (mPrimaryContentShell == aContentShell) mPrimaryContentShell = nullptr; return NS_OK; @@ -369,10 +369,10 @@ nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem, NS_ENSURE_STATE(mTreeOwner || webBrowserChrome); - if(mTreeOwner) + if (mTreeOwner) return mTreeOwner->SizeShellTo(aShellItem, aCX, aCY); - if(aShellItem == mWebBrowser->mDocShell) + if (aShellItem == mWebBrowser->mDocShell) return webBrowserChrome->SizeBrowserTo(aCX, aCY); nsCOMPtr webNav(do_QueryInterface(aShellItem)); @@ -430,7 +430,7 @@ nsDocShellTreeOwner::GetPersistence(bool* aPersistPosition, NS_IMETHODIMP nsDocShellTreeOwner::GetTargetableShellCount(uint32_t* aResult) { - if(mTreeOwner) { + if (mTreeOwner) { mTreeOwner->GetTargetableShellCount(aResult); } else { *aResult = 0; @@ -760,7 +760,7 @@ nsDocShellTreeOwner::WebBrowser() NS_IMETHODIMP nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner) { - if(aTreeOwner) { + if (aTreeOwner) { nsCOMPtr webBrowserChrome(do_GetInterface(aTreeOwner)); NS_ENSURE_TRUE(webBrowserChrome, NS_ERROR_INVALID_ARG); NS_ENSURE_SUCCESS(SetWebBrowserChrome(webBrowserChrome), NS_ERROR_INVALID_ARG); @@ -779,7 +779,7 @@ nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner) NS_IMETHODIMP nsDocShellTreeOwner::SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome) { - if(!aWebBrowserChrome) { + if (!aWebBrowserChrome) { mWebBrowserChrome = nullptr; mOwnerWin = nullptr; mOwnerRequestor = nullptr; From d91383288a554d546acc6dfe8b180f4a7f15a9f9 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:01 -0800 Subject: [PATCH 027/130] Bug 1064439, part 1c - Get rid of if ( foo ) in nsDocShellTreeOwner. r=jst --- embedding/browser/nsDocShellTreeOwner.cpp | 66 +++++++++++------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index f41b3f3e4b60..e61c20295f24 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -741,7 +741,7 @@ nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress *aWebProgress, void nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser) { - if ( !aWebBrowser ) + if (!aWebBrowser) RemoveChromeListeners(); if (aWebBrowser != mWebBrowser) { mPrompter = 0; @@ -819,13 +819,13 @@ nsDocShellTreeOwner::AddChromeListeners() return NS_ERROR_FAILURE; // install tooltips - if ( !mChromeTooltipListener ) { + if (!mChromeTooltipListener) { nsCOMPtr tooltipListener(do_QueryInterface(webBrowserChrome)); - if ( tooltipListener ) { + if (tooltipListener) { mChromeTooltipListener = new ChromeTooltipListener(mWebBrowser, webBrowserChrome); - if ( mChromeTooltipListener ) { + if (mChromeTooltipListener) { NS_ADDREF(mChromeTooltipListener); rv = mChromeTooltipListener->AddChromeListeners(); } @@ -835,15 +835,15 @@ nsDocShellTreeOwner::AddChromeListeners() } // install context menus - if ( !mChromeContextMenuListener ) { + if (!mChromeContextMenuListener) { nsCOMPtr contextListener2(do_QueryInterface(webBrowserChrome)); nsCOMPtr contextListener(do_QueryInterface(webBrowserChrome)); - if ( contextListener2 || contextListener ) { + if (contextListener2 || contextListener) { mChromeContextMenuListener = new ChromeContextMenuListener(mWebBrowser, webBrowserChrome); - if ( mChromeContextMenuListener ) { + if (mChromeContextMenuListener) { NS_ADDREF(mChromeContextMenuListener); rv = mChromeContextMenuListener->AddChromeListeners(); } @@ -872,11 +872,11 @@ nsDocShellTreeOwner::AddChromeListeners() NS_IMETHODIMP nsDocShellTreeOwner::RemoveChromeListeners() { - if ( mChromeTooltipListener ) { + if (mChromeTooltipListener) { mChromeTooltipListener->RemoveChromeListeners(); NS_RELEASE(mChromeTooltipListener); } - if ( mChromeContextMenuListener ) { + if (mChromeContextMenuListener) { mChromeContextMenuListener->RemoveChromeListeners(); NS_RELEASE(mChromeContextMenuListener); } @@ -1063,7 +1063,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText, while ( !found && current ) { nsCOMPtr currElement ( do_QueryInterface(current) ); - if ( currElement ) { + if (currElement) { nsCOMPtr content(do_QueryInterface(currElement)); if (content) { nsIAtom *tagAtom = content->Tag(); @@ -1072,7 +1072,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText, tagAtom != mTag_window) { // first try the normal title attribute... currElement->GetAttribute(NS_LITERAL_STRING("title"), outText); - if ( outText.Length() ) + if (outText.Length()) found = true; else { // ...ok, that didn't work, try it in the XLink namespace @@ -1082,7 +1082,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText, nsCOMPtr uri(linkContent->GetURIExternal()); if (uri) { currElement->GetAttributeNS(NS_LITERAL_STRING("http://www.w3.org/1999/xlink"), NS_LITERAL_STRING("title"), outText); - if ( outText.Length() ) + if (outText.Length()) found = true; } } @@ -1097,7 +1097,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText, nsIContent* child = childNodes->Item(i); if (child->IsSVG(nsGkAtoms::title)) { static_cast(child)->GetTextContent(outText); - if ( outText.Length() ) + if (outText.Length()) found = true; break; } @@ -1110,7 +1110,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText, } // not found here, walk up to the parent and keep trying - if ( !found ) { + if (!found) { nsCOMPtr temp ( current ); temp->GetParentNode(getter_AddRefs(current)); } @@ -1170,9 +1170,9 @@ ChromeTooltipListener::AddChromeListeners() // the embedding chrome cares. nsresult rv = NS_OK; nsCOMPtr tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); - if ( tooltipListener && !mTooltipListenerInstalled ) { + if (tooltipListener && !mTooltipListenerInstalled) { rv = AddTooltipListener(); - if ( NS_FAILED(rv) ) + if (NS_FAILED(rv)) return rv; } @@ -1222,7 +1222,7 @@ ChromeTooltipListener::RemoveChromeListeners ( ) { HideTooltip(); - if ( mTooltipListenerInstalled ) + if (mTooltipListenerInstalled) RemoveTooltipListener(); mEventTarget = nullptr; @@ -1306,7 +1306,7 @@ ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent) int32_t newMouseX, newMouseY; mouseEvent->GetClientX(&newMouseX); mouseEvent->GetClientY(&newMouseY); - if ( mMouseClientX == newMouseX && mMouseClientY == newMouseY ) + if (mMouseClientX == newMouseX && mMouseClientY == newMouseY) return NS_OK; // Filter out minor mouse movements. @@ -1319,17 +1319,17 @@ ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent) mouseEvent->GetScreenX(&mMouseScreenX); mouseEvent->GetScreenY(&mMouseScreenY); - if ( mTooltipTimer ) { + if (mTooltipTimer) { mTooltipTimer->Cancel(); } if (!mShowingTooltip && !mTooltipShownOnce) { mTooltipTimer = do_CreateInstance("@mozilla.org/timer;1"); - if ( mTooltipTimer ) { + if (mTooltipTimer) { nsCOMPtr eventTarget = aMouseEvent->InternalDOMEvent()->GetTarget(); - if ( eventTarget ) + if (eventTarget) mPossibleTooltipNode = do_QueryInterface(eventTarget); - if ( mPossibleTooltipNode ) { + if (mPossibleTooltipNode) { nsresult rv = mTooltipTimer->InitWithFuncCallback(sTooltipCallback, this, LookAndFeel::GetInt(LookAndFeel::eIntID_TooltipDelay, 500), @@ -1364,9 +1364,9 @@ ChromeTooltipListener::ShowTooltip(int32_t inXCoords, int32_t inYCoords, // do the work to call the client nsCOMPtr tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); - if ( tooltipListener ) { + if (tooltipListener) { rv = tooltipListener->OnShowTooltip ( inXCoords, inYCoords, PromiseFlatString(inTipText).get() ); - if ( NS_SUCCEEDED(rv) ) + if (NS_SUCCEEDED(rv)) mShowingTooltip = true; } @@ -1387,7 +1387,7 @@ ChromeTooltipListener::HideTooltip() nsresult rv = NS_OK; // shut down the relevant timers - if ( mTooltipTimer ) { + if (mTooltipTimer) { mTooltipTimer->Cancel(); mTooltipTimer = nullptr; // release tooltip target @@ -1395,11 +1395,11 @@ ChromeTooltipListener::HideTooltip() } // if we're showing the tip, tell the chrome to hide it - if ( mShowingTooltip ) { + if (mShowingTooltip) { nsCOMPtr tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); - if ( tooltipListener ) { + if (tooltipListener) { rv = tooltipListener->OnHideTooltip ( ); - if ( NS_SUCCEEDED(rv) ) + if (NS_SUCCEEDED(rv)) mShowingTooltip = false; } } @@ -1427,7 +1427,7 @@ ChromeTooltipListener::sTooltipCallback(nsITimer *aTimer, { ChromeTooltipListener* self = static_cast (aChromeTooltipListener); - if ( self && self->mPossibleTooltipNode ){ + if (self && self->mPossibleTooltipNode) { // The actual coordinates we want to put the tooltip at are relative to the // toplevel docshell of our mWebBrowser. We know what the screen // coordinates of the mouse event were, which means we just need the screen @@ -1568,7 +1568,7 @@ ChromeContextMenuListener::AddChromeListeners() nsCOMPtr contextListener2 ( do_QueryInterface(mWebBrowserChrome) ); nsCOMPtr contextListener ( do_QueryInterface(mWebBrowserChrome) ); - if ( (contextListener || contextListener2) && !mContextMenuListenerInstalled ) + if ((contextListener || contextListener2) && !mContextMenuListenerInstalled) rv = AddContextMenuListener(); return rv; @@ -1584,7 +1584,7 @@ ChromeContextMenuListener::AddChromeListeners() NS_IMETHODIMP ChromeContextMenuListener::RemoveChromeListeners() { - if ( mContextMenuListenerInstalled ) + if (mContextMenuListenerInstalled) RemoveContextMenuListener(); mEventTarget = nullptr; @@ -1769,14 +1769,14 @@ ChromeContextMenuListener::HandleEvent(nsIDOMEvent* aMouseEvent) } // Tell the listener all about the event - if ( menuListener2 ) { + if (menuListener2) { menuInfoImpl->SetMouseEvent(aMouseEvent); menuInfoImpl->SetDOMNode(targetDOMnode); menuListener2->OnShowContextMenu(flags2, menuInfo); } else { nsCOMPtr menuListener(do_QueryInterface(mWebBrowserChrome)); - if ( menuListener ) + if (menuListener) menuListener->OnShowContextMenu(flags, aMouseEvent, targetDOMnode); } From 78f3159e8a30e12bd8c07aff82744bc5b6d67cd3 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:01 -0800 Subject: [PATCH 028/130] Bug 1064439, part 1d - Cuddle else in nsDocShellTreeOwner. r=jst --- embedding/browser/nsDocShellTreeOwner.cpp | 36 ++++++++++------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index e61c20295f24..ebafa91517cb 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -765,8 +765,7 @@ nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner) NS_ENSURE_TRUE(webBrowserChrome, NS_ERROR_INVALID_ARG); NS_ENSURE_SUCCESS(SetWebBrowserChrome(webBrowserChrome), NS_ERROR_INVALID_ARG); mTreeOwner = aTreeOwner; - } - else { + } else { mTreeOwner = nullptr; nsCOMPtr webBrowserChrome = GetWebBrowserChrome(); if (!webBrowserChrome) @@ -828,9 +827,9 @@ nsDocShellTreeOwner::AddChromeListeners() if (mChromeTooltipListener) { NS_ADDREF(mChromeTooltipListener); rv = mChromeTooltipListener->AddChromeListeners(); - } - else + } else { rv = NS_ERROR_OUT_OF_MEMORY; + } } } @@ -846,9 +845,9 @@ nsDocShellTreeOwner::AddChromeListeners() if (mChromeContextMenuListener) { NS_ADDREF(mChromeContextMenuListener); rv = mChromeContextMenuListener->AddChromeListeners(); - } - else + } else { rv = NS_ERROR_OUT_OF_MEMORY; + } } } @@ -928,8 +927,7 @@ nsDocShellTreeOwner::HandleEvent(nsIDOMEvent* aEvent) if (!link.IsEmpty()) { webnav->LoadURI(link.get(), 0, nullptr, nullptr, nullptr); } - } - else { + } else { aEvent->StopPropagation(); aEvent->PreventDefault(); } @@ -1072,9 +1070,9 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText, tagAtom != mTag_window) { // first try the normal title attribute... currElement->GetAttribute(NS_LITERAL_STRING("title"), outText); - if (outText.Length()) + if (outText.Length()) { found = true; - else { + } else { // ...ok, that didn't work, try it in the XLink namespace NS_NAMED_LITERAL_STRING(xlinkNS, "http://www.w3.org/1999/xlink"); nsCOMPtr linkContent(do_QueryInterface(currElement)); @@ -1085,8 +1083,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText, if (outText.Length()) found = true; } - } - else { + } else { if (lookingForSVGTitle) { lookingForSVGTitle = UseSVGTitle(currElement); } @@ -1272,13 +1269,11 @@ ChromeTooltipListener::HandleEvent(nsIDOMEvent* aEvent) if (eventType.EqualsLiteral("keydown") || eventType.EqualsLiteral("mousedown")) { return HideTooltip(); - } - else if (eventType.EqualsLiteral("mouseout")) { + } else if (eventType.EqualsLiteral("mouseout")) { // Reset flag so that tooltip will display on the next MouseMove mTooltipShownOnce = false; return HideTooltip(); - } - else if (eventType.EqualsLiteral("mousemove")) { + } else if (eventType.EqualsLiteral("mousemove")) { return MouseMove(aEvent); } @@ -1338,10 +1333,10 @@ ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent) mPossibleTooltipNode = nullptr; } } - else + else { NS_WARNING ( "Could not create a timer for tooltip tracking" ); - } - else { + } + } else { mTooltipShownOnce = true; return HideTooltip(); } @@ -1773,8 +1768,7 @@ ChromeContextMenuListener::HandleEvent(nsIDOMEvent* aMouseEvent) menuInfoImpl->SetMouseEvent(aMouseEvent); menuInfoImpl->SetDOMNode(targetDOMnode); menuListener2->OnShowContextMenu(flags2, menuInfo); - } - else { + } else { nsCOMPtr menuListener(do_QueryInterface(mWebBrowserChrome)); if (menuListener) menuListener->OnShowContextMenu(flags, aMouseEvent, targetDOMnode); From 669aa09977e4a8f18001645a1916a048702c68ba Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:01 -0800 Subject: [PATCH 029/130] Bug 1064439, part 1e - Get rid of more space around parens in nsDocShellTreeOwner. r=jst --- embedding/browser/nsDocShellTreeOwner.cpp | 38 +++++++++++------------ embedding/browser/nsDocShellTreeOwner.h | 14 ++++----- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index ebafa91517cb..ffae93495c42 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -1021,7 +1021,7 @@ UseSVGTitle(nsIDOMElement *currElement) return element->GetParentNode()->NodeType() != nsIDOMNode::DOCUMENT_NODE; } -/* void getNodeText (in nsIDOMNode aNode, out wstring aText); */ +/* void getNodeText(in nsIDOMNode aNode, out wstring aText); */ NS_IMETHODIMP DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText, bool *_retval) @@ -1035,7 +1035,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText, bool lookingForSVGTitle = true; bool found = false; - nsCOMPtr current ( aNode ); + nsCOMPtr current(aNode); // If the element implement the constraint validation API and has no title, // show the validation message, if any. @@ -1059,8 +1059,8 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText, } } - while ( !found && current ) { - nsCOMPtr currElement ( do_QueryInterface(current) ); + while (!found && current) { + nsCOMPtr currElement(do_QueryInterface(current)); if (currElement) { nsCOMPtr content(do_QueryInterface(currElement)); if (content) { @@ -1108,7 +1108,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText, // not found here, walk up to the parent and keep trying if (!found) { - nsCOMPtr temp ( current ); + nsCOMPtr temp(current); temp->GetParentNode(getter_AddRefs(current)); } } // while not found @@ -1166,7 +1166,7 @@ ChromeTooltipListener::AddChromeListeners() // Register the appropriate events for tooltips, but only if // the embedding chrome cares. nsresult rv = NS_OK; - nsCOMPtr tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); + nsCOMPtr tooltipListener(do_QueryInterface(mWebBrowserChrome)); if (tooltipListener && !mTooltipListenerInstalled) { rv = AddTooltipListener(); if (NS_FAILED(rv)) @@ -1215,7 +1215,7 @@ ChromeTooltipListener::AddTooltipListener() // Unsubscribe from the various things we've hooked up to the window root. // NS_IMETHODIMP -ChromeTooltipListener::RemoveChromeListeners ( ) +ChromeTooltipListener::RemoveChromeListeners() { HideTooltip(); @@ -1290,7 +1290,7 @@ ChromeTooltipListener::HandleEvent(nsIDOMEvent* aEvent) nsresult ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent) { - nsCOMPtr mouseEvent ( do_QueryInterface(aMouseEvent) ); + nsCOMPtr mouseEvent(do_QueryInterface(aMouseEvent)); if (!mouseEvent) return NS_OK; @@ -1334,7 +1334,7 @@ ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent) } } else { - NS_WARNING ( "Could not create a timer for tooltip tracking" ); + NS_WARNING("Could not create a timer for tooltip tracking"); } } else { mTooltipShownOnce = true; @@ -1358,9 +1358,9 @@ ChromeTooltipListener::ShowTooltip(int32_t inXCoords, int32_t inYCoords, nsresult rv = NS_OK; // do the work to call the client - nsCOMPtr tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); + nsCOMPtr tooltipListener(do_QueryInterface(mWebBrowserChrome)); if (tooltipListener) { - rv = tooltipListener->OnShowTooltip ( inXCoords, inYCoords, PromiseFlatString(inTipText).get() ); + rv = tooltipListener->OnShowTooltip(inXCoords, inYCoords, PromiseFlatString(inTipText).get()); if (NS_SUCCEEDED(rv)) mShowingTooltip = true; } @@ -1391,9 +1391,9 @@ ChromeTooltipListener::HideTooltip() // if we're showing the tip, tell the chrome to hide it if (mShowingTooltip) { - nsCOMPtr tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); + nsCOMPtr tooltipListener(do_QueryInterface(mWebBrowserChrome)); if (tooltipListener) { - rv = tooltipListener->OnHideTooltip ( ); + rv = tooltipListener->OnHideTooltip(); if (NS_SUCCEEDED(rv)) mShowingTooltip = false; } @@ -1467,9 +1467,9 @@ ChromeTooltipListener::sTooltipCallback(nsITimer *aTimer, if (textFound) { nsString tipText(tooltipText); nsIntPoint screenDot = widget->WidgetToScreenOffset(); - self->ShowTooltip (self->mMouseScreenX - screenDot.x, - self->mMouseScreenY - screenDot.y, - tipText); + self->ShowTooltip(self->mMouseScreenX - screenDot.x, + self->mMouseScreenY - screenDot.y, + tipText); } } @@ -1486,7 +1486,7 @@ NS_IMPL_ISUPPORTS(ChromeContextMenuListener, nsIDOMEventListener) // // ChromeTooltipListener ctor // -ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) +ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome) : mContextMenuListenerInstalled(false), mWebBrowser(inBrowser), mWebBrowserChrome(inChrome) @@ -1561,8 +1561,8 @@ ChromeContextMenuListener::AddChromeListeners() // the embedding chrome cares. nsresult rv = NS_OK; - nsCOMPtr contextListener2 ( do_QueryInterface(mWebBrowserChrome) ); - nsCOMPtr contextListener ( do_QueryInterface(mWebBrowserChrome) ); + nsCOMPtr contextListener2(do_QueryInterface(mWebBrowserChrome)); + nsCOMPtr contextListener(do_QueryInterface(mWebBrowserChrome)); if ((contextListener || contextListener2) && !mContextMenuListenerInstalled) rv = AddContextMenuListener(); diff --git a/embedding/browser/nsDocShellTreeOwner.h b/embedding/browser/nsDocShellTreeOwner.h index 998d50eb58e7..35bd3230418d 100644 --- a/embedding/browser/nsDocShellTreeOwner.h +++ b/embedding/browser/nsDocShellTreeOwner.h @@ -147,12 +147,12 @@ protected: class ChromeTooltipListener MOZ_FINAL : public nsIDOMEventListener { protected: - virtual ~ChromeTooltipListener ( ) ; + virtual ~ChromeTooltipListener(); public: NS_DECL_ISUPPORTS - ChromeTooltipListener ( nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) ; + ChromeTooltipListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome); NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); NS_IMETHOD MouseMove(nsIDOMEvent* aMouseEvent); @@ -173,8 +173,8 @@ private: NS_IMETHOD AddTooltipListener(); NS_IMETHOD RemoveTooltipListener(); - NS_IMETHOD ShowTooltip ( int32_t inXCoords, int32_t inYCoords, const nsAString & inTipText ) ; - NS_IMETHOD HideTooltip ( ) ; + NS_IMETHOD ShowTooltip(int32_t inXCoords, int32_t inYCoords, const nsAString & inTipText); + NS_IMETHOD HideTooltip(); nsWebBrowser* mWebBrowser; nsCOMPtr mEventTarget; @@ -189,7 +189,7 @@ private: bool mTooltipListenerInstalled; nsCOMPtr mTooltipTimer; - static void sTooltipCallback ( nsITimer* aTimer, void* aListener ) ; + static void sTooltipCallback(nsITimer* aTimer, void* aListener); int32_t mMouseClientX, mMouseClientY; // mouse coordinates for last mousemove event we saw int32_t mMouseScreenX, mMouseScreenY; // mouse coordinates for tooltip event bool mShowingTooltip; @@ -218,12 +218,12 @@ private: class ChromeContextMenuListener : public nsIDOMEventListener { protected: - virtual ~ChromeContextMenuListener ( ) ; + virtual ~ChromeContextMenuListener(); public: NS_DECL_ISUPPORTS - ChromeContextMenuListener ( nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) ; + ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome); // nsIDOMContextMenuListener NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); From b58ae22b4b81d4f4f5ca9f3531ff1e03a453ee2f Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:01 -0800 Subject: [PATCH 030/130] Bug 1064439, part 2 - Use nullptr in a few places in nsDocShellTreeOwner. r=jst --- embedding/browser/nsDocShellTreeOwner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index ffae93495c42..6c5e9fc680ce 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -744,8 +744,8 @@ nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser) if (!aWebBrowser) RemoveChromeListeners(); if (aWebBrowser != mWebBrowser) { - mPrompter = 0; - mAuthPrompter = 0; + mPrompter = nullptr; + mAuthPrompter = nullptr; } mWebBrowser = aWebBrowser; @@ -782,7 +782,7 @@ nsDocShellTreeOwner::SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome) mWebBrowserChrome = nullptr; mOwnerWin = nullptr; mOwnerRequestor = nullptr; - mWebBrowserChromeWeak = 0; + mWebBrowserChromeWeak = nullptr; } else { nsCOMPtr supportsweak = do_QueryInterface(aWebBrowserChrome); From 3b279272a65f66a20caa7308769bc26663e19777 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:01 -0800 Subject: [PATCH 031/130] Bug 1064439, part 3 - Take advantage of infallible new in nsDocShellTreeOwner. r=jst --- embedding/browser/nsDocShellTreeOwner.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index 6c5e9fc680ce..80f7407e4867 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -824,12 +824,8 @@ nsDocShellTreeOwner::AddChromeListeners() if (tooltipListener) { mChromeTooltipListener = new ChromeTooltipListener(mWebBrowser, webBrowserChrome); - if (mChromeTooltipListener) { - NS_ADDREF(mChromeTooltipListener); - rv = mChromeTooltipListener->AddChromeListeners(); - } else { - rv = NS_ERROR_OUT_OF_MEMORY; - } + NS_ADDREF(mChromeTooltipListener); + rv = mChromeTooltipListener->AddChromeListeners(); } } @@ -842,12 +838,8 @@ nsDocShellTreeOwner::AddChromeListeners() if (contextListener2 || contextListener) { mChromeContextMenuListener = new ChromeContextMenuListener(mWebBrowser, webBrowserChrome); - if (mChromeContextMenuListener) { - NS_ADDREF(mChromeContextMenuListener); - rv = mChromeContextMenuListener->AddChromeListeners(); - } else { - rv = NS_ERROR_OUT_OF_MEMORY; - } + NS_ADDREF(mChromeContextMenuListener); + rv = mChromeContextMenuListener->AddChromeListeners(); } } From 7e5d17d702f0ead54c4b83582dbb789ae2e7e21f Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:01 -0800 Subject: [PATCH 032/130] Bug 1064439, part 4 - Use less ADDREF in nsDocShellTreeOwner. r=jst --- embedding/browser/nsDocShellTreeOwner.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index 80f7407e4867..1a78e776bc17 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -156,24 +156,22 @@ nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink) } if (aIID.Equals(NS_GET_IID(nsIPrompt))) { - nsIPrompt *prompt; + nsCOMPtr prompt; EnsurePrompter(); prompt = mPrompter; if (prompt) { - NS_ADDREF(prompt); - *aSink = prompt; + prompt.forget(aSink); return NS_OK; } return NS_NOINTERFACE; } if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) { - nsIAuthPrompt *prompt; + nsCOMPtr prompt; EnsureAuthPrompter(); prompt = mAuthPrompter; if (prompt) { - NS_ADDREF(prompt); - *aSink = prompt; + prompt.forget(aSink); return NS_OK; } return NS_NOINTERFACE; @@ -215,8 +213,8 @@ nsDocShellTreeOwner::FindItemWithName(const char16_t* aName, // see bug 217886 for details // XXXbz what if our browser isn't targetable? We need to handle that somehow. if (name.LowerCaseEqualsLiteral("_content") || name.EqualsLiteral("_main")) { - *aFoundItem = mWebBrowser->mDocShell; - NS_IF_ADDREF(*aFoundItem); + nsCOMPtr foundItem = mWebBrowser->mDocShell; + foundItem.forget(aFoundItem); return NS_OK; } @@ -355,8 +353,9 @@ nsDocShellTreeOwner::GetPrimaryContentShell(nsIDocShellTreeItem** aShell) if (mTreeOwner) return mTreeOwner->GetPrimaryContentShell(aShell); - *aShell = (mPrimaryContentShell ? mPrimaryContentShell : mWebBrowser->mDocShell); - NS_IF_ADDREF(*aShell); + nsCOMPtr shell; + shell = (mPrimaryContentShell ? mPrimaryContentShell : mWebBrowser->mDocShell); + shell.forget(aShell); return NS_OK; } From 0dae524e7419f90e8b5644f99825d6efb92f0000 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:01 -0800 Subject: [PATCH 033/130] Bug 1064439, part 5 - Use nsRefPtrs in nsDocShellTreeOwner. r=jst --- embedding/browser/nsDocShellTreeOwner.cpp | 10 +++------- embedding/browser/nsDocShellTreeOwner.h | 7 ++++--- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index 1a78e776bc17..546acc6a630e 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -108,9 +108,7 @@ nsDocShellTreeOwner::nsDocShellTreeOwner() : mPrimaryContentShell(nullptr), mWebBrowserChrome(nullptr), mOwnerWin(nullptr), - mOwnerRequestor(nullptr), - mChromeTooltipListener(nullptr), - mChromeContextMenuListener(nullptr) + mOwnerRequestor(nullptr) { } @@ -823,7 +821,6 @@ nsDocShellTreeOwner::AddChromeListeners() if (tooltipListener) { mChromeTooltipListener = new ChromeTooltipListener(mWebBrowser, webBrowserChrome); - NS_ADDREF(mChromeTooltipListener); rv = mChromeTooltipListener->AddChromeListeners(); } } @@ -837,7 +834,6 @@ nsDocShellTreeOwner::AddChromeListeners() if (contextListener2 || contextListener) { mChromeContextMenuListener = new ChromeContextMenuListener(mWebBrowser, webBrowserChrome); - NS_ADDREF(mChromeContextMenuListener); rv = mChromeContextMenuListener->AddChromeListeners(); } } @@ -864,11 +860,11 @@ nsDocShellTreeOwner::RemoveChromeListeners() { if (mChromeTooltipListener) { mChromeTooltipListener->RemoveChromeListeners(); - NS_RELEASE(mChromeTooltipListener); + mChromeTooltipListener = nullptr; } if (mChromeContextMenuListener) { mChromeContextMenuListener->RemoveChromeListeners(); - NS_RELEASE(mChromeContextMenuListener); + mChromeContextMenuListener = nullptr; } nsCOMPtr piTarget; diff --git a/embedding/browser/nsDocShellTreeOwner.h b/embedding/browser/nsDocShellTreeOwner.h index 35bd3230418d..5ae31ee5422e 100644 --- a/embedding/browser/nsDocShellTreeOwner.h +++ b/embedding/browser/nsDocShellTreeOwner.h @@ -8,6 +8,7 @@ #define nsDocShellTreeOwner_h__ // Helper Classes +#include "nsAutoPtr.h" #include "nsCOMPtr.h" #include "nsString.h" @@ -127,9 +128,9 @@ protected: // the objects that listen for chrome events like context menus and tooltips. // They are separate objects to avoid circular references between |this| - // and the DOM. These are strong, owning refs. - ChromeTooltipListener* mChromeTooltipListener; - ChromeContextMenuListener* mChromeContextMenuListener; + // and the DOM. + nsRefPtr mChromeTooltipListener; + nsRefPtr mChromeContextMenuListener; nsCOMPtr mPrompter; nsCOMPtr mAuthPrompter; From b47f361ad8883dfde7fe58f01487a5ae471a1e2f Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:01 -0800 Subject: [PATCH 034/130] Bug 1064439, part 6 - Get rid of weird C-style cast and QI of DefaultTooltipTextProvider. r=jst --- embedding/browser/nsDocShellTreeOwner.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index 546acc6a630e..0b3c17675c7b 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -1123,8 +1123,7 @@ ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* inBrowser, { mTooltipTextProvider = do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID); if (!mTooltipTextProvider) { - nsISupports *pProvider = (nsISupports *) new DefaultTooltipTextProvider; - mTooltipTextProvider = do_QueryInterface(pProvider); + mTooltipTextProvider = new DefaultTooltipTextProvider(); } } // ctor From 6161615840b3cdd34667b8b4eb0e57cef4b6e9aa Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:01 -0800 Subject: [PATCH 035/130] Bug 1064439, part 7 - Surely DefaultTooltipTextProvider doesn't need threadsafe refcounting. r=jst --- embedding/browser/nsDocShellTreeOwner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index 0b3c17675c7b..e4490a61e9ee 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -969,7 +969,7 @@ class DefaultTooltipTextProvider MOZ_FINAL : public nsITooltipTextProvider public: DefaultTooltipTextProvider(); - NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_ISUPPORTS NS_DECL_NSITOOLTIPTEXTPROVIDER protected: From 5f1a422255168da7308659fbf393e8493677a23b Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:01 -0800 Subject: [PATCH 036/130] Bug 1064439, part 8a - Get rid of trailing whitespace in nsWebBrowser. r=jst --- embedding/browser/nsWebBrowser.cpp | 78 +++++++++++++++--------------- embedding/browser/nsWebBrowser.h | 10 ++-- 2 files changed, 43 insertions(+), 45 deletions(-) diff --git a/embedding/browser/nsWebBrowser.cpp b/embedding/browser/nsWebBrowser.cpp index aac0474b8849..244747546a5c 100644 --- a/embedding/browser/nsWebBrowser.cpp +++ b/embedding/browser/nsWebBrowser.cpp @@ -64,7 +64,7 @@ static NS_DEFINE_CID(kChildCID, NS_CHILD_CID); //*** nsWebBrowser: Object Management //***************************************************************************** -nsWebBrowser::nsWebBrowser() : mDocShellTreeOwner(nullptr), +nsWebBrowser::nsWebBrowser() : mDocShellTreeOwner(nullptr), mInitInfo(nullptr), mContentType(typeContentWrapper), mActivating(false), @@ -127,7 +127,7 @@ NS_IMETHODIMP nsWebBrowser::InternalDestroy() //***************************************************************************** // nsWebBrowser::nsISupports -//***************************************************************************** +//***************************************************************************** NS_IMPL_ADDREF(nsWebBrowser) NS_IMPL_RELEASE(nsWebBrowser) @@ -152,7 +152,7 @@ NS_INTERFACE_MAP_END ///***************************************************************************** // nsWebBrowser::nsIInterfaceRequestor -//***************************************************************************** +//***************************************************************************** NS_IMETHODIMP nsWebBrowser::GetInterface(const nsIID& aIID, void** aSink) { @@ -185,12 +185,12 @@ NS_IMETHODIMP nsWebBrowser::GetInterface(const nsIID& aIID, void** aSink) //***************************************************************************** // nsWebBrowser::nsIWebBrowser -//***************************************************************************** +//***************************************************************************** // listeners that currently support registration through AddWebBrowserListener: // - nsIWebProgressListener NS_IMETHODIMP nsWebBrowser::AddWebBrowserListener(nsIWeakReference *aListener, const nsIID& aIID) -{ +{ NS_ENSURE_ARG_POINTER(aListener); nsresult rv = NS_OK; @@ -222,7 +222,7 @@ NS_IMETHODIMP nsWebBrowser::AddWebBrowserListener(nsIWeakReference *aListener, c if (!supports) return NS_ERROR_INVALID_ARG; rv = BindListener(supports, aIID); } - + return rv; } @@ -238,7 +238,7 @@ NS_IMETHODIMP nsWebBrowser::BindListener(nsISupports *aListener, const nsIID& aI NS_ENSURE_STATE(mWebProgress); rv = mWebProgress->AddProgressListener(listener, nsIWebProgress::NOTIFY_ALL); } - else if (aIID.Equals(NS_GET_IID(nsISHistoryListener))) { + else if (aIID.Equals(NS_GET_IID(nsISHistoryListener))) { nsCOMPtr shistory(do_GetInterface(mDocShell, &rv)); if (NS_FAILED(rv)) return rv; nsCOMPtr listener(do_QueryInterface(aListener, &rv)); @@ -269,7 +269,7 @@ NS_IMETHODIMP nsWebBrowser::RemoveWebBrowserListener(nsIWeakReference *aListener mListenerArray->RemoveElementAt(count); break; } - count--; + count--; } // if we've emptied the array, get rid of it. @@ -287,7 +287,7 @@ NS_IMETHODIMP nsWebBrowser::RemoveWebBrowserListener(nsIWeakReference *aListener if (!supports) return NS_ERROR_INVALID_ARG; rv = UnBindListener(supports, aIID); } - + return rv; } @@ -316,7 +316,7 @@ NS_IMETHODIMP nsWebBrowser::UnBindListener(nsISupports *aListener, const nsIID& NS_IMETHODIMP nsWebBrowser::EnableGlobalHistory(bool aEnable) { NS_ENSURE_STATE(mDocShell); - + return mDocShell->SetUseGlobalHistory(aEnable); } @@ -391,11 +391,11 @@ NS_IMETHODIMP nsWebBrowser::SetIsActive(bool aIsActive) //***************************************************************************** // nsWebBrowser::nsIDocShellTreeItem -//***************************************************************************** +//***************************************************************************** NS_IMETHODIMP nsWebBrowser::GetName(nsAString& aName) { - if(mDocShell) + if(mDocShell) mDocShell->GetName(aName); else aName = mInitInfo->name; @@ -493,21 +493,21 @@ NS_IMETHODIMP nsWebBrowser::GetSameTypeRootTreeItem(nsIDocShellTreeItem** aRootT while(parent) { *aRootTreeItem = parent; - NS_ENSURE_SUCCESS((*aRootTreeItem)->GetSameTypeParent(getter_AddRefs(parent)), + NS_ENSURE_SUCCESS((*aRootTreeItem)->GetSameTypeParent(getter_AddRefs(parent)), NS_ERROR_FAILURE); } NS_ADDREF(*aRootTreeItem); return NS_OK; } -NS_IMETHODIMP nsWebBrowser::FindItemWithName(const char16_t *aName, +NS_IMETHODIMP nsWebBrowser::FindItemWithName(const char16_t *aName, nsISupports* aRequestor, nsIDocShellTreeItem* aOriginalRequestor, nsIDocShellTreeItem **_retval) { NS_ENSURE_STATE(mDocShell); NS_ASSERTION(mDocShellTreeOwner, "This should always be set when in this situation"); - return mDocShell->FindItemWithName(aName, + return mDocShell->FindItemWithName(aName, static_cast(mDocShellTreeOwner), aOriginalRequestor, _retval); } @@ -525,7 +525,7 @@ nsWebBrowser::GetWindow() } NS_IMETHODIMP nsWebBrowser::GetTreeOwner(nsIDocShellTreeOwner** aTreeOwner) -{ +{ NS_ENSURE_ARG_POINTER(aTreeOwner); *aTreeOwner = nullptr; if(mDocShellTreeOwner) @@ -728,7 +728,7 @@ NS_IMETHODIMP nsWebBrowser::GetDocument(nsIDOMDocument** aDocument) NS_IMETHODIMP nsWebBrowser::SetProperty(uint32_t aId, uint32_t aValue) { nsresult rv = NS_OK; - + switch (aId) { case nsIWebBrowserSetup::SETUP_ALLOW_PLUGINS: @@ -811,7 +811,7 @@ NS_IMETHODIMP nsWebBrowser::SetProperty(uint32_t aId, uint32_t aValue) break; default: rv = NS_ERROR_INVALID_ARG; - + } return rv; } @@ -944,7 +944,7 @@ NS_IMETHODIMP nsWebBrowser::GetProgressListener(nsIWebProgressListener * *aProgr NS_IF_ADDREF(*aProgressListener); return NS_OK; } - + NS_IMETHODIMP nsWebBrowser::SetProgressListener(nsIWebProgressListener * aProgressListener) { mProgressListener = aProgressListener; @@ -1131,7 +1131,7 @@ NS_IMETHODIMP nsWebBrowser::Cancel(nsresult aReason) //***************************************************************************** NS_IMETHODIMP nsWebBrowser::InitWindow(nativeWindow aParentNativeWindow, - nsIWidget* aParentWidget, int32_t aX, int32_t aY, int32_t aCX, int32_t aCY) + nsIWidget* aParentWidget, int32_t aX, int32_t aY, int32_t aCX, int32_t aCY) { NS_ENSURE_ARG(aParentNativeWindow || aParentWidget); NS_ENSURE_STATE(!mDocShell || mInitInfo); @@ -1169,7 +1169,7 @@ NS_IMETHODIMP nsWebBrowser::Create() widgetInit.mWindowType = eWindowType_child; nsIntRect bounds(mInitInfo->x, mInitInfo->y, mInitInfo->cx, mInitInfo->cy); - + mInternalWidget->SetWidgetListener(this); mInternalWidget->Create(nullptr, mParentNativeWindow, bounds, nullptr, &widgetInit); } @@ -1205,9 +1205,9 @@ NS_IMETHODIMP nsWebBrowser::Create() mListenerArray = nullptr; } - // HACK ALERT - this registration registers the nsDocShellTreeOwner as a - // nsIWebBrowserListener so it can setup its MouseListener in one of the - // progress callbacks. If we can register the MouseListener another way, this + // HACK ALERT - this registration registers the nsDocShellTreeOwner as a + // nsIWebBrowserListener so it can setup its MouseListener in one of the + // progress callbacks. If we can register the MouseListener another way, this // registration can go away, and nsDocShellTreeOwner can stop implementing // nsIWebProgressListener. nsCOMPtr supports = nullptr; @@ -1229,7 +1229,7 @@ NS_IMETHODIMP nsWebBrowser::Create() mDocShell->SetItemType(nsIDocShellTreeItem::typeContent); } mDocShell->SetTreeOwner(mDocShellTreeOwner); - + // If the webbrowser is a content docshell item then we won't hear any // events from subframes. To solve that we install our own chrome event handler // that always gets called (even for subframes) for any bubbling event. @@ -1269,7 +1269,7 @@ NS_IMETHODIMP nsWebBrowser::Create() delete mInitInfo; mInitInfo = nullptr; - return NS_OK; + return NS_OK; } NS_IMETHODIMP nsWebBrowser::Destroy() @@ -1343,14 +1343,14 @@ NS_IMETHODIMP nsWebBrowser::SetPositionAndSize(int32_t aX, int32_t aY, NS_ERROR_FAILURE); } // Now reposition/ resize the doc - NS_ENSURE_SUCCESS(mDocShellAsWin->SetPositionAndSize(doc_x, doc_y, aCX, aCY, + NS_ENSURE_SUCCESS(mDocShellAsWin->SetPositionAndSize(doc_x, doc_y, aCX, aCY, aRepaint), NS_ERROR_FAILURE); } return NS_OK; } -NS_IMETHODIMP nsWebBrowser::GetPositionAndSize(int32_t* aX, int32_t* aY, +NS_IMETHODIMP nsWebBrowser::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aCX, int32_t* aCY) { if(!mDocShell) @@ -1420,7 +1420,7 @@ NS_IMETHODIMP nsWebBrowser::SetParentWidget(nsIWidget* aParentWidget) NS_IMETHODIMP nsWebBrowser::GetParentNativeWindow(nativeWindow* aParentNativeWindow) { NS_ENSURE_ARG_POINTER(aParentNativeWindow); - + *aParentNativeWindow = mParentNativeWindow; return NS_OK; @@ -1559,7 +1559,7 @@ NS_IMETHODIMP nsWebBrowser::GetScrollbarVisibility(bool* aVerticalVisible, //***************************************************************************** // nsWebBrowser::nsITextScroll -//***************************************************************************** +//***************************************************************************** NS_IMETHODIMP nsWebBrowser::ScrollByLines(int32_t aNumLines) { @@ -1578,7 +1578,7 @@ NS_IMETHODIMP nsWebBrowser::ScrollByPages(int32_t aNumPages) //***************************************************************************** // nsWebBrowser: Listener Helpers -//***************************************************************************** +//***************************************************************************** NS_IMETHODIMP nsWebBrowser::SetDocShell(nsIDocShell* aDocShell) { @@ -1586,7 +1586,7 @@ NS_IMETHODIMP nsWebBrowser::SetDocShell(nsIDocShell* aDocShell) if(aDocShell) { NS_ENSURE_TRUE(!mDocShell, NS_ERROR_FAILURE); - + nsCOMPtr req(do_QueryInterface(aDocShell)); nsCOMPtr baseWin(do_QueryInterface(aDocShell)); nsCOMPtr nav(do_QueryInterface(aDocShell)); @@ -1595,7 +1595,7 @@ NS_IMETHODIMP nsWebBrowser::SetDocShell(nsIDocShell* aDocShell) nsCOMPtr progress(do_GetInterface(aDocShell)); NS_ENSURE_TRUE(req && baseWin && nav && scrollable && textScroll && progress, NS_ERROR_FAILURE); - + mDocShell = aDocShell; mDocShellAsReq = req; mDocShellAsWin = baseWin; @@ -1630,7 +1630,7 @@ NS_IMETHODIMP nsWebBrowser::SetDocShell(nsIDocShell* aDocShell) mWebProgress = nullptr; } - return NS_OK; + return NS_OK; } NS_IMETHODIMP nsWebBrowser::EnsureDocShellTreeOwner() @@ -1643,7 +1643,7 @@ NS_IMETHODIMP nsWebBrowser::EnsureDocShellTreeOwner() NS_ADDREF(mDocShellTreeOwner); mDocShellTreeOwner->WebBrowser(this); - + return NS_OK; } @@ -1716,18 +1716,18 @@ NS_IMETHODIMP nsWebBrowser::GetPrimaryContentWindow(nsIDOMWindow** aDOMWindow) nsCOMPtr docShell; docShell = do_QueryInterface(item); NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); - + nsCOMPtr domWindow = docShell->GetWindow(); NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE); *aDOMWindow = domWindow; NS_ADDREF(*aDOMWindow); return NS_OK; - + } //***************************************************************************** // nsWebBrowser::nsIWebBrowserFocus -//***************************************************************************** +//***************************************************************************** /* void activate (); */ NS_IMETHODIMP nsWebBrowser::Activate(void) @@ -1805,7 +1805,7 @@ NS_IMETHODIMP nsWebBrowser::SetFocusedElement(nsIDOMElement * aFocusedElement) //***************************************************************************** // nsWebBrowser::nsIWebBrowserStream -//***************************************************************************** +//***************************************************************************** /* void openStream(in nsIURI aBaseURI, in ACString aContentType); */ NS_IMETHODIMP nsWebBrowser::OpenStream(nsIURI *aBaseURI, const nsACString& aContentType) diff --git a/embedding/browser/nsWebBrowser.h b/embedding/browser/nsWebBrowser.h index 77f3c71a5879..c9efdc83ee5c 100644 --- a/embedding/browser/nsWebBrowser.h +++ b/embedding/browser/nsWebBrowser.h @@ -67,7 +67,7 @@ public: nsIID mID; }; -// {cda5863a-aa9c-411e-be49-ea0d525ab4b5} - +// {cda5863a-aa9c-411e-be49-ea0d525ab4b5} - #define NS_WEBBROWSER_CID \ {0xcda5863a, 0xaa9c, 0x411e, { 0xbe, 0x49, 0xea, 0x0d, 0x52, 0x5a, 0xb4, 0xb5 }} @@ -77,8 +77,8 @@ class nsWebBrowser MOZ_FINAL : public nsIWebBrowser, public nsIWebBrowserSetup, public nsIDocShellTreeItem, public nsIBaseWindow, - public nsIScrollable, - public nsITextScroll, + public nsIScrollable, + public nsITextScroll, public nsIInterfaceRequestor, public nsIWebBrowserPersist, public nsIWebBrowserFocus, @@ -96,7 +96,7 @@ public: NS_DECL_NSIBASEWINDOW NS_DECL_NSIDOCSHELLTREEITEM NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSISCROLLABLE + NS_DECL_NSISCROLLABLE NS_DECL_NSITEXTSCROLL NS_DECL_NSIWEBBROWSER NS_DECL_NSIWEBNAVIGATION @@ -164,5 +164,3 @@ protected: }; #endif /* nsWebBrowser_h__ */ - - From 5ac2e6b958e3a17ca37cfa83e33dfe55102d6132 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:02 -0800 Subject: [PATCH 037/130] Bug 1064439, part 8b - Fix if( in nsWebBrowser.cpp. r=jst --- embedding/browser/nsWebBrowser.cpp | 64 +++++++++++++++--------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/embedding/browser/nsWebBrowser.cpp b/embedding/browser/nsWebBrowser.cpp index 244747546a5c..f2eac887f084 100644 --- a/embedding/browser/nsWebBrowser.cpp +++ b/embedding/browser/nsWebBrowser.cpp @@ -101,12 +101,12 @@ NS_IMETHODIMP nsWebBrowser::InternalDestroy() SetDocShell(nullptr); - if(mDocShellTreeOwner) + if (mDocShellTreeOwner) { mDocShellTreeOwner->WebBrowser(nullptr); NS_RELEASE(mDocShellTreeOwner); } - if(mInitInfo) + if (mInitInfo) { delete mInitInfo; mInitInfo = nullptr; @@ -158,7 +158,7 @@ NS_IMETHODIMP nsWebBrowser::GetInterface(const nsIID& aIID, void** aSink) { NS_ENSURE_ARG_POINTER(aSink); - if(NS_SUCCEEDED(QueryInterface(aIID, aSink))) + if (NS_SUCCEEDED(QueryInterface(aIID, aSink))) return NS_OK; if (mDocShell) { @@ -324,7 +324,7 @@ NS_IMETHODIMP nsWebBrowser::GetContainerWindow(nsIWebBrowserChrome** aTopWindow) { NS_ENSURE_ARG_POINTER(aTopWindow); - if(mDocShellTreeOwner) { + if (mDocShellTreeOwner) { *aTopWindow = mDocShellTreeOwner->GetWebBrowserChrome().take(); } else { *aTopWindow = nullptr; @@ -395,7 +395,7 @@ NS_IMETHODIMP nsWebBrowser::SetIsActive(bool aIsActive) NS_IMETHODIMP nsWebBrowser::GetName(nsAString& aName) { - if(mDocShell) + if (mDocShell) mDocShell->GetName(aName); else aName = mInitInfo->name; @@ -405,7 +405,7 @@ NS_IMETHODIMP nsWebBrowser::GetName(nsAString& aName) NS_IMETHODIMP nsWebBrowser::SetName(const nsAString& aName) { - if(mDocShell) + if (mDocShell) { return mDocShell->SetName(aName); } @@ -419,7 +419,7 @@ NS_IMETHODIMP nsWebBrowser::NameEquals(const char16_t *aName, bool *_retval) { NS_ENSURE_ARG_POINTER(aName); NS_ENSURE_ARG_POINTER(_retval); - if(mDocShell) + if (mDocShell) { return mDocShell->NameEquals(aName, _retval); } @@ -528,7 +528,7 @@ NS_IMETHODIMP nsWebBrowser::GetTreeOwner(nsIDocShellTreeOwner** aTreeOwner) { NS_ENSURE_ARG_POINTER(aTreeOwner); *aTreeOwner = nullptr; - if(mDocShellTreeOwner) + if (mDocShellTreeOwner) { if (mDocShellTreeOwner->mTreeOwner) { @@ -690,7 +690,7 @@ NS_IMETHODIMP nsWebBrowser::GetReferringURI(nsIURI** aURI) NS_IMETHODIMP nsWebBrowser::SetSessionHistory(nsISHistory* aSessionHistory) { - if(mDocShell) + if (mDocShell) return mDocShellAsNav->SetSessionHistory(aSessionHistory); else mInitInfo->sessionHistory = aSessionHistory; @@ -701,7 +701,7 @@ NS_IMETHODIMP nsWebBrowser::SetSessionHistory(nsISHistory* aSessionHistory) NS_IMETHODIMP nsWebBrowser::GetSessionHistory(nsISHistory** aSessionHistory) { NS_ENSURE_ARG_POINTER(aSessionHistory); - if(mDocShell) + if (mDocShell) return mDocShellAsNav->GetSessionHistory(aSessionHistory); else *aSessionHistory = mInitInfo->sessionHistory; @@ -1136,7 +1136,7 @@ NS_IMETHODIMP nsWebBrowser::InitWindow(nativeWindow aParentNativeWindow, NS_ENSURE_ARG(aParentNativeWindow || aParentWidget); NS_ENSURE_STATE(!mDocShell || mInitInfo); - if(aParentWidget) + if (aParentWidget) NS_ENSURE_SUCCESS(SetParentWidget(aParentWidget), NS_ERROR_FAILURE); else NS_ENSURE_SUCCESS(SetParentNativeWindow(aParentNativeWindow), @@ -1156,7 +1156,7 @@ NS_IMETHODIMP nsWebBrowser::Create() NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr docShellParentWidget(mParentWidget); - if(!mParentWidget) // We need to create a widget + if (!mParentWidget) // We need to create a widget { // Create the widget mInternalWidget = do_CreateInstance(kChildCID, &rv); @@ -1276,7 +1276,7 @@ NS_IMETHODIMP nsWebBrowser::Destroy() { InternalDestroy(); - if(!mInitInfo) + if (!mInitInfo) mInitInfo = new nsWebBrowserInitInfo(); return NS_OK; @@ -1321,7 +1321,7 @@ NS_IMETHODIMP nsWebBrowser::GetSize(int32_t* aCX, int32_t* aCY) NS_IMETHODIMP nsWebBrowser::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aCX, int32_t aCY, bool aRepaint) { - if(!mDocShell) + if (!mDocShell) { mInitInfo->x = aX; mInitInfo->y = aY; @@ -1336,7 +1336,7 @@ NS_IMETHODIMP nsWebBrowser::SetPositionAndSize(int32_t aX, int32_t aY, // If there is an internal widget we need to make the docShell coordinates // relative to the internal widget rather than the calling app's parent. // We also need to resize our widget then. - if(mInternalWidget) + if (mInternalWidget) { doc_x = doc_y = 0; NS_ENSURE_SUCCESS(mInternalWidget->Resize(aX, aY, aCX, aCY, aRepaint), @@ -1353,31 +1353,31 @@ NS_IMETHODIMP nsWebBrowser::SetPositionAndSize(int32_t aX, int32_t aY, NS_IMETHODIMP nsWebBrowser::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aCX, int32_t* aCY) { - if(!mDocShell) + if (!mDocShell) { - if(aX) + if (aX) *aX = mInitInfo->x; - if(aY) + if (aY) *aY = mInitInfo->y; - if(aCX) + if (aCX) *aCX = mInitInfo->cx; - if(aCY) + if (aCY) *aCY = mInitInfo->cy; } else { - if(mInternalWidget) + if (mInternalWidget) { nsIntRect bounds; NS_ENSURE_SUCCESS(mInternalWidget->GetBounds(bounds), NS_ERROR_FAILURE); - if(aX) + if (aX) *aX = bounds.x; - if(aY) + if (aY) *aY = bounds.y; - if(aCX) + if (aCX) *aCX = bounds.width; - if(aCY) + if (aCY) *aCY = bounds.height; return NS_OK; } @@ -1409,7 +1409,7 @@ NS_IMETHODIMP nsWebBrowser::SetParentWidget(nsIWidget* aParentWidget) NS_ENSURE_STATE(!mDocShell); mParentWidget = aParentWidget; - if(mParentWidget) + if (mParentWidget) mParentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET); else mParentNativeWindow = nullptr; @@ -1445,7 +1445,7 @@ NS_IMETHODIMP nsWebBrowser::GetVisibility(bool* visibility) { NS_ENSURE_ARG_POINTER(visibility); - if(!mDocShell) + if (!mDocShell) *visibility = mInitInfo->visible; else NS_ENSURE_SUCCESS(mDocShellAsWin->GetVisibility(visibility), NS_ERROR_FAILURE); @@ -1455,12 +1455,12 @@ NS_IMETHODIMP nsWebBrowser::GetVisibility(bool* visibility) NS_IMETHODIMP nsWebBrowser::SetVisibility(bool aVisibility) { - if(!mDocShell) + if (!mDocShell) mInitInfo->visible = aVisibility; else { NS_ENSURE_SUCCESS(mDocShellAsWin->SetVisibility(aVisibility), NS_ERROR_FAILURE); - if(mInternalWidget) + if (mInternalWidget) mInternalWidget->Show(aVisibility); } @@ -1488,7 +1488,7 @@ NS_IMETHODIMP nsWebBrowser::GetMainWidget(nsIWidget** mainWidget) { NS_ENSURE_ARG_POINTER(mainWidget); - if(mInternalWidget) + if (mInternalWidget) *mainWidget = mInternalWidget; else *mainWidget = mParentWidget; @@ -1583,7 +1583,7 @@ NS_IMETHODIMP nsWebBrowser::ScrollByPages(int32_t aNumPages) NS_IMETHODIMP nsWebBrowser::SetDocShell(nsIDocShell* aDocShell) { nsCOMPtr kungFuDeathGrip(mDocShell); - if(aDocShell) + if (aDocShell) { NS_ENSURE_TRUE(!mDocShell, NS_ERROR_FAILURE); @@ -1635,7 +1635,7 @@ NS_IMETHODIMP nsWebBrowser::SetDocShell(nsIDocShell* aDocShell) NS_IMETHODIMP nsWebBrowser::EnsureDocShellTreeOwner() { - if(mDocShellTreeOwner) + if (mDocShellTreeOwner) return NS_OK; mDocShellTreeOwner = new nsDocShellTreeOwner(); From 1cb173b6b42b55b27761bdea2c6d0aeca85f5e45 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:02 -0800 Subject: [PATCH 038/130] Bug 1064439, part 9 - Get rid of a take in nsWebBrowser. r=jst --- embedding/browser/nsWebBrowser.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/embedding/browser/nsWebBrowser.cpp b/embedding/browser/nsWebBrowser.cpp index f2eac887f084..b5acb8be2b8f 100644 --- a/embedding/browser/nsWebBrowser.cpp +++ b/embedding/browser/nsWebBrowser.cpp @@ -324,12 +324,13 @@ NS_IMETHODIMP nsWebBrowser::GetContainerWindow(nsIWebBrowserChrome** aTopWindow) { NS_ENSURE_ARG_POINTER(aTopWindow); + nsCOMPtr top; if (mDocShellTreeOwner) { - *aTopWindow = mDocShellTreeOwner->GetWebBrowserChrome().take(); - } else { - *aTopWindow = nullptr; + top = mDocShellTreeOwner->GetWebBrowserChrome(); } + top.forget(aTopWindow); + return NS_OK; } From f2af6c44513eb12014ccaf50a526c7644680682d Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:02 -0800 Subject: [PATCH 039/130] Bug 1064439, part 10 - Take advantage of infallible alloc in nsWebBrowser. r=jst --- embedding/browser/nsWebBrowser.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/embedding/browser/nsWebBrowser.cpp b/embedding/browser/nsWebBrowser.cpp index b5acb8be2b8f..69810cc0c4eb 100644 --- a/embedding/browser/nsWebBrowser.cpp +++ b/embedding/browser/nsWebBrowser.cpp @@ -199,21 +199,14 @@ NS_IMETHODIMP nsWebBrowser::AddWebBrowserListener(nsIWeakReference *aListener, c // registered when the window gets created. nsAutoPtr state; state = new nsWebBrowserListenerState(); - if (!state) return NS_ERROR_OUT_OF_MEMORY; - state->mWeakPtr = aListener; state->mID = aIID; if (!mListenerArray) { mListenerArray = new nsTArray(); - if (!mListenerArray) { - return NS_ERROR_OUT_OF_MEMORY; - } } - if (!mListenerArray->AppendElement(state)) { - return NS_ERROR_OUT_OF_MEMORY; - } + mListenerArray->AppendElement(state); // We're all set now; don't delete |state| after this point state.forget(); @@ -1640,7 +1633,6 @@ NS_IMETHODIMP nsWebBrowser::EnsureDocShellTreeOwner() return NS_OK; mDocShellTreeOwner = new nsDocShellTreeOwner(); - NS_ENSURE_TRUE(mDocShellTreeOwner, NS_ERROR_OUT_OF_MEMORY); NS_ADDREF(mDocShellTreeOwner); mDocShellTreeOwner->WebBrowser(this); @@ -1815,9 +1807,6 @@ NS_IMETHODIMP nsWebBrowser::OpenStream(nsIURI *aBaseURI, const nsACString& aCont if (!mStream) { mStream = new nsEmbedStream(); - if (!mStream) - return NS_ERROR_OUT_OF_MEMORY; - mStreamGuard = do_QueryInterface(mStream); mStream->InitOwner(this); rv = mStream->Init(); From edf00d88023a55fe5d5a41114b0b656b5703b22b Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:02 -0800 Subject: [PATCH 040/130] Bug 1064439, part 11 - Make nsWebBrowser::mDocShellTreeOwner into an nsRefPtr. r=jst --- embedding/browser/nsWebBrowser.cpp | 15 ++++++--------- embedding/browser/nsWebBrowser.h | 3 ++- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/embedding/browser/nsWebBrowser.cpp b/embedding/browser/nsWebBrowser.cpp index 69810cc0c4eb..3d76367e92e0 100644 --- a/embedding/browser/nsWebBrowser.cpp +++ b/embedding/browser/nsWebBrowser.cpp @@ -64,7 +64,7 @@ static NS_DEFINE_CID(kChildCID, NS_CHILD_CID); //*** nsWebBrowser: Object Management //***************************************************************************** -nsWebBrowser::nsWebBrowser() : mDocShellTreeOwner(nullptr), +nsWebBrowser::nsWebBrowser() : mInitInfo(nullptr), mContentType(typeContentWrapper), mActivating(false), @@ -101,11 +101,10 @@ NS_IMETHODIMP nsWebBrowser::InternalDestroy() SetDocShell(nullptr); - if (mDocShellTreeOwner) - { + if (mDocShellTreeOwner) { mDocShellTreeOwner->WebBrowser(nullptr); - NS_RELEASE(mDocShellTreeOwner); - } + mDocShellTreeOwner = nullptr; + } if (mInitInfo) { delete mInitInfo; @@ -502,8 +501,8 @@ NS_IMETHODIMP nsWebBrowser::FindItemWithName(const char16_t *aName, NS_ASSERTION(mDocShellTreeOwner, "This should always be set when in this situation"); return mDocShell->FindItemWithName(aName, - static_cast(mDocShellTreeOwner), - aOriginalRequestor, _retval); + static_cast(mDocShellTreeOwner), + aOriginalRequestor, _retval); } nsIDocument* @@ -1633,8 +1632,6 @@ NS_IMETHODIMP nsWebBrowser::EnsureDocShellTreeOwner() return NS_OK; mDocShellTreeOwner = new nsDocShellTreeOwner(); - - NS_ADDREF(mDocShellTreeOwner); mDocShellTreeOwner->WebBrowser(this); return NS_OK; diff --git a/embedding/browser/nsWebBrowser.h b/embedding/browser/nsWebBrowser.h index c9efdc83ee5c..77d3996c7ecb 100644 --- a/embedding/browser/nsWebBrowser.h +++ b/embedding/browser/nsWebBrowser.h @@ -11,6 +11,7 @@ #include "nsDocShellTreeOwner.h" // Core Includes +#include "nsAutoPtr.h" #include "nsCOMPtr.h" // Interfaces needed @@ -125,7 +126,7 @@ protected: virtual bool PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion) MOZ_OVERRIDE; protected: - nsDocShellTreeOwner* mDocShellTreeOwner; + nsRefPtr mDocShellTreeOwner; nsCOMPtr mDocShell; nsCOMPtr mDocShellAsReq; nsCOMPtr mDocShellAsWin; From 796da5cb524578276ca03421cb0d2e05a33eefb4 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:02 -0800 Subject: [PATCH 041/130] Bug 1064439, part 12 - Use nullptr in nsWebBrowser. r=jst --- embedding/browser/nsWebBrowser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embedding/browser/nsWebBrowser.cpp b/embedding/browser/nsWebBrowser.cpp index 3d76367e92e0..f29874bfe8e4 100644 --- a/embedding/browser/nsWebBrowser.cpp +++ b/embedding/browser/nsWebBrowser.cpp @@ -1696,7 +1696,7 @@ bool nsWebBrowser::PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion) NS_IMETHODIMP nsWebBrowser::GetPrimaryContentWindow(nsIDOMWindow** aDOMWindow) { - *aDOMWindow = 0; + *aDOMWindow = nullptr; nsCOMPtr item; NS_ENSURE_TRUE(mDocShellTreeOwner, NS_ERROR_FAILURE); @@ -1834,8 +1834,8 @@ NS_IMETHODIMP nsWebBrowser::CloseStream() rv = mStream->CloseStream(); // release - mStream = 0; - mStreamGuard = 0; + mStream = nullptr; + mStreamGuard = nullptr; return rv; } From 1f8c51305be5e2e9d5f4ac21daed1296b871cf1a Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:02 -0800 Subject: [PATCH 042/130] Bug 1064439, part 13 - Use nsAutoPtr for nsWebBrowser::mInitInfo. r=jst --- embedding/browser/nsWebBrowser.cpp | 15 +++++---------- embedding/browser/nsWebBrowser.h | 2 +- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/embedding/browser/nsWebBrowser.cpp b/embedding/browser/nsWebBrowser.cpp index f29874bfe8e4..4544a8fc9c2e 100644 --- a/embedding/browser/nsWebBrowser.cpp +++ b/embedding/browser/nsWebBrowser.cpp @@ -65,7 +65,7 @@ static NS_DEFINE_CID(kChildCID, NS_CHILD_CID); //***************************************************************************** nsWebBrowser::nsWebBrowser() : - mInitInfo(nullptr), + mInitInfo(new nsWebBrowserInitInfo()), mContentType(typeContentWrapper), mActivating(false), mShouldEnableHistory(true), @@ -80,7 +80,6 @@ nsWebBrowser::nsWebBrowser() : mParentWidget(nullptr), mListenerArray(nullptr) { - mInitInfo = new nsWebBrowserInitInfo(); mWWatch = do_GetService(NS_WINDOWWATCHER_CONTRACTID); NS_ASSERTION(mWWatch, "failed to get WindowWatcher"); } @@ -92,7 +91,6 @@ nsWebBrowser::~nsWebBrowser() NS_IMETHODIMP nsWebBrowser::InternalDestroy() { - if (mInternalWidget) { mInternalWidget->SetWidgetListener(nullptr); mInternalWidget->Destroy(); @@ -105,11 +103,8 @@ NS_IMETHODIMP nsWebBrowser::InternalDestroy() mDocShellTreeOwner->WebBrowser(nullptr); mDocShellTreeOwner = nullptr; } - if (mInitInfo) - { - delete mInitInfo; - mInitInfo = nullptr; - } + + mInitInfo = nullptr; if (mListenerArray) { for (uint32_t i = 0, end = mListenerArray->Length(); i < end; i++) { @@ -1259,7 +1254,6 @@ NS_IMETHODIMP nsWebBrowser::Create() mDocShellTreeOwner->AddToWatcher(); // evil twin of Remove in SetDocShell(0) mDocShellTreeOwner->AddChromeListeners(); - delete mInitInfo; mInitInfo = nullptr; return NS_OK; @@ -1269,8 +1263,9 @@ NS_IMETHODIMP nsWebBrowser::Destroy() { InternalDestroy(); - if (!mInitInfo) + if (!mInitInfo) { mInitInfo = new nsWebBrowserInitInfo(); + } return NS_OK; } diff --git a/embedding/browser/nsWebBrowser.h b/embedding/browser/nsWebBrowser.h index 77d3996c7ecb..5cec36e2ebc8 100644 --- a/embedding/browser/nsWebBrowser.h +++ b/embedding/browser/nsWebBrowser.h @@ -135,7 +135,7 @@ protected: nsCOMPtr mDocShellAsTextScroll; nsCOMPtr mInternalWidget; nsCOMPtr mWWatch; - nsWebBrowserInitInfo* mInitInfo; + nsAutoPtr mInitInfo; uint32_t mContentType; bool mActivating; bool mShouldEnableHistory; From fab20cd349fa77d5ae193b592b262a76fa70cba1 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:02 -0800 Subject: [PATCH 043/130] Bug 1064439, part 14 - Turn nsWebBrowser::mStream into an nsRefPtr and eliminate mStreamGuard. r=jst --- embedding/browser/nsWebBrowser.cpp | 4 ---- embedding/browser/nsWebBrowser.h | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/embedding/browser/nsWebBrowser.cpp b/embedding/browser/nsWebBrowser.cpp index 4544a8fc9c2e..e77ea884e8cb 100644 --- a/embedding/browser/nsWebBrowser.cpp +++ b/embedding/browser/nsWebBrowser.cpp @@ -76,7 +76,6 @@ nsWebBrowser::nsWebBrowser() : mPersistCurrentState(nsIWebBrowserPersist::PERSIST_STATE_READY), mPersistResult(NS_OK), mPersistFlags(nsIWebBrowserPersist::PERSIST_FLAGS_NONE), - mStream(nullptr), mParentWidget(nullptr), mListenerArray(nullptr) { @@ -1799,7 +1798,6 @@ NS_IMETHODIMP nsWebBrowser::OpenStream(nsIURI *aBaseURI, const nsACString& aCont if (!mStream) { mStream = new nsEmbedStream(); - mStreamGuard = do_QueryInterface(mStream); mStream->InitOwner(this); rv = mStream->Init(); if (NS_FAILED(rv)) @@ -1828,9 +1826,7 @@ NS_IMETHODIMP nsWebBrowser::CloseStream() return NS_ERROR_FAILURE; rv = mStream->CloseStream(); - // release mStream = nullptr; - mStreamGuard = nullptr; return rv; } diff --git a/embedding/browser/nsWebBrowser.h b/embedding/browser/nsWebBrowser.h index 5cec36e2ebc8..79f94aa83206 100644 --- a/embedding/browser/nsWebBrowser.h +++ b/embedding/browser/nsWebBrowser.h @@ -156,8 +156,7 @@ protected: uint32_t mPersistFlags; // stream - nsEmbedStream *mStream; - nsCOMPtr mStreamGuard; + nsRefPtr mStream; //Weak Reference interfaces... nsIWidget* mParentWidget; From 5eb1ca5d76caef1d87d780d9951eca425610f25b Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:02 -0800 Subject: [PATCH 044/130] Bug 1064439, part 15 - Convert nsWebBrowser::mListenerArray to an nsAutoPtr. r=jst --- embedding/browser/nsWebBrowser.cpp | 6 +----- embedding/browser/nsWebBrowser.h | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/embedding/browser/nsWebBrowser.cpp b/embedding/browser/nsWebBrowser.cpp index e77ea884e8cb..b43503475ff1 100644 --- a/embedding/browser/nsWebBrowser.cpp +++ b/embedding/browser/nsWebBrowser.cpp @@ -76,8 +76,7 @@ nsWebBrowser::nsWebBrowser() : mPersistCurrentState(nsIWebBrowserPersist::PERSIST_STATE_READY), mPersistResult(NS_OK), mPersistFlags(nsIWebBrowserPersist::PERSIST_FLAGS_NONE), - mParentWidget(nullptr), - mListenerArray(nullptr) + mParentWidget(nullptr) { mWWatch = do_GetService(NS_WINDOWWATCHER_CONTRACTID); NS_ASSERTION(mWWatch, "failed to get WindowWatcher"); @@ -110,7 +109,6 @@ NS_IMETHODIMP nsWebBrowser::InternalDestroy() nsWebBrowserListenerState *state = mListenerArray->ElementAt(i); delete state; } - delete mListenerArray; mListenerArray = nullptr; } @@ -264,7 +262,6 @@ NS_IMETHODIMP nsWebBrowser::RemoveWebBrowserListener(nsIWeakReference *aListener nsWebBrowserListenerState *state = mListenerArray->ElementAt(i); delete state; } - delete mListenerArray; mListenerArray = nullptr; } @@ -1188,7 +1185,6 @@ NS_IMETHODIMP nsWebBrowser::Create() nsWebBrowserListenerState *state = mListenerArray->ElementAt(i); delete state; } - delete mListenerArray; mListenerArray = nullptr; } diff --git a/embedding/browser/nsWebBrowser.h b/embedding/browser/nsWebBrowser.h index 79f94aa83206..51e248df143b 100644 --- a/embedding/browser/nsWebBrowser.h +++ b/embedding/browser/nsWebBrowser.h @@ -160,7 +160,7 @@ protected: //Weak Reference interfaces... nsIWidget* mParentWidget; - nsTArray* mListenerArray; + nsAutoPtr> mListenerArray; }; #endif /* nsWebBrowser_h__ */ From 2d777fa84ce3da0bb4dcd3a5e0e90e328d744862 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 16 Dec 2014 09:18:02 -0800 Subject: [PATCH 045/130] Bug 1064439, part 16 - Eliminate indirection in nsWebBrowser::mListenerArray. r=jst Incidentally, this fixes a leak in nsWebBrowser::RemoveWebBrowserListener. --- embedding/browser/nsWebBrowser.cpp | 43 +++++++----------------------- embedding/browser/nsWebBrowser.h | 2 +- 2 files changed, 10 insertions(+), 35 deletions(-) diff --git a/embedding/browser/nsWebBrowser.cpp b/embedding/browser/nsWebBrowser.cpp index b43503475ff1..03711c57b1dc 100644 --- a/embedding/browser/nsWebBrowser.cpp +++ b/embedding/browser/nsWebBrowser.cpp @@ -104,13 +104,7 @@ NS_IMETHODIMP nsWebBrowser::InternalDestroy() mInitInfo = nullptr; - if (mListenerArray) { - for (uint32_t i = 0, end = mListenerArray->Length(); i < end; i++) { - nsWebBrowserListenerState *state = mListenerArray->ElementAt(i); - delete state; - } - mListenerArray = nullptr; - } + mListenerArray = nullptr; return NS_OK; } @@ -188,19 +182,13 @@ NS_IMETHODIMP nsWebBrowser::AddWebBrowserListener(nsIWeakReference *aListener, c if (!mWebProgress) { // The window hasn't been created yet, so queue up the listener. They'll be // registered when the window gets created. - nsAutoPtr state; - state = new nsWebBrowserListenerState(); - state->mWeakPtr = aListener; - state->mID = aIID; - if (!mListenerArray) { - mListenerArray = new nsTArray(); + mListenerArray = new nsTArray(); } - mListenerArray->AppendElement(state); - - // We're all set now; don't delete |state| after this point - state.forget(); + nsWebBrowserListenerState* state = mListenerArray->AppendElement(); + state->mWeakPtr = aListener; + state->mID = aIID; } else { nsCOMPtr supports(do_QueryReferent(aListener)); if (!supports) return NS_ERROR_INVALID_ARG; @@ -245,11 +233,7 @@ NS_IMETHODIMP nsWebBrowser::RemoveWebBrowserListener(nsIWeakReference *aListener // iterate the array and remove the queued listener int32_t count = mListenerArray->Length(); while (count > 0) { - nsWebBrowserListenerState *state = mListenerArray->ElementAt(count); - NS_ASSERTION(state, "list construction problem"); - - if (state->Equals(aListener, aIID)) { - // this is the one, pull it out. + if (mListenerArray->ElementAt(count).Equals(aListener, aIID)) { mListenerArray->RemoveElementAt(count); break; } @@ -258,10 +242,6 @@ NS_IMETHODIMP nsWebBrowser::RemoveWebBrowserListener(nsIWeakReference *aListener // if we've emptied the array, get rid of it. if (0 >= mListenerArray->Length()) { - for (uint32_t i = 0, end = mListenerArray->Length(); i < end; i++) { - nsWebBrowserListenerState *state = mListenerArray->ElementAt(i); - delete state; - } mListenerArray = nullptr; } @@ -1174,17 +1154,12 @@ NS_IMETHODIMP nsWebBrowser::Create() uint32_t i = 0; NS_ASSERTION(count > 0, "array construction problem"); while (i < count) { - nsWebBrowserListenerState *state = mListenerArray->ElementAt(i); - NS_ASSERTION(state, "array construction problem"); - nsCOMPtr listener = do_QueryReferent(state->mWeakPtr); + nsWebBrowserListenerState& state = mListenerArray->ElementAt(i); + nsCOMPtr listener = do_QueryReferent(state.mWeakPtr); NS_ASSERTION(listener, "bad listener"); - (void)BindListener(listener, state->mID); + (void)BindListener(listener, state.mID); i++; } - for (uint32_t i = 0, end = mListenerArray->Length(); i < end; i++) { - nsWebBrowserListenerState *state = mListenerArray->ElementAt(i); - delete state; - } mListenerArray = nullptr; } diff --git a/embedding/browser/nsWebBrowser.h b/embedding/browser/nsWebBrowser.h index 51e248df143b..78fdd5b96ae7 100644 --- a/embedding/browser/nsWebBrowser.h +++ b/embedding/browser/nsWebBrowser.h @@ -160,7 +160,7 @@ protected: //Weak Reference interfaces... nsIWidget* mParentWidget; - nsAutoPtr> mListenerArray; + nsAutoPtr> mListenerArray; }; #endif /* nsWebBrowser_h__ */ From 413e425bf249118e343f38153718c3e5082fcbb7 Mon Sep 17 00:00:00 2001 From: ZongShen Shen Date: Tue, 16 Dec 2014 18:32:36 +0100 Subject: [PATCH 046/130] Bug 1104658 - Add a newtyped constructor for MConstant and implement the constant propagation for MMathFunction. r=nbp --- js/src/jit/MIR.cpp | 105 ++++++++++++++++++++++++++++++++++++++++++++- js/src/jit/MIR.h | 4 ++ 2 files changed, 107 insertions(+), 2 deletions(-) diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index a9f7a2657fdc..7926c776dfd5 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -590,14 +590,20 @@ MConstant::New(TempAllocator &alloc, const Value &v, types::CompilerConstraintLi } MConstant * -MConstant::NewAsmJS(TempAllocator &alloc, const Value &v, MIRType type) +MConstant::NewTypedValue(TempAllocator &alloc, const Value &v, MIRType type, types::CompilerConstraintList *constraints) { MOZ_ASSERT(!IsSimdType(type)); - MConstant *constant = new(alloc) MConstant(v, nullptr); + MConstant *constant = new(alloc) MConstant(v, constraints); constant->setResultType(type); return constant; } +MConstant * +MConstant::NewAsmJS(TempAllocator &alloc, const Value &v, MIRType type) +{ + return NewTypedValue(alloc, v, type); +} + MConstant * MConstant::NewConstraintlessObject(TempAllocator &alloc, JSObject *v) { @@ -930,6 +936,101 @@ MMathFunction::printOpcode(FILE *fp) const fprintf(fp, " %s", FunctionName(function())); } +MDefinition * +MMathFunction::foldsTo(TempAllocator &alloc) +{ + MDefinition *input = getOperand(0); + if (!input->isConstant()) + return this; + + Value val = input->toConstant()->value(); + if (!val.isNumber()) + return this; + + double in = val.toNumber(); + double out; + switch (function_) { + case Log: + out = js::math_log_uncached(in); + break; + case Sin: + out = js::math_sin_uncached(in); + break; + case Cos: + out = js::math_cos_uncached(in); + break; + case Exp: + out = js::math_exp_uncached(in); + break; + case Tan: + out = js::math_tan_uncached(in); + break; + case ACos: + out = js::math_acos_uncached(in); + break; + case ASin: + out = js::math_asin_uncached(in); + break; + case ATan: + out = js::math_atan_uncached(in); + break; + case Log10: + out = js::math_log10_uncached(in); + break; + case Log2: + out = js::math_log2_uncached(in); + break; + case Log1P: + out = js::math_log1p_uncached(in); + break; + case ExpM1: + out = js::math_expm1_uncached(in); + break; + case CosH: + out = js::math_cosh_uncached(in); + break; + case SinH: + out = js::math_sinh_uncached(in); + break; + case TanH: + out = js::math_tanh_uncached(in); + break; + case ACosH: + out = js::math_acosh_uncached(in); + break; + case ASinH: + out = js::math_asinh_uncached(in); + break; + case ATanH: + out = js::math_atanh_uncached(in); + break; + case Sign: + out = js::math_sign_uncached(in); + break; + case Trunc: + out = js::math_trunc_uncached(in); + break; + case Cbrt: + out = js::math_cbrt_uncached(in); + break; + case Floor: + out = js::math_floor_impl(in); + break; + case Ceil: + out = js::math_ceil_impl(in); + break; + case Round: + out = js::math_round_impl(in); + break; + default: + return this; + } + + if (input->type() == MIRType_Float32) + return MConstant::NewTypedValue(alloc, Float32Value(out), MIRType_Float32); + return MConstant::New(alloc, DoubleValue(out)); +} + MParameter * MParameter::New(TempAllocator &alloc, int32_t index, types::TemporaryTypeSet *types) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 39ae280f1787..61cf6b6cb683 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -1255,6 +1255,8 @@ class MConstant : public MNullaryInstruction INSTRUCTION_HEADER(Constant) static MConstant *New(TempAllocator &alloc, const Value &v, types::CompilerConstraintList *constraints = nullptr); + static MConstant *NewTypedValue(TempAllocator &alloc, const Value &v, MIRType type, + types::CompilerConstraintList *constraints = nullptr); static MConstant *NewAsmJS(TempAllocator &alloc, const Value &v, MIRType type); static MConstant *NewConstraintlessObject(TempAllocator &alloc, JSObject *v); @@ -5579,6 +5581,8 @@ class MMathFunction return true; } + MDefinition *foldsTo(TempAllocator &alloc); + void printOpcode(FILE *fp) const; static const char *FunctionName(Function function); From f2c0ff7d75cc0f447ac30ec4371583b3f059a03b Mon Sep 17 00:00:00 2001 From: Ben Turner Date: Mon, 1 Dec 2014 16:29:27 -0500 Subject: [PATCH 047/130] Bug 1111842 - Make sure QuotaManager can handle escaped URL components passed from SQLite, r=janv. --- dom/quota/QuotaManager.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dom/quota/QuotaManager.cpp b/dom/quota/QuotaManager.cpp index 836752ecc8ad..965b52925f09 100644 --- a/dom/quota/QuotaManager.cpp +++ b/dom/quota/QuotaManager.cpp @@ -42,6 +42,7 @@ #include "nsContentUtils.h" #include "nsCRTGlue.h" #include "nsDirectoryServiceUtils.h" +#include "nsEscape.h" #include "nsNetUtil.h" #include "nsPrintfCString.h" #include "nsScriptSecurityManager.h" @@ -1617,12 +1618,19 @@ QuotaManager::GetQuotaObject(PersistenceType aPersistenceType, fileSize = 0; } + // Re-escape our parameters above to make sure we get the right quota group. + nsAutoCString tempStorage1; + const nsCSubstring& group = NS_EscapeURL(aGroup, esc_Query, tempStorage1); + + nsAutoCString tempStorage2; + const nsCSubstring& origin = NS_EscapeURL(aOrigin, esc_Query, tempStorage2); + nsRefPtr result; { MutexAutoLock lock(mQuotaMutex); GroupInfoTriple* triple; - if (!mGroupInfoTriples.Get(aGroup, &triple)) { + if (!mGroupInfoTriples.Get(group, &triple)) { return nullptr; } @@ -1633,7 +1641,7 @@ QuotaManager::GetQuotaObject(PersistenceType aPersistenceType, return nullptr; } - nsRefPtr originInfo = groupInfo->LockedGetOriginInfo(aOrigin); + nsRefPtr originInfo = groupInfo->LockedGetOriginInfo(origin); if (!originInfo) { return nullptr; From a36190aea0d90f76cbf5c924f5a64fd8e2143590 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 15 Dec 2014 15:43:22 -0500 Subject: [PATCH 048/130] Bug 1111224 - Move TestExpirationTracker.cpp to gtest and enable it; r=froydnj --HG-- rename : xpcom/tests/TestExpirationTracker.cpp => xpcom/glue/tests/gtest/TestExpirationTracker.cpp extra : rebase_source : 3961e36029257b2e923fe6597aadf684f93fcc41 --- .../tests/gtest}/TestExpirationTracker.cpp | 38 +++++-------------- xpcom/glue/tests/gtest/moz.build | 1 + xpcom/tests/moz.build | 1 - 3 files changed, 10 insertions(+), 30 deletions(-) rename xpcom/{tests => glue/tests/gtest}/TestExpirationTracker.cpp (88%) diff --git a/xpcom/tests/TestExpirationTracker.cpp b/xpcom/glue/tests/gtest/TestExpirationTracker.cpp similarity index 88% rename from xpcom/tests/TestExpirationTracker.cpp rename to xpcom/glue/tests/gtest/TestExpirationTracker.cpp index d65ebf24f78e..176b7e8c7967 100644 --- a/xpcom/tests/TestExpirationTracker.cpp +++ b/xpcom/glue/tests/gtest/TestExpirationTracker.cpp @@ -18,6 +18,7 @@ #include "nsIFile.h" #include "prinrval.h" #include "nsThreadUtils.h" +#include "gtest/gtest.h" namespace TestExpirationTracker { @@ -40,11 +41,6 @@ static bool logging = 0; static uint32_t sleepPeriodMS = 50; static uint32_t slackMS = 20; // allow this much error -static void SignalError() { - printf("ERROR!\n"); - error = true; -} - template class Tracker : public nsExpirationTracker { public: Tracker() : nsExpirationTracker(periodMS) { @@ -125,11 +121,7 @@ protected: now, aObj->mLastUsed, timeDiffMS, lowerBoundMS, upperBoundMS); } if (timeDiffMS < lowerBoundMS || timeDiffMS > upperBoundMS) { - if (timeDiffMS < periodMS && aObj->mExpired) { - // This is probably OK, it probably just expired twice - } else { - SignalError(); - } + EXPECT_TRUE(timeDiffMS < periodMS && aObj->mExpired); } aObj->Touch(); aObj->mExpired = true; @@ -181,24 +173,12 @@ static const struct Test { { nullptr, nullptr } }; -} - -using namespace TestExpirationTracker; - -int main(int argc, char **argv) { - int count = 1; - if (argc > 1) - count = atoi(argv[1]); - - if (NS_FAILED(NS_InitXPCOM2(nullptr, nullptr, nullptr))) - return -1; - - while (count--) { - for (const Test* t = tests; t->name != nullptr; ++t) { - printf("%25s : %s\n", t->name, t->func() ? "SUCCESS" : "FAILURE"); - } +TEST(ExpirationTracker, main) +{ + for (const TestExpirationTracker::Test* t = tests; + t->name != nullptr; ++t) { + EXPECT_TRUE(t->func()); } - - NS_ShutdownXPCOM(nullptr); - return 0; +} + } diff --git a/xpcom/glue/tests/gtest/moz.build b/xpcom/glue/tests/gtest/moz.build index 6b7b2fa88539..213ea3d61c1b 100644 --- a/xpcom/glue/tests/gtest/moz.build +++ b/xpcom/glue/tests/gtest/moz.build @@ -8,6 +8,7 @@ UNIFIED_SOURCES += [ 'TestArray.cpp', 'TestCRT.cpp', 'TestEncoding.cpp', + 'TestExpirationTracker.cpp', 'TestFileUtils.cpp', 'TestGCPostBarriers.cpp', 'TestStrings.cpp', diff --git a/xpcom/tests/moz.build b/xpcom/tests/moz.build index 8f214147bcd4..131cacdf5452 100644 --- a/xpcom/tests/moz.build +++ b/xpcom/tests/moz.build @@ -80,7 +80,6 @@ if CONFIG['MOZ_MEMORY']: # XXX Make these tests work in libxul builds. #CPP_UNIT_TESTS += [ -# 'TestExpirationTracker', # 'TestPipes', # 'TestPriorityQueue', # 'TestStorageStream', From a8d8b9b8de496e5056e56f158f44a502fddd44ab Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 16 Dec 2014 12:52:47 -0500 Subject: [PATCH 049/130] Bug 1111225 - Build more files in netwerk/cache2 in unified mode; r=glandium --HG-- extra : rebase_source : d80afcddfc5b50b7f24b5c1266810dde61b9e61f --- netwerk/cache2/moz.build | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/netwerk/cache2/moz.build b/netwerk/cache2/moz.build index 4ed17cbc3eda..b5f3797dce78 100644 --- a/netwerk/cache2/moz.build +++ b/netwerk/cache2/moz.build @@ -21,16 +21,6 @@ EXPORTS += [ ] UNIFIED_SOURCES += [ - 'CacheHashUtils.cpp', - 'CacheIOThread.cpp', - 'CacheObserver.cpp', -] - -# AppCacheStorage.cpp cannot be built in unified mode because it uses plarena.h. -# The rest of these files cannot be built in unified mode because they rely oni -# including prlog.h after nsCache.h. -SOURCES += [ - 'AppCacheStorage.cpp', 'CacheEntry.cpp', 'CacheFile.cpp', 'CacheFileChunk.cpp', @@ -40,15 +30,23 @@ SOURCES += [ 'CacheFileMetadata.cpp', 'CacheFileOutputStream.cpp', 'CacheFileUtils.cpp', + 'CacheHashUtils.cpp', 'CacheIndex.cpp', 'CacheIndexContextIterator.cpp', 'CacheIndexIterator.cpp', + 'CacheIOThread.cpp', 'CacheLog.cpp', + 'CacheObserver.cpp', 'CacheStorage.cpp', 'CacheStorageService.cpp', 'OldWrappers.cpp', ] +# AppCacheStorage.cpp cannot be built in unified mode because it uses plarena.h. +SOURCES += [ + 'AppCacheStorage.cpp', +] + LOCAL_INCLUDES += [ '../base/src', '../cache', From cceccb6af3abfa06a8388ac51e3e042737d8a643 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 16 Dec 2014 12:53:13 -0500 Subject: [PATCH 050/130] Bug 1111227 - Remove the MSVC2005 special casing in gfx/2d/moz.build; r=glandium --HG-- extra : rebase_source : 0d86c3cff1f3775c0994a9f2f71762f77641ca18 --- gfx/2d/moz.build | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build index e8b3a14b5966..467ac072ef8b 100644 --- a/gfx/2d/moz.build +++ b/gfx/2d/moz.build @@ -85,25 +85,23 @@ if CONFIG['MOZ_ENABLE_SKIA']: # Are we targeting x86 or x64? If so, build SSE2 files. if CONFIG['INTEL_ARCHITECTURE']: - # VC2005 doesn't support _mm_castsi128_ps, so SSE2 is turned off - if CONFIG['_MSC_VER'] != '1400': + SOURCES += [ + 'BlurSSE2.cpp', + 'FilterProcessingSSE2.cpp', + 'ImageScalingSSE2.cpp', + ] + if CONFIG['MOZ_ENABLE_SKIA']: SOURCES += [ - 'BlurSSE2.cpp', - 'FilterProcessingSSE2.cpp', - 'ImageScalingSSE2.cpp', + 'convolverSSE2.cpp', ] - if CONFIG['MOZ_ENABLE_SKIA']: - SOURCES += [ - 'convolverSSE2.cpp', - ] - DEFINES['USE_SSE2'] = True - # The file uses SSE2 intrinsics, so it needs special compile flags on some - # compilers. - SOURCES['BlurSSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] - SOURCES['FilterProcessingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] - SOURCES['ImageScalingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] - if CONFIG['MOZ_ENABLE_SKIA']: - SOURCES['convolverSSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] + DEFINES['USE_SSE2'] = True + # The file uses SSE2 intrinsics, so it needs special compile flags on some + # compilers. + SOURCES['BlurSSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] + SOURCES['FilterProcessingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] + SOURCES['ImageScalingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] + if CONFIG['MOZ_ENABLE_SKIA']: + SOURCES['convolverSSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] UNIFIED_SOURCES += [ 'Blur.cpp', From 32b3f4a0fb2ce0dd0dbb9069798c223aa160cab3 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 16 Dec 2014 12:53:37 -0500 Subject: [PATCH 051/130] Bug 1111231 - Remove support for packaging unsupported MSVC libraries; r=glandium --HG-- extra : rebase_source : 061a631c14e77e413eb5ae9d431f23a1a6973b4b --- toolkit/mozapps/installer/packager.mk | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index eef656c9994b..7a67a64f8da6 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -71,16 +71,6 @@ JSSHELL_BINS = \ $(DIST)/bin/$(DLL_PREFIX)mozglue$(DLL_SUFFIX) \ $(NULL) ifndef MOZ_NATIVE_NSPR -ifeq ($(_MSC_VER),1400) -JSSHELL_BINS += $(DIST)/bin/Microsoft.VC80.CRT.manifest -JSSHELL_BINS += $(DIST)/bin/msvcr80.dll -JSSHELL_BINS += $(DIST)/bin/msvcp80.dll -endif -ifeq ($(_MSC_VER),1500) -JSSHELL_BINS += $(DIST)/bin/Microsoft.VC90.CRT.manifest -JSSHELL_BINS += $(DIST)/bin/msvcr90.dll -JSSHELL_BINS += $(DIST)/bin/msvcp90.dll -endif ifeq ($(_MSC_VER),1600) JSSHELL_BINS += $(DIST)/bin/msvcr100.dll JSSHELL_BINS += $(DIST)/bin/msvcp100.dll From c4df1e993f109e8d2252a2a1e8bb26d588cec09e Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 16 Dec 2014 12:54:06 -0500 Subject: [PATCH 052/130] Bug 1111266 - Optimize the clang plugin a bit; r=jrmuizel --HG-- extra : rebase_source : a716418dc06db34fe62ee08bcf33e99c41400c32 --- build/clang-plugin/clang-plugin.cpp | 32 ++++++++++++++++------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/build/clang-plugin/clang-plugin.cpp b/build/clang-plugin/clang-plugin.cpp index ac8628c89448..f28c9fecbdc2 100644 --- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -72,20 +72,22 @@ bool isInIgnoredNamespace(const Decl *decl) { ND = cast(ParentDC); } + const auto& name = ND->getName(); + // namespace std and icu are ignored for now - return ND->getName() == "std" || // standard C++ lib - ND->getName() == "__gnu_cxx" || // gnu C++ lib - ND->getName() == "boost" || // boost - ND->getName() == "webrtc" || // upstream webrtc - ND->getName() == "icu_52" || // icu - ND->getName() == "google" || // protobuf - ND->getName() == "google_breakpad" || // breakpad - ND->getName() == "soundtouch" || // libsoundtouch - ND->getName() == "stagefright" || // libstagefright - ND->getName() == "MacFileUtilities" || // MacFileUtilities - ND->getName() == "dwarf2reader" || // dwarf2reader - ND->getName() == "arm_ex_to_module" || // arm_ex_to_module - ND->getName() == "testing"; // gtest + return name == "std" || // standard C++ lib + name == "__gnu_cxx" || // gnu C++ lib + name == "boost" || // boost + name == "webrtc" || // upstream webrtc + name == "icu_52" || // icu + name == "google" || // protobuf + name == "google_breakpad" || // breakpad + name == "soundtouch" || // libsoundtouch + name == "stagefright" || // libstagefright + name == "MacFileUtilities" || // MacFileUtilities + name == "dwarf2reader" || // dwarf2reader + name == "arm_ex_to_module" || // arm_ex_to_module + name == "testing"; // gtest } bool isIgnoredPath(const Decl *decl) { @@ -175,8 +177,10 @@ public: // The way that Clang checks if a method M overrides its parent method // is if the method has the same name but would not overload. if (M->getName() == (*it)->getName() && - !CI.getSema().IsOverload(*M, (*it), false)) + !CI.getSema().IsOverload(*M, (*it), false)) { overridden = true; + break; + } } if (!overridden) { unsigned overrideID = Diag.getDiagnosticIDs()->getCustomDiagID( From 1497d8eae052635659a704640a89ef7e15a73b62 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 9 Dec 2014 11:37:01 +0100 Subject: [PATCH 053/130] Bug 1108455 - r=jesup --- dom/media/MediaStreamGraph.cpp | 1 - dom/media/MediaStreamGraph.h | 23 ++++++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index 6533e668a331..2a18c14fb67c 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -2242,7 +2242,6 @@ MediaStream::SetTrackEnabled(TrackID aTrackID, bool aEnabled) void MediaStream::ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, MediaSegment* aRawSegment) { - // mMutex must be owned here if this is a SourceMediaStream if (!mDisabledTrackIDs.Contains(aTrackID)) { return; } diff --git a/dom/media/MediaStreamGraph.h b/dom/media/MediaStreamGraph.h index cf120e6578ed..7ac84eb5487d 100644 --- a/dom/media/MediaStreamGraph.h +++ b/dom/media/MediaStreamGraph.h @@ -458,7 +458,7 @@ public: void AddListenerImpl(already_AddRefed aListener); void RemoveListenerImpl(MediaStreamListener* aListener); void RemoveAllListenersImpl(); - void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled); + virtual void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled); /** * Returns true when this stream requires the contents of its inputs even if * its own outputs are not being consumed. This is used to signal inputs to @@ -536,7 +536,7 @@ public: StreamBuffer::Track* EnsureTrack(TrackID aTrack); - void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, MediaSegment* aRawSegment = nullptr); + virtual void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, MediaSegment* aRawSegment = nullptr); DOMMediaStream* GetWrapper() { @@ -776,17 +776,26 @@ public: */ void FinishWithLockHeld(); void Finish() - { - MutexAutoLock lock(mMutex); - FinishWithLockHeld(); - } + { + MutexAutoLock lock(mMutex); + FinishWithLockHeld(); + } // Overriding allows us to hold the mMutex lock while changing the track enable status - void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled) { + virtual void + SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled) MOZ_OVERRIDE { MutexAutoLock lock(mMutex); MediaStream::SetTrackEnabledImpl(aTrackID, aEnabled); } + // Overriding allows us to ensure mMutex is locked while changing the track enable status + virtual void + ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, + MediaSegment* aRawSegment = nullptr) MOZ_OVERRIDE { + mMutex.AssertCurrentThreadOwns(); + MediaStream::ApplyTrackDisabling(aTrackID, aSegment, aRawSegment); + } + /** * End all tracks and Finish() this stream. Used to voluntarily revoke access * to a LocalMediaStream. From f1241b66bf2f2d4167ef57e562c26a0c91211189 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 16 Dec 2014 18:45:40 +0100 Subject: [PATCH 054/130] Bug 1108455 - r=kinetik --- media/libcubeb/src/cubeb_wasapi.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasapi.cpp index b22b3b44ba2a..70c7d4f3af54 100644 --- a/media/libcubeb/src/cubeb_wasapi.cpp +++ b/media/libcubeb/src/cubeb_wasapi.cpp @@ -318,10 +318,8 @@ wasapi_stream_render_loop(LPVOID stream) assert(padding <= stm->buffer_frame_count); if (stm->draining) { - if (padding == 0) { - stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED); - is_playing = false; - } + stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED); + is_playing = false; continue; } From 8e54c7f088cc59cd93051c6f1a643d6b6cadd920 Mon Sep 17 00:00:00 2001 From: "Byron Campen [:bwc]" Date: Fri, 12 Dec 2014 14:30:14 -0800 Subject: [PATCH 055/130] Bug 1110976 - Part 1: Test case that demonstrates the underlying bug. r=jesup --- .../signaling/test/jsep_session_unittest.cpp | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/media/webrtc/signaling/test/jsep_session_unittest.cpp b/media/webrtc/signaling/test/jsep_session_unittest.cpp index b56ce8b18a8d..e90925c8d930 100644 --- a/media/webrtc/signaling/test/jsep_session_unittest.cpp +++ b/media/webrtc/signaling/test/jsep_session_unittest.cpp @@ -933,6 +933,54 @@ TEST_F(JsepSessionTest, ValidateAnsweredCodecParams) ASSERT_EQ((uint32_t)12288, parsed_vp8_params.max_fs); ASSERT_EQ((uint32_t)60, parsed_vp8_params.max_fr); + + SetLocalAnswer(answer); + SetRemoteAnswer(answer); + + ASSERT_EQ(2U, mSessionOff.GetNegotiatedTrackPairCount()); + const JsepTrackPair* offerVideoPair; + ASSERT_EQ(NS_OK, mSessionOff.GetNegotiatedTrackPair(1, &offerVideoPair)); + ASSERT_TRUE(offerVideoPair->mSending); + ASSERT_TRUE(offerVideoPair->mReceiving); + ASSERT_TRUE(offerVideoPair->mSending->GetNegotiatedDetails()); + ASSERT_TRUE(offerVideoPair->mReceiving->GetNegotiatedDetails()); + ASSERT_EQ(1U, + offerVideoPair->mSending->GetNegotiatedDetails()->GetCodecCount()); + ASSERT_EQ(1U, + offerVideoPair->mReceiving->GetNegotiatedDetails()->GetCodecCount()); + const JsepCodecDescription* offerRecvCodec; + ASSERT_EQ(NS_OK, + offerVideoPair->mReceiving->GetNegotiatedDetails()->GetCodec( + 0, + &offerRecvCodec)); + const JsepCodecDescription* offerSendCodec; + ASSERT_EQ(NS_OK, + offerVideoPair->mSending->GetNegotiatedDetails()->GetCodec( + 0, + &offerSendCodec)); + + ASSERT_EQ(2U, mSessionAns.GetNegotiatedTrackPairCount()); + const JsepTrackPair* answerVideoPair; + ASSERT_EQ(NS_OK, mSessionAns.GetNegotiatedTrackPair(1, &answerVideoPair)); + ASSERT_TRUE(answerVideoPair->mSending); + ASSERT_TRUE(answerVideoPair->mReceiving); + ASSERT_TRUE(answerVideoPair->mSending->GetNegotiatedDetails()); + ASSERT_TRUE(answerVideoPair->mReceiving->GetNegotiatedDetails()); + ASSERT_EQ(1U, + answerVideoPair->mSending->GetNegotiatedDetails()->GetCodecCount()); + ASSERT_EQ(1U, + answerVideoPair->mReceiving->GetNegotiatedDetails()->GetCodecCount()); + const JsepCodecDescription* answerRecvCodec; + ASSERT_EQ(NS_OK, + answerVideoPair->mReceiving->GetNegotiatedDetails()->GetCodec( + 0, + &answerRecvCodec)); + const JsepCodecDescription* answerSendCodec; + ASSERT_EQ(NS_OK, + answerVideoPair->mSending->GetNegotiatedDetails()->GetCodec( + 0, + &answerSendCodec)); + #if 0 // H264 packetization mode 1 ASSERT_EQ("126", fmtps[1].format); From 544114ca0f7fc837746b97b93e2eec0d417d4814 Mon Sep 17 00:00:00 2001 From: "Byron Campen [:bwc]" Date: Fri, 12 Dec 2014 14:33:12 -0800 Subject: [PATCH 056/130] Bug 1110976 - Part 2: Don't configure multiple recv codecs if we are the answerer. r=jesup --- media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp | 1 + media/webrtc/signaling/src/media-conduit/VideoConduit.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp b/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp index 11ea817e36d6..5130b282fd17 100644 --- a/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp +++ b/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp @@ -1037,6 +1037,7 @@ JsepSessionImpl::NegotiateTrack(const SdpMediaSection& remoteMsection, } negotiatedDetails->mCodecs.push_back(negotiated); + break; } if (negotiatedDetails->mCodecs.empty()) { diff --git a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp index d2748ffb856d..d95fefc1a834 100755 --- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp +++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp @@ -1137,7 +1137,7 @@ WebrtcVideoConduit::ReceivedRTCPPacket(const void *data, int len) if(mPtrViENetwork->ReceivedRTCPPacket(mChannel,data,len) == -1) { int error = mPtrViEBase->LastError(); - CSFLogError(logTag, "%s RTP Processing Failed %d", __FUNCTION__, error); + CSFLogError(logTag, "%s RTCP Processing Failed %d", __FUNCTION__, error); if(error >= kViERtpRtcpInvalidChannelId && error <= kViERtpRtcpRtcpDisabled) { return kMediaConduitRTPProcessingFailed; From e144df00928c4bab1bc876cfec620f316b3c5328 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Sat, 13 Dec 2014 15:40:18 -0500 Subject: [PATCH 057/130] Bug 1111258 - Let the profiler turn on layout.display-list.dump. r=mstange --- gfx/thebes/gfxUtils.cpp | 2 +- tools/profiler/TableTicker.h | 3 +++ tools/profiler/platform.cpp | 9 +++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 9dd8ee262dc0..6e5a1dc1bb8f 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -1443,7 +1443,7 @@ static bool sDumpPaintList = getenv("MOZ_DUMP_PAINT_LIST") != 0; /* static */ bool gfxUtils::DumpPaintList() { - return sDumpPaintList || gfxPrefs::LayoutDumpDisplayList(); + return sDumpPaintList || gfxPrefs::LayoutDumpDisplayList() || profiler_feature_active("displaylistdump"); } bool gfxUtils::sDumpPainting = getenv("MOZ_DUMP_PAINT") != 0; diff --git a/tools/profiler/TableTicker.h b/tools/profiler/TableTicker.h index bfd06dd3573b..da5f94acbc0f 100644 --- a/tools/profiler/TableTicker.h +++ b/tools/profiler/TableTicker.h @@ -79,6 +79,7 @@ class TableTicker: public Sampler { mProfileMemory = hasFeature(aFeatures, aFeatureCount, "memory"); mTaskTracer = hasFeature(aFeatures, aFeatureCount, "tasktracer"); mLayersDump = hasFeature(aFeatures, aFeatureCount, "layersdump"); + mDisplayListDump = hasFeature(aFeatures, aFeatureCount, "displaylistdump"); #if defined(XP_WIN) if (mProfilePower) { @@ -210,6 +211,7 @@ class TableTicker: public Sampler { bool ProfileMemory() const { return mProfileMemory; } bool TaskTracer() const { return mTaskTracer; } bool LayersDump() const { return mLayersDump; } + bool DisplayListDump() const { return mDisplayListDump; } protected: // Called within a signal. This function must be reentrant @@ -236,6 +238,7 @@ protected: bool mProfileJava; bool mProfilePower; bool mLayersDump; + bool mDisplayListDump; // Keep the thread filter to check against new thread that // are started while profiling diff --git a/tools/profiler/platform.cpp b/tools/profiler/platform.cpp index 2798aad8774d..6d3d977ddd9b 100644 --- a/tools/profiler/platform.cpp +++ b/tools/profiler/platform.cpp @@ -47,6 +47,7 @@ int sInitCount = 0; // Each init must have a matched shutdown. static bool sIsProfiling = false; // is raced on static bool sIsGPUProfiling = false; // is raced on static bool sIsLayersDump = false; // is raced on +static bool sIsDisplayListDump = false; // is raced on // env variables to control the profiler const char* PROFILER_MODE = "MOZ_PROFILER_MODE"; @@ -703,6 +704,8 @@ const char** mozilla_sampler_get_features() "privacy", // Dump the layer tree with the textures. "layersdump", + // Dump the display list with the textures. + "displaylistdump", // Add main thread I/O to the profile "mainthreadio", // Add RSS collection @@ -802,6 +805,7 @@ void mozilla_sampler_start(int aProfileEntries, double aInterval, sIsProfiling = true; sIsGPUProfiling = t->ProfileGPU(); sIsLayersDump = t->LayersDump(); + sIsDisplayListDump = t->DisplayListDump(); if (Sampler::CanNotifyObservers()) { nsCOMPtr os = mozilla::services::GetObserverService(); @@ -873,6 +877,7 @@ void mozilla_sampler_stop() sIsProfiling = false; sIsGPUProfiling = false; sIsLayersDump = false; + sIsDisplayListDump = false; if (Sampler::CanNotifyObservers()) { nsCOMPtr os = mozilla::services::GetObserverService(); @@ -917,6 +922,10 @@ bool mozilla_sampler_feature_active(const char* aName) return sIsLayersDump; } + if (strcmp(aName, "displaylistdump") == 0) { + return sIsDisplayListDump; + } + return false; } From 93795aa6b04c6817e5cbb6fb82e37b6fd2f14401 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 16 Dec 2014 10:50:43 -0800 Subject: [PATCH 058/130] Bug 1102541 - Add JS::ubi::RootList::addRoot; r=shu --- js/public/UbiNode.h | 16 ++++++++++----- js/src/vm/Debugger.cpp | 10 +-------- js/src/vm/DebuggerMemory.cpp | 12 ++++------- js/src/vm/UbiNode.cpp | 39 ++++++++++++++++++++++++++++++++---- 4 files changed, 51 insertions(+), 26 deletions(-) diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h index 589ecbf2ce44..9aff07057f6b 100644 --- a/js/public/UbiNode.h +++ b/js/public/UbiNode.h @@ -472,7 +472,7 @@ typedef mozilla::Vector SimpleEdgeVector; // // RootList::init itself causes a minor collection, but once the list of roots // has been created, GC must not occur, as the referent ubi::Nodes are not -// stable across GC. The init calls emplace |gcp|'s AutoCheckCannotGC, whose +// stable across GC. The init calls emplace on |noGC|'s AutoCheckCannotGC, whose // lifetime must extend at least as long as the RootList itself. // // Example usage: @@ -480,7 +480,7 @@ typedef mozilla::Vector SimpleEdgeVector; // { // mozilla::Maybe maybeNoGC; // JS::ubi::RootList rootList(cx, maybeNoGC); -// if (!rootList.init(cx)) +// if (!rootList.init()) // return false; // // // The AutoCheckCannotGC is guaranteed to exist if init returned true. @@ -492,6 +492,7 @@ typedef mozilla::Vector SimpleEdgeVector; // } class MOZ_STACK_CLASS RootList { Maybe &noGC; + JSContext *cx; public: SimpleEdgeVector edges; @@ -500,11 +501,16 @@ class MOZ_STACK_CLASS RootList { RootList(JSContext *cx, Maybe &noGC, bool wantNames = false); // Find all GC roots. - bool init(JSContext *cx); + bool init(); // Find only GC roots in the provided set of |Zone|s. - bool init(JSContext *cx, ZoneSet &debuggees); + bool init(ZoneSet &debuggees); // Find only GC roots in the given Debugger object's set of debuggee zones. - bool init(JSContext *cx, HandleObject debuggees); + bool init(HandleObject debuggees); + + // Explicitly add the given Node as a root in this RootList. If wantNames is + // true, you must pass an edgeName. The RootList does not take ownership of + // edgeName. + bool addRoot(Node node, const char16_t *edgeName = nullptr); }; diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index ca773b49384c..97104a438b3c 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -3559,14 +3559,6 @@ class MOZ_STACK_CLASS Debugger::ObjectQuery if (!prepareQuery()) return false; - // Ensure that all of our debuggee globals are rooted so that they are - // visible in the RootList. - JS::AutoObjectVector debuggees(cx); - for (GlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty(); r.popFront()) { - if (!debuggees.append(r.front())) - return false; - } - { /* * We can't tolerate the GC moving things around while we're @@ -3575,7 +3567,7 @@ class MOZ_STACK_CLASS Debugger::ObjectQuery Maybe maybeNoGC; RootedObject dbgObj(cx, dbg->object); JS::ubi::RootList rootList(cx, maybeNoGC); - if (!rootList.init(cx, dbgObj)) + if (!rootList.init(dbgObj)) return false; Traversal traversal(cx, *this, maybeNoGC.ref()); diff --git a/js/src/vm/DebuggerMemory.cpp b/js/src/vm/DebuggerMemory.cpp index 238fa05555fa..3812ee99ef6c 100644 --- a/js/src/vm/DebuggerMemory.cpp +++ b/js/src/vm/DebuggerMemory.cpp @@ -757,22 +757,18 @@ DebuggerMemory::takeCensus(JSContext *cx, unsigned argc, Value *vp) return false; Debugger *dbg = memory->getDebugger(); + RootedObject dbgObj(cx, dbg->object); - // Populate census.debuggeeZones and ensure that all of our debuggee globals - // are rooted so that they are visible in the RootList. - JS::AutoObjectVector debuggees(cx); + // Populate our target set of debuggee zones. for (GlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty(); r.popFront()) { - if (!census.debuggeeZones.put(r.front()->zone()) || - !debuggees.append(static_cast(r.front()))) - { + if (!census.debuggeeZones.put(r.front()->zone())) return false; - } } { Maybe maybeNoGC; JS::ubi::RootList rootList(cx, maybeNoGC); - if (!rootList.init(cx, census.debuggeeZones)) + if (!rootList.init(dbgObj)) return false; dbg::DefaultCensusTraversal traversal(cx, handler, maybeNoGC.ref()); diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp index 78fc5eea4869..7df359e9bd1d 100644 --- a/js/src/vm/UbiNode.cpp +++ b/js/src/vm/UbiNode.cpp @@ -9,11 +9,13 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/Scoped.h" +#include "mozilla/UniquePtr.h" #include "jscntxt.h" #include "jsinfer.h" #include "jsobj.h" #include "jsscript.h" +#include "jsstr.h" #include "jit/IonCode.h" #include "js/Debug.h" @@ -263,13 +265,14 @@ namespace ubi { RootList::RootList(JSContext *cx, Maybe &noGC, bool wantNames /* = false */) : noGC(noGC), + cx(cx), edges(cx), wantNames(wantNames) { } bool -RootList::init(JSContext *cx) +RootList::init() { SimpleEdgeVectorTracer tracer(cx, &edges, wantNames); JS_TraceRuntime(&tracer); @@ -280,7 +283,7 @@ RootList::init(JSContext *cx) } bool -RootList::init(JSContext *cx, ZoneSet &debuggees) +RootList::init(ZoneSet &debuggees) { SimpleEdgeVector allRootEdges(cx); SimpleEdgeVectorTracer tracer(cx, &allRootEdges, wantNames); @@ -306,7 +309,7 @@ RootList::init(JSContext *cx, ZoneSet &debuggees) } bool -RootList::init(JSContext *cx, HandleObject debuggees) +RootList::init(HandleObject debuggees) { MOZ_ASSERT(debuggees && JS::dbg::IsDebugger(ObjectValue(*debuggees))); js::Debugger *dbg = js::Debugger::fromJSObject(debuggees); @@ -320,7 +323,35 @@ RootList::init(JSContext *cx, HandleObject debuggees) return false; } - return init(cx, debuggeeZones); + if (!init(debuggeeZones)) + return false; + + // Ensure that each of our debuggee globals are in the root list. + for (js::GlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty(); r.popFront()) { + if (!addRoot(JS::ubi::Node(static_cast(r.front())), + MOZ_UTF16("debuggee global"))) + { + return false; + } + } + + return true; +} + +bool +RootList::addRoot(Node node, const char16_t *edgeName) +{ + MOZ_ASSERT(noGC.isSome()); + MOZ_ASSERT_IF(wantNames, edgeName); + + mozilla::UniquePtr name; + if (edgeName) { + name = DuplicateString(cx, edgeName); + if (!name) + return false; + } + + return edges.append(mozilla::Move(SimpleEdge(name.release(), node))); } // An EdgeRange concrete class that holds a pre-existing vector of SimpleEdges. From 856a41ceb3ccd55d9d4302c49c6ef1af194612fc Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 16 Dec 2014 10:50:44 -0800 Subject: [PATCH 059/130] Bug 1110327 - Fix assertion failure: dbg->isDebuggee(node.compartment()), at vm/Debugger.cpp. For Debugger.prototype.findObjects, do result accumulation in the ubi::BreadthFirst traversal callback rather than by iterating over the traversed set of nodes after the traversal. r=shu --- js/src/jit-test/tests/debug/bug-1110327.js | 5 ++ js/src/vm/Debugger.cpp | 97 +++++++++++----------- 2 files changed, 55 insertions(+), 47 deletions(-) create mode 100644 js/src/jit-test/tests/debug/bug-1110327.js diff --git a/js/src/jit-test/tests/debug/bug-1110327.js b/js/src/jit-test/tests/debug/bug-1110327.js new file mode 100644 index 000000000000..0e2a66fc0ab8 --- /dev/null +++ b/js/src/jit-test/tests/debug/bug-1110327.js @@ -0,0 +1,5 @@ +// Randomly chosen test: js/src/jit-test/tests/debug/Debugger-debuggees-10.js +x = newGlobal() +x.t = this +// Randomly chosen test: js/src/jit-test/tests/debug/Debugger-findObjects-06.js +Debugger(x).findObjects() diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 97104a438b3c..40717c2a87a7 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -3522,8 +3522,11 @@ class MOZ_STACK_CLASS Debugger::ObjectQuery public: /* Construct an ObjectQuery to use matching scripts for |dbg|. */ ObjectQuery(JSContext *cx, Debugger *dbg) : - cx(cx), dbg(dbg), className(cx) - {} + objects(cx), cx(cx), dbg(dbg), className(cx) + { } + + /* The vector that we are accumulating results in. */ + AutoObjectVector objects; /* * Parse the query object |query|, and prepare to match only the objects it @@ -3555,7 +3558,7 @@ class MOZ_STACK_CLASS Debugger::ObjectQuery * Traverse the heap to find all relevant objects and add them to the * provided vector. */ - bool findObjects(AutoObjectVector &objs) { + bool findObjects() { if (!prepareQuery()) return false; @@ -3575,35 +3578,8 @@ class MOZ_STACK_CLASS Debugger::ObjectQuery return false; traversal.wantNames = false; - if (!traversal.addStart(JS::ubi::Node(&rootList)) || - !traversal.traverse()) - { - return false; - } - - /* - * Iterate over the visited set of nodes and accumulate all - * |JSObject|s matching our criteria in the given vector. - */ - for (Traversal::NodeMap::Range r = traversal.visited.all(); !r.empty(); r.popFront()) { - JS::ubi::Node node = r.front().key(); - if (!node.is()) - continue; - MOZ_ASSERT(dbg->isDebuggee(node.compartment())); - - JSObject *obj = node.as(); - - if (!className.isUndefined()) { - const char *objClassName = obj->getClass()->name; - if (strcmp(objClassName, classNameCString.ptr()) != 0) - continue; - } - - if (!objs.append(obj)) - return false; - } - - return true; + return traversal.addStart(JS::ubi::Node(&rootList)) && + traversal.traverse(); } } @@ -3615,12 +3591,46 @@ class MOZ_STACK_CLASS Debugger::ObjectQuery bool operator() (Traversal &traversal, JS::ubi::Node origin, const JS::ubi::Edge &edge, NodeData *, bool first) { - /* Only follow edges within our set of debuggee compartments. */ - JSCompartment *comp = edge.referent.compartment(); - if (first && comp && !dbg->isDebuggee(edge.referent.compartment())) - traversal.abandonReferent(); + if (!first) + return true; - return true; + JS::ubi::Node referent = edge.referent; + /* + * Only follow edges within our set of debuggee compartments; we don't + * care about the heap's subgraphs outside of our debuggee compartments, + * so we abandon the referent. Either (1) there is not a path from this + * non-debuggee node back to a node in our debuggee compartments, and we + * don't need to follow edges to or from this node, or (2) there does + * exist some path from this non-debuggee node back to a node in our + * debuggee compartments. However, if that were true, then the incoming + * cross compartment edge back into a debuggee compartment is already + * listed as an edge in the RootList we started traversal with, and + * therefore we don't need to follow edges to or from this non-debuggee + * node. + */ + JSCompartment *comp = referent.compartment(); + if (comp && !dbg->isDebuggee(comp)) { + traversal.abandonReferent(); + return true; + } + + /* + * If the referent is an object and matches our query's restrictions, + * add it to the vector accumulating results. + */ + + if (!referent.is()) + return true; + + JSObject *obj = referent.as(); + + if (!className.isUndefined()) { + const char *objClassName = obj->getClass()->name; + if (strcmp(objClassName, classNameCString.ptr()) != 0) + return true; + } + + return objects.append(obj); } private: @@ -3668,17 +3678,10 @@ Debugger::findObjects(JSContext *cx, unsigned argc, Value *vp) query.omittedQuery(); } - /* - * Accumulate the objects in an AutoObjectVector, instead of creating the JS - * array as we go, because we mustn't allocate JS objects or GC while we - * traverse the heap graph. - */ - AutoObjectVector objects(cx); - - if (!query.findObjects(objects)) + if (!query.findObjects()) return false; - size_t length = objects.length(); + size_t length = query.objects.length(); RootedArrayObject result(cx, NewDenseFullyAllocatedArray(cx, length)); if (!result) return false; @@ -3686,7 +3689,7 @@ Debugger::findObjects(JSContext *cx, unsigned argc, Value *vp) result->ensureDenseInitializedLength(cx, 0, length); for (size_t i = 0; i < length; i++) { - RootedValue debuggeeVal(cx, ObjectValue(*objects[i])); + RootedValue debuggeeVal(cx, ObjectValue(*query.objects[i])); if (!dbg->wrapDebuggeeValue(cx, &debuggeeVal)) return false; result->setDenseElement(i, debuggeeVal); From 19a2e8054b9347db9b5f5747e2c908251bb06582 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Tue, 16 Dec 2014 14:13:36 -0500 Subject: [PATCH 060/130] Bug 1111564 - Backout 10692972a7b6 (bug 1084177) for increasing memory usage. r=me --- js/src/jsscript.cpp | 5 +- js/src/vm/Compression.cpp | 99 +++++++++++++++---------------------- js/src/vm/Compression.h | 22 ++------- js/src/vm/HelperThreads.cpp | 6 +-- js/src/vm/HelperThreads.h | 9 +--- 5 files changed, 52 insertions(+), 89 deletions(-) diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index a2e9a1797b99..fda383bf9128 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1752,7 +1752,7 @@ ScriptSource::setSourceCopy(ExclusiveContext *cx, SourceBufferHolder &srcBuf, } SourceCompressionTask::ResultType -SourceCompressionTask::work(Compressor &comp) +SourceCompressionTask::work() { // Try to keep the maximum memory usage down by only allocating half the // size of the string, first. @@ -1762,7 +1762,8 @@ SourceCompressionTask::work(Compressor &comp) if (!compressed) return OOM; - if (!comp.prepare(reinterpret_cast(ss->uncompressedChars()), inputBytes)) + Compressor comp(reinterpret_cast(ss->uncompressedChars()), inputBytes); + if (!comp.init()) return OOM; comp.setOutput((unsigned char *) compressed, firstSize); diff --git a/js/src/vm/Compression.cpp b/js/src/vm/Compression.cpp index 5e261d8122b9..ddacbab8564f 100644 --- a/js/src/vm/Compression.cpp +++ b/js/src/vm/Compression.cpp @@ -6,13 +6,8 @@ #include "vm/Compression.h" -#include "mozilla/DebugOnly.h" - -#include - #include "js/Utility.h" -using mozilla::DebugOnly; using namespace js; static void * @@ -27,91 +22,79 @@ zlib_free(void *cx, void *addr) js_free(addr); } +Compressor::Compressor(const unsigned char *inp, size_t inplen) + : inp(inp), + inplen(inplen), + outbytes(0), + initialized(false) +{ + MOZ_ASSERT(inplen > 0); + zs.opaque = nullptr; + zs.next_in = (Bytef *)inp; + zs.avail_in = 0; + zs.next_out = nullptr; + zs.avail_out = 0; + zs.zalloc = zlib_alloc; + zs.zfree = zlib_free; +} + + Compressor::~Compressor() { if (initialized) { - int ret = deflateEnd(zs); + int ret = deflateEnd(&zs); if (ret != Z_OK) { // If we finished early, we can get a Z_DATA_ERROR. MOZ_ASSERT(ret == Z_DATA_ERROR); - MOZ_ASSERT(uInt(zs->next_in - inp) < inplen || !zs->avail_out); + MOZ_ASSERT(uInt(zs.next_in - inp) < inplen || !zs.avail_out); } } - js_free(zs); } bool -Compressor::prepare(const unsigned char *inp_, size_t inplen_) +Compressor::init() { - MOZ_ASSERT(inplen_ > 0); - - if (inplen_ >= UINT32_MAX) + if (inplen >= UINT32_MAX) + return false; + // zlib is slow and we'd rather be done compression sooner + // even if it means decompression is slower which penalizes + // Function.toString() + int ret = deflateInit(&zs, Z_BEST_SPEED); + if (ret != Z_OK) { + MOZ_ASSERT(ret == Z_MEM_ERROR); return false; - - if (!zs) { - zs = js_pod_malloc(); - if (!zs) - return false; - zs->zalloc = zlib_alloc; - zs->zfree = zlib_free; } - - inp = inp_; - inplen = inplen_; - outbytes = 0; - - zs->opaque = nullptr; - zs->next_in = (Bytef *)inp; - zs->avail_in = 0; - zs->next_out = nullptr; - zs->avail_out = 0; - - if (initialized) { - DebugOnly ret = deflateReset(zs); - MOZ_ASSERT(ret == Z_OK); - } else { - // zlib is slow and we'd rather be done compression sooner even if it - // means decompression is slower which penalizes Function.toString() - int ret = deflateInit(zs, Z_BEST_SPEED); - if (ret != Z_OK) { - MOZ_ASSERT(ret == Z_MEM_ERROR); - return false; - } - initialized = true; - } - + initialized = true; return true; } void Compressor::setOutput(unsigned char *out, size_t outlen) { - MOZ_ASSERT(initialized); MOZ_ASSERT(outlen > outbytes); - zs->next_out = out + outbytes; - zs->avail_out = outlen - outbytes; + zs.next_out = out + outbytes; + zs.avail_out = outlen - outbytes; } Compressor::Status Compressor::compressMore() { - MOZ_ASSERT(initialized); - MOZ_ASSERT(zs->next_out); - uInt left = inplen - (zs->next_in - inp); + MOZ_ASSERT(zs.next_out); + uInt left = inplen - (zs.next_in - inp); bool done = left <= CHUNKSIZE; if (done) - zs->avail_in = left; - else if (zs->avail_in == 0) - zs->avail_in = CHUNKSIZE; - Bytef *oldout = zs->next_out; - int ret = deflate(zs, done ? Z_FINISH : Z_NO_FLUSH); - outbytes += zs->next_out - oldout; + zs.avail_in = left; + else if (zs.avail_in == 0) + zs.avail_in = CHUNKSIZE; + Bytef *oldout = zs.next_out; + int ret = deflate(&zs, done ? Z_FINISH : Z_NO_FLUSH); + outbytes += zs.next_out - oldout; if (ret == Z_MEM_ERROR) { - zs->avail_out = 0; + zs.avail_out = 0; return OOM; } if (ret == Z_BUF_ERROR || (done && ret == Z_OK)) { - MOZ_ASSERT(zs->avail_out == 0); + MOZ_ASSERT(zs.avail_out == 0); return MOREOUTPUT; } MOZ_ASSERT_IF(!done, ret == Z_OK); diff --git a/js/src/vm/Compression.h b/js/src/vm/Compression.h index 3c49e403bd32..1fede47c0588 100644 --- a/js/src/vm/Compression.h +++ b/js/src/vm/Compression.h @@ -7,19 +7,17 @@ #ifndef vm_Compression_h #define vm_Compression_h -#include "mozilla/NullPtr.h" +#include #include "jstypes.h" -struct z_stream_s; // from - namespace js { class Compressor { /* Number of bytes we should hand to zlib each compressMore() call. */ static const size_t CHUNKSIZE = 2048; - struct z_stream_s *zs; + z_stream zs; const unsigned char *inp; size_t inplen; size_t outbytes; @@ -33,22 +31,12 @@ class Compressor OOM }; - Compressor() - : zs(nullptr), - initialized(false) - {} + Compressor(const unsigned char *inp, size_t inplen); ~Compressor(); - /* - * Prepare the compressor to process the string |inp| of length - * |inplen|. Return false if initialization failed (usually OOM). - * - * The compressor may be reused for a different input by calling prepare() - * again. - */ - bool prepare(const unsigned char *inp, size_t inplen); + bool init(); void setOutput(unsigned char *out, size_t outlen); size_t outWritten() const { return outbytes; } - /* Compress some of the input. Return CONTINUE if it should be called again. */ + /* Compress some of the input. Return true if it should be called again. */ Status compressMore(); }; diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index 122711f6ffb5..55e6e8770a4f 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -493,10 +493,8 @@ GlobalHelperThreadState::finish() { if (threads) { MOZ_ASSERT(CanUseExtraThreads()); - for (size_t i = 0; i < threadCount; i++) { + for (size_t i = 0; i < threadCount; i++) threads[i].destroy(); - threads[i].~HelperThread(); - } js_free(threads); } @@ -1212,7 +1210,7 @@ HelperThread::handleCompressionWorkload() { AutoUnlockHelperThreadState unlock; - compressionTask->result = compressionTask->work(sourceCompressor); + compressionTask->result = compressionTask->work(); } compressionTask->helperThread = nullptr; diff --git a/js/src/vm/HelperThreads.h b/js/src/vm/HelperThreads.h index 19ed92855a9e..0da3207822ce 100644 --- a/js/src/vm/HelperThreads.h +++ b/js/src/vm/HelperThreads.h @@ -21,7 +21,6 @@ #include "frontend/TokenStream.h" #include "jit/Ion.h" -#include "vm/Compression.h" namespace js { @@ -309,12 +308,6 @@ struct HelperThread /* Any source being compressed on this thread. */ SourceCompressionTask *compressionTask; - /* - * Compressor that is used for servicing SourceCompressionTasks on this - * thread. - */ - Compressor sourceCompressor; - /* Any GC state for background sweeping or allocating being performed. */ GCHelperState *gcHelperState; @@ -550,7 +543,7 @@ struct SourceCompressionTask complete(); } - ResultType work(Compressor &comp); + ResultType work(); bool complete(); void abort() { abort_ = true; } bool active() const { return !!ss; } From b9503b77b24ec111ccdca04fb2569778c6e18000 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Fri, 5 Dec 2014 09:38:33 -0800 Subject: [PATCH 061/130] Bug 1105069 - Part 13: Take uintptr_t directly in the GC's detail methods; r=jonco --HG-- extra : rebase_source : 2a755ea61e4dab88abfcef44f49e6bda058c7f92 --- js/public/GCAPI.h | 2 +- js/public/HeapAPI.h | 46 +++++++++++++++------------- js/src/gc/Heap.h | 2 +- js/src/jsapi-tests/testGCCellPtr.cpp | 2 +- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/js/public/GCAPI.h b/js/public/GCAPI.h index 407bc68ebdd3..9c6aad03dcbd 100644 --- a/js/public/GCAPI.h +++ b/js/public/GCAPI.h @@ -498,7 +498,6 @@ ExposeGCThingToActiveJS(JS::GCCellPtr thing) { MOZ_ASSERT(thing.kind() != JSTRACE_SHAPE); - JS::shadow::Runtime *rt = GetGCThingRuntime(thing.asCell()); /* * GC things residing in the nursery cannot be gray: they have no mark bits. * All live objects in the nursery are moved to tenured at the beginning of @@ -506,6 +505,7 @@ ExposeGCThingToActiveJS(JS::GCCellPtr thing) */ if (IsInsideNursery(thing.asCell())) return; + JS::shadow::Runtime *rt = detail::GetGCThingRuntime(thing.unsafeAsUIntPtr()); if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) JS::IncrementalReferenceBarrier(thing); else if (JS::GCThingIsMarkedGray(thing.asCell())) diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h index 94b974241152..4c2626f793cf 100644 --- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -282,6 +282,10 @@ class JS_FRIEND_API(GCCellPtr) uint64_t unsafeAsInteger() const { return reinterpret_cast(unsafeGetUntypedPtr()); } + // Inline mark bitmap access requires direct pointer arithmetic. + uintptr_t unsafeAsUIntPtr() const { + return reinterpret_cast(unsafeGetUntypedPtr()); + } private: uintptr_t checkedCast(void *p, JSGCTraceKind traceKind) { @@ -304,48 +308,46 @@ class JS_FRIEND_API(GCCellPtr) namespace js { namespace gc { +namespace detail { static MOZ_ALWAYS_INLINE uintptr_t * -GetGCThingMarkBitmap(const void *thing) +GetGCThingMarkBitmap(const uintptr_t addr) { - MOZ_ASSERT(thing); - uintptr_t addr = uintptr_t(thing); - addr &= ~js::gc::ChunkMask; - addr |= js::gc::ChunkMarkBitmapOffset; - return reinterpret_cast(addr); + MOZ_ASSERT(addr); + const uintptr_t bmap_addr = (addr & ~ChunkMask) | ChunkMarkBitmapOffset; + return reinterpret_cast(bmap_addr); } static MOZ_ALWAYS_INLINE JS::shadow::Runtime * -GetGCThingRuntime(const void *thing) +GetGCThingRuntime(const uintptr_t addr) { - MOZ_ASSERT(thing); - uintptr_t addr = uintptr_t(thing); - addr &= ~js::gc::ChunkMask; - addr |= js::gc::ChunkRuntimeOffset; - return *reinterpret_cast(addr); + MOZ_ASSERT(addr); + const uintptr_t rt_addr = (addr & ~ChunkMask) | ChunkRuntimeOffset; + return *reinterpret_cast(rt_addr); } static MOZ_ALWAYS_INLINE void -GetGCThingMarkWordAndMask(const void *thing, uint32_t color, +GetGCThingMarkWordAndMask(const uintptr_t addr, uint32_t color, uintptr_t **wordp, uintptr_t *maskp) { - uintptr_t addr = uintptr_t(thing); - size_t bit = (addr & js::gc::ChunkMask) / js::gc::CellSize + color; + MOZ_ASSERT(addr); + const size_t bit = (addr & js::gc::ChunkMask) / js::gc::CellSize + color; MOZ_ASSERT(bit < js::gc::ChunkMarkBitmapBits); - uintptr_t *bitmap = GetGCThingMarkBitmap(thing); + uintptr_t *bitmap = GetGCThingMarkBitmap(addr); const uintptr_t nbits = sizeof(*bitmap) * CHAR_BIT; *maskp = uintptr_t(1) << (bit % nbits); *wordp = &bitmap[bit / nbits]; } static MOZ_ALWAYS_INLINE JS::shadow::ArenaHeader * -GetGCThingArena(void *thing) +GetGCThingArena(const uintptr_t addr) { - uintptr_t addr = uintptr_t(thing); - addr &= ~js::gc::ArenaMask; - return reinterpret_cast(addr); + MOZ_ASSERT(addr); + return reinterpret_cast(addr & ~ArenaMask); } +} /* namespace detail */ + MOZ_ALWAYS_INLINE bool IsInsideNursery(const js::gc::Cell *cell) { @@ -369,7 +371,7 @@ GetTenuredGCThingZone(void *thing) { MOZ_ASSERT(thing); MOZ_ASSERT(!js::gc::IsInsideNursery((js::gc::Cell *)thing)); - return js::gc::GetGCThingArena(thing)->zone; + return js::gc::detail::GetGCThingArena(uintptr_t(thing))->zone; } extern JS_PUBLIC_API(Zone *) @@ -387,7 +389,7 @@ GCThingIsMarkedGray(void *thing) if (js::gc::IsInsideNursery((js::gc::Cell *)thing)) return false; uintptr_t *word, mask; - js::gc::GetGCThingMarkWordAndMask(thing, js::gc::GRAY, &word, &mask); + js::gc::detail::GetGCThingMarkWordAndMask(uintptr_t(thing), js::gc::GRAY, &word, &mask); return *word & mask; } diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h index 1c8cc74564c4..ece83ba92955 100644 --- a/js/src/gc/Heap.h +++ b/js/src/gc/Heap.h @@ -839,7 +839,7 @@ struct ChunkBitmap MOZ_ALWAYS_INLINE void getMarkWordAndMask(const Cell *cell, uint32_t color, uintptr_t **wordp, uintptr_t *maskp) { - GetGCThingMarkWordAndMask(cell, color, wordp, maskp); + detail::GetGCThingMarkWordAndMask(uintptr_t(cell), color, wordp, maskp); } MOZ_ALWAYS_INLINE MOZ_TSAN_BLACKLIST bool isMarked(const Cell *cell, uint32_t color) { diff --git a/js/src/jsapi-tests/testGCCellPtr.cpp b/js/src/jsapi-tests/testGCCellPtr.cpp index 28078c6dcfe1..f3b251544f77 100644 --- a/js/src/jsapi-tests/testGCCellPtr.cpp +++ b/js/src/jsapi-tests/testGCCellPtr.cpp @@ -54,7 +54,7 @@ BEGIN_TEST(testGCCellPtr) JS::GCCellPtr copy = objcell; CHECK(copy == objcell); - CHECK(js::gc::GetGCThingRuntime(scriptcell.asCell()) == rt); + CHECK(js::gc::detail::GetGCThingRuntime(scriptcell.unsafeAsUIntPtr()) == rt); return true; } From e4a4d0c7faba3fc928cbae1a78b26a5aa458a94a Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Fri, 5 Dec 2014 09:38:34 -0800 Subject: [PATCH 062/130] Bug 1105069 - Part 14: Convert NoteJSChild to GCCellPtr; r=mccr8, r=jonco --HG-- extra : rebase_source : 2338e0a57779401f9bc4744bc2fa59a4b31d76bf --- dom/base/nsWrapperCache.cpp | 19 +++++++--- dom/base/nsWrapperCacheInlines.h | 4 +- dom/xbl/nsXBLDocumentInfo.cpp | 4 +- js/public/Id.h | 8 +++- js/xpconnect/src/XPCVariant.cpp | 4 +- js/xpconnect/src/XPCWrappedJS.cpp | 2 +- js/xpconnect/src/XPCWrappedNative.cpp | 2 +- js/xpconnect/src/xpcprivate.h | 6 --- xpcom/base/CycleCollectedJSRuntime.cpp | 21 +++++----- xpcom/base/CycleCollectedJSRuntime.h | 6 +++ xpcom/base/nsCycleCollector.cpp | 38 +++++++++++++++---- xpcom/glue/nsCycleCollectionParticipant.cpp | 29 ++++++++------ xpcom/glue/nsCycleCollectionParticipant.h | 4 +- .../glue/nsCycleCollectionTraversalCallback.h | 6 ++- 14 files changed, 99 insertions(+), 54 deletions(-) diff --git a/dom/base/nsWrapperCache.cpp b/dom/base/nsWrapperCache.cpp index 6dc3f9603036..bd59fc3f61db 100644 --- a/dom/base/nsWrapperCache.cpp +++ b/dom/base/nsWrapperCache.cpp @@ -43,7 +43,7 @@ nsWrapperCache::ReleaseWrapper(void* aScriptObjectHolder) class DebugWrapperTraversalCallback : public nsCycleCollectionTraversalCallback { public: - explicit DebugWrapperTraversalCallback(void* aWrapper) + explicit DebugWrapperTraversalCallback(JSObject* aWrapper) : mFound(false) , mWrapper(aWrapper) { @@ -60,12 +60,15 @@ public: { } - NS_IMETHOD_(void) NoteJSChild(void* aChild) + NS_IMETHOD_(void) NoteJSObject(JSObject* aChild) { if (aChild == mWrapper) { mFound = true; } } + NS_IMETHOD_(void) NoteJSScript(JSScript* aChild) + { + } NS_IMETHOD_(void) NoteXPCOMChild(nsISupports* aChild) { } @@ -81,15 +84,17 @@ public: bool mFound; private: - void* mWrapper; + JSObject* mWrapper; }; static void -DebugWrapperTraceCallback(void* aP, const char* aName, void* aClosure) +DebugWrapperTraceCallback(JS::GCCellPtr aPtr, const char* aName, void* aClosure) { DebugWrapperTraversalCallback* callback = static_cast(aClosure); - callback->NoteJSChild(aP); + if (aPtr.isObject()) { + callback->NoteJSObject(aPtr.toObject()); + } } void @@ -103,6 +108,10 @@ nsWrapperCache::CheckCCWrapperTraversal(void* aScriptObjectHolder, DebugWrapperTraversalCallback callback(wrapper); + // The CC traversal machinery cannot trigger GC; however, the analysis cannot + // see through the COM layer, so we use a suppression to help it. + JS::AutoSuppressGCAnalysis suppress; + aTracer->Traverse(aScriptObjectHolder, callback); MOZ_ASSERT(callback.mFound, "Cycle collection participant didn't traverse to preserved " diff --git a/dom/base/nsWrapperCacheInlines.h b/dom/base/nsWrapperCacheInlines.h index 6eec9de9d975..08328337246d 100644 --- a/dom/base/nsWrapperCacheInlines.h +++ b/dom/base/nsWrapperCacheInlines.h @@ -28,10 +28,10 @@ nsWrapperCache::IsBlack() } static void -SearchGray(void* aGCThing, const char* aName, void* aClosure) +SearchGray(JS::GCCellPtr aGCThing, const char* aName, void* aClosure) { bool* hasGrayObjects = static_cast(aClosure); - if (!*hasGrayObjects && aGCThing && JS::GCThingIsMarkedGray(aGCThing)) { + if (!*hasGrayObjects && aGCThing && JS::GCThingIsMarkedGray(aGCThing.asCell())) { *hasGrayObjects = true; } } diff --git a/dom/xbl/nsXBLDocumentInfo.cpp b/dom/xbl/nsXBLDocumentInfo.cpp index 265c6235418e..a3dd2ad7e7e4 100644 --- a/dom/xbl/nsXBLDocumentInfo.cpp +++ b/dom/xbl/nsXBLDocumentInfo.cpp @@ -98,9 +98,9 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXBLDocumentInfo) NS_IMPL_CYCLE_COLLECTION_TRACE_END static void -UnmarkXBLJSObject(void* aP, const char* aName, void* aClosure) +UnmarkXBLJSObject(JS::GCCellPtr aPtr, const char* aName, void* aClosure) { - JS::ExposeObjectToActiveJS(static_cast(aP)); + JS::ExposeObjectToActiveJS(aPtr.toObject()); } static PLDHashOperator diff --git a/js/public/Id.h b/js/public/Id.h index 5cf78ff57520..63473d07bf44 100644 --- a/js/public/Id.h +++ b/js/public/Id.h @@ -139,10 +139,14 @@ JSID_IS_GCTHING(jsid id) return JSID_IS_STRING(id) || JSID_IS_SYMBOL(id); } -static MOZ_ALWAYS_INLINE void * +static MOZ_ALWAYS_INLINE JS::GCCellPtr JSID_TO_GCTHING(jsid id) { - return (void *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); + void *thing = (void *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); + if (JSID_IS_STRING(id)) + return JS::GCCellPtr(thing, JSTRACE_STRING); + MOZ_ASSERT(JSID_IS_SYMBOL(id)); + return JS::GCCellPtr(thing, JSTRACE_SYMBOL); } static MOZ_ALWAYS_INLINE bool diff --git a/js/xpconnect/src/XPCVariant.cpp b/js/xpconnect/src/XPCVariant.cpp index 15530d1d85df..d39c1e449c4e 100644 --- a/js/xpconnect/src/XPCVariant.cpp +++ b/js/xpconnect/src/XPCVariant.cpp @@ -83,9 +83,9 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(XPCVariant) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XPCVariant) JS::Value val = tmp->GetJSValPreserveColor(); - if (val.isObjectOrNull()) { + if (val.isObject()) { NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSVal"); - cb.NoteJSChild(val.toObjectOrNull()); + cb.NoteJSObject(&val.toObject()); } nsVariant::Traverse(tmp->mData, cb); diff --git a/js/xpconnect/src/XPCWrappedJS.cpp b/js/xpconnect/src/XPCWrappedJS.cpp index 9d9dca439f35..06488745e2c6 100644 --- a/js/xpconnect/src/XPCWrappedJS.cpp +++ b/js/xpconnect/src/XPCWrappedJS.cpp @@ -123,7 +123,7 @@ NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Traverse if (tmp->IsValid()) { MOZ_ASSERT(refcnt > 1); NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSObj"); - cb.NoteJSChild(tmp->GetJSObjectPreserveColor()); + cb.NoteJSObject(tmp->GetJSObjectPreserveColor()); } if (tmp->IsRootWrapper()) { diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index 74660f7752d4..e4ed25ce049d 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -77,7 +77,7 @@ NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse JSObject *obj = tmp->GetFlatJSObjectPreserveColor(); NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFlatJSObject"); - cb.NoteJSChild(obj); + cb.NoteJSObject(obj); } // XPCWrappedNative keeps its native object alive. diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index c407d18f028f..78d0f716aad0 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -243,12 +243,6 @@ static inline bool IS_WN_REFLECTOR(JSObject *obj) // returned as function call result values they are not addref'd. Exceptions // to this rule are noted explicitly. -inline bool -AddToCCKind(JSGCTraceKind kind) -{ - return kind == JSTRACE_OBJECT || kind == JSTRACE_SCRIPT; -} - class nsXPConnect : public nsIXPConnect, public nsIThreadObserver, public nsSupportsWeakReference, diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index fa1dcf3377b4..4259b4da72e9 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -119,12 +119,6 @@ public: } // namespace mozilla -inline bool -AddToCCKind(JSGCTraceKind aKind) -{ - return aKind == JSTRACE_OBJECT || aKind == JSTRACE_SCRIPT; -} - static void TraceWeakMappingChild(JSTracer* aTrc, void** aThingp, JSGCTraceKind aKind); @@ -308,7 +302,7 @@ struct Closure }; static void -CheckParticipatesInCycleCollection(void* aThing, const char* aName, +CheckParticipatesInCycleCollection(JS::GCCellPtr aThing, const char* aName, void* aClosure) { Closure* closure = static_cast(aClosure); @@ -317,8 +311,8 @@ CheckParticipatesInCycleCollection(void* aThing, const char* aName, return; } - if (AddToCCKind(js::GCThingTraceKind(aThing)) && - xpc_IsGrayGCThing(aThing)) { + if (AddToCCKind(aThing.kind()) && + xpc_IsGrayGCThing(aThing.asCell())) { closure->mCycleCollectionEnabled = true; } } @@ -424,7 +418,12 @@ NoteJSChild(JSTracer* aTrc, void* aThing, JSGCTraceKind aTraceKind) tracer->mCb.NoteNextEdgeName(static_cast(tracer->debugPrintArg())); } } - tracer->mCb.NoteJSChild(aThing); + JS::GCCellPtr thing(aThing, aTraceKind); + if (thing.isObject()) { + tracer->mCb.NoteJSObject(thing.toObject()); + } else { + tracer->mCb.NoteJSScript(thing.toScript()); + } } else if (aTraceKind == JSTRACE_SHAPE) { JS_TraceShapeCycleCollectorChildren(aTrc, aThing); } else if (aTraceKind != JSTRACE_STRING) { @@ -915,7 +914,7 @@ CycleCollectedJSRuntime::IsJSHolder(void* aHolder) } static void -AssertNoGcThing(void* aGCThing, const char* aName, void* aClosure) +AssertNoGcThing(JS::GCCellPtr aGCThing, const char* aName, void* aClosure) { MOZ_ASSERT(!aGCThing); } diff --git a/xpcom/base/CycleCollectedJSRuntime.h b/xpcom/base/CycleCollectedJSRuntime.h index a5e603c173db..68a764d9671e 100644 --- a/xpcom/base/CycleCollectedJSRuntime.h +++ b/xpcom/base/CycleCollectedJSRuntime.h @@ -334,6 +334,12 @@ MOZ_FINISH_NESTED_ENUM_CLASS(CycleCollectedJSRuntime::OOMState) void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer); +// Returns true if the JSGCTraceKind is one the cycle collector cares about. +inline bool AddToCCKind(JSGCTraceKind aKind) +{ + return aKind == JSTRACE_OBJECT || aKind == JSTRACE_SCRIPT; +} + } // namespace mozilla #endif // mozilla_CycleCollectedJSRuntime_h__ diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 61ecefb9e654..edeee7110952 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -2082,12 +2082,15 @@ public: uint64_t aCompartmentAddress); NS_IMETHOD_(void) NoteXPCOMChild(nsISupports* aChild); - NS_IMETHOD_(void) NoteJSChild(void* aChild); + NS_IMETHOD_(void) NoteJSObject(JSObject* aChild); + NS_IMETHOD_(void) NoteJSScript(JSScript* aChild); NS_IMETHOD_(void) NoteNativeChild(void* aChild, nsCycleCollectionParticipant* aParticipant); NS_IMETHOD_(void) NoteNextEdgeName(const char* aName); private: + void NoteJSChild(JS::GCCellPtr aChild); + NS_IMETHOD_(void) NoteRoot(void* aRoot, nsCycleCollectionParticipant* aParticipant) { @@ -2318,7 +2321,19 @@ CCGraphBuilder::NoteNativeChild(void* aChild, } NS_IMETHODIMP_(void) -CCGraphBuilder::NoteJSChild(void* aChild) +CCGraphBuilder::NoteJSObject(JSObject* aChild) +{ + return NoteJSChild(JS::GCCellPtr(aChild)); +} + +NS_IMETHODIMP_(void) +CCGraphBuilder::NoteJSScript(JSScript* aChild) +{ + return NoteJSChild(JS::GCCellPtr(aChild)); +} + +void +CCGraphBuilder::NoteJSChild(JS::GCCellPtr aChild) { if (!aChild) { return; @@ -2330,11 +2345,11 @@ CCGraphBuilder::NoteJSChild(void* aChild) mNextEdgeName.Truncate(); } - if (xpc_GCThingIsGrayCCThing(aChild) || MOZ_UNLIKELY(WantAllTraces())) { - if (JS::Zone* zone = MergeZone(aChild)) { + if (xpc_GCThingIsGrayCCThing(aChild.asCell()) || MOZ_UNLIKELY(WantAllTraces())) { + if (JS::Zone* zone = MergeZone(aChild.asCell())) { NoteChild(zone, mJSZoneParticipant, edgeName); } else { - NoteChild(aChild, mJSParticipant, edgeName); + NoteChild(aChild.asCell(), mJSParticipant, edgeName); } } } @@ -2410,7 +2425,8 @@ public: NS_IMETHOD_(void) NoteXPCOMChild(nsISupports* aChild); NS_IMETHOD_(void) NoteNativeChild(void* aChild, nsCycleCollectionParticipant* aHelper); - NS_IMETHOD_(void) NoteJSChild(void* aChild); + NS_IMETHOD_(void) NoteJSObject(JSObject* aChild); + NS_IMETHOD_(void) NoteJSScript(JSScript* aChild); NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt aRefcount, const char* aObjname) @@ -2459,7 +2475,15 @@ ChildFinder::NoteNativeChild(void* aChild, } NS_IMETHODIMP_(void) -ChildFinder::NoteJSChild(void* aChild) +ChildFinder::NoteJSObject(JSObject* aChild) +{ + if (aChild && xpc_GCThingIsGrayCCThing(aChild)) { + mMayHaveChild = true; + } +} + +NS_IMETHODIMP_(void) +ChildFinder::NoteJSScript(JSScript* aChild) { if (aChild && xpc_GCThingIsGrayCCThing(aChild)) { mMayHaveChild = true; diff --git a/xpcom/glue/nsCycleCollectionParticipant.cpp b/xpcom/glue/nsCycleCollectionParticipant.cpp index 9739240d81b3..b0763def432d 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.cpp +++ b/xpcom/glue/nsCycleCollectionParticipant.cpp @@ -5,8 +5,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsCycleCollectionParticipant.h" +#include "mozilla/CycleCollectedJSRuntime.h" #include "nsCOMPtr.h" #include "jsapi.h" +#include "jsfriendapi.h" #ifdef MOZILLA_INTERNAL_API #include "nsString.h" @@ -15,13 +17,19 @@ #endif void -nsScriptObjectTracer::NoteJSChild(void* aScriptThing, const char* aName, +nsScriptObjectTracer::NoteJSChild(JS::GCCellPtr aGCThing, const char* aName, void* aClosure) { nsCycleCollectionTraversalCallback* cb = static_cast(aClosure); NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, aName); - cb->NoteJSChild(aScriptThing); + if (aGCThing.isObject()) { + cb->NoteJSObject(aGCThing.toObject()); + } else if (aGCThing.isScript()) { + cb->NoteJSScript(aGCThing.toScript()); + } else { + MOZ_ASSERT(!mozilla::AddToCCKind(aGCThing.kind())); + } } NS_IMETHODIMP_(void) @@ -72,7 +80,7 @@ TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { if (aPtr->isMarkable()) { - mCallback(aPtr->toGCThing(), aName, aClosure); + mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); } } @@ -80,9 +88,8 @@ void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - void* thing = JSID_TO_GCTHING(*aPtr); - if (thing) { - mCallback(thing, aName, aClosure); + if (JSID_IS_GCTHING(*aPtr)) { + mCallback(JSID_TO_GCTHING(*aPtr), aName, aClosure); } } @@ -90,33 +97,33 @@ void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(*aPtr, aName, aClosure); + mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); } void TraceCallbackFunc::Trace(JS::TenuredHeap* aPtr, const char* aName, void* aClosure) const { - mCallback(*aPtr, aName, aClosure); + mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); } void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(*aPtr, aName, aClosure); + mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); } void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(*aPtr, aName, aClosure); + mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); } void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(aPtr->get(), aName, aClosure); + mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); } diff --git a/xpcom/glue/nsCycleCollectionParticipant.h b/xpcom/glue/nsCycleCollectionParticipant.h index cfc227d9d6f5..c84868a0a2df 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.h +++ b/xpcom/glue/nsCycleCollectionParticipant.h @@ -80,7 +80,7 @@ struct TraceCallbacks */ struct TraceCallbackFunc : public TraceCallbacks { - typedef void (*Func)(void* aPtr, const char* aName, void* aClosure); + typedef void (*Func)(JS::GCCellPtr aPtr, const char* aName, void* aClosure); explicit TraceCallbackFunc(Func aCb) : mCallback(aCb) {} @@ -184,7 +184,7 @@ public: NS_IMETHOD_(void) Trace(void* aPtr, const TraceCallbacks& aCb, void* aClosure) = 0; - static void NoteJSChild(void* aScriptThing, const char* aName, + static void NoteJSChild(JS::GCCellPtr aGCThing, const char* aName, void* aClosure); }; diff --git a/xpcom/glue/nsCycleCollectionTraversalCallback.h b/xpcom/glue/nsCycleCollectionTraversalCallback.h index 89655ec209a0..fe3e7108851e 100644 --- a/xpcom/glue/nsCycleCollectionTraversalCallback.h +++ b/xpcom/glue/nsCycleCollectionTraversalCallback.h @@ -7,6 +7,7 @@ #ifndef nsCycleCollectionTraversalCallback_h__ #define nsCycleCollectionTraversalCallback_h__ +#include "jspubtd.h" #include "nsISupports.h" class nsCycleCollectionParticipant; @@ -26,12 +27,13 @@ public: uint64_t aCompartmentAddress = 0) = 0; NS_IMETHOD_(void) NoteXPCOMChild(nsISupports* aChild) = 0; - NS_IMETHOD_(void) NoteJSChild(void* aChild) = 0; + NS_IMETHOD_(void) NoteJSObject(JSObject* aChild) = 0; + NS_IMETHOD_(void) NoteJSScript(JSScript* aChild) = 0; NS_IMETHOD_(void) NoteNativeChild(void* aChild, nsCycleCollectionParticipant* aHelper) = 0; // Give a name to the edge associated with the next call to - // NoteXPCOMChild, NoteJSChild, or NoteNativeChild. + // NoteXPCOMChild, NoteJSObject, NoteJSScript, or NoteNativeChild. // Callbacks who care about this should set WANT_DEBUG_INFO in the // flags. NS_IMETHOD_(void) NoteNextEdgeName(const char* aName) = 0; From a99f92dd64d479e088bb49b4473cbb53d757f8e1 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Tue, 9 Dec 2014 16:22:51 -0800 Subject: [PATCH 063/130] Bug 1105069 - Part 15: Convert xpc_GCThingIsGrayCCThing to GCCellPtr; r=mccr8, r=jonco --HG-- extra : rebase_source : 096b8eaf5b46afc1c40b0b9e8b233ec13c638c85 --- js/public/HeapAPI.h | 12 +++++++ js/xpconnect/src/nsXPConnect.cpp | 7 ---- js/xpconnect/src/xpcpublic.h | 5 --- xpcom/base/nsCycleCollector.cpp | 56 +++++++++++++++++++++----------- 4 files changed, 49 insertions(+), 31 deletions(-) diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h index 4c2626f793cf..4606cb0501bc 100644 --- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -393,6 +393,18 @@ GCThingIsMarkedGray(void *thing) return *word & mask; } +static MOZ_ALWAYS_INLINE bool +ObjectIsMarkedGray(JSObject *obj) +{ + return GCThingIsMarkedGray(obj); +} + +static MOZ_ALWAYS_INLINE bool +ScriptIsMarkedGray(JSScript *script) +{ + return GCThingIsMarkedGray(script); +} + } /* namespace JS */ namespace js { diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 76cb1da9d7c0..4b803ad7bb49 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -295,13 +295,6 @@ nsXPConnect::GarbageCollect(uint32_t reason) return NS_OK; } -bool -xpc_GCThingIsGrayCCThing(void *thing) -{ - return AddToCCKind(js::GCThingTraceKind(thing)) && - xpc_IsGrayGCThing(thing); -} - void xpc_MarkInCCGeneration(nsISupports* aVariant, uint32_t aGeneration) { diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 39204ab309f9..ab76a9e887fd 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -185,11 +185,6 @@ xpc_IsGrayGCThing(void *thing) return JS::GCThingIsMarkedGray(thing); } -// The cycle collector only cares about some kinds of GCthings that are -// reachable from an XPConnect root. Implemented in nsXPConnect.cpp. -extern bool -xpc_GCThingIsGrayCCThing(void *thing); - inline JSScript * xpc_UnmarkGrayScript(JSScript *script) { diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index edeee7110952..ac26d8f18490 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -2017,6 +2017,20 @@ nsCycleCollectorLoggerConstructor(nsISupports* aOuter, return logger->QueryInterface(aIID, aInstancePtr); } +static bool +GCThingIsGrayCCThing(JS::GCCellPtr thing) +{ + return AddToCCKind(thing.kind()) && + JS::GCThingIsMarkedGray(thing.asCell()); +} + +static bool +ValueIsGrayCCThing(const JS::Value& value) +{ + return AddToCCKind(value.gcKind()) && + JS::GCThingIsMarkedGray(value.toGCThing()); +} + //////////////////////////////////////////////////////////////////////// // Bacon & Rajan's |MarkRoots| routine. //////////////////////////////////////////////////////////////////////// @@ -2051,7 +2065,8 @@ public: } PtrInfo* AddNode(void* aPtr, nsCycleCollectionParticipant* aParticipant); - PtrInfo* AddWeakMapNode(void* aNode); + PtrInfo* AddWeakMapNode(JS::GCCellPtr aThing); + PtrInfo* AddWeakMapNode(JSObject* aObject); void Traverse(PtrInfo* aPtrInfo); void SetLastChild(); @@ -2345,7 +2360,7 @@ CCGraphBuilder::NoteJSChild(JS::GCCellPtr aChild) mNextEdgeName.Truncate(); } - if (xpc_GCThingIsGrayCCThing(aChild.asCell()) || MOZ_UNLIKELY(WantAllTraces())) { + if (GCThingIsGrayCCThing(aChild) || MOZ_UNLIKELY(WantAllTraces())) { if (JS::Zone* zone = MergeZone(aChild.asCell())) { NoteChild(zone, mJSZoneParticipant, edgeName); } else { @@ -2363,18 +2378,24 @@ CCGraphBuilder::NoteNextEdgeName(const char* aName) } PtrInfo* -CCGraphBuilder::AddWeakMapNode(void* aNode) +CCGraphBuilder::AddWeakMapNode(JS::GCCellPtr aNode) { MOZ_ASSERT(aNode, "Weak map node should be non-null."); - if (!xpc_GCThingIsGrayCCThing(aNode) && !WantAllTraces()) { + if (!GCThingIsGrayCCThing(aNode) && !WantAllTraces()) { return nullptr; } - if (JS::Zone* zone = MergeZone(aNode)) { + if (JS::Zone* zone = MergeZone(aNode.asCell())) { return AddNode(zone, mJSZoneParticipant); } - return AddNode(aNode, mJSParticipant); + return AddNode(aNode.asCell(), mJSParticipant); +} + +PtrInfo* +CCGraphBuilder::AddWeakMapNode(JSObject* aObject) +{ + return AddWeakMapNode(JS::GCCellPtr(aObject)); } NS_IMETHODIMP_(void) @@ -2385,9 +2406,9 @@ CCGraphBuilder::NoteWeakMapping(JSObject* aMap, JS::GCCellPtr aKey, // do that in TraceWeakMapping in nsXPConnect. WeakMapping* mapping = mGraph.mWeakMaps.AppendElement(); mapping->mMap = aMap ? AddWeakMapNode(aMap) : nullptr; - mapping->mKey = aKey ? AddWeakMapNode(aKey.asCell()) : nullptr; + mapping->mKey = aKey ? AddWeakMapNode(aKey) : nullptr; mapping->mKeyDelegate = aKdelegate ? AddWeakMapNode(aKdelegate) : mapping->mKey; - mapping->mVal = aVal ? AddWeakMapNode(aVal.asCell()) : nullptr; + mapping->mVal = aVal ? AddWeakMapNode(aVal) : nullptr; if (mListener) { mListener->NoteWeakMapEntry((uint64_t)aMap, aKey.unsafeAsInteger(), @@ -2477,7 +2498,7 @@ ChildFinder::NoteNativeChild(void* aChild, NS_IMETHODIMP_(void) ChildFinder::NoteJSObject(JSObject* aChild) { - if (aChild && xpc_GCThingIsGrayCCThing(aChild)) { + if (aChild && JS::ObjectIsMarkedGray(aChild)) { mMayHaveChild = true; } } @@ -2485,7 +2506,7 @@ ChildFinder::NoteJSObject(JSObject* aChild) NS_IMETHODIMP_(void) ChildFinder::NoteJSScript(JSScript* aChild) { - if (aChild && xpc_GCThingIsGrayCCThing(aChild)) { + if (aChild && JS::ScriptIsMarkedGray(aChild)) { mMayHaveChild = true; } } @@ -2629,13 +2650,9 @@ public: virtual void Trace(JS::Heap* aValue, const char* aName, void* aClosure) const { - JS::Value val = *aValue; - if (val.isMarkable()) { - void* thing = val.toGCThing(); - if (thing && xpc_GCThingIsGrayCCThing(thing)) { - MOZ_ASSERT(!js::gc::IsInsideNursery((js::gc::Cell*)thing)); - mCollector->GetJSPurpleBuffer()->mValues.InfallibleAppend(val); - } + if (aValue->isMarkable() && ValueIsGrayCCThing(*aValue)) { + MOZ_ASSERT(!js::gc::IsInsideNursery(aValue->toGCThing())); + mCollector->GetJSPurpleBuffer()->mValues.InfallibleAppend(*aValue); } } @@ -2646,7 +2663,7 @@ public: void AppendJSObjectToPurpleBuffer(JSObject* obj) const { - if (obj && xpc_GCThingIsGrayCCThing(obj)) { + if (obj && JS::ObjectIsMarkedGray(obj)) { MOZ_ASSERT(!js::gc::IsInsideNursery(JS::AsCell(obj))); mCollector->GetJSPurpleBuffer()->mObjects.InfallibleAppend(obj); } @@ -3027,7 +3044,8 @@ nsCycleCollector::ScanIncrementalRoots() // If the object is still marked gray by the GC, nothing could have gotten // hold of it, so it isn't an incremental root. if (pi->mParticipant == jsParticipant) { - if (xpc_GCThingIsGrayCCThing(pi->mPointer)) { + JS::GCCellPtr ptr(pi->mPointer, js::GCThingTraceKind(pi->mPointer)); + if (GCThingIsGrayCCThing(ptr)) { continue; } } else if (pi->mParticipant == zoneParticipant) { From c11cd8a3414c724c643c09e2e77ec8cee0a2ebe4 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Fri, 12 Dec 2014 14:13:29 -0800 Subject: [PATCH 064/130] Bug 1105069 - Part 16: Convert UnmarkGrayChildren to strongly typed internal APIs; r=jonco --HG-- extra : rebase_source : 0f45ac749ce210688dd1b81299736c8a71fe55e8 --- js/src/gc/Heap.h | 8 +++-- js/src/gc/Marking.cpp | 68 ++++++++++++++++++++++++------------------- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h index ece83ba92955..a9c41acbedab 100644 --- a/js/src/gc/Heap.h +++ b/js/src/gc/Heap.h @@ -50,6 +50,9 @@ extern bool CurrentThreadIsIonCompiling(); #endif +extern bool +UnmarkGrayCellRecursively(gc::Cell *cell, JSGCTraceKind kind); + namespace gc { struct Arena; @@ -1353,9 +1356,8 @@ TenuredCell::readBarrier(TenuredCell *thing) MapAllocToTraceKind(thing->getAllocKind())); MOZ_ASSERT(tmp == thing); } - JS::GCCellPtr cellptr(thing, thing->getTraceKind()); - if (JS::GCThingIsMarkedGray(thing)) - JS::UnmarkGrayGCThingRecursively(cellptr); + if (thing->isMarked(js::gc::GRAY)) + UnmarkGrayCellRecursively(thing, thing->getTraceKind()); } /* static */ MOZ_ALWAYS_INLINE void diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 9e6f07e05394..40329f1fb521 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -1984,7 +1984,8 @@ js::TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind) static void AssertNonGrayGCThing(JSTracer *trc, void **thingp, JSGCTraceKind kind) { - MOZ_ASSERT(!JS::GCThingIsMarkedGray(*thingp)); + DebugOnly thing(static_cast(*thingp)); + MOZ_ASSERT_IF(thing->isTenured(), !thing->asTenured().isMarked(js::gc::GRAY)); } #endif @@ -2015,7 +2016,7 @@ struct UnmarkGrayTracer : public JSTracer bool tracingShape; /* If tracingShape, shape child or nullptr. Otherwise, nullptr. */ - void *previousShape; + Shape *previousShape; /* Whether we unmarked anything. */ bool unmarkedAny; @@ -2054,9 +2055,10 @@ struct UnmarkGrayTracer : public JSTracer static void UnmarkGrayChildren(JSTracer *trc, void **thingp, JSGCTraceKind kind) { - void *thing = *thingp; int stackDummy; - if (!JS_CHECK_STACK_SIZE(trc->runtime()->mainThread.nativeStackLimit[StackForSystemCode], &stackDummy)) { + if (!JS_CHECK_STACK_SIZE(trc->runtime()->mainThread.nativeStackLimit[StackForSystemCode], + &stackDummy)) + { /* * If we run out of stack, we take a more drastic measure: require that * we GC again before the next CC. @@ -2065,53 +2067,59 @@ UnmarkGrayChildren(JSTracer *trc, void **thingp, JSGCTraceKind kind) return; } -#ifdef DEBUG - if (gc::IsInsideNursery(static_cast(thing))) { - JSTracer nongray(trc->runtime(), AssertNonGrayGCThing); - JS_TraceChildren(&nongray, thing, kind); - } -#endif + Cell *cell = static_cast(*thingp); - if (!JS::GCThingIsMarkedGray(thing)) + // Cells in the nursery cannot be gray, and therefore must necessarily point + // to only black edges. + if (!cell->isTenured()) { +#ifdef DEBUG + JSTracer nongray(trc->runtime(), AssertNonGrayGCThing); + TraceChildren(&nongray, cell, kind); +#endif return; + } + + TenuredCell &tenured = cell->asTenured(); + if (!tenured.isMarked(js::gc::GRAY)) + return; + tenured.unmark(js::gc::GRAY); UnmarkGrayTracer *tracer = static_cast(trc); - TenuredCell::fromPointer(thing)->unmark(js::gc::GRAY); tracer->unmarkedAny = true; - /* - * Trace children of |thing|. If |thing| and its parent are both shapes, - * |thing| will get saved to mPreviousShape without being traced. The parent - * will later trace |thing|. This is done to avoid increasing the stack - * depth during shape tracing. It is safe to do because a shape can only - * have one child that is a shape. - */ + // Trace children of |tenured|. If |tenured| and its parent are both + // shapes, |tenured| will get saved to mPreviousShape without being traced. + // The parent will later trace |tenured|. This is done to avoid increasing + // the stack depth during shape tracing. It is safe to do because a shape + // can only have one child that is a shape. UnmarkGrayTracer childTracer(tracer, kind == JSTRACE_SHAPE); if (kind != JSTRACE_SHAPE) { - JS_TraceChildren(&childTracer, thing, kind); + TraceChildren(&childTracer, &tenured, kind); MOZ_ASSERT(!childTracer.previousShape); tracer->unmarkedAny |= childTracer.unmarkedAny; return; } + MOZ_ASSERT(kind == JSTRACE_SHAPE); + Shape *shape = static_cast(&tenured); if (tracer->tracingShape) { MOZ_ASSERT(!tracer->previousShape); - tracer->previousShape = thing; + tracer->previousShape = shape; return; } do { - MOZ_ASSERT(!JS::GCThingIsMarkedGray(thing)); - JS_TraceChildren(&childTracer, thing, JSTRACE_SHAPE); - thing = childTracer.previousShape; + MOZ_ASSERT(!shape->isMarked(js::gc::GRAY)); + TraceChildren(&childTracer, shape, JSTRACE_SHAPE); + shape = childTracer.previousShape; childTracer.previousShape = nullptr; - } while (thing); + } while (shape); tracer->unmarkedAny |= childTracer.unmarkedAny; } -static bool -UnmarkGrayCellRecursively(gc::Cell *cell, JSGCTraceKind kind) +bool +js::UnmarkGrayCellRecursively(gc::Cell *cell, JSGCTraceKind kind) { MOZ_ASSERT(cell); @@ -2132,7 +2140,7 @@ UnmarkGrayCellRecursively(gc::Cell *cell, JSGCTraceKind kind) } UnmarkGrayTracer trc(rt); - JS_TraceChildren(&trc, cell, kind); + TraceChildren(&trc, cell, kind); return unmarkedArg || trc.unmarkedAny; } @@ -2140,11 +2148,11 @@ UnmarkGrayCellRecursively(gc::Cell *cell, JSGCTraceKind kind) bool js::UnmarkGrayShapeRecursively(Shape *shape) { - return UnmarkGrayCellRecursively(shape, JSTRACE_SHAPE); + return js::UnmarkGrayCellRecursively(shape, JSTRACE_SHAPE); } JS_FRIEND_API(bool) JS::UnmarkGrayGCThingRecursively(JS::GCCellPtr thing) { - return UnmarkGrayCellRecursively(thing.asCell(), thing.kind()); + return js::UnmarkGrayCellRecursively(thing.asCell(), thing.kind()); } From 20e03ef2a5e4b36d45ada19e4fcf68ec0ad1b928 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Fri, 5 Dec 2014 09:38:34 -0800 Subject: [PATCH 065/130] Bug 1105069 - Part 17: Convert xpc_IsGrayGCThing to GCCellPtr; r=mccr8, j=jonco --HG-- extra : rebase_source : 9fdc5ac9ca8de9c12a399532db7e77bc34abb7da --- dom/base/FragmentOrElement.cpp | 2 +- dom/base/nsGlobalWindow.cpp | 3 +- dom/base/nsWrapperCacheInlines.h | 4 +-- dom/bindings/CallbackFunction.h | 2 +- js/public/GCAPI.h | 2 +- js/public/HeapAPI.h | 35 +++++++++++++-------- js/public/Value.h | 4 +++ js/src/jsfriendapi.cpp | 2 +- js/src/jsgc.cpp | 4 +-- js/xpconnect/src/XPCJSRuntime.cpp | 6 ++-- js/xpconnect/src/XPCWrappedJS.cpp | 2 +- js/xpconnect/src/xpcpublic.h | 9 ------ xpcom/base/CycleCollectedJSRuntime.cpp | 42 ++++++++++++-------------- xpcom/base/nsCycleCollector.cpp | 4 +-- 14 files changed, 62 insertions(+), 59 deletions(-) diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 03ba04286e38..62d623a7f570 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -1620,7 +1620,7 @@ ShouldClearPurple(nsIContent* aContent) } JSObject* o = GetJSObjectChild(aContent); - if (o && xpc_IsGrayGCThing(o)) { + if (o && JS::ObjectIsMarkedGray(o)) { return true; } diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 4cfd7329bbcd..93a166ae3fad 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -1913,7 +1913,8 @@ nsGlobalWindow::UnmarkGrayTimers() if (f) { // Callable() already does xpc_UnmarkGrayObject. DebugOnly > o = f->Callable(); - MOZ_ASSERT(!xpc_IsGrayGCThing(o.value), "Should have been unmarked"); + MOZ_ASSERT(!JS::ObjectIsMarkedGray(o.value), + "Should have been unmarked"); } } } diff --git a/dom/base/nsWrapperCacheInlines.h b/dom/base/nsWrapperCacheInlines.h index 08328337246d..6be909420bda 100644 --- a/dom/base/nsWrapperCacheInlines.h +++ b/dom/base/nsWrapperCacheInlines.h @@ -24,14 +24,14 @@ inline bool nsWrapperCache::IsBlack() { JSObject* o = GetWrapperPreserveColor(); - return o && !JS::GCThingIsMarkedGray(o); + return o && !JS::ObjectIsMarkedGray(o); } static void SearchGray(JS::GCCellPtr aGCThing, const char* aName, void* aClosure) { bool* hasGrayObjects = static_cast(aClosure); - if (!*hasGrayObjects && aGCThing && JS::GCThingIsMarkedGray(aGCThing.asCell())) { + if (!*hasGrayObjects && aGCThing && JS::GCThingIsMarkedGray(aGCThing)) { *hasGrayObjects = true; } } diff --git a/dom/bindings/CallbackFunction.h b/dom/bindings/CallbackFunction.h index 400c19942bea..ec1834b2a447 100644 --- a/dom/bindings/CallbackFunction.h +++ b/dom/bindings/CallbackFunction.h @@ -39,7 +39,7 @@ public: bool HasGrayCallable() const { // Play it safe in case this gets called after unlink. - return mCallback && xpc_IsGrayGCThing(mCallback); + return mCallback && JS::ObjectIsMarkedGray(mCallback); } protected: diff --git a/js/public/GCAPI.h b/js/public/GCAPI.h index 9c6aad03dcbd..67843d40fe3a 100644 --- a/js/public/GCAPI.h +++ b/js/public/GCAPI.h @@ -508,7 +508,7 @@ ExposeGCThingToActiveJS(JS::GCCellPtr thing) JS::shadow::Runtime *rt = detail::GetGCThingRuntime(thing.unsafeAsUIntPtr()); if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) JS::IncrementalReferenceBarrier(thing); - else if (JS::GCThingIsMarkedGray(thing.asCell())) + else if (JS::GCThingIsMarkedGray(thing)) JS::UnmarkGrayGCThingRecursively(thing); } diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h index 4606cb0501bc..c2fecc6ea7c5 100644 --- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -346,6 +346,16 @@ GetGCThingArena(const uintptr_t addr) return reinterpret_cast(addr & ~ArenaMask); } +static MOZ_ALWAYS_INLINE bool +CellIsMarkedGray(const Cell *cell) +{ + MOZ_ASSERT(cell); + MOZ_ASSERT(!js::gc::IsInsideNursery(cell)); + uintptr_t *word, mask; + js::gc::detail::GetGCThingMarkWordAndMask(uintptr_t(cell), js::gc::GRAY, &word, &mask); + return *word & mask; +} + } /* namespace detail */ MOZ_ALWAYS_INLINE bool @@ -378,31 +388,30 @@ extern JS_PUBLIC_API(Zone *) GetObjectZone(JSObject *obj); static MOZ_ALWAYS_INLINE bool -GCThingIsMarkedGray(void *thing) +ObjectIsMarkedGray(JSObject *obj) { - MOZ_ASSERT(thing); /* * GC things residing in the nursery cannot be gray: they have no mark bits. * All live objects in the nursery are moved to tenured at the beginning of * each GC slice, so the gray marker never sees nursery things. */ - if (js::gc::IsInsideNursery((js::gc::Cell *)thing)) + if (js::gc::IsInsideNursery(reinterpret_cast(obj))) return false; - uintptr_t *word, mask; - js::gc::detail::GetGCThingMarkWordAndMask(uintptr_t(thing), js::gc::GRAY, &word, &mask); - return *word & mask; -} - -static MOZ_ALWAYS_INLINE bool -ObjectIsMarkedGray(JSObject *obj) -{ - return GCThingIsMarkedGray(obj); + return js::gc::detail::CellIsMarkedGray(reinterpret_cast(obj)); } static MOZ_ALWAYS_INLINE bool ScriptIsMarkedGray(JSScript *script) { - return GCThingIsMarkedGray(script); + return js::gc::detail::CellIsMarkedGray(reinterpret_cast(script)); +} + +static MOZ_ALWAYS_INLINE bool +GCThingIsMarkedGray(GCCellPtr thing) +{ + if (js::gc::IsInsideNursery(thing.asCell())) + return false; + return js::gc::detail::CellIsMarkedGray(thing.asCell()); } } /* namespace JS */ diff --git a/js/public/Value.h b/js/public/Value.h index 7c6ae50473eb..5fba05dc22b7 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -1251,6 +1251,10 @@ class Value return JSVAL_TO_GCTHING_IMPL(data); } + GCCellPtr toGCCellPtr() const { + return GCCellPtr(toGCThing(), gcKind()); + } + bool toBoolean() const { MOZ_ASSERT(isBoolean()); return JSVAL_TO_BOOLEAN_IMPL(data); diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 4fb0ad6fe100..02c28269b3db 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -639,7 +639,7 @@ js::ZoneGlobalsAreAllGray(JS::Zone *zone) { for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { JSObject *obj = comp->maybeGlobal(); - if (!obj || !JS::GCThingIsMarkedGray(obj)) + if (!obj || !JS::ObjectIsMarkedGray(obj)) return false; } return true; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index d854d023fe84..e9c56f06a035 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -830,8 +830,8 @@ Chunk::init(JSRuntime *rt) JS_POISON(this, JS_FRESH_TENURED_PATTERN, ChunkSize); /* - * We clear the bitmap to guard against xpc_IsGrayGCThing being called on - * uninitialized data, which would happen before the first GC cycle. + * We clear the bitmap to guard against JS::GCThingIsMarkedGray being called + * on uninitialized data, which would happen before the first GC cycle. */ bitmap.clear(); diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 60745c0b4966..ba74878797bb 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -652,7 +652,7 @@ XPCJSRuntime::SuspectWrappedNative(XPCWrappedNative *wrapper, // Only record objects that might be part of a cycle as roots, unless // the callback wants all traces (a debug feature). JSObject* obj = wrapper->GetFlatJSObjectPreserveColor(); - if (xpc_IsGrayGCThing(obj) || cb.WantAllTraces()) + if (JS::ObjectIsMarkedGray(obj) || cb.WantAllTraces()) cb.NoteJSRoot(obj); } @@ -665,8 +665,8 @@ XPCJSRuntime::TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback &c XPCTraceableVariant* v = static_cast(e); if (nsCCUncollectableMarker::InGeneration(cb, v->CCGeneration())) { - jsval val = v->GetJSValPreserveColor(); - if (val.isObject() && !xpc_IsGrayGCThing(&val.toObject())) + JS::Value val = v->GetJSValPreserveColor(); + if (val.isObject() && !JS::ObjectIsMarkedGray(&val.toObject())) continue; } cb.NoteXPCOMRoot(v); diff --git a/js/xpconnect/src/XPCWrappedJS.cpp b/js/xpconnect/src/XPCWrappedJS.cpp index 06488745e2c6..24eedc91b17b 100644 --- a/js/xpconnect/src/XPCWrappedJS.cpp +++ b/js/xpconnect/src/XPCWrappedJS.cpp @@ -65,7 +65,7 @@ nsXPCWrappedJS::CanSkip() // If this wrapper holds a gray object, need to trace it. JSObject *obj = GetJSObjectPreserveColor(); - if (obj && xpc_IsGrayGCThing(obj)) + if (obj && JS::ObjectIsMarkedGray(obj)) return false; // For non-root wrappers, check if the root wrapper will be diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index ab76a9e887fd..37de79cb9570 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -176,15 +176,6 @@ xpc_FastGetCachedWrapper(JSContext *cx, nsWrapperCache *cache, JS::MutableHandle return nullptr; } -// The JS GC marks objects gray that are held alive directly or -// indirectly by an XPConnect root. The cycle collector explores only -// this subset of the JS heap. -inline bool -xpc_IsGrayGCThing(void *thing) -{ - return JS::GCThingIsMarkedGray(thing); -} - inline JSScript * xpc_UnmarkGrayScript(JSScript *script) { diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index 4259b4da72e9..6513482b48c5 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -141,25 +141,24 @@ static void TraceWeakMappingChild(JSTracer* aTrc, void** aThingp, JSGCTraceKind aKind) { MOZ_ASSERT(aTrc->callback == TraceWeakMappingChild); - void* thing = *aThingp; NoteWeakMapChildrenTracer* tracer = static_cast(aTrc); + JS::GCCellPtr thing(*aThingp, aKind); - if (aKind == JSTRACE_STRING) { + if (thing.isString()) { return; } - if (!xpc_IsGrayGCThing(thing) && !tracer->mCb.WantAllTraces()) { + if (!JS::GCThingIsMarkedGray(thing) && !tracer->mCb.WantAllTraces()) { return; } - if (AddToCCKind(aKind)) { + if (AddToCCKind(thing.kind())) { tracer->mCb.NoteWeakMapping(tracer->mMap, tracer->mKey, - tracer->mKeyDelegate, - JS::GCCellPtr(thing, aKind)); + tracer->mKeyDelegate, thing); tracer->mTracedAny = true; } else { - JS_TraceChildren(aTrc, thing, aKind); + JS_TraceChildren(aTrc, thing.asCell(), thing.kind()); } } @@ -182,9 +181,9 @@ TraceWeakMapping(js::WeakMapTracer* aTrc, JSObject* aMap, NoteWeakMapsTracer* tracer = static_cast(aTrc); // If nothing that could be held alive by this entry is marked gray, return. - if ((!aKey || !xpc_IsGrayGCThing(aKey.asCell())) && + if ((!aKey || !JS::GCThingIsMarkedGray(aKey)) && MOZ_LIKELY(!tracer->mCb.WantAllTraces())) { - if (!aValue || !xpc_IsGrayGCThing(aValue.asCell()) || aValue.isString()) { + if (!aValue || !JS::GCThingIsMarkedGray(aValue) || aValue.isString()) { return; } } @@ -223,7 +222,7 @@ TraceWeakMapping(js::WeakMapTracer* aTrc, JSObject* aMap, // The delegate could hold alive the key, so report something to the CC // if we haven't already. if (!tracer->mChildTracer.mTracedAny && - aKey && xpc_IsGrayGCThing(aKey.asCell()) && kdelegate) { + aKey && JS::GCThingIsMarkedGray(aKey) && kdelegate) { tracer->mCb.NoteWeakMapping(aMap, aKey, kdelegate, JS::GCCellPtr::NullPtr()); } @@ -257,8 +256,8 @@ private: static_cast(aTrc); // If nothing that could be held alive by this entry is marked gray, return. - bool delegateMightNeedMarking = aKey && xpc_IsGrayGCThing(aKey.asCell()); - bool valueMightNeedMarking = aValue && xpc_IsGrayGCThing(aValue.asCell()) && + bool delegateMightNeedMarking = aKey && JS::GCThingIsMarkedGray(aKey); + bool valueMightNeedMarking = aValue && JS::GCThingIsMarkedGray(aValue) && aValue.kind() != JSTRACE_STRING; if (!delegateMightNeedMarking && !valueMightNeedMarking) { return; @@ -270,16 +269,16 @@ private: if (delegateMightNeedMarking && aKey.isObject()) { JSObject* kdelegate = js::GetWeakmapKeyDelegate(aKey.toObject()); - if (kdelegate && !xpc_IsGrayGCThing(kdelegate)) { + if (kdelegate && !JS::ObjectIsMarkedGray(kdelegate)) { if (JS::UnmarkGrayGCThingRecursively(aKey)) { tracer->mAnyMarked = true; } } } - if (aValue && xpc_IsGrayGCThing(aValue.asCell()) && - (!aKey || !xpc_IsGrayGCThing(aKey.asCell())) && - (!aMap || !xpc_IsGrayGCThing(aMap)) && + if (aValue && JS::GCThingIsMarkedGray(aValue) && + (!aKey || !JS::GCThingIsMarkedGray(aKey)) && + (!aMap || !JS::ObjectIsMarkedGray(aMap)) && aValue.kind() != JSTRACE_SHAPE) { if (JS::UnmarkGrayGCThingRecursively(aValue)) { tracer->mAnyMarked = true; @@ -311,8 +310,7 @@ CheckParticipatesInCycleCollection(JS::GCCellPtr aThing, const char* aName, return; } - if (AddToCCKind(aThing.kind()) && - xpc_IsGrayGCThing(aThing.asCell())) { + if (AddToCCKind(aThing.kind()) && JS::GCThingIsMarkedGray(aThing)) { closure->mCycleCollectionEnabled = true; } } @@ -386,10 +384,11 @@ struct TraversalTracer : public JSTracer static void NoteJSChild(JSTracer* aTrc, void* aThing, JSGCTraceKind aTraceKind) { + JS::GCCellPtr thing(aThing, aTraceKind); TraversalTracer* tracer = static_cast(aTrc); // Don't traverse non-gray objects, unless we want all traces. - if (!xpc_IsGrayGCThing(aThing) && !tracer->mCb.WantAllTraces()) { + if (!JS::GCThingIsMarkedGray(thing) && !tracer->mCb.WantAllTraces()) { return; } @@ -418,7 +417,6 @@ NoteJSChild(JSTracer* aTrc, void* aThing, JSGCTraceKind aTraceKind) tracer->mCb.NoteNextEdgeName(static_cast(tracer->debugPrintArg())); } } - JS::GCCellPtr thing(aThing, aTraceKind); if (thing.isObject()) { tracer->mCb.NoteJSObject(thing.toObject()); } else { @@ -639,7 +637,7 @@ CycleCollectedJSRuntime::TraverseGCThing(TraverseSelect aTs, void* aThing, nsCycleCollectionTraversalCallback& aCb) { MOZ_ASSERT(aTraceKind == js::GCThingTraceKind(aThing)); - bool isMarkedGray = xpc_IsGrayGCThing(aThing); + bool isMarkedGray = JS::GCThingIsMarkedGray(JS::GCCellPtr(aThing, aTraceKind)); if (aTs == TRAVERSE_FULL) { DescribeGCThing(!isMarkedGray, aThing, aTraceKind, aCb); @@ -997,7 +995,7 @@ CycleCollectedJSRuntime::UsefulToMergeZones() const // Grab the inner from the outer. obj = JS_ObjectToInnerObject(cx, obj); MOZ_ASSERT(!js::GetObjectParent(obj)); - if (JS::GCThingIsMarkedGray(obj) && + if (JS::ObjectIsMarkedGray(obj) && !js::IsSystemCompartment(js::GetObjectCompartment(obj))) { return true; } diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index ac26d8f18490..f171b767c67b 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -2021,14 +2021,14 @@ static bool GCThingIsGrayCCThing(JS::GCCellPtr thing) { return AddToCCKind(thing.kind()) && - JS::GCThingIsMarkedGray(thing.asCell()); + JS::GCThingIsMarkedGray(thing); } static bool ValueIsGrayCCThing(const JS::Value& value) { return AddToCCKind(value.gcKind()) && - JS::GCThingIsMarkedGray(value.toGCThing()); + JS::GCThingIsMarkedGray(value.toGCCellPtr()); } //////////////////////////////////////////////////////////////////////// From c9b34f12ea10adeda250e4d15d7bba002846b101 Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Wed, 10 Dec 2014 15:36:03 -0800 Subject: [PATCH 066/130] Bug 1087442 - Attach LoadInfo inside each individual ProtocolHandler - loadinfo changes (r=sicking) --- docshell/base/LoadInfo.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docshell/base/LoadInfo.cpp b/docshell/base/LoadInfo.cpp index 068408c9f350..e2e8c2c4c637 100644 --- a/docshell/base/LoadInfo.cpp +++ b/docshell/base/LoadInfo.cpp @@ -20,16 +20,23 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType, nsIURI* aBaseURI) - : mLoadingPrincipal(aLoadingPrincipal) + : mLoadingPrincipal(aLoadingContext ? + aLoadingContext->NodePrincipal() : aLoadingPrincipal) , mTriggeringPrincipal(aTriggeringPrincipal ? - aTriggeringPrincipal : aLoadingPrincipal) + aTriggeringPrincipal : mLoadingPrincipal.get()) , mLoadingContext(do_GetWeakReference(aLoadingContext)) , mSecurityFlags(aSecurityFlags) , mContentPolicyType(aContentPolicyType) , mBaseURI(aBaseURI) { - MOZ_ASSERT(aLoadingPrincipal); + MOZ_ASSERT(mLoadingPrincipal); MOZ_ASSERT(mTriggeringPrincipal); + + // if consumers pass both, aLoadingContext and aLoadingPrincipal + // then the loadingPrincipal must be the same as the node's principal + MOZ_ASSERT(!aLoadingContext || !aLoadingPrincipal || + aLoadingContext->NodePrincipal() == aLoadingPrincipal); + // if the load is sandboxed, we can not also inherit the principal if (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED) { mSecurityFlags ^= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; From a697bb48b16a4ccf5337029b067d1f6da084bfb8 Mon Sep 17 00:00:00 2001 From: Stephen Pohl Date: Tue, 16 Dec 2014 15:41:35 -0500 Subject: [PATCH 067/130] Bug 1108056: Fix AutoConfig on OSX, broken by the package layout changes due to v2 signatures. Original patch by :mkaply. r=bsmedberg --- extensions/pref/autoconfig/src/nsReadConfig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/pref/autoconfig/src/nsReadConfig.cpp b/extensions/pref/autoconfig/src/nsReadConfig.cpp index 7255916ce3bb..c2621321f073 100644 --- a/extensions/pref/autoconfig/src/nsReadConfig.cpp +++ b/extensions/pref/autoconfig/src/nsReadConfig.cpp @@ -239,12 +239,12 @@ nsresult nsReadConfig::openAndEvaluateJSFile(const char *aFileName, int32_t obsc nsCOMPtr inStr; if (isBinDir) { nsCOMPtr jsFile; - rv = NS_GetSpecialDirectory(XRE_EXECUTABLE_FILE, + rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(jsFile)); if (NS_FAILED(rv)) return rv; - rv = jsFile->SetNativeLeafName(nsDependentCString(aFileName)); + rv = jsFile->AppendNative(nsDependentCString(aFileName)); if (NS_FAILED(rv)) return rv; From 4c7c42ba33753e19b4a725e207cb96369ec4a441 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Tue, 16 Dec 2014 15:50:45 -0500 Subject: [PATCH 068/130] Bug 1112281. Add notes to the crash reporter when the D3D11Device does not work. --HG-- extra : rebase_source : 9932b05493a8a5c54f671044d40c9a1092d5c55b --- gfx/thebes/gfxWindowsPlatform.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 14a0aa9f487d..b50918202152 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -1688,6 +1688,9 @@ bool DoesD3D11DeviceWork(ID3D11Device *device) // This if(FAILED()) is the one that actually fails on systems affected by bug 1083071. if (FAILED(device->CreateShaderResourceView(sharedTexture, NULL, byRef(sharedView)))) { +#if defined(MOZ_CRASHREPORTER) + CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("CreateShaderResourceView failed\n")); +#endif return false; } From ced0228bf5f478d269b381cf19405d3af103c4e5 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Thu, 11 Dec 2014 13:05:08 -0800 Subject: [PATCH 069/130] Bug 1085355; Simplify the context check used when refilling the free lists; r=sfink --HG-- extra : rebase_source : fe735dc061965a5b0600fcf06fd02d9c4ce1eb79 --- js/src/jsgc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index e9c56f06a035..d37ccd67dace 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3103,7 +3103,7 @@ GCRuntime::refillFreeListFromAnyThread(ThreadSafeContext *cx, AllocKind thingKin if (cx->isJSContext()) return refillFreeListFromMainThread(cx->asJSContext(), thingKind); - if (cx->allocator()->zone_->runtimeFromAnyThread()->exclusiveThreadsPresent()) + if (cx->isExclusiveContext()) return refillFreeListOffMainThread(cx->asExclusiveContext(), thingKind); return refillFreeListPJS(cx->asForkJoinContext(), thingKind); From 2b781f88bf81efb874e6a1d9efee1a1ba0b67b43 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 16 Dec 2014 16:01:05 -0500 Subject: [PATCH 070/130] Backed out changeset 0a736a01d342 (bug 1104658) for frequent OSX 10.6 jittest failures. --- js/src/jit/MIR.cpp | 109 ++------------------------------------------- js/src/jit/MIR.h | 4 -- 2 files changed, 4 insertions(+), 109 deletions(-) diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 7926c776dfd5..a9f7a2657fdc 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -589,19 +589,13 @@ MConstant::New(TempAllocator &alloc, const Value &v, types::CompilerConstraintLi return new(alloc) MConstant(v, constraints); } -MConstant * -MConstant::NewTypedValue(TempAllocator &alloc, const Value &v, MIRType type, types::CompilerConstraintList *constraints) -{ - MOZ_ASSERT(!IsSimdType(type)); - MConstant *constant = new(alloc) MConstant(v, constraints); - constant->setResultType(type); - return constant; -} - MConstant * MConstant::NewAsmJS(TempAllocator &alloc, const Value &v, MIRType type) { - return NewTypedValue(alloc, v, type); + MOZ_ASSERT(!IsSimdType(type)); + MConstant *constant = new(alloc) MConstant(v, nullptr); + constant->setResultType(type); + return constant; } MConstant * @@ -936,101 +930,6 @@ MMathFunction::printOpcode(FILE *fp) const fprintf(fp, " %s", FunctionName(function())); } -MDefinition * -MMathFunction::foldsTo(TempAllocator &alloc) -{ - MDefinition *input = getOperand(0); - if (!input->isConstant()) - return this; - - Value val = input->toConstant()->value(); - if (!val.isNumber()) - return this; - - double in = val.toNumber(); - double out; - switch (function_) { - case Log: - out = js::math_log_uncached(in); - break; - case Sin: - out = js::math_sin_uncached(in); - break; - case Cos: - out = js::math_cos_uncached(in); - break; - case Exp: - out = js::math_exp_uncached(in); - break; - case Tan: - out = js::math_tan_uncached(in); - break; - case ACos: - out = js::math_acos_uncached(in); - break; - case ASin: - out = js::math_asin_uncached(in); - break; - case ATan: - out = js::math_atan_uncached(in); - break; - case Log10: - out = js::math_log10_uncached(in); - break; - case Log2: - out = js::math_log2_uncached(in); - break; - case Log1P: - out = js::math_log1p_uncached(in); - break; - case ExpM1: - out = js::math_expm1_uncached(in); - break; - case CosH: - out = js::math_cosh_uncached(in); - break; - case SinH: - out = js::math_sinh_uncached(in); - break; - case TanH: - out = js::math_tanh_uncached(in); - break; - case ACosH: - out = js::math_acosh_uncached(in); - break; - case ASinH: - out = js::math_asinh_uncached(in); - break; - case ATanH: - out = js::math_atanh_uncached(in); - break; - case Sign: - out = js::math_sign_uncached(in); - break; - case Trunc: - out = js::math_trunc_uncached(in); - break; - case Cbrt: - out = js::math_cbrt_uncached(in); - break; - case Floor: - out = js::math_floor_impl(in); - break; - case Ceil: - out = js::math_ceil_impl(in); - break; - case Round: - out = js::math_round_impl(in); - break; - default: - return this; - } - - if (input->type() == MIRType_Float32) - return MConstant::NewTypedValue(alloc, Float32Value(out), MIRType_Float32); - return MConstant::New(alloc, DoubleValue(out)); -} - MParameter * MParameter::New(TempAllocator &alloc, int32_t index, types::TemporaryTypeSet *types) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 61cf6b6cb683..39ae280f1787 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -1255,8 +1255,6 @@ class MConstant : public MNullaryInstruction INSTRUCTION_HEADER(Constant) static MConstant *New(TempAllocator &alloc, const Value &v, types::CompilerConstraintList *constraints = nullptr); - static MConstant *NewTypedValue(TempAllocator &alloc, const Value &v, MIRType type, - types::CompilerConstraintList *constraints = nullptr); static MConstant *NewAsmJS(TempAllocator &alloc, const Value &v, MIRType type); static MConstant *NewConstraintlessObject(TempAllocator &alloc, JSObject *v); @@ -5581,8 +5579,6 @@ class MMathFunction return true; } - MDefinition *foldsTo(TempAllocator &alloc); - void printOpcode(FILE *fp) const; static const char *FunctionName(Function function); From b518f856e9ca078043367503b40ff17d33b9e266 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Thu, 11 Dec 2014 14:28:41 -0500 Subject: [PATCH 071/130] Bug 1103258 - Add a reftest for culled container layers with an intermediate surface. r=jmuizel --HG-- extra : rebase_source : 22e35ccb3c08df96bc391fc764835469e0bd87fe --- layout/reftests/bugs/1103258-1-ref.html | 13 +++++++++ layout/reftests/bugs/1103258-1.html | 37 +++++++++++++++++++++++++ layout/reftests/bugs/reftest.list | 1 + 3 files changed, 51 insertions(+) create mode 100644 layout/reftests/bugs/1103258-1-ref.html create mode 100644 layout/reftests/bugs/1103258-1.html diff --git a/layout/reftests/bugs/1103258-1-ref.html b/layout/reftests/bugs/1103258-1-ref.html new file mode 100644 index 000000000000..96d79e14fa56 --- /dev/null +++ b/layout/reftests/bugs/1103258-1-ref.html @@ -0,0 +1,13 @@ + +
+
diff --git a/layout/reftests/bugs/1103258-1.html b/layout/reftests/bugs/1103258-1.html new file mode 100644 index 000000000000..9f56c8f49ad9 --- /dev/null +++ b/layout/reftests/bugs/1103258-1.html @@ -0,0 +1,37 @@ + +
+
+ sadf +
+
+ sdf +
+
+
+
diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 884758254948..cb2e242ec9b6 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1845,4 +1845,5 @@ test-pref(dom.webcomponents.enabled,true) == 1066554-1.html 1066554-1-ref.html test-pref(layout.testing.overlay-scrollbars.always-visible,false) == 1081072-1.html 1081072-1-ref.html fuzzy-if(winWidget&&!layersGPUAccelerated,1,31) == 1081185-1.html 1081185-1-ref.html == 1097437-1.html 1097437-1-ref.html +== 1103258-1.html 1103258-1-ref.html # assertion crash test with layers culling test == 1105137-1.html 1105137-1-ref.html From fd366734cc457ce119f24c5fb6bcefbfba0ea852 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Thu, 11 Dec 2014 15:55:31 -0500 Subject: [PATCH 072/130] Bug 1103258 - Don't prepare a container layer that's been culled. r=jmuizel --- gfx/layers/composite/ContainerLayerComposite.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gfx/layers/composite/ContainerLayerComposite.cpp b/gfx/layers/composite/ContainerLayerComposite.cpp index 536fe8882c83..d707b6de8f4f 100644 --- a/gfx/layers/composite/ContainerLayerComposite.cpp +++ b/gfx/layers/composite/ContainerLayerComposite.cpp @@ -258,6 +258,11 @@ ContainerPrepare(ContainerT* aContainer, return; } + gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer); + if (surfaceRect.IsEmpty()) { + return; + } + /** * Determine which layers to draw. */ @@ -300,7 +305,6 @@ ContainerPrepare(ContainerT* aContainer, RefPtr surface = nullptr; RefPtr& lastSurf = aContainer->mLastIntermediateSurface; - gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer); if (lastSurf && !aContainer->mChildrenChanged && lastSurf->GetRect().IsEqualEdges(surfaceRect)) { surface = lastSurf; } From e11921de62a077ffb83c72f13cd23399c698eb2c Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Fri, 12 Dec 2014 10:44:46 -0800 Subject: [PATCH 073/130] Bug 1110931 - Do not use volatile for synchronization; r=jonco --HG-- extra : rebase_source : 661aae837633799ed70db1a5e64ba9dcc21aaf66 --- js/src/gc/GCRuntime.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 05f50e8cc050..829b181463e3 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -697,7 +697,7 @@ class GCRuntime */ bool grayBitsValid; - volatile uintptr_t majorGCRequested; + mozilla::Atomic majorGCRequested; JS::gcreason::Reason majorGCTriggerReason; bool minorGCRequested; @@ -792,7 +792,7 @@ class GCRuntime * frame, rather than at the beginning. In this case, the next slice will be * delayed so that we don't get back-to-back slices. */ - volatile uintptr_t interFrameGC; + mozilla::Atomic interFrameGC; /* Default budget for incremental GC slice. See SliceBudget in jsgc.h. */ int64_t sliceBudget; @@ -836,7 +836,7 @@ class GCRuntime bool poked; - volatile js::HeapState heapState; + mozilla::Atomic heapState; /* * ForkJoin workers enter and leave GC independently; this counter From ea37d24bba15dd61b800a8e1ac9024c4de513926 Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Fri, 12 Dec 2014 11:19:28 -0500 Subject: [PATCH 074/130] bug 1107881 - h2/spdy :path when proxying shouldn't be absolute uri r=hurley --HG-- extra : rebase_source : d0847b03e2f7cd2f5425e3de635b68248d49eec3 --- netwerk/protocol/http/Http2Stream.cpp | 2 +- netwerk/protocol/http/SpdyStream31.cpp | 2 +- netwerk/protocol/http/nsHttpChannel.cpp | 50 +++++++++++++++-------- netwerk/protocol/http/nsHttpRequestHead.h | 7 ++++ 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/netwerk/protocol/http/Http2Stream.cpp b/netwerk/protocol/http/Http2Stream.cpp index b4864b358a16..b21368fed8a7 100644 --- a/netwerk/protocol/http/Http2Stream.cpp +++ b/netwerk/protocol/http/Http2Stream.cpp @@ -446,7 +446,7 @@ Http2Stream::ParseHttpRequestHeaders(const char *buf, mSession->Compressor()->EncodeHeaderBlock(mFlatHttpRequestHeaders, head->Method(), - head->RequestURI(), + head->Path(), authorityHeader, scheme, head->IsConnect(), diff --git a/netwerk/protocol/http/SpdyStream31.cpp b/netwerk/protocol/http/SpdyStream31.cpp index 08ca7dca2d28..068720575ae6 100644 --- a/netwerk/protocol/http/SpdyStream31.cpp +++ b/netwerk/protocol/http/SpdyStream31.cpp @@ -488,7 +488,7 @@ SpdyStream31::ParseHttpRequestHeaders(const char *buf, CompressToFrame(NS_LITERAL_CSTRING(":path")); if (!mTransaction->RequestHead()->IsConnect()) { - CompressToFrame(mTransaction->RequestHead()->RequestURI()); + CompressToFrame(mTransaction->RequestHead()->Path()); } else { MOZ_ASSERT(mTransaction->QuerySpdyConnectTransaction()); mIsTunnel = true; diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 9b63b0169b7d..1c323febd0e6 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -697,18 +697,34 @@ nsHttpChannel::SetupTransaction() // CONNECT does not count here). Also figure out what HTTP version to use. nsAutoCString buf, path; nsCString* requestURI; - if (mConnectionInfo->UsingConnect() || - !mConnectionInfo->UsingHttpProxy()) { - rv = mURI->GetPath(path); - if (NS_FAILED(rv)) return rv; - // path may contain UTF-8 characters, so ensure that they're escaped. - if (NS_EscapeURL(path.get(), path.Length(), esc_OnlyNonASCII, buf)) - requestURI = &buf; - else - requestURI = &path; + + // This is the normal e2e H1 path syntax "/index.html" + rv = mURI->GetPath(path); + if (NS_FAILED(rv)) { + return rv; + } + + // path may contain UTF-8 characters, so ensure that they're escaped. + if (NS_EscapeURL(path.get(), path.Length(), esc_OnlyNonASCII, buf)) { + requestURI = &buf; + } else { + requestURI = &path; + } + + // trim off the #ref portion if any... + int32_t ref = requestURI->FindChar('#'); + if (ref != kNotFound) { + requestURI->SetLength(ref); + } + + if (mConnectionInfo->UsingConnect() || !mConnectionInfo->UsingHttpProxy()) { mRequestHead.SetVersion(gHttpHandler->HttpVersion()); } else { + mRequestHead.SetPath(*requestURI); + + // RequestURI should be the absolute uri H1 proxy syntax "http://foo/index.html" + // so we will overwrite the relative version in requestURI rv = mURI->GetUserPass(buf); if (NS_FAILED(rv)) return rv; if (!buf.IsEmpty() && ((strncmp(mSpec.get(), "http:", 5) == 0) || @@ -721,17 +737,19 @@ nsHttpChannel::SetupTransaction() rv = tempURI->GetAsciiSpec(path); if (NS_FAILED(rv)) return rv; requestURI = &path; - } - else + } else { requestURI = &mSpec; + } + + // trim off the #ref portion if any... + int32_t ref = requestURI->FindChar('#'); + if (ref != kNotFound) { + requestURI->SetLength(ref); + } + mRequestHead.SetVersion(gHttpHandler->ProxyHttpVersion()); } - // trim off the #ref portion if any... - int32_t ref = requestURI->FindChar('#'); - if (ref != kNotFound) - requestURI->SetLength(ref); - mRequestHead.SetRequestURI(*requestURI); // set the request time for cache expiration calculations diff --git a/netwerk/protocol/http/nsHttpRequestHead.h b/netwerk/protocol/http/nsHttpRequestHead.h index 5be6f626cf90..a7ac6b31baa9 100644 --- a/netwerk/protocol/http/nsHttpRequestHead.h +++ b/netwerk/protocol/http/nsHttpRequestHead.h @@ -26,12 +26,14 @@ public: void SetMethod(const nsACString &method); void SetVersion(nsHttpVersion version) { mVersion = version; } void SetRequestURI(const nsCSubstring &s) { mRequestURI = s; } + void SetPath(const nsCSubstring &s) { mPath = s; } const nsHttpHeaderArray &Headers() const { return mHeaders; } nsHttpHeaderArray & Headers() { return mHeaders; } const nsCString &Method() const { return mMethod; } nsHttpVersion Version() const { return mVersion; } const nsCSubstring &RequestURI() const { return mRequestURI; } + const nsCSubstring &Path() const { return mPath.IsEmpty() ? mRequestURI : mPath; } void SetHTTPS(bool val) { mHTTPS = val; } bool IsHTTPS() const { return mHTTPS; } @@ -100,7 +102,12 @@ private: nsHttpHeaderArray mHeaders; nsCString mMethod; nsHttpVersion mVersion; + + // mRequestURI and mPath are strings instead of an nsIURI + // because this is used off the main thread nsCString mRequestURI; + nsCString mPath; + nsCString mOrigin; ParsedMethodType mParsedMethod; bool mHTTPS; From a269def4466d86dc732e484632e29cab25ee1110 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Tue, 16 Dec 2014 13:26:42 -0800 Subject: [PATCH 075/130] Bug 1107923 - Followup to fix non-unified bustage a=me --- hal/linux/LinuxPower.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/hal/linux/LinuxPower.cpp b/hal/linux/LinuxPower.cpp index 1b88bbc497e2..70ab4a3f6e01 100644 --- a/hal/linux/LinuxPower.cpp +++ b/hal/linux/LinuxPower.cpp @@ -4,6 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "Hal.h" +#include "HalLog.h" #include #include From d1744908ba57497a129bbf31bfba1de2093b4678 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Fri, 12 Dec 2014 14:13:29 -0800 Subject: [PATCH 076/130] Bug 1105069 - Part 19: Remove JS_DumpHeap; r=jonco --HG-- extra : rebase_source : a8ec7eee96d4e9937490bf9c9cdbd5e32cc7c993 --- js/src/jsapi.cpp | 235 ------------------ js/src/shell/js.cpp | 82 ------ .../tests/js1_8/extensions/regress-378789.js | 34 --- 3 files changed, 351 deletions(-) delete mode 100644 js/src/tests/js1_8/extensions/regress-378789.js diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 10504df21ffb..8bffa6f1e428 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1614,241 +1614,6 @@ JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data) return rt->gc.removeBlackRootsTracer(traceOp, data); } -#ifdef DEBUG - -typedef struct JSHeapDumpNode JSHeapDumpNode; - -struct JSHeapDumpNode { - void *thing; - JSGCTraceKind kind; - JSHeapDumpNode *next; /* next sibling */ - JSHeapDumpNode *parent; /* node with the thing that refer to thing - from this node */ - char edgeName[1]; /* name of the edge from parent->thing - into thing */ -}; - -typedef HashSet, SystemAllocPolicy> VisitedSet; - -class DumpingTracer -{ - public: - DumpingTracer(JSRuntime *rt, JSTraceCallback callback) - : base(rt, callback) - {} - - JSTracer base; - VisitedSet visited; - bool ok; - void *startThing; - void *thingToFind; - void *thingToIgnore; - JSHeapDumpNode *parentNode; - JSHeapDumpNode **lastNodep; - char buffer[200]; -}; - -static void -DumpNotify(JSTracer *trc, void **thingp, JSGCTraceKind kind) -{ - MOZ_ASSERT(trc->callback == DumpNotify); - - DumpingTracer *dtrc = (DumpingTracer *)trc; - void *thing = *thingp; - - if (!dtrc->ok || thing == dtrc->thingToIgnore) - return; - - /* - * Check if we have already seen thing unless it is thingToFind to include - * it to the graph each time we reach it and print all live things that - * refer to thingToFind. - * - * This does not print all possible paths leading to thingToFind since - * when a thing A refers directly or indirectly to thingToFind and A is - * present several times in the graph, we will print only the first path - * leading to A and thingToFind, other ways to reach A will be ignored. - */ - if (dtrc->thingToFind != thing) { - /* - * The startThing check allows to avoid putting startThing into the - * hash table before tracing startThing in JS_DumpHeap. - */ - if (thing == dtrc->startThing) - return; - VisitedSet::AddPtr p = dtrc->visited.lookupForAdd(thing); - if (p) - return; - if (!dtrc->visited.add(p, thing)) { - dtrc->ok = false; - return; - } - } - - const char *edgeName = dtrc->base.getTracingEdgeName(dtrc->buffer, sizeof(dtrc->buffer)); - size_t edgeNameSize = strlen(edgeName) + 1; - size_t bytes = offsetof(JSHeapDumpNode, edgeName) + edgeNameSize; - JSHeapDumpNode *node = (JSHeapDumpNode *) js_malloc(bytes); - if (!node) { - dtrc->ok = false; - return; - } - - node->thing = thing; - node->kind = kind; - node->next = nullptr; - node->parent = dtrc->parentNode; - js_memcpy(node->edgeName, edgeName, edgeNameSize); - - MOZ_ASSERT(!*dtrc->lastNodep); - *dtrc->lastNodep = node; - dtrc->lastNodep = &node->next; -} - -/* Dump node and the chain that leads to thing it contains. */ -static bool -DumpNode(DumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node) -{ - JSHeapDumpNode *prev, *following; - size_t chainLimit; - enum { MAX_PARENTS_TO_PRINT = 10 }; - - JS_GetTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer, - &dtrc->base, node->thing, node->kind, true); - if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0) - return false; - - /* - * We need to print the parent chain in the reverse order. To do it in - * O(N) time where N is the chain length we first reverse the chain while - * searching for the top and then print each node while restoring the - * chain order. - */ - chainLimit = MAX_PARENTS_TO_PRINT; - prev = nullptr; - for (;;) { - following = node->parent; - node->parent = prev; - prev = node; - node = following; - if (!node) - break; - if (chainLimit == 0) { - if (fputs("...", fp) < 0) - return false; - break; - } - --chainLimit; - } - - node = prev; - prev = following; - bool ok = true; - do { - /* Loop must continue even when !ok to restore the parent chain. */ - if (ok) { - if (!prev) { - /* Print edge from some runtime root or startThing. */ - if (fputs(node->edgeName, fp) < 0) - ok = false; - } else { - JS_GetTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer, - &dtrc->base, prev->thing, prev->kind, - false); - if (fprintf(fp, "(%p %s).%s", - prev->thing, dtrc->buffer, node->edgeName) < 0) { - ok = false; - } - } - } - following = node->parent; - node->parent = prev; - prev = node; - node = following; - } while (node); - - return ok && putc('\n', fp) >= 0; -} - -JS_PUBLIC_API(bool) -JS_DumpHeap(JSRuntime *rt, FILE *fp, void* startThing, JSGCTraceKind startKind, - void *thingToFind, size_t maxDepth, void *thingToIgnore) -{ - if (maxDepth == 0) - return true; - - DumpingTracer dtrc(rt, DumpNotify); - if (!dtrc.visited.init()) - return false; - dtrc.ok = true; - dtrc.startThing = startThing; - dtrc.thingToFind = thingToFind; - dtrc.thingToIgnore = thingToIgnore; - dtrc.parentNode = nullptr; - JSHeapDumpNode *node = nullptr; - dtrc.lastNodep = &node; - if (!startThing) { - MOZ_ASSERT(startKind == JSTRACE_OBJECT); - TraceRuntime(&dtrc.base); - } else { - JS_TraceChildren(&dtrc.base, startThing, startKind); - } - - if (!node) - return dtrc.ok; - - size_t depth = 1; - JSHeapDumpNode *children, *next, *parent; - bool thingToFindWasTraced = thingToFind && thingToFind == startThing; - for (;;) { - /* - * Loop must continue even when !dtrc.ok to free all nodes allocated - * so far. - */ - if (dtrc.ok) { - if (thingToFind == nullptr || thingToFind == node->thing) - dtrc.ok = DumpNode(&dtrc, fp, node); - - /* Descend into children. */ - if (dtrc.ok && - depth < maxDepth && - (thingToFind != node->thing || !thingToFindWasTraced)) { - dtrc.parentNode = node; - children = nullptr; - dtrc.lastNodep = &children; - JS_TraceChildren(&dtrc.base, node->thing, node->kind); - if (thingToFind == node->thing) - thingToFindWasTraced = true; - if (children != nullptr) { - ++depth; - node = children; - continue; - } - } - } - - /* Move to next or parents next and free the node. */ - for (;;) { - next = node->next; - parent = node->parent; - js_free(node); - node = next; - if (node) - break; - if (!parent) - return dtrc.ok; - MOZ_ASSERT(depth > 1); - --depth; - node = parent; - } - } - - MOZ_ASSERT(depth == 1); - return dtrc.ok; -} - -#endif /* DEBUG */ - extern JS_PUBLIC_API(bool) JS_IsGCMarkingTracer(JSTracer *trc) { diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 077561e76553..2885f8e7ee8f 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2331,82 +2331,6 @@ DisassWithSrc(JSContext *cx, unsigned argc, jsval *vp) #undef LINE_BUF_LEN } -static bool -DumpHeap(JSContext *cx, unsigned argc, jsval *vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - JSAutoByteString fileName; - if (args.hasDefined(0) && !args[0].isNull()) { - RootedString str(cx, JS::ToString(cx, args[0])); - if (!str) - return false; - - if (!fileName.encodeLatin1(cx, str)) - return false; - } - - RootedValue startThing(cx); - if (args.hasDefined(1)) { - if (!args[1].isGCThing()) { - JS_ReportError(cx, "dumpHeap: Second argument not a GC thing!"); - return false; - } - startThing = args[1]; - } - - RootedValue thingToFind(cx); - if (args.hasDefined(2)) { - if (!args[2].isGCThing()) { - JS_ReportError(cx, "dumpHeap: Third argument not a GC thing!"); - return false; - } - thingToFind = args[2]; - } - - size_t maxDepth = size_t(-1); - if (args.hasDefined(3)) { - uint32_t depth; - if (!ToUint32(cx, args[3], &depth)) - return false; - maxDepth = depth; - } - - RootedValue thingToIgnore(cx); - if (args.hasDefined(4)) { - if (!args[2].isGCThing()) { - JS_ReportError(cx, "dumpHeap: Fifth argument not a GC thing!"); - return false; - } - thingToIgnore = args[4]; - } - - FILE *dumpFile = stdout; - if (fileName.length()) { - dumpFile = fopen(fileName.ptr(), "w"); - if (!dumpFile) { - JS_ReportError(cx, "dumpHeap: can't open %s: %s\n", - fileName.ptr(), strerror(errno)); - return false; - } - } - - bool ok = JS_DumpHeap(JS_GetRuntime(cx), dumpFile, - startThing.isUndefined() ? nullptr : startThing.toGCThing(), - startThing.isUndefined() ? JSTRACE_OBJECT : startThing.get().gcKind(), - thingToFind.isUndefined() ? nullptr : thingToFind.toGCThing(), - maxDepth, - thingToIgnore.isUndefined() ? nullptr : thingToIgnore.toGCThing()); - - if (dumpFile != stdout) - fclose(dumpFile); - - if (!ok) - JS_ReportOutOfMemory(cx); - - return ok; -} - #endif /* DEBUG */ static bool @@ -4542,12 +4466,6 @@ static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = { " Get a self-hosted value by its name. Note that these values don't get \n" " cached, so repeatedly getting the same value creates multiple distinct clones."), -#ifdef DEBUG - JS_FN_HELP("dumpHeap", DumpHeap, 0, 0, -"dumpHeap([fileName[, start[, toFind[, maxDepth[, toIgnore]]]]])", -" Interface to JS_DumpHeap with output sent to file."), -#endif - JS_FN_HELP("parent", Parent, 1, 0, "parent(obj)", " Returns the parent of obj."), diff --git a/js/src/tests/js1_8/extensions/regress-378789.js b/js/src/tests/js1_8/extensions/regress-378789.js deleted file mode 100644 index f7738556a955..000000000000 --- a/js/src/tests/js1_8/extensions/regress-378789.js +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 378789; -var summary = 'js_PutEscapedString should handle nulls'; -var actual = ''; -var expect = ''; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - if (typeof dumpHeap == 'undefined') - { - print('dumpHeap not supported'); - } - else - { - dumpHeap(null, [ "a\0b" ], null, 1); - } - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} From ed78ccb34a28ead6168071f2443c3201c7891def Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Sun, 14 Dec 2014 08:27:51 -0800 Subject: [PATCH 077/130] Bug 1105069 - Part 20: Standardize GC structure accessors; r=jonco --HG-- extra : rebase_source : 109967b39544ef7afcdee1c2fe443d8ffcf85736 --- js/public/HeapAPI.h | 17 +++++++---------- js/src/gc/Heap.h | 8 ++++++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h index c2fecc6ea7c5..858fb8bf5da6 100644 --- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -53,6 +53,7 @@ const size_t ChunkMarkBitmapBits = 129024; #endif const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*); const size_t ChunkLocationOffset = ChunkSize - 2 * sizeof(void*) - sizeof(uint64_t); +const size_t ArenaZoneOffset = 0; /* * Live objects are marked black. How many other additional colors are available @@ -158,11 +159,6 @@ AsCell(JSScript *script) namespace shadow { -struct ArenaHeader -{ - JS::Zone *zone; -}; - struct Zone { protected: @@ -339,11 +335,13 @@ GetGCThingMarkWordAndMask(const uintptr_t addr, uint32_t color, *wordp = &bitmap[bit / nbits]; } -static MOZ_ALWAYS_INLINE JS::shadow::ArenaHeader * -GetGCThingArena(const uintptr_t addr) +static MOZ_ALWAYS_INLINE JS::Zone * +GetGCThingZone(const uintptr_t addr) { MOZ_ASSERT(addr); - return reinterpret_cast(addr & ~ArenaMask); + const uintptr_t zone_addr = (addr & ~ArenaMask) | ArenaZoneOffset; + return *reinterpret_cast(zone_addr); + } static MOZ_ALWAYS_INLINE bool @@ -379,9 +377,8 @@ namespace JS { static MOZ_ALWAYS_INLINE Zone * GetTenuredGCThingZone(void *thing) { - MOZ_ASSERT(thing); MOZ_ASSERT(!js::gc::IsInsideNursery((js::gc::Cell *)thing)); - return js::gc::detail::GetGCThingArena(uintptr_t(thing))->zone; + return js::gc::detail::GetGCThingZone(uintptr_t(thing)); } extern JS_PUBLIC_API(Zone *) diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h index a9c41acbedab..f18d82cd9325 100644 --- a/js/src/gc/Heap.h +++ b/js/src/gc/Heap.h @@ -505,16 +505,18 @@ class FreeList }; /* Every arena has a header. */ -struct ArenaHeader : public JS::shadow::ArenaHeader +struct ArenaHeader { friend struct FreeLists; + JS::Zone *zone; + /* * ArenaHeader::next has two purposes: when unallocated, it points to the * next available Arena's header. When allocated, it points to the next * arena of the same size class and compartment. */ - ArenaHeader *next; + ArenaHeader *next; private: /* @@ -645,6 +647,8 @@ struct ArenaHeader : public JS::shadow::ArenaHeader size_t countFreeCells(); #endif }; +static_assert(ArenaZoneOffset == offsetof(ArenaHeader, zone), + "The hardcoded API zone offset must match the actual offset."); struct Arena { From 4b6a74fbf29050c2de43e7915a8550f47b089cf0 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Sun, 14 Dec 2014 08:27:52 -0800 Subject: [PATCH 078/130] Bug 1105069 - Part 21: Remove AsCell in preference of GCCellPtr; r=jonco, r=mccr8 --HG-- extra : rebase_source : 5c4470f3efbd9dbe3caee08ed88b07da549912e0 --- js/public/HeapAPI.h | 58 ++----------------- js/public/Id.h | 2 +- js/src/gc/StoreBuffer.h | 4 +- xpcom/base/nsCycleCollector.cpp | 2 +- xpcom/glue/tests/gtest/TestGCPostBarriers.cpp | 4 +- 5 files changed, 12 insertions(+), 58 deletions(-) diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h index 858fb8bf5da6..96ff6cb161d1 100644 --- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -105,58 +105,6 @@ const uint32_t DefaultNurseryBytes = 16 * js::gc::ChunkSize; /* Default maximum heap size in bytes to pass to JS_NewRuntime(). */ const uint32_t DefaultHeapMaxBytes = 32 * 1024 * 1024; -/* - * We cannot expose the class hierarchy: the implementation is hidden. Instead - * we provide cast functions with strong debug-mode assertions. - */ -static MOZ_ALWAYS_INLINE js::gc::Cell * -AsCell(JSObject *obj) -{ - js::gc::Cell *cell = reinterpret_cast(obj); - js::gc::AssertGCThingHasType(cell, JSTRACE_OBJECT); - return cell; -} - -static MOZ_ALWAYS_INLINE js::gc::Cell * -AsCell(JSFunction *fun) -{ - js::gc::Cell *cell = reinterpret_cast(fun); - js::gc::AssertGCThingHasType(cell, JSTRACE_OBJECT); - return cell; -} - -static MOZ_ALWAYS_INLINE js::gc::Cell * -AsCell(JSString *str) -{ - js::gc::Cell *cell = reinterpret_cast(str); - js::gc::AssertGCThingHasType(cell, JSTRACE_STRING); - return cell; -} - -static MOZ_ALWAYS_INLINE js::gc::Cell * -AsCell(JSFlatString *flat) -{ - js::gc::Cell *cell = reinterpret_cast(flat); - js::gc::AssertGCThingHasType(cell, JSTRACE_STRING); - return cell; -} - -static MOZ_ALWAYS_INLINE js::gc::Cell * -AsCell(JS::Symbol *sym) -{ - js::gc::Cell *cell = reinterpret_cast(sym); - js::gc::AssertGCThingHasType(cell, JSTRACE_SYMBOL); - return cell; -} - -static MOZ_ALWAYS_INLINE js::gc::Cell * -AsCell(JSScript *script) -{ - js::gc::Cell *cell = reinterpret_cast(script); - js::gc::AssertGCThingHasType(cell, JSTRACE_SCRIPT); - return cell; -} - namespace shadow { struct Zone @@ -384,6 +332,12 @@ GetTenuredGCThingZone(void *thing) extern JS_PUBLIC_API(Zone *) GetObjectZone(JSObject *obj); +static MOZ_ALWAYS_INLINE bool +ObjectIsTenured(JSObject *obj) +{ + return !js::gc::IsInsideNursery(reinterpret_cast(obj)); +} + static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray(JSObject *obj) { diff --git a/js/public/Id.h b/js/public/Id.h index 63473d07bf44..dd0e7234caf2 100644 --- a/js/public/Id.h +++ b/js/public/Id.h @@ -127,7 +127,7 @@ SYMBOL_TO_JSID(JS::Symbol *sym) jsid id; MOZ_ASSERT(sym != nullptr); MOZ_ASSERT((size_t(sym) & JSID_TYPE_MASK) == 0); - MOZ_ASSERT(!js::gc::IsInsideNursery(JS::AsCell(sym))); + MOZ_ASSERT(!js::gc::IsInsideNursery(reinterpret_cast(sym))); MOZ_ASSERT(!JS::IsPoisonedPtr(sym)); JSID_BITS(id) = (size_t(sym) | JSID_TYPE_SYMBOL); return id; diff --git a/js/src/gc/StoreBuffer.h b/js/src/gc/StoreBuffer.h index e9951101adb3..7e333fd80e52 100644 --- a/js/src/gc/StoreBuffer.h +++ b/js/src/gc/StoreBuffer.h @@ -307,8 +307,8 @@ class StoreBuffer return !(*this == other); } - bool maybeInRememberedSet(const Nursery &) const { - return !IsInsideNursery(JS::AsCell(reinterpret_cast(object()))); + bool maybeInRememberedSet(const Nursery &n) const { + return !IsInsideNursery(reinterpret_cast(object())); } void mark(JSTracer *trc) const; diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index f171b767c67b..9310a9c2c396 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -2664,7 +2664,7 @@ public: void AppendJSObjectToPurpleBuffer(JSObject* obj) const { if (obj && JS::ObjectIsMarkedGray(obj)) { - MOZ_ASSERT(!js::gc::IsInsideNursery(JS::AsCell(obj))); + MOZ_ASSERT(JS::ObjectIsTenured(obj)); mCollector->GetJSPurpleBuffer()->mObjects.InfallibleAppend(obj); } } diff --git a/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp b/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp index 1aabe54aaad4..40a5b50329ea 100644 --- a/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp +++ b/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp @@ -55,7 +55,7 @@ RunTest(JSRuntime* rt, JSContext* cx, ArrayT* array) const char* property = "foo"; for (size_t i = 0; i < ElementCount; ++i) { RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); - ASSERT_TRUE(js::gc::IsInsideNursery(AsCell(obj))); + ASSERT_FALSE(JS::ObjectIsTenured(obj)); value = Int32Value(i); ASSERT_TRUE(JS_SetProperty(cx, obj, property, value)); array->AppendElement(obj); @@ -72,7 +72,7 @@ RunTest(JSRuntime* rt, JSContext* cx, ArrayT* array) */ for (size_t i = 0; i < ElementCount; ++i) { RootedObject obj(cx, array->ElementAt(i)); - ASSERT_FALSE(js::gc::IsInsideNursery(AsCell(obj))); + ASSERT_TRUE(JS::ObjectIsTenured(obj)); ASSERT_TRUE(JS_GetProperty(cx, obj, property, &value)); ASSERT_TRUE(value.isInt32()); ASSERT_EQ(static_cast(i), value.toInt32()); From a75dd2b420f0e8d336525233556d207ea3dc670a Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Mon, 15 Dec 2014 14:37:15 +1100 Subject: [PATCH 079/130] Bug 1052123 - Autohide ruby annotations which are identical to their ruby bases. r=dbaron --HG-- extra : rebase_source : a458af255ceeb6a384b7f879ab5d060052142b76 extra : source : 5f0779afa4060c867bf94d7c798e9eccf0cdb9bd --- layout/generic/nsFrameState.cpp | 1 + layout/generic/nsFrameStateBits.h | 9 +++++ layout/generic/nsRubyBaseContainerFrame.cpp | 32 +++++++++++++++-- layout/generic/nsRubyTextFrame.cpp | 34 ++++++++++++++++++ layout/generic/nsRubyTextFrame.h | 9 +++++ .../reftests/css-ruby/autohiding-1-ref.html | 14 ++++++++ layout/reftests/css-ruby/autohiding-1.html | 14 ++++++++ .../reftests/css-ruby/autohiding-2-ref.html | 26 ++++++++++++++ layout/reftests/css-ruby/autohiding-2.html | 36 +++++++++++++++++++ .../reftests/css-ruby/autohiding-3-ref.html | 17 +++++++++ layout/reftests/css-ruby/autohiding-3.html | 17 +++++++++ layout/reftests/css-ruby/reftest.list | 3 ++ 12 files changed, 209 insertions(+), 3 deletions(-) create mode 100644 layout/reftests/css-ruby/autohiding-1-ref.html create mode 100644 layout/reftests/css-ruby/autohiding-1.html create mode 100644 layout/reftests/css-ruby/autohiding-2-ref.html create mode 100644 layout/reftests/css-ruby/autohiding-2.html create mode 100644 layout/reftests/css-ruby/autohiding-3-ref.html create mode 100644 layout/reftests/css-ruby/autohiding-3.html diff --git a/layout/generic/nsFrameState.cpp b/layout/generic/nsFrameState.cpp index 61ee67d442bf..6a58ac2e5853 100644 --- a/layout/generic/nsFrameState.cpp +++ b/layout/generic/nsFrameState.cpp @@ -17,6 +17,7 @@ #include "nsImageFrame.h" #include "nsInlineFrame.h" #include "nsPlaceholderFrame.h" +#include "nsRubyTextFrame.h" #include "nsSVGContainerFrame.h" #include "nsTableCellFrame.h" #include "nsTableRowFrame.h" diff --git a/layout/generic/nsFrameStateBits.h b/layout/generic/nsFrameStateBits.h index e2c647c833e7..ebe65fb40fed 100644 --- a/layout/generic/nsFrameStateBits.h +++ b/layout/generic/nsFrameStateBits.h @@ -512,6 +512,15 @@ FRAME_STATE_GROUP(Inline, nsInlineFrame) FRAME_STATE_BIT(Inline, 21, NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) FRAME_STATE_BIT(Inline, 22, NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST) FRAME_STATE_BIT(Inline, 23, NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST) +// nsRubyTextFrame inherits from nsInlineFrame + + +// == Frame state bits that apply to ruby text frames ========================= + +FRAME_STATE_GROUP(RubyText, nsRubyTextFrame) + +// inherits from nsInlineFrame +FRAME_STATE_BIT(RubyText, 24, NS_RUBY_TEXT_FRAME_AUTOHIDE) // == Frame state bits that apply to placeholder frames ======================= diff --git a/layout/generic/nsRubyBaseContainerFrame.cpp b/layout/generic/nsRubyBaseContainerFrame.cpp index 01e3b623e8ed..123a4cc82efb 100644 --- a/layout/generic/nsRubyBaseContainerFrame.cpp +++ b/layout/generic/nsRubyBaseContainerFrame.cpp @@ -7,6 +7,7 @@ /* rendering object for CSS "display: ruby-base-container" */ #include "nsRubyBaseContainerFrame.h" +#include "nsContentUtils.h" #include "nsLineLayout.h" #include "nsPresContext.h" #include "nsStyleContext.h" @@ -523,15 +524,40 @@ nsRubyBaseContainerFrame::ReflowOnePair(nsPresContext* aPresContext, nscoord istart = aReflowState.mLineLayout->GetCurrentICoord(); nscoord pairISize = 0; + nsAutoString baseText; + if (aBaseFrame) { + if (!nsContentUtils::GetNodeTextContent(aBaseFrame->GetContent(), + true, baseText)) { + NS_RUNTIMEABORT("OOM"); + } + } + // Reflow text frames for (uint32_t i = 0; i < rtcCount; i++) { - if (aTextFrames[i]) { - MOZ_ASSERT(aTextFrames[i]->GetType() == nsGkAtoms::rubyTextFrame); + nsIFrame* textFrame = aTextFrames[i]; + if (textFrame) { + MOZ_ASSERT(textFrame->GetType() == nsGkAtoms::rubyTextFrame); + nsAutoString annotationText; + if (!nsContentUtils::GetNodeTextContent(textFrame->GetContent(), + true, annotationText)) { + NS_RUNTIMEABORT("OOM"); + } + // Per CSS Ruby spec, the content comparison for auto-hiding + // takes place prior to white spaces collapsing (white-space) + // and text transformation (text-transform), and ignores elements + // (considers only the textContent of the boxes). Which means + // using the content tree text comparison is correct. + if (annotationText.Equals(baseText)) { + textFrame->AddStateBits(NS_RUBY_TEXT_FRAME_AUTOHIDE); + } else { + textFrame->RemoveStateBits(NS_RUBY_TEXT_FRAME_AUTOHIDE); + } + nsReflowStatus reflowStatus; nsHTMLReflowMetrics metrics(*aReflowStates[i]); bool pushedFrame; - aReflowStates[i]->mLineLayout->ReflowFrame(aTextFrames[i], reflowStatus, + aReflowStates[i]->mLineLayout->ReflowFrame(textFrame, reflowStatus, &metrics, pushedFrame); if (NS_INLINE_IS_BREAK(reflowStatus)) { // If any breaking occurs when reflowing a ruby text frame, diff --git a/layout/generic/nsRubyTextFrame.cpp b/layout/generic/nsRubyTextFrame.cpp index c71686241f87..707a9c01ab51 100644 --- a/layout/generic/nsRubyTextFrame.cpp +++ b/layout/generic/nsRubyTextFrame.cpp @@ -60,3 +60,37 @@ nsRubyTextFrame::IsFrameOfType(uint32_t aFlags) const } return nsRubyTextFrameSuper::IsFrameOfType(aFlags); } + + +/* virtual */ void +nsRubyTextFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) +{ + if (GetStateBits() & NS_RUBY_TEXT_FRAME_AUTOHIDE) { + return; + } + + nsRubyTextFrameSuper::BuildDisplayList(aBuilder, aDirtyRect, aLists); +} + +/* virtual */ void +nsRubyTextFrame::Reflow(nsPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + // Even if we want to hide this frame, we have to reflow it first. + // If we leave it dirty, changes to its content will never be + // propagated to the ancestors, then it won't be displayed even if + // the content is no longer the same, until next reflow triggered by + // some other change. In general, we always reflow all the frames we + // created. There might be other problems if we don't do that. + nsRubyTextFrameSuper::Reflow(aPresContext, aDesiredSize, + aReflowState, aStatus); + + if (GetStateBits() & NS_RUBY_TEXT_FRAME_AUTOHIDE) { + aDesiredSize.ClearSize(); + aDesiredSize.SetOverflowAreasToDesiredBounds(); + } +} diff --git a/layout/generic/nsRubyTextFrame.h b/layout/generic/nsRubyTextFrame.h index f08a05db18b9..287f970b6b65 100644 --- a/layout/generic/nsRubyTextFrame.h +++ b/layout/generic/nsRubyTextFrame.h @@ -35,6 +35,15 @@ public: virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; #endif + virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) MOZ_OVERRIDE; + + virtual void Reflow(nsPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) MOZ_OVERRIDE; + protected: friend nsContainerFrame* NS_NewRubyTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); diff --git a/layout/reftests/css-ruby/autohiding-1-ref.html b/layout/reftests/css-ruby/autohiding-1-ref.html new file mode 100644 index 000000000000..12f15a2e879b --- /dev/null +++ b/layout/reftests/css-ruby/autohiding-1-ref.html @@ -0,0 +1,14 @@ + + + + + Bug 1052123 - Autohide ruby annotations which are identical to their bases + + + + + + + + + diff --git a/layout/reftests/css-ruby/autohiding-1.html b/layout/reftests/css-ruby/autohiding-1.html new file mode 100644 index 000000000000..9c6ecfaaa34c --- /dev/null +++ b/layout/reftests/css-ruby/autohiding-1.html @@ -0,0 +1,14 @@ + + + + + Bug 1052123 - Autohide ruby annotations which are identical to their bases + + + + + + + + + diff --git a/layout/reftests/css-ruby/autohiding-2-ref.html b/layout/reftests/css-ruby/autohiding-2-ref.html new file mode 100644 index 000000000000..e389154bb661 --- /dev/null +++ b/layout/reftests/css-ruby/autohiding-2-ref.html @@ -0,0 +1,26 @@ + + + + + Bug 1052123 - Autohide ruby annotations which are identical to their bases + + + +

+ + ri +

+

+ ri + +

+

+ + +

+

+ + +

+ + diff --git a/layout/reftests/css-ruby/autohiding-2.html b/layout/reftests/css-ruby/autohiding-2.html new file mode 100644 index 000000000000..b05a87f658ec --- /dev/null +++ b/layout/reftests/css-ruby/autohiding-2.html @@ -0,0 +1,36 @@ + + + + + Bug 1052123 - Autohide ruby annotations which are identical to their bases + + + + +

+ + +

+

+ + +

+

+ + ri +

+

+ ri + +

+ + diff --git a/layout/reftests/css-ruby/autohiding-3-ref.html b/layout/reftests/css-ruby/autohiding-3-ref.html new file mode 100644 index 000000000000..70549f0477bb --- /dev/null +++ b/layout/reftests/css-ruby/autohiding-3-ref.html @@ -0,0 +1,17 @@ + + + + + Bug 1052123 - Autohide ruby annotations which are identical to their bases + + + + + + + + + + diff --git a/layout/reftests/css-ruby/autohiding-3.html b/layout/reftests/css-ruby/autohiding-3.html new file mode 100644 index 000000000000..1a39171877b7 --- /dev/null +++ b/layout/reftests/css-ruby/autohiding-3.html @@ -0,0 +1,17 @@ + + + + + Bug 1052123 - Autohide ruby annotations which are identical to their bases + + + + + + + + + + diff --git a/layout/reftests/css-ruby/reftest.list b/layout/reftests/css-ruby/reftest.list index bb2ee6087571..b260f64c65d5 100644 --- a/layout/reftests/css-ruby/reftest.list +++ b/layout/reftests/css-ruby/reftest.list @@ -1,5 +1,8 @@ default-preferences pref(layout.css.ruby.enabled,true) +== autohiding-1.html autohiding-1-ref.html +== autohiding-2.html autohiding-2-ref.html +== autohiding-3.html autohiding-3-ref.html == box-generation-1.html box-generation-1-ref.html == box-generation-2.html box-generation-2-ref.html == box-generation-3.html box-generation-3-ref.html From fc744d5f78a0925b33f7c48c8d90a6699c3e2b69 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 16 Dec 2014 13:53:06 -0800 Subject: [PATCH 080/130] Bug 1111477 - Always initialize scope chain for bailout to baseline if bailing in-place for debug mode. (r=jandem) --- js/src/jit/BaselineBailouts.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index bffd657ebbad..34110d7af66b 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -675,8 +675,15 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC, // If pcOffset == 0, we may have to push a new call object, so // we leave scopeChain nullptr and enter baseline code before // the prologue. - if (iter.pcOffset() != 0 || iter.resumeAfter()) + // + // If we are propagating an exception for debug mode, we will + // not resume into baseline code, but instead into + // HandleExceptionBaseline, so *do* set the scope chain here. + if (iter.pcOffset() != 0 || iter.resumeAfter() || + (excInfo && excInfo->propagatingIonExceptionForDebugMode())) + { scopeChain = fun->environment(); + } } else { // For global, compile-and-go scripts the scope chain is the // script's global (Ion does not compile non-compile-and-go From 0227edfaf91c8ba7f12f72944b2c7d4980471c0d Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 16 Dec 2014 22:52:51 +0100 Subject: [PATCH 081/130] Bug 1109889 - Share more exception handling code. r=nbp --HG-- extra : rebase_source : 4bb5eaff6c0e97a8b8c8b2b491597cf222ce5606 --- js/src/jit/Ion.cpp | 11 ++++++++++- js/src/jit/JitCompartment.h | 8 ++++++-- js/src/jit/MacroAssembler.cpp | 8 ++++---- js/src/jit/arm/MacroAssembler-arm.cpp | 11 ++--------- js/src/jit/arm/MacroAssembler-arm.h | 3 +-- js/src/jit/arm/Trampoline-arm.cpp | 4 ++-- js/src/jit/mips/MacroAssembler-mips.cpp | 11 ++--------- js/src/jit/mips/MacroAssembler-mips.h | 3 +-- js/src/jit/mips/Trampoline-mips.cpp | 4 ++-- js/src/jit/none/MacroAssembler-none.h | 2 +- js/src/jit/none/Trampoline-none.cpp | 2 +- js/src/jit/x64/MacroAssembler-x64.cpp | 11 ++--------- js/src/jit/x64/MacroAssembler-x64.h | 3 +-- js/src/jit/x64/Trampoline-x64.cpp | 4 ++-- js/src/jit/x86/MacroAssembler-x86.cpp | 11 ++--------- js/src/jit/x86/MacroAssembler-x86.h | 3 +-- js/src/jit/x86/Trampoline-x86.cpp | 4 ++-- 17 files changed, 42 insertions(+), 61 deletions(-) diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 564aa238fc76..537b95538222 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -154,6 +154,7 @@ JitRuntime::JitRuntime() : execAlloc_(nullptr), ionAlloc_(nullptr), exceptionTail_(nullptr), + exceptionTailParallel_(nullptr), bailoutTail_(nullptr), enterJIT_(nullptr), bailoutHandler_(nullptr), @@ -207,10 +208,18 @@ JitRuntime::initialize(JSContext *cx) return false; JitSpew(JitSpew_Codegen, "# Emitting exception tail stub"); - exceptionTail_ = generateExceptionTailStub(cx); + + void *handler = JS_FUNC_TO_DATA_PTR(void *, jit::HandleException); + void *handlerParallel = JS_FUNC_TO_DATA_PTR(void *, jit::HandleParallelFailure); + + exceptionTail_ = generateExceptionTailStub(cx, handler); if (!exceptionTail_) return false; + exceptionTailParallel_ = generateExceptionTailStub(cx, handlerParallel); + if (!exceptionTailParallel_) + return false; + JitSpew(JitSpew_Codegen, "# Emitting bailout tail stub"); bailoutTail_ = generateBailoutTailStub(cx); if (!bailoutTail_) diff --git a/js/src/jit/JitCompartment.h b/js/src/jit/JitCompartment.h index fb57462f2a6e..4b36a3d23602 100644 --- a/js/src/jit/JitCompartment.h +++ b/js/src/jit/JitCompartment.h @@ -152,8 +152,9 @@ class JitRuntime // need for explicit interrupt checks. ExecutableAllocator *ionAlloc_; - // Shared post-exception-handler tail + // Shared exception-handler tail. JitCode *exceptionTail_; + JitCode *exceptionTailParallel_; // Shared post-bailout-handler tail. JitCode *bailoutTail_; @@ -243,7 +244,7 @@ class JitRuntime private: JitCode *generateLazyLinkStub(JSContext *cx); - JitCode *generateExceptionTailStub(JSContext *cx); + JitCode *generateExceptionTailStub(JSContext *cx, void *handler); JitCode *generateBailoutTailStub(JSContext *cx); JitCode *generateEnterJIT(JSContext *cx, EnterJitType type); JitCode *generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void **returnAddrOut); @@ -332,6 +333,9 @@ class JitRuntime JitCode *getExceptionTail() const { return exceptionTail_; } + JitCode *getExceptionTailParallel() const { + return exceptionTailParallel_; + } JitCode *getBailoutTail() const { return bailoutTail_; diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index afb836036a7c..cde9a8fc2699 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -1571,18 +1571,18 @@ MacroAssembler::handleFailure(ExecutionMode executionMode) sps_->skipNextReenter(); leaveSPSFrame(); - void *handler; + JitCode *excTail; switch (executionMode) { case SequentialExecution: - handler = JS_FUNC_TO_DATA_PTR(void *, jit::HandleException); + excTail = GetJitContext()->runtime->jitRuntime()->getExceptionTail(); break; case ParallelExecution: - handler = JS_FUNC_TO_DATA_PTR(void *, jit::HandleParallelFailure); + excTail = GetJitContext()->runtime->jitRuntime()->getExceptionTailParallel(); break; default: MOZ_CRASH("No such execution mode"); } - MacroAssemblerSpecific::handleFailureWithHandler(handler); + jump(excTail); // Doesn't actually emit code, but balances the leave() if (sps_) diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 6e795d942680..e274b5d1c5c9 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -4205,7 +4205,7 @@ MacroAssemblerARMCompat::callWithABI(Register fun, MoveOp::Type result) } void -MacroAssemblerARMCompat::handleFailureWithHandler(void *handler) +MacroAssemblerARMCompat::handleFailureWithHandlerTail(void *handler) { // Reserve space for exception information. int size = (sizeof(ResumeFromException) + 7) & ~7; @@ -4213,18 +4213,11 @@ MacroAssemblerARMCompat::handleFailureWithHandler(void *handler) ma_sub(Imm32(size), sp); ma_mov(sp, r0); - // Ask for an exception handler. + // Call the handler. setupUnalignedABICall(1, r1); passABIArg(r0); callWithABI(handler); - JitCode *excTail = GetJitContext()->runtime->jitRuntime()->getExceptionTail(); - branch(excTail); -} - -void -MacroAssemblerARMCompat::handleFailureWithHandlerTail() -{ Label entryFrame; Label catch_; Label finally; diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 5447be33d2fd..925b9b1ebc17 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1222,8 +1222,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM ma_orr(Imm32(type), frameSizeReg); } - void handleFailureWithHandler(void *handler); - void handleFailureWithHandlerTail(); + void handleFailureWithHandlerTail(void *handler); ///////////////////////////////////////////////////////////////// // Common interface. diff --git a/js/src/jit/arm/Trampoline-arm.cpp b/js/src/jit/arm/Trampoline-arm.cpp index 5cabc0910cfb..8fb1b6102ee0 100644 --- a/js/src/jit/arm/Trampoline-arm.cpp +++ b/js/src/jit/arm/Trampoline-arm.cpp @@ -1002,11 +1002,11 @@ JitRuntime::generateDebugTrapHandler(JSContext *cx) } JitCode * -JitRuntime::generateExceptionTailStub(JSContext *cx) +JitRuntime::generateExceptionTailStub(JSContext *cx, void *handler) { MacroAssembler masm; - masm.handleFailureWithHandlerTail(); + masm.handleFailureWithHandlerTail(handler); Linker linker(masm); AutoFlushICache afc("ExceptionTailStub"); diff --git a/js/src/jit/mips/MacroAssembler-mips.cpp b/js/src/jit/mips/MacroAssembler-mips.cpp index 658c98010b01..20bd5503483c 100644 --- a/js/src/jit/mips/MacroAssembler-mips.cpp +++ b/js/src/jit/mips/MacroAssembler-mips.cpp @@ -3526,25 +3526,18 @@ MacroAssemblerMIPSCompat::callWithABI(Register fun, MoveOp::Type result) } void -MacroAssemblerMIPSCompat::handleFailureWithHandler(void *handler) +MacroAssemblerMIPSCompat::handleFailureWithHandlerTail(void *handler) { // Reserve space for exception information. int size = (sizeof(ResumeFromException) + ABIStackAlignment) & ~(ABIStackAlignment - 1); ma_subu(StackPointer, StackPointer, Imm32(size)); ma_move(a0, StackPointer); // Use a0 since it is a first function argument - // Ask for an exception handler. + // Call the handler. setupUnalignedABICall(1, a1); passABIArg(a0); callWithABI(handler); - JitCode *excTail = GetJitContext()->runtime->jitRuntime()->getExceptionTail(); - branch(excTail); -} - -void -MacroAssemblerMIPSCompat::handleFailureWithHandlerTail() -{ Label entryFrame; Label catch_; Label finally; diff --git a/js/src/jit/mips/MacroAssembler-mips.h b/js/src/jit/mips/MacroAssembler-mips.h index 67574ca3c82f..7f95f2f489f5 100644 --- a/js/src/jit/mips/MacroAssembler-mips.h +++ b/js/src/jit/mips/MacroAssembler-mips.h @@ -944,8 +944,7 @@ public: ma_or(frameSizeReg, frameSizeReg, Imm32(type)); } - void handleFailureWithHandler(void *handler); - void handleFailureWithHandlerTail(); + void handleFailureWithHandlerTail(void *handler); ///////////////////////////////////////////////////////////////// // Common interface. diff --git a/js/src/jit/mips/Trampoline-mips.cpp b/js/src/jit/mips/Trampoline-mips.cpp index 4bd9d9062638..328de42e7323 100644 --- a/js/src/jit/mips/Trampoline-mips.cpp +++ b/js/src/jit/mips/Trampoline-mips.cpp @@ -1005,11 +1005,11 @@ JitRuntime::generateDebugTrapHandler(JSContext *cx) JitCode * -JitRuntime::generateExceptionTailStub(JSContext *cx) +JitRuntime::generateExceptionTailStub(JSContext *cx, void *handler) { MacroAssembler masm; - masm.handleFailureWithHandlerTail(); + masm.handleFailureWithHandlerTail(handler); Linker linker(masm); AutoFlushICache afc("ExceptionTailStub"); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index abd21346a3b7..e65115b2cfb2 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -410,7 +410,7 @@ class MacroAssemblerNone : public Assembler void inc64(AbsoluteAddress) { MOZ_CRASH(); } void incrementInt32Value(Address) { MOZ_CRASH(); } void ensureDouble(ValueOperand, FloatRegister, Label *) { MOZ_CRASH(); } - void handleFailureWithHandler(void *) { MOZ_CRASH(); } + void handleFailureWithHandlerTail(void *) { MOZ_CRASH(); } void makeFrameDescriptor(Register, FrameType) { MOZ_CRASH(); } void branchPtrInNurseryRange(Condition, Register, Register, Label *) { MOZ_CRASH(); } diff --git a/js/src/jit/none/Trampoline-none.cpp b/js/src/jit/none/Trampoline-none.cpp index d3853dff7f6e..3e8d65b088f7 100644 --- a/js/src/jit/none/Trampoline-none.cpp +++ b/js/src/jit/none/Trampoline-none.cpp @@ -25,7 +25,7 @@ JitCode *JitRuntime::generateBailoutHandler(JSContext *, ExecutionMode) { MOZ_CR JitCode *JitRuntime::generateVMWrapper(JSContext *, const VMFunction &) { MOZ_CRASH(); } JitCode *JitRuntime::generatePreBarrier(JSContext *, MIRType) { MOZ_CRASH(); } JitCode *JitRuntime::generateDebugTrapHandler(JSContext *) { MOZ_CRASH(); } -JitCode *JitRuntime::generateExceptionTailStub(JSContext *) { MOZ_CRASH(); } +JitCode *JitRuntime::generateExceptionTailStub(JSContext *, void *) { MOZ_CRASH(); } JitCode *JitRuntime::generateBailoutTailStub(JSContext *) { MOZ_CRASH(); } JitCode *JitRuntime::generateForkJoinGetSliceStub(JSContext *) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index 69b71e2db865..743bdc78a888 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -378,24 +378,17 @@ MacroAssemblerX64::callWithABI(Register fun, MoveOp::Type result) } void -MacroAssemblerX64::handleFailureWithHandler(void *handler) +MacroAssemblerX64::handleFailureWithHandlerTail(void *handler) { // Reserve space for exception information. subq(Imm32(sizeof(ResumeFromException)), rsp); movq(rsp, rax); - // Ask for an exception handler. + // Call the handler. setupUnalignedABICall(1, rcx); passABIArg(rax); callWithABI(handler); - JitCode *excTail = GetJitContext()->runtime->jitRuntime()->getExceptionTail(); - jmp(excTail); -} - -void -MacroAssemblerX64::handleFailureWithHandlerTail() -{ Label entryFrame; Label catch_; Label finally; diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index 81cc4fb7d4f9..3d599aa4b3fb 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -1420,8 +1420,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void callWithABI(Address fun, MoveOp::Type result = MoveOp::GENERAL); void callWithABI(Register fun, MoveOp::Type result = MoveOp::GENERAL); - void handleFailureWithHandler(void *handler); - void handleFailureWithHandlerTail(); + void handleFailureWithHandlerTail(void *handler); void makeFrameDescriptor(Register frameSizeReg, FrameType type) { shlq(Imm32(FRAMESIZE_SHIFT), frameSizeReg); diff --git a/js/src/jit/x64/Trampoline-x64.cpp b/js/src/jit/x64/Trampoline-x64.cpp index 5451b2646107..2eab2f53d92c 100644 --- a/js/src/jit/x64/Trampoline-x64.cpp +++ b/js/src/jit/x64/Trampoline-x64.cpp @@ -823,11 +823,11 @@ JitRuntime::generateDebugTrapHandler(JSContext *cx) } JitCode * -JitRuntime::generateExceptionTailStub(JSContext *cx) +JitRuntime::generateExceptionTailStub(JSContext *cx, void *handler) { MacroAssembler masm; - masm.handleFailureWithHandlerTail(); + masm.handleFailureWithHandlerTail(handler); Linker linker(masm); JitCode *code = linker.newCode(cx, OTHER_CODE); diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index 4c77552df0fa..dcc350faee24 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -358,24 +358,17 @@ MacroAssemblerX86::callWithABI(Register fun, MoveOp::Type result) } void -MacroAssemblerX86::handleFailureWithHandler(void *handler) +MacroAssemblerX86::handleFailureWithHandlerTail(void *handler) { // Reserve space for exception information. subl(Imm32(sizeof(ResumeFromException)), esp); movl(esp, eax); - // Ask for an exception handler. + // Call the handler. setupUnalignedABICall(1, ecx); passABIArg(eax); callWithABI(handler); - JitCode *excTail = GetJitContext()->runtime->jitRuntime()->getExceptionTail(); - jmp(excTail); -} - -void -MacroAssemblerX86::handleFailureWithHandlerTail() -{ Label entryFrame; Label catch_; Label finally; diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 3d8d4d0c56d8..0e5997a42e91 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -1172,8 +1172,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared void callWithABI(Register fun, MoveOp::Type result = MoveOp::GENERAL); // Used from within an Exit frame to handle a pending exception. - void handleFailureWithHandler(void *handler); - void handleFailureWithHandlerTail(); + void handleFailureWithHandlerTail(void *handler); void makeFrameDescriptor(Register frameSizeReg, FrameType type) { shll(Imm32(FRAMESIZE_SHIFT), frameSizeReg); diff --git a/js/src/jit/x86/Trampoline-x86.cpp b/js/src/jit/x86/Trampoline-x86.cpp index 2964b0045f2e..7837b7254fb8 100644 --- a/js/src/jit/x86/Trampoline-x86.cpp +++ b/js/src/jit/x86/Trampoline-x86.cpp @@ -863,11 +863,11 @@ JitRuntime::generateDebugTrapHandler(JSContext *cx) } JitCode * -JitRuntime::generateExceptionTailStub(JSContext *cx) +JitRuntime::generateExceptionTailStub(JSContext *cx, void *handler) { MacroAssembler masm; - masm.handleFailureWithHandlerTail(); + masm.handleFailureWithHandlerTail(handler); Linker linker(masm); JitCode *code = linker.newCode(cx, OTHER_CODE); From 3794dbb5b21e1e1ac717293f23b2cf0fc3a11e87 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 16 Dec 2014 17:09:17 -0500 Subject: [PATCH 082/130] Bug 1109291 - Include better paths for hanging chrome scripts in profile extensions directory; r=snorp r=bsmedberg --HG-- extra : amend_source : 82f1911bd294cc38076bf2bea2113b9e58e4bcc5 --- xpcom/threads/ThreadStackHelper.cpp | 40 +++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/xpcom/threads/ThreadStackHelper.cpp b/xpcom/threads/ThreadStackHelper.cpp index af841b18e732..3e57d17dafb2 100644 --- a/xpcom/threads/ThreadStackHelper.cpp +++ b/xpcom/threads/ThreadStackHelper.cpp @@ -541,6 +541,8 @@ IsChromeJSScript(JSScript* aScript) return secman->IsSystemPrincipal(nsJSPrincipals::get(principals)); } +// Get the full path after the URI scheme, if the URI matches the scheme. +// For example, GetFullPathForScheme("a://b/c/d/e", "a://") returns "b/c/d/e". template const char* GetFullPathForScheme(const char* filename, const char (&scheme)[LEN]) { @@ -551,6 +553,23 @@ GetFullPathForScheme(const char* filename, const char (&scheme)[LEN]) { return nullptr; } +// Get the full path after a URI component, if the URI contains the component. +// For example, GetPathAfterComponent("a://b/c/d/e", "/c/") returns "d/e". +template +const char* +GetPathAfterComponent(const char* filename, const char (&component)[LEN]) { + const char* found = nullptr; + const char* next = strstr(filename, component); + while (next) { + // Move 'found' to end of the component, after the separator '/'. + // 'LEN - 1' accounts for the null terminator included in LEN, + found = next + LEN - 1; + // Resume searching before the separator '/'. + next = strstr(found - 1, component); + } + return found; +} + } // namespace const char* @@ -566,19 +585,30 @@ ThreadStackHelper::AppendJSEntry(const volatile StackEntry* aEntry, const char* label; if (IsChromeJSScript(aEntry->script())) { - const char* const filename = JS_GetScriptFilename(aEntry->script()); - unsigned lineno = JS_PCToLineNumber(aEntry->script(), aEntry->pc()); + const char* filename = JS_GetScriptFilename(aEntry->script()); + const unsigned lineno = JS_PCToLineNumber(aEntry->script(), aEntry->pc()); MOZ_ASSERT(filename); - char buffer[64]; // Enough to fit longest js file name from the tree - const char* basename; + char buffer[128]; // Enough to fit longest js file name from the tree + + // Some script names are in the form "foo -> bar -> baz". + // Here we find the origin of these redirected scripts. + const char* basename = GetPathAfterComponent(filename, " -> "); + if (basename) { + filename = basename; + } basename = GetFullPathForScheme(filename, "chrome://"); if (!basename) { basename = GetFullPathForScheme(filename, "resource://"); } if (!basename) { - // Only keep the file base name for paths not under the above schemes. + // If the (add-on) script is located under the {profile}/extensions + // directory, extract the path after the /extensions/ part. + basename = GetPathAfterComponent(filename, "/extensions/"); + } + if (!basename) { + // Only keep the file base name for paths outside the above formats. basename = strrchr(filename, '/'); basename = basename ? basename + 1 : filename; } From 2c7e571767d56280dc20d1ce7853330d0b94694c Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Tue, 16 Dec 2014 22:52:57 +1300 Subject: [PATCH 083/130] Bug 1111413 - Part 1: Use MediaPromises for seeking. r=bholley --- dom/media/MediaDataDecodedListener.h | 14 ------- dom/media/MediaDecoderReader.h | 12 ++---- dom/media/MediaDecoderStateMachine.cpp | 27 ++++++++----- dom/media/MediaDecoderStateMachine.h | 3 +- dom/media/MediaPromise.h | 18 +++++++++ dom/media/android/AndroidMediaReader.cpp | 5 ++- dom/media/android/AndroidMediaReader.h | 3 +- dom/media/apple/AppleMP3Reader.cpp | 7 ++-- dom/media/apple/AppleMP3Reader.h | 9 +++-- dom/media/directshow/DirectShowReader.cpp | 8 +++- dom/media/directshow/DirectShowReader.h | 9 +++-- dom/media/fmp4/MP4Reader.cpp | 7 ++-- dom/media/fmp4/MP4Reader.h | 9 +++-- dom/media/gstreamer/GStreamerReader.cpp | 14 +++---- dom/media/gstreamer/GStreamerReader.h | 9 +++-- dom/media/mediasource/MediaSourceReader.cpp | 43 +++++++++++++++++---- dom/media/mediasource/MediaSourceReader.h | 10 +++-- dom/media/ogg/OggReader.cpp | 15 ++++--- dom/media/ogg/OggReader.h | 3 +- dom/media/omx/MediaCodecReader.cpp | 7 ++-- dom/media/omx/MediaCodecReader.h | 9 +++-- dom/media/omx/MediaOmxReader.cpp | 5 ++- dom/media/omx/MediaOmxReader.h | 3 +- dom/media/omx/RtspMediaCodecReader.cpp | 4 +- dom/media/omx/RtspMediaCodecReader.h | 5 ++- dom/media/omx/RtspOmxReader.cpp | 7 ++-- dom/media/omx/RtspOmxReader.h | 5 ++- dom/media/raw/RawReader.cpp | 9 ++++- dom/media/raw/RawReader.h | 4 +- dom/media/wave/WaveReader.cpp | 13 +++++-- dom/media/wave/WaveReader.h | 4 +- dom/media/webm/WebMReader.cpp | 9 ++++- dom/media/webm/WebMReader.h | 5 ++- dom/media/wmf/WMFReader.cpp | 8 +++- dom/media/wmf/WMFReader.h | 9 +++-- 35 files changed, 209 insertions(+), 122 deletions(-) diff --git a/dom/media/MediaDataDecodedListener.h b/dom/media/MediaDataDecodedListener.h index 2151d5bf940d..e5bf1c190dcc 100644 --- a/dom/media/MediaDataDecodedListener.h +++ b/dom/media/MediaDataDecodedListener.h @@ -36,20 +36,6 @@ public: mTaskQueue = nullptr; } - virtual void OnSeekCompleted(nsresult aResult) MOZ_OVERRIDE { - MonitorAutoLock lock(mMonitor); - if (!mTarget || !mTaskQueue) { - // We've been shutdown, abort. - return; - } - RefPtr task(NS_NewRunnableMethodWithArg(mTarget, - &Target::OnSeekCompleted, - aResult)); - if (NS_FAILED(mTaskQueue->Dispatch(task))) { - NS_WARNING("Failed to dispatch OnSeekCompleted task"); - } - } - private: Monitor mMonitor; RefPtr mTaskQueue; diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h index f29255612851..b94a61f8f6e4 100644 --- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -40,6 +40,7 @@ public: typedef MediaPromise, NotDecodedReason> AudioDataPromise; typedef MediaPromise, NotDecodedReason> VideoDataPromise; + typedef MediaPromise SeekPromise; NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReader) @@ -131,15 +132,12 @@ public: // ReadUpdatedMetadata will always be called once ReadMetadata has succeeded. virtual void ReadUpdatedMetadata(MediaInfo* aInfo) { }; - // Requests the Reader to seek and call OnSeekCompleted on the callback - // once completed. // Moves the decode head to aTime microseconds. aStartTime and aEndTime // denote the start and end times of the media in usecs, and aCurrentTime // is the current playback position in microseconds. - virtual void Seek(int64_t aTime, - int64_t aStartTime, - int64_t aEndTime, - int64_t aCurrentTime) = 0; + virtual nsRefPtr + Seek(int64_t aTime, int64_t aStartTime, + int64_t aEndTime, int64_t aCurrentTime) = 0; // Called to move the reader into idle state. When the reader is // created it is assumed to be active (i.e. not idle). When the media @@ -312,8 +310,6 @@ class RequestSampleCallback { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RequestSampleCallback) - virtual void OnSeekCompleted(nsresult aResult) = 0; - // Called during shutdown to break any reference cycles. virtual void BreakCycles() = 0; diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 9a1e401dd218..7447faed2fcb 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -2306,10 +2306,10 @@ void MediaDecoderStateMachine::DecodeSeek() // the reader, since it could do I/O or deadlock some other way. res = mReader->ResetDecode(); if (NS_SUCCEEDED(res)) { - mReader->Seek(seekTime, - mStartTime, - mEndTime, - mCurrentTimeBeforeSeek); + mReader->Seek(seekTime, mStartTime, mEndTime, mCurrentTimeBeforeSeek) + ->Then(DecodeTaskQueue(), __func__, this, + &MediaDecoderStateMachine::OnSeekCompleted, + &MediaDecoderStateMachine::OnSeekFailed); } } if (NS_FAILED(res)) { @@ -2321,14 +2321,10 @@ void MediaDecoderStateMachine::DecodeSeek() } void -MediaDecoderStateMachine::OnSeekCompleted(nsresult aResult) +MediaDecoderStateMachine::OnSeekCompleted() { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mWaitingForDecoderSeek = false; - if (NS_FAILED(aResult)) { - DecodeError(); - return; - } // We must decode the first samples of active streams, so we can determine // the new stream time. So dispatch tasks to do that. @@ -2336,6 +2332,19 @@ MediaDecoderStateMachine::OnSeekCompleted(nsresult aResult) DispatchDecodeTasksIfNeeded(); } +void +MediaDecoderStateMachine::OnSeekFailed(nsresult aResult) +{ + ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); + mWaitingForDecoderSeek = false; + // Sometimes we reject the promise for non-failure reasons, like + // when we request a second seek before the previous one has + // completed. + if (NS_FAILED(aResult)) { + DecodeError(); + } +} + void MediaDecoderStateMachine::SeekCompleted() { diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index 1592ab8266ae..f4f424e54107 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -387,7 +387,8 @@ public: OnNotDecoded(MediaData::VIDEO_DATA, aReason); } - void OnSeekCompleted(nsresult aResult); + void OnSeekCompleted(); + void OnSeekFailed(nsresult aResult); private: void AcquireMonitorAndInvokeDecodeError(); diff --git a/dom/media/MediaPromise.h b/dom/media/MediaPromise.h index d09bdbc259cf..f9e462962f05 100644 --- a/dom/media/MediaPromise.h +++ b/dom/media/MediaPromise.h @@ -65,6 +65,24 @@ public: PROMISE_LOG("%s creating MediaPromise (%p)", mCreationSite, this); } + static nsRefPtr> + CreateAndResolve(ResolveValueType aResolveValue, const char* aResolveSite) + { + nsRefPtr> p = + new MediaPromise(aResolveSite); + p->Resolve(aResolveValue, aResolveSite); + return p; + } + + static nsRefPtr> + CreateAndReject(RejectValueType aRejectValue, const char* aRejectSite) + { + nsRefPtr> p = + new MediaPromise(aRejectSite); + p->Reject(aRejectValue, aRejectSite); + return p; + } + protected: /* diff --git a/dom/media/android/AndroidMediaReader.cpp b/dom/media/android/AndroidMediaReader.cpp index cf8c463f1ad2..fb9a4fc2da9a 100644 --- a/dom/media/android/AndroidMediaReader.cpp +++ b/dom/media/android/AndroidMediaReader.cpp @@ -319,7 +319,8 @@ bool AndroidMediaReader::DecodeAudioData() source.mAudioChannels)); } -void AndroidMediaReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) +nsRefPtr +AndroidMediaReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); @@ -339,7 +340,7 @@ void AndroidMediaReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndT mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget; } - GetCallback()->OnSeekCompleted(NS_OK); + return SeekPromise::CreateAndResolve(true, __func__); } AndroidMediaReader::ImageBufferCallback::ImageBufferCallback(mozilla::layers::ImageContainer *aImageContainer) : diff --git a/dom/media/android/AndroidMediaReader.h b/dom/media/android/AndroidMediaReader.h index 4738cfa7b6a0..09894a16c97e 100644 --- a/dom/media/android/AndroidMediaReader.h +++ b/dom/media/android/AndroidMediaReader.h @@ -69,7 +69,8 @@ public: virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags); - virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); + virtual nsRefPtr + Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) MOZ_OVERRIDE; virtual nsRefPtr Shutdown() MOZ_OVERRIDE; diff --git a/dom/media/apple/AppleMP3Reader.cpp b/dom/media/apple/AppleMP3Reader.cpp index 07146ff13ba9..193bd6e107f8 100644 --- a/dom/media/apple/AppleMP3Reader.cpp +++ b/dom/media/apple/AppleMP3Reader.cpp @@ -492,7 +492,7 @@ AppleMP3Reader::SetupDecoder() } -void +nsRefPtr AppleMP3Reader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, @@ -518,8 +518,7 @@ AppleMP3Reader::Seek(int64_t aTime, if (rv) { LOGE("Couldn't seek demuxer. Error code %x\n", rv); - GetCallback()->OnSeekCompleted(NS_ERROR_FAILURE); - return; + return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); } LOGD("computed byte offset = %lld; estimated = %s\n", @@ -530,7 +529,7 @@ AppleMP3Reader::Seek(int64_t aTime, ResetDecode(); - GetCallback()->OnSeekCompleted(NS_OK); + return SeekPromise::CreateAndResolve(true, __func__); } void diff --git a/dom/media/apple/AppleMP3Reader.h b/dom/media/apple/AppleMP3Reader.h index c0f0ccaf800c..17547b2fd0aa 100644 --- a/dom/media/apple/AppleMP3Reader.h +++ b/dom/media/apple/AppleMP3Reader.h @@ -33,10 +33,11 @@ public: virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE; - virtual void Seek(int64_t aTime, - int64_t aStartTime, - int64_t aEndTime, - int64_t aCurrentTime) MOZ_OVERRIDE; + virtual nsRefPtr + Seek(int64_t aTime, + int64_t aStartTime, + int64_t aEndTime, + int64_t aCurrentTime) MOZ_OVERRIDE; void AudioSampleCallback(UInt32 aNumBytes, UInt32 aNumPackets, diff --git a/dom/media/directshow/DirectShowReader.cpp b/dom/media/directshow/DirectShowReader.cpp index 9f1ace647b61..f9bfafa36bda 100644 --- a/dom/media/directshow/DirectShowReader.cpp +++ b/dom/media/directshow/DirectShowReader.cpp @@ -367,14 +367,18 @@ DirectShowReader::HasVideo() return false; } -void +nsRefPtr DirectShowReader::Seek(int64_t aTargetUs, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { nsresult res = SeekInternal(aTargetUs); - GetCallback()->OnSeekCompleted(res); + if (NS_FAILED(res)) { + return SeekPromise::CreateAndReject(res, __func__); + } else { + return SeekPromise::CreateAndResolve(true, __func__); + } } nsresult diff --git a/dom/media/directshow/DirectShowReader.h b/dom/media/directshow/DirectShowReader.h index 704c806957fe..f6cf3590f7e3 100644 --- a/dom/media/directshow/DirectShowReader.h +++ b/dom/media/directshow/DirectShowReader.h @@ -60,10 +60,11 @@ public: nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE; - void Seek(int64_t aTime, - int64_t aStartTime, - int64_t aEndTime, - int64_t aCurrentTime) MOZ_OVERRIDE; + nsRefPtr + Seek(int64_t aTime, + int64_t aStartTime, + int64_t aEndTime, + int64_t aCurrentTime) MOZ_OVERRIDE; void NotifyDataArrived(const char* aBuffer, uint32_t aLength, diff --git a/dom/media/fmp4/MP4Reader.cpp b/dom/media/fmp4/MP4Reader.cpp index f593e8ca7ef8..c5f4eb7a5094 100644 --- a/dom/media/fmp4/MP4Reader.cpp +++ b/dom/media/fmp4/MP4Reader.cpp @@ -783,7 +783,7 @@ MP4Reader::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed return true; } -void +nsRefPtr MP4Reader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, @@ -793,8 +793,7 @@ MP4Reader::Seek(int64_t aTime, MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn()); if (!mDecoder->GetResource()->IsTransportSeekable() || !mDemuxer->CanSeek()) { VLOG("Seek() END (Unseekable)"); - GetCallback()->OnSeekCompleted(NS_ERROR_FAILURE); - return; + return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); } mQueuedVideoSample = nullptr; @@ -807,7 +806,7 @@ MP4Reader::Seek(int64_t aTime, mQueuedVideoSample ? mQueuedVideoSample->composition_timestamp : aTime); } LOG("MP4Reader::Seek(%lld) exit", aTime); - GetCallback()->OnSeekCompleted(NS_OK); + return SeekPromise::CreateAndResolve(true, __func__); } void diff --git a/dom/media/fmp4/MP4Reader.h b/dom/media/fmp4/MP4Reader.h index 041f2f7a5685..e391eb822fe7 100644 --- a/dom/media/fmp4/MP4Reader.h +++ b/dom/media/fmp4/MP4Reader.h @@ -55,10 +55,11 @@ public: virtual void ReadUpdatedMetadata(MediaInfo* aInfo) MOZ_OVERRIDE; - virtual void Seek(int64_t aTime, - int64_t aStartTime, - int64_t aEndTime, - int64_t aCurrentTime) MOZ_OVERRIDE; + virtual nsRefPtr + Seek(int64_t aTime, + int64_t aStartTime, + int64_t aEndTime, + int64_t aCurrentTime) MOZ_OVERRIDE; virtual bool IsMediaSeekable() MOZ_OVERRIDE; diff --git a/dom/media/gstreamer/GStreamerReader.cpp b/dom/media/gstreamer/GStreamerReader.cpp index 18d99d4cd251..d80901ec3e08 100644 --- a/dom/media/gstreamer/GStreamerReader.cpp +++ b/dom/media/gstreamer/GStreamerReader.cpp @@ -787,10 +787,11 @@ bool GStreamerReader::DecodeVideoFrame(bool &aKeyFrameSkip, return true; } -void GStreamerReader::Seek(int64_t aTarget, - int64_t aStartTime, - int64_t aEndTime, - int64_t aCurrentTime) +nsRefPtr +GStreamerReader::Seek(int64_t aTarget, + int64_t aStartTime, + int64_t aEndTime, + int64_t aCurrentTime) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); @@ -804,8 +805,7 @@ void GStreamerReader::Seek(int64_t aTarget, static_cast(flags), seekPos)) { LOG(PR_LOG_ERROR, "seek failed"); - GetCallback()->OnSeekCompleted(NS_ERROR_FAILURE); - return; + return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); } LOG(PR_LOG_DEBUG, "seek succeeded"); GstMessage* message = gst_bus_timed_pop_filtered(mBus, GST_CLOCK_TIME_NONE, @@ -813,7 +813,7 @@ void GStreamerReader::Seek(int64_t aTarget, gst_message_unref(message); LOG(PR_LOG_DEBUG, "seek completed"); - GetCallback()->OnSeekCompleted(NS_OK); + return SeekPromise::CreateAndResolve(true, __func__); } nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered) diff --git a/dom/media/gstreamer/GStreamerReader.h b/dom/media/gstreamer/GStreamerReader.h index 548164df6414..5c81b13f16d6 100644 --- a/dom/media/gstreamer/GStreamerReader.h +++ b/dom/media/gstreamer/GStreamerReader.h @@ -48,10 +48,11 @@ public: int64_t aTimeThreshold); virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags); - virtual void Seek(int64_t aTime, - int64_t aStartTime, - int64_t aEndTime, - int64_t aCurrentTime); + virtual nsRefPtr + Seek(int64_t aTime, + int64_t aStartTime, + int64_t aEndTime, + int64_t aCurrentTime) MOZ_OVERRIDE; virtual nsresult GetBuffered(dom::TimeRanges* aBuffered); virtual void NotifyDataArrived(const char *aBuffer, diff --git a/dom/media/mediasource/MediaSourceReader.cpp b/dom/media/mediasource/MediaSourceReader.cpp index 49abf3e76171..85c4b0f4e14a 100644 --- a/dom/media/mediasource/MediaSourceReader.cpp +++ b/dom/media/mediasource/MediaSourceReader.cpp @@ -296,6 +296,8 @@ MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason) nsRefPtr MediaSourceReader::Shutdown() { + mSeekPromise.RejectIfExists(NS_ERROR_FAILURE, __func__); + MOZ_ASSERT(mMediaSourceShutdownPromise.IsEmpty()); nsRefPtr p = mMediaSourceShutdownPromise.Ensure(__func__); @@ -538,16 +540,19 @@ MediaSourceReader::NotifyTimeRangesChanged() } } -void +nsRefPtr MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { MSE_DEBUG("MediaSourceReader(%p)::Seek(aTime=%lld, aStart=%lld, aEnd=%lld, aCurrent=%lld)", this, aTime, aStartTime, aEndTime, aCurrentTime); + mSeekPromise.RejectIfExists(NS_OK, __func__); + nsRefPtr p = mSeekPromise.Ensure(__func__); + if (IsShutdown()) { - GetCallback()->OnSeekCompleted(NS_ERROR_FAILURE); - return; + mSeekPromise.Reject(NS_ERROR_FAILURE, __func__); + return p; } // Store pending seek target in case the track buffers don't contain @@ -575,20 +580,38 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, } AttemptSeek(); + return p; } void -MediaSourceReader::OnSeekCompleted(nsresult aResult) +MediaSourceReader::OnSeekCompleted() +{ + mPendingSeeks--; + FinalizeSeek(); +} + +void +MediaSourceReader::OnSeekFailed(nsresult aResult) { mPendingSeeks--; // Keep the most recent failed result (if any) if (NS_FAILED(aResult)) { mSeekResult = aResult; } + FinalizeSeek(); +} + +void +MediaSourceReader::FinalizeSeek() +{ // Only dispatch the final event onto the state machine // since it's only expecting one response. if (!mPendingSeeks) { - GetCallback()->OnSeekCompleted(mSeekResult); + if (NS_FAILED(mSeekResult)) { + mSeekPromise.Reject(mSeekResult, __func__); + } else { + mSeekPromise.Resolve(true, __func__); + } mSeekResult = NS_OK; } } @@ -620,7 +643,10 @@ MediaSourceReader::AttemptSeek() mAudioReader->Seek(mPendingSeekTime, mPendingStartTime, mPendingEndTime, - mPendingCurrentTime); + mPendingCurrentTime) + ->Then(GetTaskQueue(), __func__, this, + &MediaSourceReader::OnSeekCompleted, + &MediaSourceReader::OnSeekFailed); MSE_DEBUG("MediaSourceReader(%p)::Seek audio reader=%p", this, mAudioReader.get()); } if (mVideoTrack) { @@ -629,7 +655,10 @@ MediaSourceReader::AttemptSeek() mVideoReader->Seek(mPendingSeekTime, mPendingStartTime, mPendingEndTime, - mPendingCurrentTime); + mPendingCurrentTime) + ->Then(GetTaskQueue(), __func__, this, + &MediaSourceReader::OnSeekCompleted, + &MediaSourceReader::OnSeekFailed); MSE_DEBUG("MediaSourceReader(%p)::Seek video reader=%p", this, mVideoReader.get()); } { diff --git a/dom/media/mediasource/MediaSourceReader.h b/dom/media/mediasource/MediaSourceReader.h index cf0eb6e02bd2..e7b7362a3a77 100644 --- a/dom/media/mediasource/MediaSourceReader.h +++ b/dom/media/mediasource/MediaSourceReader.h @@ -55,7 +55,8 @@ public: void OnVideoDecoded(VideoData* aSample); void OnVideoNotDecoded(NotDecodedReason aReason); - void OnSeekCompleted(nsresult aResult); + void OnSeekCompleted(); + void OnSeekFailed(nsresult aResult); bool HasVideo() MOZ_OVERRIDE { @@ -84,8 +85,9 @@ public: nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE; void ReadUpdatedMetadata(MediaInfo* aInfo) MOZ_OVERRIDE; - void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, - int64_t aCurrentTime) MOZ_OVERRIDE; + nsRefPtr + Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, + int64_t aCurrentTime) MOZ_OVERRIDE; // Acquires the decoder monitor, and is thus callable on any thread. nsresult GetBuffered(dom::TimeRanges* aBuffered) MOZ_OVERRIDE; @@ -129,6 +131,7 @@ private: const nsTArray>& aTrackDecoders); void AttemptSeek(); + void FinalizeSeek(); nsRefPtr mAudioReader; nsRefPtr mVideoReader; @@ -152,6 +155,7 @@ private: // Temporary seek information while we wait for the data // to be added to the track buffer. + MediaPromiseHolder mSeekPromise; int64_t mPendingSeekTime; int64_t mPendingStartTime; int64_t mPendingEndTime; diff --git a/dom/media/ogg/OggReader.cpp b/dom/media/ogg/OggReader.cpp index 6d32b6f3056e..72a63cb6fa09 100644 --- a/dom/media/ogg/OggReader.cpp +++ b/dom/media/ogg/OggReader.cpp @@ -1424,13 +1424,18 @@ nsresult OggReader::SeekInUnbuffered(int64_t aTarget, return SeekBisection(seekTarget, k, SEEK_FUZZ_USECS); } -void OggReader::Seek(int64_t aTarget, - int64_t aStartTime, - int64_t aEndTime, - int64_t aCurrentTime) +nsRefPtr +OggReader::Seek(int64_t aTarget, + int64_t aStartTime, + int64_t aEndTime, + int64_t aCurrentTime) { nsresult res = SeekInternal(aTarget, aStartTime, aEndTime, aCurrentTime); - GetCallback()->OnSeekCompleted(res); + if (NS_FAILED(res)) { + return SeekPromise::CreateAndReject(res, __func__); + } else { + return SeekPromise::CreateAndResolve(true, __func__); + } } nsresult OggReader::SeekInternal(int64_t aTarget, diff --git a/dom/media/ogg/OggReader.h b/dom/media/ogg/OggReader.h index 2dbedfcec842..d318ac2d5c57 100644 --- a/dom/media/ogg/OggReader.h +++ b/dom/media/ogg/OggReader.h @@ -75,7 +75,8 @@ public: virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags); - virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); + virtual nsRefPtr + Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) MOZ_OVERRIDE; virtual nsresult GetBuffered(dom::TimeRanges* aBuffered); virtual bool IsMediaSeekable() MOZ_OVERRIDE; diff --git a/dom/media/omx/MediaCodecReader.cpp b/dom/media/omx/MediaCodecReader.cpp index 74d12575c198..43cdc4911512 100644 --- a/dom/media/omx/MediaCodecReader.cpp +++ b/dom/media/omx/MediaCodecReader.cpp @@ -999,7 +999,7 @@ MediaCodecReader::DecodeVideoFrameSync(int64_t aTimeThreshold) return result; } -void +nsRefPtr MediaCodecReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, @@ -1031,8 +1031,7 @@ MediaCodecReader::Seek(int64_t aTime, options.setSeekTo(aTime, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); if (mVideoTrack.mSource->read(&source_buffer, &options) != OK || source_buffer == nullptr) { - GetCallback()->OnSeekCompleted(NS_ERROR_FAILURE); - return; + return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); } sp format = source_buffer->meta_data(); if (format != nullptr) { @@ -1056,7 +1055,7 @@ MediaCodecReader::Seek(int64_t aTime, MOZ_ASSERT(mAudioTrack.mTaskQueue->IsEmpty()); DispatchAudioTask(); } - GetCallback()->OnSeekCompleted(NS_OK); + return SeekPromise::CreateAndResolve(true, __func__); } bool diff --git a/dom/media/omx/MediaCodecReader.h b/dom/media/omx/MediaCodecReader.h index e6b3b164ad13..858a97ccc86b 100644 --- a/dom/media/omx/MediaCodecReader.h +++ b/dom/media/omx/MediaCodecReader.h @@ -100,10 +100,11 @@ public: // Moves the decode head to aTime microseconds. aStartTime and aEndTime // denote the start and end times of the media in usecs, and aCurrentTime // is the current playback position in microseconds. - virtual void Seek(int64_t aTime, - int64_t aStartTime, - int64_t aEndTime, - int64_t aCurrentTime); + virtual nsRefPtr + Seek(int64_t aTime, + int64_t aStartTime, + int64_t aEndTime, + int64_t aCurrentTime) MOZ_OVERRIDE; virtual bool IsMediaSeekable() MOZ_OVERRIDE; diff --git a/dom/media/omx/MediaOmxReader.cpp b/dom/media/omx/MediaOmxReader.cpp index 1fe3680b48c0..7ab49a5fe209 100644 --- a/dom/media/omx/MediaOmxReader.cpp +++ b/dom/media/omx/MediaOmxReader.cpp @@ -545,7 +545,8 @@ bool MediaOmxReader::DecodeAudioData() source.mAudioChannels)); } -void MediaOmxReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) +nsRefPtr +MediaOmxReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); EnsureActive(); @@ -571,7 +572,7 @@ void MediaOmxReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget; } - GetCallback()->OnSeekCompleted(NS_OK); + return SeekPromise::CreateAndResolve(true, __func__); } void MediaOmxReader::SetIdle() { diff --git a/dom/media/omx/MediaOmxReader.h b/dom/media/omx/MediaOmxReader.h index cbe88c09c726..4a9521552371 100644 --- a/dom/media/omx/MediaOmxReader.h +++ b/dom/media/omx/MediaOmxReader.h @@ -98,7 +98,8 @@ public: virtual void PreReadMetadata() MOZ_OVERRIDE; virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags); - virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); + virtual nsRefPtr + Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) MOZ_OVERRIDE; virtual bool IsMediaSeekable() MOZ_OVERRIDE; diff --git a/dom/media/omx/RtspMediaCodecReader.cpp b/dom/media/omx/RtspMediaCodecReader.cpp index bfa7592b8c51..dce678ab4a8f 100644 --- a/dom/media/omx/RtspMediaCodecReader.cpp +++ b/dom/media/omx/RtspMediaCodecReader.cpp @@ -38,7 +38,7 @@ RtspMediaCodecReader::CreateExtractor() return mExtractor != nullptr; } -void +nsRefPtr RtspMediaCodecReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { @@ -48,7 +48,7 @@ RtspMediaCodecReader::Seek(int64_t aTime, int64_t aStartTime, // RtspMediaResource. mRtspResource->SeekTime(aTime); - MediaCodecReader::Seek(aTime, aStartTime, aEndTime, aCurrentTime); + return MediaCodecReader::Seek(aTime, aStartTime, aEndTime, aCurrentTime); } void diff --git a/dom/media/omx/RtspMediaCodecReader.h b/dom/media/omx/RtspMediaCodecReader.h index 7617cbea1cfe..39de7d9aed6c 100644 --- a/dom/media/omx/RtspMediaCodecReader.h +++ b/dom/media/omx/RtspMediaCodecReader.h @@ -36,8 +36,9 @@ public: virtual ~RtspMediaCodecReader(); // Implement a time-based seek instead of byte-based. - virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, - int64_t aCurrentTime) MOZ_OVERRIDE; + virtual nsRefPtr + Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, + int64_t aCurrentTime) MOZ_OVERRIDE; // Override GetBuffered() to do nothing for below reasons: // 1. Because the Rtsp stream is a/v separated. The buffered data in a/v diff --git a/dom/media/omx/RtspOmxReader.cpp b/dom/media/omx/RtspOmxReader.cpp index fbce381ca198..7bae223f17ea 100644 --- a/dom/media/omx/RtspOmxReader.cpp +++ b/dom/media/omx/RtspOmxReader.cpp @@ -32,8 +32,9 @@ nsresult RtspOmxReader::InitOmxDecoder() return NS_OK; } -void RtspOmxReader::Seek(int64_t aTime, int64_t aStartTime, - int64_t aEndTime, int64_t aCurrentTime) +nsRefPtr +RtspOmxReader::Seek(int64_t aTime, int64_t aStartTime, + int64_t aEndTime, int64_t aCurrentTime) { // The seek function of Rtsp is time-based, we call the SeekTime function in // RtspMediaResource. The SeekTime function finally send a seek command to @@ -48,7 +49,7 @@ void RtspOmxReader::Seek(int64_t aTime, int64_t aStartTime, // seek operation. The function will clear the |mVideoQueue| and |mAudioQueue| // that store the decoded data and also call the |DecodeToTarget| to pass // the seek time to OMX a/v decoders. - MediaOmxReader::Seek(aTime, aStartTime, aEndTime, aCurrentTime); + return MediaOmxReader::Seek(aTime, aStartTime, aEndTime, aCurrentTime); } void RtspOmxReader::SetIdle() { diff --git a/dom/media/omx/RtspOmxReader.h b/dom/media/omx/RtspOmxReader.h index 4ef4beabd95f..f2a530650ce2 100644 --- a/dom/media/omx/RtspOmxReader.h +++ b/dom/media/omx/RtspOmxReader.h @@ -46,8 +46,9 @@ public: } // Implement a time-based seek instead of byte-based.. - virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, - int64_t aCurrentTime) MOZ_FINAL MOZ_OVERRIDE; + virtual nsRefPtr + Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, + int64_t aCurrentTime) MOZ_FINAL MOZ_OVERRIDE; // Override GetBuffered() to do nothing for below reasons: // 1. Because the Rtsp stream is a/v separated. The buffered data in a/v diff --git a/dom/media/raw/RawReader.cpp b/dom/media/raw/RawReader.cpp index eb0add453926..3d59e4605de3 100644 --- a/dom/media/raw/RawReader.cpp +++ b/dom/media/raw/RawReader.cpp @@ -235,10 +235,15 @@ bool RawReader::DecodeVideoFrame(bool &aKeyframeSkip, return true; } -void RawReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) +nsRefPtr +RawReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { nsresult res = SeekInternal(aTime); - GetCallback()->OnSeekCompleted(res); + if (NS_FAILED(res)) { + return SeekPromise::CreateAndReject(res, __func__); + } else { + return SeekPromise::CreateAndResolve(true, __func__); + } } nsresult RawReader::SeekInternal(int64_t aTime) diff --git a/dom/media/raw/RawReader.h b/dom/media/raw/RawReader.h index 1396a3c548f2..935c48fee72e 100644 --- a/dom/media/raw/RawReader.h +++ b/dom/media/raw/RawReader.h @@ -39,7 +39,9 @@ public: virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags); - virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); + virtual nsRefPtr + Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) MOZ_OVERRIDE; + virtual nsresult GetBuffered(dom::TimeRanges* aBuffered); virtual bool IsMediaSeekable() MOZ_OVERRIDE; diff --git a/dom/media/wave/WaveReader.cpp b/dom/media/wave/WaveReader.cpp index 865eb305b920..65c00280fbcb 100644 --- a/dom/media/wave/WaveReader.cpp +++ b/dom/media/wave/WaveReader.cpp @@ -257,13 +257,14 @@ bool WaveReader::DecodeVideoFrame(bool &aKeyframeSkip, return false; } -void WaveReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) +nsRefPtr +WaveReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); LOG(PR_LOG_DEBUG, ("%p About to seek to %lld", mDecoder, aTarget)); + if (NS_FAILED(ResetDecode())) { - GetCallback()->OnSeekCompleted(NS_ERROR_FAILURE); - return; + return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); } double d = BytesToTime(GetDataLength()); NS_ASSERTION(d < INT64_MAX / USECS_PER_S, "Duration overflow"); @@ -273,7 +274,11 @@ void WaveReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int NS_ASSERTION(INT64_MAX - mWavePCMOffset > position, "Integer overflow during wave seek"); position += mWavePCMOffset; nsresult res = mDecoder->GetResource()->Seek(nsISeekableStream::NS_SEEK_SET, position); - GetCallback()->OnSeekCompleted(res); + if (NS_FAILED(res)) { + return SeekPromise::CreateAndReject(res, __func__); + } else { + return SeekPromise::CreateAndResolve(true, __func__); + } } static double RoundToUsecs(double aSeconds) { diff --git a/dom/media/wave/WaveReader.h b/dom/media/wave/WaveReader.h index 0fd36410c82f..037fc73df4c3 100644 --- a/dom/media/wave/WaveReader.h +++ b/dom/media/wave/WaveReader.h @@ -43,7 +43,9 @@ public: virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags); - virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); + virtual nsRefPtr + Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) MOZ_OVERRIDE; + virtual nsresult GetBuffered(dom::TimeRanges* aBuffered); // To seek in a buffered range, we just have to seek the stream. diff --git a/dom/media/webm/WebMReader.cpp b/dom/media/webm/WebMReader.cpp index 35bc9eb67d63..6b196760e99b 100644 --- a/dom/media/webm/WebMReader.cpp +++ b/dom/media/webm/WebMReader.cpp @@ -951,11 +951,16 @@ void WebMReader::PushVideoPacket(NesteggPacketHolder* aItem) mVideoPackets.PushFront(aItem); } -void WebMReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, +nsRefPtr +WebMReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { nsresult res = SeekInternal(aTarget, aStartTime); - GetCallback()->OnSeekCompleted(res); + if (NS_FAILED(res)) { + return SeekPromise::CreateAndReject(res, __func__); + } else { + return SeekPromise::CreateAndResolve(true, __func__); + } } nsresult WebMReader::SeekInternal(int64_t aTarget, int64_t aStartTime) diff --git a/dom/media/webm/WebMReader.h b/dom/media/webm/WebMReader.h index 94b4f5d42d1f..e636595f26d8 100644 --- a/dom/media/webm/WebMReader.h +++ b/dom/media/webm/WebMReader.h @@ -155,8 +155,9 @@ public: virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags); - virtual void Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, - int64_t aCurrentTime); + virtual nsRefPtr + Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) MOZ_OVERRIDE; + virtual nsresult GetBuffered(dom::TimeRanges* aBuffered); virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset); diff --git a/dom/media/wmf/WMFReader.cpp b/dom/media/wmf/WMFReader.cpp index fde1c4c5155e..be6c18af9a4c 100644 --- a/dom/media/wmf/WMFReader.cpp +++ b/dom/media/wmf/WMFReader.cpp @@ -888,14 +888,18 @@ WMFReader::DecodeVideoFrame(bool &aKeyframeSkip, return true; } -void +nsRefPtr WMFReader::Seek(int64_t aTargetUs, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { nsresult res = SeekInternal(aTargetUs); - GetCallback()->OnSeekCompleted(res); + if (NS_FAILED(res)) { + return SeekPromise::CreateAndReject(res, __func__); + } else { + return SeekPromise::CreateAndResolve(true, __func__); + } } nsresult diff --git a/dom/media/wmf/WMFReader.h b/dom/media/wmf/WMFReader.h index deb51e23c891..22e353877e87 100644 --- a/dom/media/wmf/WMFReader.h +++ b/dom/media/wmf/WMFReader.h @@ -43,10 +43,11 @@ public: nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE; - void Seek(int64_t aTime, - int64_t aStartTime, - int64_t aEndTime, - int64_t aCurrentTime) MOZ_OVERRIDE; + nsRefPtr + Seek(int64_t aTime, + int64_t aStartTime, + int64_t aEndTime, + int64_t aCurrentTime) MOZ_OVERRIDE; bool IsMediaSeekable() MOZ_OVERRIDE; From 646b842413481b9eae87513e8c50ff9850638d59 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Tue, 16 Dec 2014 23:08:42 +1300 Subject: [PATCH 084/130] Bug 1111413 - Part 2: Remove RequestSampleCallback. r=bholley --- dom/media/MediaDataDecodedListener.h | 47 --------------------- dom/media/MediaDecoderReader.cpp | 10 ----- dom/media/MediaDecoderReader.h | 24 ----------- dom/media/MediaDecoderStateMachine.cpp | 6 --- dom/media/MediaDecoderStateMachine.h | 3 -- dom/media/mediasource/MediaSourceReader.cpp | 8 ---- dom/media/moz.build | 1 - 7 files changed, 99 deletions(-) delete mode 100644 dom/media/MediaDataDecodedListener.h diff --git a/dom/media/MediaDataDecodedListener.h b/dom/media/MediaDataDecodedListener.h deleted file mode 100644 index e5bf1c190dcc..000000000000 --- a/dom/media/MediaDataDecodedListener.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MediaDataDecodedListener_h_ -#define MediaDataDecodedListener_h_ - -#include "mozilla/Monitor.h" -#include "MediaDecoderReader.h" - -namespace mozilla { - -class MediaDecoderStateMachine; -class MediaData; - -// A RequestSampleCallback implementation that forwards samples onto the -// MediaDecoderStateMachine via tasks that run on the supplied task queue. -template -class MediaDataDecodedListener : public RequestSampleCallback { -public: - MediaDataDecodedListener(Target* aTarget, - MediaTaskQueue* aTaskQueue) - : mMonitor("MediaDataDecodedListener") - , mTaskQueue(aTaskQueue) - , mTarget(aTarget) - { - MOZ_ASSERT(aTarget); - MOZ_ASSERT(aTaskQueue); - } - - void BreakCycles() { - MonitorAutoLock lock(mMonitor); - mTarget = nullptr; - mTaskQueue = nullptr; - } - -private: - Monitor mMonitor; - RefPtr mTaskQueue; - RefPtr mTarget; -}; - -} /* namespace mozilla */ - -#endif // MediaDataDecodedListener_h_ diff --git a/dom/media/MediaDecoderReader.cpp b/dom/media/MediaDecoderReader.cpp index f5c8cf605e3d..e5e4b09a6bf0 100644 --- a/dom/media/MediaDecoderReader.cpp +++ b/dom/media/MediaDecoderReader.cpp @@ -263,12 +263,6 @@ MediaDecoderReader::RequestAudioData() return p; } -void -MediaDecoderReader::SetCallback(RequestSampleCallback* aCallback) -{ - mSampleDecodedCallback = aCallback; -} - MediaTaskQueue* MediaDecoderReader::EnsureTaskQueue() { @@ -286,10 +280,6 @@ MediaDecoderReader::EnsureTaskQueue() void MediaDecoderReader::BreakCycles() { - if (mSampleDecodedCallback) { - mSampleDecodedCallback->BreakCycles(); - mSampleDecodedCallback = nullptr; - } mTaskQueue = nullptr; } diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h index b94a61f8f6e4..acb0f8328bab 100644 --- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -19,7 +19,6 @@ namespace dom { class TimeRanges; } -class RequestSampleCallback; class MediaDecoderReader; class SharedDecoderManager; @@ -72,7 +71,6 @@ public: // thread. virtual nsRefPtr Shutdown(); - virtual void SetCallback(RequestSampleCallback* aDecodedSampleCallback); MediaTaskQueue* EnsureTaskQueue(); virtual bool OnDecodeThread() @@ -242,11 +240,6 @@ protected: return false; } - RequestSampleCallback* GetCallback() { - MOZ_ASSERT(mSampleDecodedCallback); - return mSampleDecodedCallback; - } - // Queue of audio frames. This queue is threadsafe, and is accessed from // the audio, decoder, state machine, and main threads. MediaQueue mAudioQueue; @@ -285,8 +278,6 @@ protected: bool mHitAudioDecodeError; private: - nsRefPtr mSampleDecodedCallback; - // Promises used only for the base-class (sync->async adapter) implementation // of Request{Audio,Video}Data. MediaPromiseHolder mBaseAudioPromise; @@ -302,21 +293,6 @@ private: bool mShutdown; }; -// Interface that callers to MediaDecoderReader::Request{Audio,Video}Data() -// must implement to receive the requested samples asynchronously. -// This object is refcounted, and cycles must be broken by calling -// BreakCycles() during shutdown. -class RequestSampleCallback { -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RequestSampleCallback) - - // Called during shutdown to break any reference cycles. - virtual void BreakCycles() = 0; - -protected: - virtual ~RequestSampleCallback() {} -}; - } // namespace mozilla #endif diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 7447faed2fcb..5b64c57ea619 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -1098,12 +1098,6 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor) nsresult rv = mScheduler->Init(); NS_ENSURE_SUCCESS(rv, rv); - // Note: This creates a cycle, broken in shutdown. - mMediaDecodedListener = - new MediaDataDecodedListener(this, - DecodeTaskQueue()); - mReader->SetCallback(mMediaDecodedListener); - rv = mReader->Init(cloneReader); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index f4f424e54107..06a842d43298 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -89,7 +89,6 @@ hardware (via AudioStream). #include "MediaDecoderReader.h" #include "MediaDecoderOwner.h" #include "MediaMetadataManager.h" -#include "MediaDataDecodedListener.h" class nsITimer; @@ -445,8 +444,6 @@ protected: nsresult FinishDecodeFirstFrame(); - RefPtr> mMediaDecodedListener; - nsAutoPtr mMetadataTags; // True if our buffers of decoded audio are not full, and we should diff --git a/dom/media/mediasource/MediaSourceReader.cpp b/dom/media/mediasource/MediaSourceReader.cpp index 85c4b0f4e14a..75cdcc2fdfe5 100644 --- a/dom/media/mediasource/MediaSourceReader.cpp +++ b/dom/media/mediasource/MediaSourceReader.cpp @@ -8,7 +8,6 @@ #include "prlog.h" #include "mozilla/dom/TimeRanges.h" #include "DecoderTraits.h" -#include "MediaDataDecodedListener.h" #include "MediaDecoderOwner.h" #include "MediaSourceDecoder.h" #include "MediaSourceUtils.h" @@ -455,13 +454,6 @@ MediaSourceReader::CreateSubDecoder(const nsACString& aType) // borrowing. reader->SetBorrowedTaskQueue(GetTaskQueue()); - // Set a callback on the subreader that forwards calls to this reader. - // This reader will then forward them onto the state machine via this - // reader's callback. - RefPtr> callback = - new MediaDataDecodedListener(this, reader->GetTaskQueue()); - reader->SetCallback(callback); - #ifdef MOZ_FMP4 reader->SetSharedDecoderManager(mSharedDecoderManager); #endif diff --git a/dom/media/moz.build b/dom/media/moz.build index 6b48e49dbfb9..1320a3e67d73 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -98,7 +98,6 @@ EXPORTS += [ 'Latency.h', 'MediaCache.h', 'MediaData.h', - 'MediaDataDecodedListener.h', 'MediaDecoder.h', 'MediaDecoderOwner.h', 'MediaDecoderReader.h', From 38354269a6dd11ec859341cbe50922e7e31eca57 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Wed, 17 Dec 2014 11:31:17 +1300 Subject: [PATCH 085/130] Bug 1111966 - Fix reporting of parsed and decoded frames for MP4Reader. r=cpearce --- dom/media/fmp4/MP4Reader.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/dom/media/fmp4/MP4Reader.cpp b/dom/media/fmp4/MP4Reader.cpp index c5f4eb7a5094..25faeac8970d 100644 --- a/dom/media/fmp4/MP4Reader.cpp +++ b/dom/media/fmp4/MP4Reader.cpp @@ -470,19 +470,16 @@ MP4Reader::RequestVideoData(bool aSkipToNextKeyframe, MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn()); VLOG("RequestVideoData skip=%d time=%lld", aSkipToNextKeyframe, aTimeThreshold); - // Record number of frames decoded and parsed. Automatically update the - // stats counters using the AutoNotifyDecoded stack-based class. - uint32_t parsed = 0, decoded = 0; - AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded); - MOZ_ASSERT(HasVideo() && mPlatform && mVideo.mDecoder); bool eos = false; if (aSkipToNextKeyframe) { + uint32_t parsed = 0; eos = !SkipVideoDemuxToNextKeyFrame(aTimeThreshold, parsed); if (!eos && NS_FAILED(mVideo.mDecoder->Flush())) { NS_WARNING("Failed to skip/flush video when skipping-to-next-keyframe."); } + mDecoder->NotifyDecodedFrames(parsed, 0); } MonitorAutoLock lock(mVideo.mMonitor); @@ -493,12 +490,6 @@ MP4Reader::RequestVideoData(bool aSkipToNextKeyframe, ScheduleUpdate(kVideo); } - // Report the number of "decoded" frames as the difference in the - // mNumSamplesOutput field since the last time we were called. - uint64_t delta = mVideo.mNumSamplesOutput - mLastReportedNumDecodedFrames; - decoded = static_cast(delta); - mLastReportedNumDecodedFrames = mVideo.mNumSamplesOutput; - return p; } @@ -551,6 +542,11 @@ MP4Reader::Update(TrackType aTrack) { MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn()); + // Record number of frames decoded and parsed. Automatically update the + // stats counters using the AutoNotifyDecoded stack-based class. + uint32_t parsed = 0, decoded = 0; + AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded); + bool needInput = false; bool needOutput = false; auto& decoder = GetDecoderData(aTrack); @@ -562,6 +558,11 @@ MP4Reader::Update(TrackType aTrack) decoder.mInputExhausted = false; decoder.mNumSamplesInput++; } + if (aTrack == kVideo) { + uint64_t delta = decoder.mNumSamplesOutput - mLastReportedNumDecodedFrames; + decoded = static_cast(delta); + mLastReportedNumDecodedFrames = decoder.mNumSamplesOutput; + } if (decoder.HasPromise()) { needOutput = true; if (!decoder.mOutput.IsEmpty()) { @@ -585,6 +586,9 @@ MP4Reader::Update(TrackType aTrack) MP4Sample* sample = PopSample(aTrack); if (sample) { decoder.mDecoder->Input(sample); + if (aTrack == kVideo) { + parsed++; + } } else { { MonitorAutoLock lock(decoder.mMonitor); From 3837d59146cebf7c7161ca4ee68abec5af260b0a Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 16 Dec 2014 23:02:37 +0000 Subject: [PATCH 086/130] Bug 1111879 - Avoid copying an nsFont when we don't need to modify it locally. r=dbaron --- layout/base/nsLayoutUtils.cpp | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 6ec0b9fb99dc..f56ab2c74e41 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -3755,19 +3755,29 @@ nsLayoutUtils::GetFontMetricsForStyleContext(nsStyleContext* aStyleContext, gfxUserFontSet* fs = pc->GetUserFontSet(); gfxTextPerfMetrics* tp = pc->GetTextPerfMetrics(); - nsFont font = aStyleContext->StyleFont()->mFont; - // We need to not run font.size through floats when it's large since - // doing so would be lossy. Fortunately, in such cases, aInflation is - // guaranteed to be 1.0f. - if (aInflation != 1.0f) { - font.size = NSToCoordRound(font.size * aInflation); - } WritingMode wm(aStyleContext); - return pc->DeviceContext()->GetMetricsFor( - font, aStyleContext->StyleFont()->mLanguage, - wm.IsVertical() && !wm.IsSideways() - ? gfxFont::eVertical : gfxFont::eHorizontal, - fs, tp, *aFontMetrics); + gfxFont::Orientation orientation = + wm.IsVertical() && !wm.IsSideways() ? gfxFont::eVertical + : gfxFont::eHorizontal; + + const nsStyleFont* styleFont = aStyleContext->StyleFont(); + + // When aInflation is 1.0, avoid making a local copy of the nsFont. + // This also avoids running font.size through floats when it is large, + // which would be lossy. Fortunately, in such cases, aInflation is + // guaranteed to be 1.0f. + if (aInflation == 1.0f) { + return pc->DeviceContext()->GetMetricsFor(styleFont->mFont, + styleFont->mLanguage, + orientation, fs, tp, + *aFontMetrics); + } + + nsFont font = styleFont->mFont; + font.size = NSToCoordRound(font.size * aInflation); + return pc->DeviceContext()->GetMetricsFor(font, styleFont->mLanguage, + orientation, fs, tp, + *aFontMetrics); } nsIFrame* From d4bff69580bbc986fbd07ec8997db85ceb94f78a Mon Sep 17 00:00:00 2001 From: Ben Turner Date: Tue, 16 Dec 2014 15:19:19 -0800 Subject: [PATCH 087/130] Bug 1104853 - Add a null check to an async IDB open operation, r=khuey. --- dom/indexedDB/ActorsParent.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index 8e8924d64407..02e233e5764d 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -11920,7 +11920,8 @@ OpenDatabaseOp::SendResults() nsRefPtr kungFuDeathGrip; DatabaseActorInfo* info; - if (gLiveDatabaseHashtable->Get(mDatabaseId, &info) && + if (gLiveDatabaseHashtable && + gLiveDatabaseHashtable->Get(mDatabaseId, &info) && info->mWaitingFactoryOp) { MOZ_ASSERT(info->mWaitingFactoryOp == this); kungFuDeathGrip = From 56b818b46f18a1025c97148a7f604b351b385221 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Tue, 16 Dec 2014 15:24:45 -0800 Subject: [PATCH 088/130] Backed out 2 changesets (bug 1103258) for b2g reftest failures Backed out changeset 64e9d08ae14b (bug 1103258) Backed out changeset bca5954a31d2 (bug 1103258) --- .../composite/ContainerLayerComposite.cpp | 6 +-- layout/reftests/bugs/1103258-1-ref.html | 13 ------- layout/reftests/bugs/1103258-1.html | 37 ------------------- layout/reftests/bugs/reftest.list | 1 - 4 files changed, 1 insertion(+), 56 deletions(-) delete mode 100644 layout/reftests/bugs/1103258-1-ref.html delete mode 100644 layout/reftests/bugs/1103258-1.html diff --git a/gfx/layers/composite/ContainerLayerComposite.cpp b/gfx/layers/composite/ContainerLayerComposite.cpp index d707b6de8f4f..536fe8882c83 100644 --- a/gfx/layers/composite/ContainerLayerComposite.cpp +++ b/gfx/layers/composite/ContainerLayerComposite.cpp @@ -258,11 +258,6 @@ ContainerPrepare(ContainerT* aContainer, return; } - gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer); - if (surfaceRect.IsEmpty()) { - return; - } - /** * Determine which layers to draw. */ @@ -305,6 +300,7 @@ ContainerPrepare(ContainerT* aContainer, RefPtr surface = nullptr; RefPtr& lastSurf = aContainer->mLastIntermediateSurface; + gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer); if (lastSurf && !aContainer->mChildrenChanged && lastSurf->GetRect().IsEqualEdges(surfaceRect)) { surface = lastSurf; } diff --git a/layout/reftests/bugs/1103258-1-ref.html b/layout/reftests/bugs/1103258-1-ref.html deleted file mode 100644 index 96d79e14fa56..000000000000 --- a/layout/reftests/bugs/1103258-1-ref.html +++ /dev/null @@ -1,13 +0,0 @@ - -
-
diff --git a/layout/reftests/bugs/1103258-1.html b/layout/reftests/bugs/1103258-1.html deleted file mode 100644 index 9f56c8f49ad9..000000000000 --- a/layout/reftests/bugs/1103258-1.html +++ /dev/null @@ -1,37 +0,0 @@ - -
-
- sadf -
-
- sdf -
-
-
-
diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index cb2e242ec9b6..884758254948 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1845,5 +1845,4 @@ test-pref(dom.webcomponents.enabled,true) == 1066554-1.html 1066554-1-ref.html test-pref(layout.testing.overlay-scrollbars.always-visible,false) == 1081072-1.html 1081072-1-ref.html fuzzy-if(winWidget&&!layersGPUAccelerated,1,31) == 1081185-1.html 1081185-1-ref.html == 1097437-1.html 1097437-1-ref.html -== 1103258-1.html 1103258-1-ref.html # assertion crash test with layers culling test == 1105137-1.html 1105137-1-ref.html From 73077d1cd2520cee733f92e309acb5dd43ef83f0 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Wed, 17 Dec 2014 00:28:37 +0100 Subject: [PATCH 089/130] Bug 783829 - Factor out NativeIteratorNext. r=efaust --- js/src/jsiter.cpp | 77 +++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 62e212565549..8ca0b5e947fb 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -849,6 +849,38 @@ js::IteratorConstructor(JSContext *cx, unsigned argc, Value *vp) return true; } +MOZ_ALWAYS_INLINE bool +NativeIteratorNext(JSContext *cx, NativeIterator *ni, MutableHandleValue rval, bool *done) +{ + *done = false; + + if (ni->props_cursor >= ni->props_end) { + *done = true; + return true; + } + + if (MOZ_LIKELY(ni->isKeyIter())) { + rval.setString(*ni->current()); + ni->incCursor(); + return true; + } + + // Non-standard Iterator for "for each" + RootedId id(cx); + RootedValue current(cx, StringValue(*ni->current())); + if (!ValueToId(cx, current, &id)) + return false; + ni->incCursor(); + RootedObject obj(cx, ni->obj); + if (!JSObject::getGeneric(cx, obj, obj, id, rval)) + return false; + + // JS 1.7 only: for each (let [k, v] in obj) + if (ni->flags & JSITER_KEYVALUE) + return NewKeyValuePair(cx, id, rval, rval); + return true; +} + MOZ_ALWAYS_INLINE bool IsIterator(HandleValue v) { @@ -862,14 +894,19 @@ iterator_next_impl(JSContext *cx, CallArgs args) RootedObject thisObj(cx, &args.thisv().toObject()); - if (!IteratorMore(cx, thisObj, args.rval())) - return false; + NativeIterator *ni = thisObj.as()->getNativeIterator(); + RootedValue value(cx); + bool done; + if (!NativeIteratorNext(cx, ni, &value, &done)) + return false; - if (args.rval().isMagic(JS_NO_ITER_VALUE)) { + // Use old iterator protocol for compatibility reasons. + if (done) { ThrowStopIteration(cx); return false; } + args.rval().set(value); return true; } @@ -1226,40 +1263,20 @@ bool js::IteratorMore(JSContext *cx, HandleObject iterobj, MutableHandleValue rval) { /* Fast path for native iterators */ - NativeIterator *ni = nullptr; if (iterobj->is()) { - /* Key iterators are handled by fast-paths. */ - ni = iterobj->as().getNativeIterator(); - if (ni->props_cursor >= ni->props_end) { + NativeIterator *ni = iterobj->as().getNativeIterator(); + bool done; + if (!NativeIteratorNext(cx, ni, rval, &done)) + return false; + + if (done) rval.setMagic(JS_NO_ITER_VALUE); - return true; - } - if (ni->isKeyIter()) { - rval.setString(*ni->current()); - ni->incCursor(); - return true; - } + return true; } /* We're reentering below and can call anything. */ JS_CHECK_RECURSION(cx, return false); - /* Fetch and cache the next value from the iterator. */ - if (ni) { - MOZ_ASSERT(!ni->isKeyIter()); - RootedId id(cx); - RootedValue current(cx, StringValue(*ni->current())); - if (!ValueToId(cx, current, &id)) - return false; - ni->incCursor(); - RootedObject obj(cx, ni->obj); - if (!JSObject::getGeneric(cx, obj, obj, id, rval)) - return false; - if ((ni->flags & JSITER_KEYVALUE) && !NewKeyValuePair(cx, id, rval, rval)) - return false; - return true; - } - /* Call the iterator object's .next method. */ if (!JSObject::getProperty(cx, iterobj, iterobj, cx->names().next, rval)) return false; From f834688bbc32135b674d7fe846d264c0bb6f0311 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Wed, 17 Dec 2014 00:28:38 +0100 Subject: [PATCH 090/130] Bug 783829 - Change from Proxy iterate to enumerate. r=efaust,bholley --- dom/base/nsGlobalWindow.cpp | 15 +++-- dom/bindings/DOMJSProxyHandler.cpp | 7 +++ dom/bindings/DOMJSProxyHandler.h | 2 + js/ipc/WrapperOwner.cpp | 9 +++ js/ipc/WrapperOwner.h | 1 - js/src/jit-test/tests/basic/testBug771242.js | 14 ----- js/src/jsiter.cpp | 56 +++++++++++++++--- js/src/jsobj.h | 7 ++- js/src/jsobjinlines.h | 10 +++- js/src/jsproxy.h | 12 ++-- js/src/jswrapper.h | 4 +- js/src/proxy/BaseProxyHandler.cpp | 11 +--- js/src/proxy/CrossCompartmentWrapper.cpp | 6 +- js/src/proxy/DeadObjectProxy.cpp | 7 +++ js/src/proxy/DeadObjectProxy.h | 1 + js/src/proxy/DirectProxyHandler.cpp | 19 +++--- js/src/proxy/Proxy.cpp | 13 ++-- js/src/proxy/Proxy.h | 2 +- js/src/proxy/ScriptedDirectProxyHandler.cpp | 59 +++++++++++++------ js/src/proxy/ScriptedDirectProxyHandler.h | 3 +- js/src/proxy/ScriptedIndirectProxyHandler.cpp | 41 ++++++------- js/src/proxy/ScriptedIndirectProxyHandler.h | 4 +- js/src/vm/ScopeObject.cpp | 5 ++ js/xpconnect/src/Sandbox.cpp | 6 +- js/xpconnect/wrappers/FilteringWrapper.cpp | 12 ++-- js/xpconnect/wrappers/FilteringWrapper.h | 4 +- js/xpconnect/wrappers/WaiveXrayWrapper.cpp | 8 +-- js/xpconnect/wrappers/WaiveXrayWrapper.h | 4 +- js/xpconnect/wrappers/XrayWrapper.cpp | 6 +- js/xpconnect/wrappers/XrayWrapper.h | 8 +-- 30 files changed, 218 insertions(+), 138 deletions(-) delete mode 100644 js/src/jit-test/tests/basic/testBug771242.js diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 93a166ae3fad..67f51df703fd 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -621,6 +621,8 @@ public: virtual bool delete_(JSContext *cx, JS::Handle proxy, JS::Handle id, bool *bp) const MOZ_OVERRIDE; + virtual bool enumerate(JSContext *cx, JS::Handle proxy, + JS::MutableHandle vp) const MOZ_OVERRIDE; virtual bool preventExtensions(JSContext *cx, JS::Handle proxy, bool *succeeded) const MOZ_OVERRIDE; @@ -650,9 +652,6 @@ public: JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle proxy, JS::AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool iterate(JSContext *cx, JS::Handle proxy, - unsigned flags, - JS::MutableHandle objp) const MOZ_OVERRIDE; virtual const char *className(JSContext *cx, JS::Handle wrapper) const MOZ_OVERRIDE; @@ -944,12 +943,12 @@ nsOuterWindowProxy::getEnumerablePropertyKeys(JSContext *cx, JS::Handle proxy, - unsigned flags, JS::MutableHandle objp) const +nsOuterWindowProxy::enumerate(JSContext *cx, JS::Handle proxy, + JS::MutableHandle objp) const { - // BaseProxyHandler::iterate seems to do what we want here: fall - // back on the property names returned from keys() and enumerate(). - return js::BaseProxyHandler::iterate(cx, proxy, flags, objp); + // BaseProxyHandler::enumerate seems to do what we want here: fall + // back on the property names returned from getEnumerablePropertyKeys() + return js::BaseProxyHandler::enumerate(cx, proxy, objp); } bool diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index 4c424c445615..95233a93218b 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -309,6 +309,13 @@ BaseDOMProxyHandler::getEnumerablePropertyKeys(JSContext* cx, (!proto || js::GetPropertyKeys(cx, proto, 0, &props)); } +bool +BaseDOMProxyHandler::enumerate(JSContext *cx, JS::Handle proxy, + JS::MutableHandle objp) const +{ + return BaseProxyHandler::enumerate(cx, proxy, objp); +} + bool DOMProxyHandler::has(JSContext* cx, JS::Handle proxy, JS::Handle id, bool* bp) const { diff --git a/dom/bindings/DOMJSProxyHandler.h b/dom/bindings/DOMJSProxyHandler.h index 4709ab18f73e..839537e901b9 100644 --- a/dom/bindings/DOMJSProxyHandler.h +++ b/dom/bindings/DOMJSProxyHandler.h @@ -62,6 +62,8 @@ public: JS::Handle id, JS::MutableHandle desc) const MOZ_OVERRIDE; + virtual bool enumerate(JSContext *cx, JS::Handle proxy, + JS::MutableHandle objp) const MOZ_OVERRIDE; // We override getOwnEnumerablePropertyKeys() and implement it directly // instead of using the default implementation, which would call diff --git a/js/ipc/WrapperOwner.cpp b/js/ipc/WrapperOwner.cpp index 42918eba549b..bc9ed632b3f0 100644 --- a/js/ipc/WrapperOwner.cpp +++ b/js/ipc/WrapperOwner.cpp @@ -94,6 +94,7 @@ class CPOWProxyHandler : public BaseProxyHandler virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE; virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE; virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; @@ -267,6 +268,14 @@ WrapperOwner::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) return ok(cx, status); } +bool +CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const +{ + // Using a CPOW for the Iterator would slow down for .. in performance, instead + // call the base hook, that will use our implementation of getEnumerablePropertyKeys. + return BaseProxyHandler::enumerate(cx, proxy, objp); +} + bool CPOWProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const { diff --git a/js/ipc/WrapperOwner.h b/js/ipc/WrapperOwner.h index 18f8b9939bae..1a26fa36db86 100644 --- a/js/ipc/WrapperOwner.h +++ b/js/ipc/WrapperOwner.h @@ -57,7 +57,6 @@ class WrapperOwner : public virtual JavaScriptShared JS::AutoIdVector &props); bool getEnumerablePropertyKeys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props); - // We use "iterate" provided by the base class here. bool hasInstance(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool *bp); bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue); const char* className(JSContext *cx, JS::HandleObject proxy); diff --git a/js/src/jit-test/tests/basic/testBug771242.js b/js/src/jit-test/tests/basic/testBug771242.js deleted file mode 100644 index deb7266bcb20..000000000000 --- a/js/src/jit-test/tests/basic/testBug771242.js +++ /dev/null @@ -1,14 +0,0 @@ -a = function() { - b = newGlobal() -}; -c = [0, 0] -c.sort(a) -function d() { - yield arguments[4] -} -b.iterate = d -f = Proxy.create(b) -e = Iterator(f, true) -for (p in f) { - e.next() -} diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 8ca0b5e947fb..aeeee349d89c 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -669,6 +669,16 @@ js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleOb return true; } + // We should only call the enumerate trap for "for-in". + // Or when we call GetIterator from the Proxy [[Enumerate]] hook. + // In the future also for Reflect.enumerate. + // JSITER_ENUMERATE is just an optimization and the same + // as flags == 0 otherwise. + if (flags == 0 || flags == JSITER_ENUMERATE) { + if (obj->is()) + return Proxy::enumerate(cx, obj, objp); + } + Vector shapes(cx); uint32_t key = 0; if (flags == JSITER_ENUMERATE) { @@ -747,9 +757,6 @@ js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleOb } miss: - if (obj->is()) - return Proxy::iterate(cx, obj, flags, objp); - if (!GetCustomIterator(cx, obj, flags, objp)) return false; if (objp) @@ -1262,7 +1269,7 @@ js::SuppressDeletedElements(JSContext *cx, HandleObject obj, uint32_t begin, uin bool js::IteratorMore(JSContext *cx, HandleObject iterobj, MutableHandleValue rval) { - /* Fast path for native iterators */ + // Fast path for native iterators. if (iterobj->is()) { NativeIterator *ni = iterobj->as().getNativeIterator(); bool done; @@ -1274,14 +1281,15 @@ js::IteratorMore(JSContext *cx, HandleObject iterobj, MutableHandleValue rval) return true; } - /* We're reentering below and can call anything. */ + // We're reentering below and can call anything. JS_CHECK_RECURSION(cx, return false); - /* Call the iterator object's .next method. */ + // Call the iterator object's .next method. if (!JSObject::getProperty(cx, iterobj, iterobj, cx->names().next, rval)) return false; + // We try to support the old and new iterator protocol at the same time! if (!Invoke(cx, ObjectValue(*iterobj), rval, 0, nullptr, rval)) { - /* Check for StopIteration. */ + // We still check for StopIterator if (!cx->isExceptionPending()) return false; RootedValue exception(cx); @@ -1295,7 +1303,39 @@ js::IteratorMore(JSContext *cx, HandleObject iterobj, MutableHandleValue rval) return true; } - return true; + if (!rval.isObject()) { + // Old style generators might return primitive values + return true; + } + + // If the object has both the done and value property, we assume + // it's using the new style protocol. Otherwise just return the object. + RootedObject result(cx, &rval.toObject()); + bool found = false; + if (!JSObject::hasProperty(cx, result, cx->names().done, &found)) + return false; + if (!found) + return true; + if (!JSObject::hasProperty(cx, result, cx->names().value, &found)) + return false; + if (!found) + return true; + + // At this point we hopefully have a new style iterator result + + // 7.4.4 IteratorComplete + // Get iterResult.done + if (!JSObject::getProperty(cx, result, result, cx->names().done, rval)) + return false; + + bool done = ToBoolean(rval); + if (done) { + rval.setMagic(JS_NO_ITER_VALUE); + return true; + } + + // 7.4.5 IteratorValue + return JSObject::getProperty(cx, result, result, cx->names().value, rval); } static bool diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 731166ad647f..4036631ac47a 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -566,8 +566,11 @@ class JSObject : public js::gc::Cell MOZ_ALWAYS_INLINE void finalize(js::FreeOp *fop); - static inline bool hasProperty(JSContext *cx, js::HandleObject obj, - js::HandleId id, bool *foundp); + static inline bool hasProperty(JSContext *cx, js::HandleObject obj, js::HandleId id, + bool *foundp); + + static inline bool hasProperty(JSContext *cx, js::HandleObject obj, js::PropertyName *name, + bool *foundp); public: static bool reportReadOnly(js::ThreadSafeContext *cx, jsid id, unsigned report = JSREPORT_ERROR); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index a5f863d201e7..fb0cf6a1db2b 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -362,8 +362,7 @@ JSObject::setInitialElementsMaybeNonNative(js::HeapSlot *elements) } /* static */ inline bool -JSObject::hasProperty(JSContext *cx, js::HandleObject obj, - js::HandleId id, bool *foundp) +JSObject::hasProperty(JSContext *cx, js::HandleObject obj, js::HandleId id, bool *foundp) { JS::RootedObject pobj(cx); js::RootedShape prop(cx); @@ -375,6 +374,13 @@ JSObject::hasProperty(JSContext *cx, js::HandleObject obj, return true; } +/* static */ inline bool +JSObject::hasProperty(JSContext *cx, js::HandleObject obj, js::PropertyName *name, bool *foundp) +{ + JS::RootedId id(cx, js::NameToId(name)); + return hasProperty(cx, obj, id, foundp); +} + /* static */ inline bool JSObject::getElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, uint32_t index, js::MutableHandleValue vp) diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index a0526e17b03f..b9adc8070b1c 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -255,6 +255,12 @@ class JS_FRIEND_API(BaseProxyHandler) virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const = 0; virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const = 0; + /* + * Because [[Enumerate]] is one of the standard traps it should be overridden. + * However for convenience BaseProxyHandler includes a pure virtual implementation, + * that turns the properties returned by getEnumerablePropertyKeys into an Iterator object. + */ + virtual bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const = 0; /* * These methods are standard, but the engine does not normally call them. @@ -307,8 +313,6 @@ class JS_FRIEND_API(BaseProxyHandler) AutoIdVector &props) const; virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const = 0; - virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, - MutableHandleObject objp) const; virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const; virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp) const; virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) const; @@ -368,6 +372,8 @@ class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool enumerate(JSContext *cx, HandleObject proxy, + MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const MOZ_OVERRIDE; virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, @@ -394,8 +400,6 @@ class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler AutoIdVector &props) const MOZ_OVERRIDE; virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, - MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const MOZ_OVERRIDE; virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 217e3f0db591..94c179846118 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -121,10 +121,12 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper virtual bool ownPropertyKeys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool enumerate(JSContext *cx, HandleObject wrapper, MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const MOZ_OVERRIDE; virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp) const MOZ_OVERRIDE; + virtual bool setImmutablePrototype(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE; virtual bool preventExtensions(JSContext *cx, HandleObject wrapper, bool *succeeded) const MOZ_OVERRIDE; @@ -145,8 +147,6 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper AutoIdVector &props) const MOZ_OVERRIDE; virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool iterate(JSContext *cx, HandleObject wrapper, unsigned flags, - MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const MOZ_OVERRIDE; virtual bool hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v, diff --git a/js/src/proxy/BaseProxyHandler.cpp b/js/src/proxy/BaseProxyHandler.cpp index 9e36555522e3..b64d635a8a62 100644 --- a/js/src/proxy/BaseProxyHandler.cpp +++ b/js/src/proxy/BaseProxyHandler.cpp @@ -230,19 +230,14 @@ BaseProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy } bool -BaseProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags, - MutableHandleObject objp) const +BaseProxyHandler::enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const { assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE); AutoIdVector props(cx); - if ((flags & JSITER_OWNONLY) - ? !getOwnEnumerablePropertyKeys(cx, proxy, props) - : !getEnumerablePropertyKeys(cx, proxy, props)) { + if (!getEnumerablePropertyKeys(cx, proxy, props)) return false; - } - - return EnumeratedIdVectorToIterator(cx, proxy, flags, props, objp); + return EnumeratedIdVectorToIterator(cx, proxy, 0, props, objp); } bool diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp index 5f4a93c5442d..b27aa80ea3a6 100644 --- a/js/src/proxy/CrossCompartmentWrapper.cpp +++ b/js/src/proxy/CrossCompartmentWrapper.cpp @@ -262,12 +262,12 @@ Reify(JSContext *cx, JSCompartment *origin, MutableHandleObject objp) } bool -CrossCompartmentWrapper::iterate(JSContext *cx, HandleObject wrapper, unsigned flags, - MutableHandleObject objp) const +CrossCompartmentWrapper::enumerate(JSContext *cx, HandleObject wrapper, + MutableHandleObject objp) const { { AutoCompartment call(cx, wrappedObject(wrapper)); - if (!Wrapper::iterate(cx, wrapper, flags, objp)) + if (!Wrapper::enumerate(cx, wrapper, objp)) return false; } diff --git a/js/src/proxy/DeadObjectProxy.cpp b/js/src/proxy/DeadObjectProxy.cpp index 3e98f938de9a..7142e442686d 100644 --- a/js/src/proxy/DeadObjectProxy.cpp +++ b/js/src/proxy/DeadObjectProxy.cpp @@ -53,6 +53,13 @@ DeadObjectProxy::delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool return false; } +bool +DeadObjectProxy::enumerate(JSContext *cx, HandleObject wrapper, MutableHandleObject objp) const +{ + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT); + return false; +} + bool DeadObjectProxy::getEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const diff --git a/js/src/proxy/DeadObjectProxy.h b/js/src/proxy/DeadObjectProxy.h index 2eeaf60937f7..342daa6ea464 100644 --- a/js/src/proxy/DeadObjectProxy.h +++ b/js/src/proxy/DeadObjectProxy.h @@ -26,6 +26,7 @@ class DeadObjectProxy : public BaseProxyHandler virtual bool ownPropertyKeys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool enumerate(JSContext *cx, HandleObject wrapper, MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const MOZ_OVERRIDE; virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE; diff --git a/js/src/proxy/DirectProxyHandler.cpp b/js/src/proxy/DirectProxyHandler.cpp index a5fd0bbcba0f..653f6f4a5860 100644 --- a/js/src/proxy/DirectProxyHandler.cpp +++ b/js/src/proxy/DirectProxyHandler.cpp @@ -62,6 +62,15 @@ DirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool return JSObject::deleteGeneric(cx, target, id, bp); } +bool +DirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const +{ + assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE); + MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype. + RootedObject target(cx, proxy->as().target()); + return GetIterator(cx, target, 0, objp); +} + bool DirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) const { @@ -243,16 +252,6 @@ DirectProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, return GetPropertyKeys(cx, target, 0, &props); } -bool -DirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags, - MutableHandleObject objp) const -{ - assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE); - MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype. - RootedObject target(cx, proxy->as().target()); - return GetIterator(cx, target, flags, objp); -} - bool DirectProxyHandler::isCallable(JSObject *obj) const { diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index da2ec3d71f42..718b6e781b33 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -366,7 +366,7 @@ Proxy::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector } bool -Proxy::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleObject objp) +Proxy::enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) { JS_CHECK_RECURSION(cx, return false); const BaseProxyHandler *handler = proxy->as().handler(); @@ -378,18 +378,15 @@ Proxy::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleO // to hand a valid (empty) iterator object to the caller. if (!policy.allowed()) { return policy.returnValue() && - NewEmptyPropertyIterator(cx, flags, objp); + NewEmptyPropertyIterator(cx, 0, objp); } - return handler->iterate(cx, proxy, flags, objp); + return handler->enumerate(cx, proxy, objp); } AutoIdVector props(cx); // The other Proxy::foo methods do the prototype-aware work for us here. - if ((flags & JSITER_OWNONLY) - ? !Proxy::getOwnEnumerablePropertyKeys(cx, proxy, props) - : !Proxy::getEnumerablePropertyKeys(cx, proxy, props)) { + if (!Proxy::getEnumerablePropertyKeys(cx, proxy, props)) return false; - } - return EnumeratedIdVectorToIterator(cx, proxy, flags, props, objp); + return EnumeratedIdVectorToIterator(cx, proxy, 0, props, objp); } bool diff --git a/js/src/proxy/Proxy.h b/js/src/proxy/Proxy.h index 889303e2d69f..0f11ae3af9bf 100644 --- a/js/src/proxy/Proxy.h +++ b/js/src/proxy/Proxy.h @@ -34,6 +34,7 @@ class Proxy MutableHandle desc); static bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props); static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); + static bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp); static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible); static bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded); static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop); @@ -56,7 +57,6 @@ class Proxy static bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props); static bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props); - static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleObject objp); static bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args); static bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp); static bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx); diff --git a/js/src/proxy/ScriptedDirectProxyHandler.cpp b/js/src/proxy/ScriptedDirectProxyHandler.cpp index 00bb9097dacd..5d1ccd507748 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp @@ -749,9 +749,10 @@ ScriptedDirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId return true; } -// ES6 (22 May, 2014) 9.5.11 Proxy.[[Enumerate]] +// ES6 (14 October, 2014) 9.5.11 Proxy.[[Enumerate]] bool -ScriptedDirectProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const +ScriptedDirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy, + MutableHandleObject objp) const { // step 1 RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); @@ -762,19 +763,20 @@ ScriptedDirectProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObjec return false; } - // step 3 + // step 3: unnecessary assert + // step 4 RootedObject target(cx, proxy->as().target()); - // step 4-5 + // step 5-6 RootedValue trap(cx); if (!JSObject::getProperty(cx, handler, handler, cx->names().enumerate, &trap)) return false; - // step 6 + // step 7 if (trap.isUndefined()) - return DirectProxyHandler::getEnumerablePropertyKeys(cx, proxy, props); + return DirectProxyHandler::enumerate(cx, proxy, objp); - // step 7-8 + // step 8-9 Value argv[] = { ObjectOrNullValue(target) }; @@ -782,7 +784,7 @@ ScriptedDirectProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObjec if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult)) return false; - // step 9 + // step 10 if (trapResult.isPrimitive()) { JSAutoByteString bytes; if (!AtomToPrintableString(cx, cx->names().enumerate, &bytes)) @@ -793,10 +795,36 @@ ScriptedDirectProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObjec return false; } - // step 10 - // FIXME: the trap should return an iterator object, see bug 783826. Since this isn't very - // useful for us internally, we convery to an id vector. - return ArrayToIdVector(cx, proxy, target, trapResult, props, 0, cx->names().enumerate); + // step 11 + objp.set(&trapResult.toObject()); + return true; +} + +// Non-standard, try to convert iterator result to ids +bool +ScriptedDirectProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const +{ + RootedObject iterator(cx); + if (!enumerate(cx, proxy, &iterator)) + return false; + + do { + RootedValue rval(cx); + if (!IteratorMore(cx, iterator, &rval)) + return false; + + if (rval.isMagic(JS_NO_ITER_VALUE)) + break; + + RootedId id(cx); + if (!ValueToId(cx, rval, &id)) + return false; + + if (!props.append(id)) + return false; + } while (true); + + return true; } // ES6 (22 May, 2014) 9.5.7 Proxy.[[HasProperty]](P) @@ -1008,13 +1036,6 @@ ScriptedDirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject return true; } -bool -ScriptedDirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags, - MutableHandleObject objp) const -{ - // FIXME: Provide a proper implementation for this trap, see bug 787004 - return DirectProxyHandler::iterate(cx, proxy, flags, objp); -} // ES6 (22 May, 2014) 9.5.13 Proxy.[[Call]] bool diff --git a/js/src/proxy/ScriptedDirectProxyHandler.h b/js/src/proxy/ScriptedDirectProxyHandler.h index d6121740aa44..1cdff97cdf08 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.h +++ b/js/src/proxy/ScriptedDirectProxyHandler.h @@ -26,6 +26,7 @@ class ScriptedDirectProxyHandler : public DirectProxyHandler { virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const MOZ_OVERRIDE; /* These two are standard internal methods but aren't implemented to spec yet. */ virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, @@ -64,8 +65,6 @@ class ScriptedDirectProxyHandler : public DirectProxyHandler { } virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, - MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE; virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE { diff --git a/js/src/proxy/ScriptedIndirectProxyHandler.cpp b/js/src/proxy/ScriptedIndirectProxyHandler.cpp index ccb98479ded7..fa206f8848b0 100644 --- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp @@ -226,6 +226,27 @@ ScriptedIndirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleI ValueToBool(value, bp); } +bool +ScriptedIndirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy, + MutableHandleObject objp) const +{ + // The hook that is called "enumerate" in the spec, used to be "iterate" + RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy)); + RootedValue value(cx); + if (!GetDerivedTrap(cx, handler, cx->names().iterate, &value)) + return false; + if (!IsCallable(value)) + return BaseProxyHandler::enumerate(cx, proxy, objp); + + RootedValue rval(cx); + if (!Trap(cx, handler, value, 0, nullptr, &rval)) + return false; + if (!ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().iterate, rval)) + return false; + objp.set(&rval.toObject()); + return true; +} + bool ScriptedIndirectProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const { @@ -336,26 +357,6 @@ ScriptedIndirectProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObj ArrayToIdVector(cx, value, props); } -bool -ScriptedIndirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags, - MutableHandleObject objp) const -{ - RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy)); - RootedValue value(cx); - if (!GetDerivedTrap(cx, handler, cx->names().iterate, &value)) - return false; - if (!IsCallable(value)) - return BaseProxyHandler::iterate(cx, proxy, flags, objp); - - RootedValue rval(cx); - if (!Trap(cx, handler, value, 0, nullptr, &rval)) - return false; - if (!ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().iterate, rval)) - return false; - objp.set(&rval.toObject()); - return true; -} - bool ScriptedIndirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const diff --git a/js/src/proxy/ScriptedIndirectProxyHandler.h b/js/src/proxy/ScriptedIndirectProxyHandler.h index c4f624b455a9..34a3102c85c3 100644 --- a/js/src/proxy/ScriptedIndirectProxyHandler.h +++ b/js/src/proxy/ScriptedIndirectProxyHandler.h @@ -27,6 +27,8 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; + virtual bool enumerate(JSContext *cx, HandleObject proxy, + MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const MOZ_OVERRIDE; virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE; virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; @@ -43,8 +45,6 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler AutoIdVector &props) const MOZ_OVERRIDE; virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, - MutableHandleObject objp) const MOZ_OVERRIDE; virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const MOZ_OVERRIDE; virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE; diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index a6dad183c6fd..fa60ac69e0fc 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -1780,6 +1780,11 @@ class DebugScopeProxy : public BaseProxyHandler return getScopePropertyNames(cx, proxy, props, 0); } + bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const MOZ_OVERRIDE + { + return BaseProxyHandler::enumerate(cx, proxy, objp); + } + bool has(JSContext *cx, HandleObject proxy, HandleId id_, bool *bp) const MOZ_OVERRIDE { RootedId id(cx, id_); diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index a889ce19a9de..926897822e29 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -737,10 +737,10 @@ xpc::SandboxProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, } bool -xpc::SandboxProxyHandler::iterate(JSContext *cx, JS::Handle proxy, - unsigned flags, JS::MutableHandle objp) const +xpc::SandboxProxyHandler::enumerate(JSContext *cx, JS::Handle proxy, + JS::MutableHandle objp) const { - return BaseProxyHandler::iterate(cx, proxy, flags, objp); + return BaseProxyHandler::enumerate(cx, proxy, objp); } bool diff --git a/js/xpconnect/wrappers/FilteringWrapper.cpp b/js/xpconnect/wrappers/FilteringWrapper.cpp index 2245ed73566f..ba9310030f40 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.cpp +++ b/js/xpconnect/wrappers/FilteringWrapper.cpp @@ -124,15 +124,15 @@ FilteringWrapper::getEnumerablePropertyKeys(JSContext *cx, template bool -FilteringWrapper::iterate(JSContext *cx, HandleObject wrapper, - unsigned flags, MutableHandleObject objp) const +FilteringWrapper::enumerate(JSContext *cx, HandleObject wrapper, + MutableHandleObject objp) const { assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE); - // We refuse to trigger the iterator hook across chrome wrappers because + // We refuse to trigger the enumerate hook across chrome wrappers because // we don't know how to censor custom iterator objects. Instead we trigger - // the default proxy iterate trap, which will ask enumerate() for the list - // of (censored) ids. - return js::BaseProxyHandler::iterate(cx, wrapper, flags, objp); + // the default proxy enumerate trap, which will ask getEnumerablePropertyKeys() + // for the list of (censored) ids. + return js::BaseProxyHandler::enumerate(cx, wrapper, objp); } template diff --git a/js/xpconnect/wrappers/FilteringWrapper.h b/js/xpconnect/wrappers/FilteringWrapper.h index 97f3dce7095c..59b0e0f94418 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.h +++ b/js/xpconnect/wrappers/FilteringWrapper.h @@ -41,8 +41,8 @@ class FilteringWrapper : public Base { JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle wrapper, JS::AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool iterate(JSContext *cx, JS::Handle wrapper, unsigned flags, - JS::MutableHandle objp) const MOZ_OVERRIDE; + virtual bool enumerate(JSContext *cx, JS::Handle wrapper, + JS::MutableHandle objp) const MOZ_OVERRIDE; virtual bool call(JSContext *cx, JS::Handle wrapper, const JS::CallArgs &args) const MOZ_OVERRIDE; diff --git a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp index a4375f70442c..65bd2efb4baf 100644 --- a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp +++ b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp @@ -59,11 +59,11 @@ WaiveXrayWrapper::get(JSContext *cx, HandleObject wrapper, } bool -WaiveXrayWrapper::iterate(JSContext *cx, HandleObject proxy, unsigned flags, - MutableHandleObject objp) const +WaiveXrayWrapper::enumerate(JSContext *cx, HandleObject proxy, + MutableHandleObject objp) const { - return CrossCompartmentWrapper::iterate(cx, proxy, flags, objp) && - (!objp || WrapperFactory::WaiveXrayAndWrap(cx, objp)); + return CrossCompartmentWrapper::enumerate(cx, proxy, objp) && + WrapperFactory::WaiveXrayAndWrap(cx, objp); } bool diff --git a/js/xpconnect/wrappers/WaiveXrayWrapper.h b/js/xpconnect/wrappers/WaiveXrayWrapper.h index bea036f2ce1a..8936543b215d 100644 --- a/js/xpconnect/wrappers/WaiveXrayWrapper.h +++ b/js/xpconnect/wrappers/WaiveXrayWrapper.h @@ -29,8 +29,8 @@ class WaiveXrayWrapper : public js::CrossCompartmentWrapper { virtual bool construct(JSContext *cx, JS::Handle wrapper, const JS::CallArgs &args) const MOZ_OVERRIDE; - virtual bool iterate(JSContext *cx, JS::Handle proxy, unsigned flags, - JS::MutableHandle objp) const MOZ_OVERRIDE; + virtual bool enumerate(JSContext *cx, JS::Handle proxy, + JS::MutableHandle objp) const MOZ_OVERRIDE; virtual bool nativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl, JS::CallArgs args) const MOZ_OVERRIDE; virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 91b124a041f4..f724e8b6813a 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -2120,11 +2120,11 @@ XrayWrapper::getEnumerablePropertyKeys(JSContext *cx, HandleObject template bool -XrayWrapper::iterate(JSContext *cx, HandleObject wrapper, - unsigned flags, MutableHandleObject objp) const +XrayWrapper::enumerate(JSContext *cx, HandleObject wrapper, + MutableHandleObject objp) const { // Skip our Base if it isn't already ProxyHandler. - return js::BaseProxyHandler::iterate(cx, wrapper, flags, objp); + return js::BaseProxyHandler::enumerate(cx, wrapper, objp); } template diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index 65d781f5845b..e793a5a1ab1d 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -413,6 +413,8 @@ class XrayWrapper : public Base { JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual bool delete_(JSContext *cx, JS::Handle wrapper, JS::Handle id, bool *bp) const MOZ_OVERRIDE; + virtual bool enumerate(JSContext *cx, JS::Handle wrapper, + JS::MutableHandle objp) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper, JS::MutableHandleObject protop) const MOZ_OVERRIDE; virtual bool setPrototypeOf(JSContext *cx, JS::HandleObject wrapper, @@ -441,8 +443,6 @@ class XrayWrapper : public Base { JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle wrapper, JS::AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool iterate(JSContext *cx, JS::Handle wrapper, unsigned flags, - JS::MutableHandle objp) const MOZ_OVERRIDE; virtual const char *className(JSContext *cx, JS::HandleObject proxy) const MOZ_OVERRIDE; virtual bool defaultValue(JSContext *cx, JS::HandleObject wrapper, @@ -512,8 +512,8 @@ public: bool *bp) const MOZ_OVERRIDE; virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle proxy, JS::AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool iterate(JSContext *cx, JS::Handle proxy, unsigned flags, - JS::MutableHandle objp) const MOZ_OVERRIDE; + virtual bool enumerate(JSContext *cx, JS::Handle proxy, + JS::MutableHandle objp) const MOZ_OVERRIDE; }; extern const SandboxProxyHandler sandboxProxyHandler; From e15d84143490b84e20e16d09da90f673af1c9b64 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Wed, 17 Dec 2014 00:28:38 +0100 Subject: [PATCH 091/130] Bug 783829 - Some tests for the enumerate trap. r=efaust --- .../tests/proxy/testDirectProxyEnumerate1.js | 14 ++++++++++++++ .../tests/proxy/testDirectProxyEnumerate2.js | 16 ++++++++++++++++ .../tests/proxy/testDirectProxyEnumerate3.js | 16 ++++++++++++++++ .../tests/proxy/testDirectProxyEnumerate4.js | 15 +++++++++++++++ .../tests/proxy/testDirectProxyWithForEach.js | 2 ++ 5 files changed, 63 insertions(+) create mode 100644 js/src/jit-test/tests/proxy/testDirectProxyEnumerate1.js create mode 100644 js/src/jit-test/tests/proxy/testDirectProxyEnumerate2.js create mode 100644 js/src/jit-test/tests/proxy/testDirectProxyEnumerate3.js create mode 100644 js/src/jit-test/tests/proxy/testDirectProxyEnumerate4.js create mode 100644 js/src/jit-test/tests/proxy/testDirectProxyWithForEach.js diff --git a/js/src/jit-test/tests/proxy/testDirectProxyEnumerate1.js b/js/src/jit-test/tests/proxy/testDirectProxyEnumerate1.js new file mode 100644 index 000000000000..485e03182e9a --- /dev/null +++ b/js/src/jit-test/tests/proxy/testDirectProxyEnumerate1.js @@ -0,0 +1,14 @@ +// for-in with revoked Proxy +load(libdir + "asserts.js"); + +let {proxy, revoke} = Proxy.revocable({a: 1}, {}); + +for (let x in proxy) + assertEq(x, "a") + +revoke(); + +assertThrowsInstanceOf(function() { + for (let x in proxy) + assertEq(true, false); +}, TypeError) diff --git a/js/src/jit-test/tests/proxy/testDirectProxyEnumerate2.js b/js/src/jit-test/tests/proxy/testDirectProxyEnumerate2.js new file mode 100644 index 000000000000..ceec6ff1de33 --- /dev/null +++ b/js/src/jit-test/tests/proxy/testDirectProxyEnumerate2.js @@ -0,0 +1,16 @@ +// Throwing [[Enumerate]] handler +load(libdir + "asserts.js"); + +let handler = new Proxy({}, { + get: function(target, name) { + assertEq(name, "enumerate"); + throw new SyntaxError(); + } +}); + +let proxy = new Proxy({}, handler); + +assertThrowsInstanceOf(function() { + for (let x in proxy) + assertEq(true, false); +}, SyntaxError) diff --git a/js/src/jit-test/tests/proxy/testDirectProxyEnumerate3.js b/js/src/jit-test/tests/proxy/testDirectProxyEnumerate3.js new file mode 100644 index 000000000000..b74c13f0fa3f --- /dev/null +++ b/js/src/jit-test/tests/proxy/testDirectProxyEnumerate3.js @@ -0,0 +1,16 @@ +// Basic [[Enumerate]] functionality test +let inner = []; +let handler = { + enumerate: function(target) { + assertEq(target, inner); + assertEq(arguments.length, 1); + assertEq(this, handler); + return (function*() { yield 'a'; })(); + } +}; + +let x; +for (let y in new Proxy(inner, handler)) { + x = y; +} +assertEq(x, 'a'); diff --git a/js/src/jit-test/tests/proxy/testDirectProxyEnumerate4.js b/js/src/jit-test/tests/proxy/testDirectProxyEnumerate4.js new file mode 100644 index 000000000000..dac1545d1245 --- /dev/null +++ b/js/src/jit-test/tests/proxy/testDirectProxyEnumerate4.js @@ -0,0 +1,15 @@ +// Returning primitive from [[Enumerate]] handler +load(libdir + "asserts.js"); + +let handler = { + enumerate: function() { + return undefined; + } +}; + +let proxy = new Proxy({}, handler); + +assertThrowsInstanceOf(function() { + for (let x in proxy) + assertEq(true, false); +}, TypeError) diff --git a/js/src/jit-test/tests/proxy/testDirectProxyWithForEach.js b/js/src/jit-test/tests/proxy/testDirectProxyWithForEach.js new file mode 100644 index 000000000000..54bfb85329f6 --- /dev/null +++ b/js/src/jit-test/tests/proxy/testDirectProxyWithForEach.js @@ -0,0 +1,2 @@ +var proxy = new Proxy(['a', 'b', 'c'], {}); +assertEq([x for each (x in proxy)].toString(), 'a,b,c'); From 7ed0e36ad2cb0bf377b022fab332c18d4c29148c Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Wed, 17 Dec 2014 00:28:38 +0100 Subject: [PATCH 092/130] Bug 783829 - Remove getEnumerablePropertyKeys. r=efaust,bholley --- dom/base/nsGlobalWindow.cpp | 20 +---------- dom/bindings/DOMJSProxyHandler.cpp | 13 ------- dom/bindings/DOMJSProxyHandler.h | 2 -- js/ipc/WrapperOwner.cpp | 17 ++------- js/ipc/WrapperOwner.h | 2 -- .../proxy/testDirectProxyOnProtoWithForIn.js | 19 ++++++++++ js/src/jsiter.cpp | 28 ++++++--------- js/src/jsproxy.h | 7 ++-- js/src/jswrapper.h | 2 -- js/src/proxy/BaseProxyHandler.cpp | 5 ++- js/src/proxy/CrossCompartmentWrapper.cpp | 10 ------ js/src/proxy/DeadObjectProxy.cpp | 8 ----- js/src/proxy/DeadObjectProxy.h | 2 -- js/src/proxy/DirectProxyHandler.cpp | 10 ------ js/src/proxy/Proxy.cpp | 35 ++++++++----------- js/src/proxy/Proxy.h | 1 - js/src/proxy/ScriptedDirectProxyHandler.cpp | 27 -------------- js/src/proxy/ScriptedDirectProxyHandler.h | 2 -- js/src/proxy/ScriptedIndirectProxyHandler.cpp | 11 ------ js/src/proxy/ScriptedIndirectProxyHandler.h | 2 -- js/src/vm/ScopeObject.cpp | 15 ++------ js/xpconnect/wrappers/FilteringWrapper.cpp | 21 +---------- js/xpconnect/wrappers/FilteringWrapper.h | 4 --- js/xpconnect/wrappers/XrayWrapper.cpp | 8 ----- js/xpconnect/wrappers/XrayWrapper.h | 2 -- 25 files changed, 56 insertions(+), 217 deletions(-) create mode 100644 js/src/jit-test/tests/proxy/testDirectProxyOnProtoWithForIn.js diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 67f51df703fd..f1a729c6702b 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -650,8 +650,6 @@ public: JS::Handle id, bool *bp) const MOZ_OVERRIDE; virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle proxy, JS::AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle proxy, - JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual const char *className(JSContext *cx, JS::Handle wrapper) const MOZ_OVERRIDE; @@ -926,28 +924,12 @@ nsOuterWindowProxy::getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle proxy, - JS::AutoIdVector &props) const -{ - // Just our indexed stuff followed by our "normal" own property names. - if (!AppendIndexedPropertyNames(cx, proxy, props)) { - return false; - } - - JS::AutoIdVector innerProps(cx); - if (!js::Wrapper::getEnumerablePropertyKeys(cx, proxy, innerProps)) { - return false; - } - return js::AppendUnique(cx, props, innerProps); -} - bool nsOuterWindowProxy::enumerate(JSContext *cx, JS::Handle proxy, JS::MutableHandle objp) const { // BaseProxyHandler::enumerate seems to do what we want here: fall - // back on the property names returned from getEnumerablePropertyKeys() + // back on the property names returned from js::GetPropertyKeys() return js::BaseProxyHandler::enumerate(cx, proxy, objp); } diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index 95233a93218b..0b9444e0f2a3 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -296,19 +296,6 @@ BaseDOMProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx, return ownPropNames(cx, proxy, JSITER_OWNONLY, props); } -bool -BaseDOMProxyHandler::getEnumerablePropertyKeys(JSContext* cx, - JS::Handle proxy, - AutoIdVector& props) const -{ - JS::Rooted proto(cx); - if (!JS_GetPrototype(cx, proxy, &proto)) { - return false; - } - return getOwnEnumerablePropertyKeys(cx, proxy, props) && - (!proto || js::GetPropertyKeys(cx, proto, 0, &props)); -} - bool BaseDOMProxyHandler::enumerate(JSContext *cx, JS::Handle proxy, JS::MutableHandle objp) const diff --git a/dom/bindings/DOMJSProxyHandler.h b/dom/bindings/DOMJSProxyHandler.h index 839537e901b9..a17dbafd9b13 100644 --- a/dom/bindings/DOMJSProxyHandler.h +++ b/dom/bindings/DOMJSProxyHandler.h @@ -71,8 +71,6 @@ public: // unnecessary work during enumeration. virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle proxy, JS::AutoIdVector &props) const MOZ_OVERRIDE; - bool getEnumerablePropertyKeys(JSContext* cx, JS::Handle proxy, - JS::AutoIdVector& props) const MOZ_OVERRIDE; bool watch(JSContext* cx, JS::Handle proxy, JS::Handle id, JS::Handle callable) const MOZ_OVERRIDE; diff --git a/js/ipc/WrapperOwner.cpp b/js/ipc/WrapperOwner.cpp index bc9ed632b3f0..b701fecdba3e 100644 --- a/js/ipc/WrapperOwner.cpp +++ b/js/ipc/WrapperOwner.cpp @@ -110,8 +110,6 @@ class CPOWProxyHandler : public BaseProxyHandler virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, - AutoIdVector &props) const MOZ_OVERRIDE; virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp) const MOZ_OVERRIDE; virtual bool objectClassIs(HandleObject obj, js::ESClassValue classValue, @@ -272,7 +270,8 @@ bool CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const { // Using a CPOW for the Iterator would slow down for .. in performance, instead - // call the base hook, that will use our implementation of getEnumerablePropertyKeys. + // call the base hook, that will use our implementation of getOwnEnumerablePropertyKeys + // and follow the proto chain. return BaseProxyHandler::enumerate(cx, proxy, objp); } @@ -480,18 +479,6 @@ WrapperOwner::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, Au return getPropertyKeys(cx, proxy, JSITER_OWNONLY, props); } -bool -CPOWProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const -{ - FORWARD(getEnumerablePropertyKeys, (cx, proxy, props)); -} - -bool -WrapperOwner::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) -{ - return getPropertyKeys(cx, proxy, 0, props); -} - bool CPOWProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy, bool *succeeded) const { diff --git a/js/ipc/WrapperOwner.h b/js/ipc/WrapperOwner.h index 1a26fa36db86..d95b1d9a2cf3 100644 --- a/js/ipc/WrapperOwner.h +++ b/js/ipc/WrapperOwner.h @@ -55,8 +55,6 @@ class WrapperOwner : public virtual JavaScriptShared bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp); bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props); - bool getEnumerablePropertyKeys(JSContext *cx, JS::HandleObject proxy, - JS::AutoIdVector &props); bool hasInstance(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool *bp); bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue); const char* className(JSContext *cx, JS::HandleObject proxy); diff --git a/js/src/jit-test/tests/proxy/testDirectProxyOnProtoWithForIn.js b/js/src/jit-test/tests/proxy/testDirectProxyOnProtoWithForIn.js new file mode 100644 index 000000000000..721862a5e62c --- /dev/null +++ b/js/src/jit-test/tests/proxy/testDirectProxyOnProtoWithForIn.js @@ -0,0 +1,19 @@ +let proxy = new Proxy({ + a: 1, + b: 2, + c: 3 +}, { + enumerate() { + // Should not be invoked. + assertEq(false, true); + }, + + ownKeys() { + return ['a', 'b']; + } +}); + +let object = Object.create(proxy); +object.d = 4; + +assertEq([x for (x in object)].toString(), "d,a,b"); diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index aeeee349d89c..049e21c062a2 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -306,19 +306,14 @@ Snapshot(JSContext *cx, HandleObject pobj_, unsigned flags, AutoIdVector *props) return false; } else if (pobj->is()) { AutoIdVector proxyProps(cx); - if (flags & JSITER_OWNONLY) { - if (flags & JSITER_HIDDEN) { - // This gets all property keys, both strings and - // symbols. The call to Enumerate in the loop below - // will filter out unwanted keys, per the flags. - if (!Proxy::ownPropertyKeys(cx, pobj, proxyProps)) - return false; - } else { - if (!Proxy::getOwnEnumerablePropertyKeys(cx, pobj, proxyProps)) - return false; - } + if (flags & JSITER_HIDDEN || flags & JSITER_SYMBOLS) { + // This gets all property keys, both strings and + // symbols. The call to Enumerate in the loop below + // will filter out unwanted keys, per the flags. + if (!Proxy::ownPropertyKeys(cx, pobj, proxyProps)) + return false; } else { - if (!Proxy::getEnumerablePropertyKeys(cx, pobj, proxyProps)) + if (!Proxy::getOwnEnumerablePropertyKeys(cx, pobj, proxyProps)) return false; } @@ -326,10 +321,6 @@ Snapshot(JSContext *cx, HandleObject pobj_, unsigned flags, AutoIdVector *props) if (!Enumerate(cx, pobj, proxyProps[n], true, flags, ht, props)) return false; } - - // Proxy objects enumerate the prototype on their own, so we're - // done here. - break; } else { MOZ_CRASH("non-native objects must have an enumerate op"); } @@ -337,7 +328,10 @@ Snapshot(JSContext *cx, HandleObject pobj_, unsigned flags, AutoIdVector *props) if (flags & JSITER_OWNONLY) break; - } while ((pobj = pobj->getProto()) != nullptr); + if (!JSObject::getProto(cx, pobj, &pobj)) + return false; + + } while (pobj != nullptr); #ifdef JS_MORE_DETERMINISTIC diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index b9adc8070b1c..33e8c423a710 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -258,7 +258,8 @@ class JS_FRIEND_API(BaseProxyHandler) /* * Because [[Enumerate]] is one of the standard traps it should be overridden. * However for convenience BaseProxyHandler includes a pure virtual implementation, - * that turns the properties returned by getEnumerablePropertyKeys into an Iterator object. + * that turns the properties returned by getOwnEnumerablePropertyKeys (and proto walking) + * into an Iterator object. */ virtual bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const = 0; @@ -311,8 +312,6 @@ class JS_FRIEND_API(BaseProxyHandler) virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const; virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const; - virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, - AutoIdVector &props) const = 0; virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const; virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp) const; virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) const; @@ -398,8 +397,6 @@ class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler bool *bp) const MOZ_OVERRIDE; virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, - AutoIdVector &props) const MOZ_OVERRIDE; virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const MOZ_OVERRIDE; virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 94c179846118..e8e1d6ffe6b2 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -145,8 +145,6 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper, - AutoIdVector &props) const MOZ_OVERRIDE; virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const MOZ_OVERRIDE; virtual bool hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v, diff --git a/js/src/proxy/BaseProxyHandler.cpp b/js/src/proxy/BaseProxyHandler.cpp index b64d635a8a62..f58551b7002c 100644 --- a/js/src/proxy/BaseProxyHandler.cpp +++ b/js/src/proxy/BaseProxyHandler.cpp @@ -234,9 +234,12 @@ BaseProxyHandler::enumerate(JSContext *cx, HandleObject proxy, MutableHandleObje { assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE); + // GetPropertyKeys will invoke getOwnEnumerablePropertyKeys along the proto + // chain for us. AutoIdVector props(cx); - if (!getEnumerablePropertyKeys(cx, proxy, props)) + if (!GetPropertyKeys(cx, proxy, 0, &props)) return false; + return EnumeratedIdVectorToIterator(cx, proxy, 0, props, objp); } diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp index b27aa80ea3a6..21cd71c7bd34 100644 --- a/js/src/proxy/CrossCompartmentWrapper.cpp +++ b/js/src/proxy/CrossCompartmentWrapper.cpp @@ -188,16 +188,6 @@ CrossCompartmentWrapper::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObjec NOTHING); } -bool -CrossCompartmentWrapper::getEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper, - AutoIdVector &props) const -{ - PIERCE(cx, wrapper, - NOTHING, - Wrapper::getEnumerablePropertyKeys(cx, wrapper, props), - NOTHING); -} - /* * We can reify non-escaping iterator objects instead of having to wrap them. This * allows fast iteration over objects across a compartment boundary. diff --git a/js/src/proxy/DeadObjectProxy.cpp b/js/src/proxy/DeadObjectProxy.cpp index 7142e442686d..0b968c474332 100644 --- a/js/src/proxy/DeadObjectProxy.cpp +++ b/js/src/proxy/DeadObjectProxy.cpp @@ -60,14 +60,6 @@ DeadObjectProxy::enumerate(JSContext *cx, HandleObject wrapper, MutableHandleObj return false; } -bool -DeadObjectProxy::getEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper, - AutoIdVector &props) const -{ - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT); - return false; -} - bool DeadObjectProxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const { diff --git a/js/src/proxy/DeadObjectProxy.h b/js/src/proxy/DeadObjectProxy.h index 342daa6ea464..20e98106483b 100644 --- a/js/src/proxy/DeadObjectProxy.h +++ b/js/src/proxy/DeadObjectProxy.h @@ -37,8 +37,6 @@ class DeadObjectProxy : public BaseProxyHandler /* SpiderMonkey extensions. */ virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id, MutableHandle desc) const MOZ_OVERRIDE; - virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper, - AutoIdVector &props) const MOZ_OVERRIDE; virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const MOZ_OVERRIDE; virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, diff --git a/js/src/proxy/DirectProxyHandler.cpp b/js/src/proxy/DirectProxyHandler.cpp index 653f6f4a5860..e3ceed5efee5 100644 --- a/js/src/proxy/DirectProxyHandler.cpp +++ b/js/src/proxy/DirectProxyHandler.cpp @@ -242,16 +242,6 @@ DirectProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject pro return GetPropertyKeys(cx, target, JSITER_OWNONLY, &props); } -bool -DirectProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, - AutoIdVector &props) const -{ - assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE); - MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype. - RootedObject target(cx, proxy->as().target()); - return GetPropertyKeys(cx, target, 0, &props); -} - bool DirectProxyHandler::isCallable(JSObject *obj) const { diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index 718b6e781b33..ae8a0c5d6488 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -347,24 +347,6 @@ Proxy::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVec return handler->getOwnEnumerablePropertyKeys(cx, proxy, props); } -bool -Proxy::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) -{ - JS_CHECK_RECURSION(cx, return false); - const BaseProxyHandler *handler = proxy->as().handler(); - AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true); - if (!policy.allowed()) - return policy.returnValue(); - if (!handler->hasPrototype()) - return proxy->as().handler()->getEnumerablePropertyKeys(cx, proxy, props); - if (!handler->getOwnEnumerablePropertyKeys(cx, proxy, props)) - return false; - AutoIdVector protoProps(cx); - INVOKE_ON_PROTOTYPE(cx, handler, proxy, - GetPropertyKeys(cx, proto, 0, &protoProps) && - AppendUnique(cx, props, protoProps)); -} - bool Proxy::enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) { @@ -382,11 +364,22 @@ Proxy::enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) } return handler->enumerate(cx, proxy, objp); } + AutoIdVector props(cx); - // The other Proxy::foo methods do the prototype-aware work for us here. - if (!Proxy::getEnumerablePropertyKeys(cx, proxy, props)) + if (!Proxy::getOwnEnumerablePropertyKeys(cx, proxy, props)) return false; - return EnumeratedIdVectorToIterator(cx, proxy, 0, props, objp); + + RootedObject proto(cx); + if (!JSObject::getProto(cx, proxy, &proto)) + return false; + if (!proto) + return EnumeratedIdVectorToIterator(cx, proxy, 0, props, objp); + assertSameCompartment(cx, proxy, proto); + + AutoIdVector protoProps(cx); + return GetPropertyKeys(cx, proto, 0, &protoProps) && + AppendUnique(cx, props, protoProps) && + EnumeratedIdVectorToIterator(cx, proxy, 0, props, objp); } bool diff --git a/js/src/proxy/Proxy.h b/js/src/proxy/Proxy.h index 0f11ae3af9bf..e72f2a22716c 100644 --- a/js/src/proxy/Proxy.h +++ b/js/src/proxy/Proxy.h @@ -56,7 +56,6 @@ class Proxy static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); static bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props); - static bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props); static bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args); static bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp); static bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx); diff --git a/js/src/proxy/ScriptedDirectProxyHandler.cpp b/js/src/proxy/ScriptedDirectProxyHandler.cpp index 5d1ccd507748..5c81b3cb1399 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp @@ -800,33 +800,6 @@ ScriptedDirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy, return true; } -// Non-standard, try to convert iterator result to ids -bool -ScriptedDirectProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const -{ - RootedObject iterator(cx); - if (!enumerate(cx, proxy, &iterator)) - return false; - - do { - RootedValue rval(cx); - if (!IteratorMore(cx, iterator, &rval)) - return false; - - if (rval.isMagic(JS_NO_ITER_VALUE)) - break; - - RootedId id(cx); - if (!ValueToId(cx, rval, &id)) - return false; - - if (!props.append(id)) - return false; - } while (true); - - return true; -} - // ES6 (22 May, 2014) 9.5.7 Proxy.[[HasProperty]](P) bool ScriptedDirectProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const diff --git a/js/src/proxy/ScriptedDirectProxyHandler.h b/js/src/proxy/ScriptedDirectProxyHandler.h index 1cdff97cdf08..004706177c6a 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.h +++ b/js/src/proxy/ScriptedDirectProxyHandler.h @@ -63,8 +63,6 @@ class ScriptedDirectProxyHandler : public DirectProxyHandler { AutoIdVector &props) const MOZ_OVERRIDE { return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props); } - virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, - AutoIdVector &props) const MOZ_OVERRIDE; virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE; virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE { diff --git a/js/src/proxy/ScriptedIndirectProxyHandler.cpp b/js/src/proxy/ScriptedIndirectProxyHandler.cpp index fa206f8848b0..b3a56a67ebe5 100644 --- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp @@ -346,17 +346,6 @@ ScriptedIndirectProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, Handle ArrayToIdVector(cx, value, props); } -bool -ScriptedIndirectProxyHandler::getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, - AutoIdVector &props) const -{ - RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy)); - RootedValue fval(cx), value(cx); - return GetFundamentalTrap(cx, handler, cx->names().enumerate, &fval) && - Trap(cx, handler, fval, 0, nullptr, &value) && - ArrayToIdVector(cx, value, props); -} - bool ScriptedIndirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const diff --git a/js/src/proxy/ScriptedIndirectProxyHandler.h b/js/src/proxy/ScriptedIndirectProxyHandler.h index 34a3102c85c3..eff50513dfdb 100644 --- a/js/src/proxy/ScriptedIndirectProxyHandler.h +++ b/js/src/proxy/ScriptedIndirectProxyHandler.h @@ -43,8 +43,6 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE; virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, - AutoIdVector &props) const MOZ_OVERRIDE; virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const MOZ_OVERRIDE; virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE; diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index fa60ac69e0fc..aa81164d34db 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -1734,8 +1734,7 @@ class DebugScopeProxy : public BaseProxyHandler JS_PROPERTYOP_SETTER(desc.setter())); } - bool getScopePropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props, - unsigned flags) const + bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const { Rooted scope(cx, &proxy->as().scope()); @@ -1752,7 +1751,7 @@ class DebugScopeProxy : public BaseProxyHandler // issue, and punch a hole through to the with object target. Rooted target(cx, (scope->is() ? &scope->as().object() : scope)); - if (!GetPropertyKeys(cx, target, flags, &props)) + if (!GetPropertyKeys(cx, target, JSITER_OWNONLY, &props)) return false; /* @@ -1770,16 +1769,6 @@ class DebugScopeProxy : public BaseProxyHandler return true; } - bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE - { - return getScopePropertyNames(cx, proxy, props, JSITER_OWNONLY); - } - - bool getEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE - { - return getScopePropertyNames(cx, proxy, props, 0); - } - bool enumerate(JSContext *cx, HandleObject proxy, MutableHandleObject objp) const MOZ_OVERRIDE { return BaseProxyHandler::enumerate(cx, proxy, objp); diff --git a/js/xpconnect/wrappers/FilteringWrapper.cpp b/js/xpconnect/wrappers/FilteringWrapper.cpp index ba9310030f40..d8aecb9b0f72 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.cpp +++ b/js/xpconnect/wrappers/FilteringWrapper.cpp @@ -111,17 +111,6 @@ FilteringWrapper::getOwnEnumerablePropertyKeys(JSContext *cx, Filter(cx, wrapper, props); } -template -bool -FilteringWrapper::getEnumerablePropertyKeys(JSContext *cx, - HandleObject wrapper, - AutoIdVector &props) const -{ - assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE); - return Base::getEnumerablePropertyKeys(cx, wrapper, props) && - Filter(cx, wrapper, props); -} - template bool FilteringWrapper::enumerate(JSContext *cx, HandleObject wrapper, @@ -130,7 +119,7 @@ FilteringWrapper::enumerate(JSContext *cx, HandleObject wrapper, assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE); // We refuse to trigger the enumerate hook across chrome wrappers because // we don't know how to censor custom iterator objects. Instead we trigger - // the default proxy enumerate trap, which will ask getEnumerablePropertyKeys() + // the default proxy enumerate trap, which will use js::GetPropertyKeys // for the list of (censored) ids. return js::BaseProxyHandler::enumerate(cx, wrapper, objp); } @@ -259,14 +248,6 @@ CrossOriginXrayWrapper::delete_(JSContext *cx, JS::Handle wrapper, return false; } -bool -CrossOriginXrayWrapper::getEnumerablePropertyKeys(JSContext *cx, JS::Handle wrapper, - JS::AutoIdVector &props) const -{ - // Cross-origin properties are non-enumerable. - return true; -} - #define XOW FilteringWrapper #define NNXOW FilteringWrapper #define NNXOWC FilteringWrapper diff --git a/js/xpconnect/wrappers/FilteringWrapper.h b/js/xpconnect/wrappers/FilteringWrapper.h index 59b0e0f94418..477f39df95c0 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.h +++ b/js/xpconnect/wrappers/FilteringWrapper.h @@ -39,8 +39,6 @@ class FilteringWrapper : public Base { JS::MutableHandle desc) const MOZ_OVERRIDE; virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle wrapper, JS::AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle wrapper, - JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual bool enumerate(JSContext *cx, JS::Handle wrapper, JS::MutableHandle objp) const MOZ_OVERRIDE; @@ -84,8 +82,6 @@ class CrossOriginXrayWrapper : public SecurityXrayDOM { virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper, JS::Handle id, JS::MutableHandle desc) const MOZ_OVERRIDE; - virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle wrapper, - JS::AutoIdVector &props) const MOZ_OVERRIDE; }; } diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index f724e8b6813a..e5cc882d39d5 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -2110,14 +2110,6 @@ XrayWrapper::getOwnEnumerablePropertyKeys(JSContext *cx, return js::BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, wrapper, props); } -template -bool -XrayWrapper::getEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper, - AutoIdVector &props) const -{ - return getPropertyKeys(cx, wrapper, 0, props); -} - template bool XrayWrapper::enumerate(JSContext *cx, HandleObject wrapper, diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index e793a5a1ab1d..81e2d53e4c87 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -441,8 +441,6 @@ class XrayWrapper : public Base { bool *bp) const MOZ_OVERRIDE; virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle wrapper, JS::AutoIdVector &props) const MOZ_OVERRIDE; - virtual bool getEnumerablePropertyKeys(JSContext *cx, JS::Handle wrapper, - JS::AutoIdVector &props) const MOZ_OVERRIDE; virtual const char *className(JSContext *cx, JS::HandleObject proxy) const MOZ_OVERRIDE; virtual bool defaultValue(JSContext *cx, JS::HandleObject wrapper, From d398e6a3f707de46b32d591fa02249393612136e Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Wed, 17 Dec 2014 00:28:38 +0100 Subject: [PATCH 093/130] Bug 783829 - Fix for bug when enumerating just enumerable symbols. r=efaust --- .../proxy/testDirectProxyOwnKeysSymbol.js | 33 +++++++++++++++++++ js/src/jsiter.cpp | 25 +++++++++++--- .../tests/js1_8_5/regress/regress-620376-1.js | 2 +- .../tests/js1_8_5/regress/regress-620376-2.js | 2 +- 4 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 js/src/jit-test/tests/proxy/testDirectProxyOwnKeysSymbol.js diff --git a/js/src/jit-test/tests/proxy/testDirectProxyOwnKeysSymbol.js b/js/src/jit-test/tests/proxy/testDirectProxyOwnKeysSymbol.js new file mode 100644 index 000000000000..ad6e1845e154 --- /dev/null +++ b/js/src/jit-test/tests/proxy/testDirectProxyOwnKeysSymbol.js @@ -0,0 +1,33 @@ +// Make sure that we can find own, enumerable symbols. +var symbol = Symbol("bad"); +var symbol2 = Symbol("good"); +var proxy = new Proxy({}, { + ownKeys() { + return [symbol, symbol2]; + }, + getOwnPropertyDescriptor(target, name) { + if (name == symbol) + return {configurable: true, enumerable: false, value: {}}; + // Only this enumerable symbol should be defined. + if (name == symbol2) + return {configurable: true, enumerable: true, value: {}}; + assertEq(true, false); + }, + get(target, name) { + // Slightly confusing, but these are the descriptors that defineProperties + // is going to define on the object. + if (name == symbol) + return {configurable: true, value: "bad"}; + if (name == symbol2) + return {configurable: true, value: "good"}; + assertEq(true, false); + } +}); +assertEq(Object.getOwnPropertySymbols(proxy).length, 2); + +var obj = {}; +Object.defineProperties(obj, proxy); +assertEq(Object.getOwnPropertySymbols(obj).length, 1); +assertEq(symbol in obj, false); +assertEq(symbol2 in obj, true); +assertEq(obj[symbol2], "good"); diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 049e21c062a2..d7d39ebcc758 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -312,14 +312,31 @@ Snapshot(JSContext *cx, HandleObject pobj_, unsigned flags, AutoIdVector *props) // will filter out unwanted keys, per the flags. if (!Proxy::ownPropertyKeys(cx, pobj, proxyProps)) return false; + + Rooted desc(cx); + for (size_t n = 0, len = proxyProps.length(); n < len; n++) { + bool enumerable = false; + + // We need to filter, if the caller just wants enumerable + // symbols. + if (!(flags & JSITER_HIDDEN)) { + if (!Proxy::getOwnPropertyDescriptor(cx, pobj, proxyProps[n], &desc)) + return false; + enumerable = desc.isEnumerable(); + } + + if (!Enumerate(cx, pobj, proxyProps[n], enumerable, flags, ht, props)) + return false; + } } else { + // Returns enumerable property names (no symbols). if (!Proxy::getOwnEnumerablePropertyKeys(cx, pobj, proxyProps)) return false; - } - for (size_t n = 0, len = proxyProps.length(); n < len; n++) { - if (!Enumerate(cx, pobj, proxyProps[n], true, flags, ht, props)) - return false; + for (size_t n = 0, len = proxyProps.length(); n < len; n++) { + if (!Enumerate(cx, pobj, proxyProps[n], true, flags, ht, props)) + return false; + } } } else { MOZ_CRASH("non-native objects must have an enumerate op"); diff --git a/js/src/tests/js1_8_5/regress/regress-620376-1.js b/js/src/tests/js1_8_5/regress/regress-620376-1.js index 3bb60af43c6a..9fa6b889f43d 100644 --- a/js/src/tests/js1_8_5/regress/regress-620376-1.js +++ b/js/src/tests/js1_8_5/regress/regress-620376-1.js @@ -10,7 +10,7 @@ function test() { if (typeof timeout != "function") return; - var p = Proxy.create({ enumerate: function() { return Array(1e9); }}); + var p = Proxy.create({ keys: function() { return Array(1e9); }}); expectExitCode(6); timeout(0.001); diff --git a/js/src/tests/js1_8_5/regress/regress-620376-2.js b/js/src/tests/js1_8_5/regress/regress-620376-2.js index acae97e36449..e886b6804b0b 100644 --- a/js/src/tests/js1_8_5/regress/regress-620376-2.js +++ b/js/src/tests/js1_8_5/regress/regress-620376-2.js @@ -5,7 +5,7 @@ */ function test() { - var p = Proxy.create({ enumerate: function() { return { get length() { throw 1; }}; }}); + var p = Proxy.create({ keys: function() { return { get length() { throw 1; }}; }}); try { for (i in p); From 6847f14b74e316130c3a734a9f7b5d741318d2ea Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Wed, 17 Dec 2014 00:28:39 +0100 Subject: [PATCH 094/130] Bug 783829 - Make PlacesUtils.nodeAncestors a new generator. r=mak --- browser/components/places/content/treeView.js | 4 ++-- toolkit/components/places/PlacesUtils.jsm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/browser/components/places/content/treeView.js b/browser/components/places/content/treeView.js index bb072489ad47..fe904d98a42f 100644 --- a/browser/components/places/content/treeView.js +++ b/browser/components/places/content/treeView.js @@ -152,7 +152,7 @@ PlacesTreeView.prototype = { // A node is removed form the view either if it has no parent or if its // root-ancestor is not the root node (in which case that's the node // for which nodeRemoved was called). - let ancestors = [x for each (x in PlacesUtils.nodeAncestors(aNode))]; + let ancestors = [x for (x of PlacesUtils.nodeAncestors(aNode))]; if (ancestors.length == 0 || ancestors[ancestors.length - 1] != this._rootNode) { throw new Error("Removed node passed to _getRowForNode"); @@ -417,7 +417,7 @@ PlacesTreeView.prototype = { // However, if any of the node's ancestor is closed, the node is // invisible. let ancestors = PlacesUtils.nodeAncestors(aOldNode); - for (let ancestor in ancestors) { + for (let ancestor of ancestors) { if (!ancestor.containerOpen) return -1; } diff --git a/toolkit/components/places/PlacesUtils.jsm b/toolkit/components/places/PlacesUtils.jsm index 7ec5b61369c5..dd30efad040f 100644 --- a/toolkit/components/places/PlacesUtils.jsm +++ b/toolkit/components/places/PlacesUtils.jsm @@ -200,7 +200,7 @@ this.PlacesUtils = { * @param aNode * A result node */ - nodeAncestors: function PU_nodeAncestors(aNode) { + nodeAncestors: function* PU_nodeAncestors(aNode) { let node = aNode.parent; while (node) { yield node; From 8ea607887720e107d136799cc3188566974e9d05 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Wed, 17 Dec 2014 00:28:39 +0100 Subject: [PATCH 095/130] Bug 1094176 - Remove lookup JSAPI from js. r=jorendorff --- js/src/jsapi-tests/testLookup.cpp | 2 +- js/src/jsapi.cpp | 118 +++--------------------------- js/src/jsapi.h | 15 ---- js/src/jscntxt.cpp | 4 +- js/src/shell/js.cpp | 6 +- 5 files changed, 15 insertions(+), 130 deletions(-) diff --git a/js/src/jsapi-tests/testLookup.cpp b/js/src/jsapi-tests/testLookup.cpp index c5a56c84f9e4..7470adbccdd2 100644 --- a/js/src/jsapi-tests/testLookup.cpp +++ b/js/src/jsapi-tests/testLookup.cpp @@ -27,7 +27,7 @@ BEGIN_TEST(testLookup_bug522590) // This lookup must not return an internal function object. JS::RootedValue r(cx); - CHECK(JS_LookupProperty(cx, xobj, "f", &r)); + CHECK(JS_GetProperty(cx, xobj, "f", &r)); CHECK(r.isObject()); JSObject *funobj = &r.toObject(); CHECK(funobj->is()); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 8bffa6f1e428..ab25e80f4b29 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2263,108 +2263,13 @@ JS_DeepFreezeObject(JSContext *cx, HandleObject obj) return true; } -static bool -LookupPropertyById(JSContext *cx, HandleObject obj, HandleId id, - MutableHandleObject objp, MutableHandleShape propp) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, id); - - return JSObject::lookupGeneric(cx, obj, id, objp, propp); -} - -#define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n)) - -static bool -LookupResult(JSContext *cx, HandleObject obj, HandleObject obj2, HandleId id, - HandleShape shape, MutableHandleValue vp) -{ - if (!shape) { - /* XXX bad API: no way to tell "not defined" from "void value" */ - vp.setUndefined(); - return true; - } - - if (!obj2->isNative()) { - if (obj2->is()) { - Rooted desc(cx); - if (!Proxy::getPropertyDescriptor(cx, obj2, id, &desc)) - return false; - if (!desc.isShared()) { - vp.set(desc.value()); - return true; - } - } - } else if (IsImplicitDenseOrTypedArrayElement(shape)) { - vp.set(obj2->as().getDenseOrTypedArrayElement(JSID_TO_INT(id))); - return true; - } else { - /* Peek at the native property's slot value, without doing a Get. */ - if (shape->hasSlot()) { - vp.set(obj2->as().getSlot(shape->slot())); - return true; - } - } - - /* XXX bad API: no way to return "defined but value unknown" */ - vp.setBoolean(true); - return true; -} - -JS_PUBLIC_API(bool) -JS_LookupPropertyById(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) -{ - RootedObject obj2(cx); - RootedShape prop(cx); - - return LookupPropertyById(cx, obj, id, &obj2, &prop) && - LookupResult(cx, obj, obj2, id, prop, vp); -} - -JS_PUBLIC_API(bool) -JS_LookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp) -{ - CHECK_REQUEST(cx); - RootedId id(cx); - if (!IndexToId(cx, index, &id)) - return false; - return JS_LookupPropertyById(cx, obj, id, vp); -} - -JS_PUBLIC_API(bool) -JS_LookupProperty(JSContext *cx, HandleObject objArg, const char *name, MutableHandleValue vp) -{ - RootedObject obj(cx, objArg); - JSAtom *atom = Atomize(cx, name, strlen(name)); - if (!atom) - return false; - - RootedId id(cx, AtomToId(atom)); - return JS_LookupPropertyById(cx, obj, id, vp); -} - -JS_PUBLIC_API(bool) -JS_LookupUCProperty(JSContext *cx, HandleObject objArg, const char16_t *name, size_t namelen, - MutableHandleValue vp) -{ - RootedObject obj(cx, objArg); - JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); - if (!atom) - return false; - - RootedId id(cx, AtomToId(atom)); - return JS_LookupPropertyById(cx, obj, id, vp); -} - JS_PUBLIC_API(bool) JS_HasPropertyById(JSContext *cx, HandleObject obj, HandleId id, bool *foundp) { - RootedObject obj2(cx); - RootedShape prop(cx); - bool ok = LookupPropertyById(cx, obj, id, &obj2, &prop); - *foundp = (prop != nullptr); - return ok; + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + + return JSObject::hasProperty(cx, obj, id, foundp); } JS_PUBLIC_API(bool) @@ -2388,6 +2293,8 @@ JS_HasProperty(JSContext *cx, HandleObject obj, const char *name, bool *foundp) return JS_HasPropertyById(cx, obj, id, foundp); } +#define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n)) + JS_PUBLIC_API(bool) JS_HasUCProperty(JSContext *cx, HandleObject obj, const char16_t *name, size_t namelen, bool *foundp) { @@ -2405,15 +2312,8 @@ JS_AlreadyHasOwnPropertyById(JSContext *cx, HandleObject obj, HandleId id, bool CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); - if (!obj->isNative()) { - RootedObject obj2(cx); - RootedShape prop(cx); - - if (!LookupPropertyById(cx, obj, id, &obj2, &prop)) - return false; - *foundp = (obj == obj2); - return true; - } + if (!obj->isNative()) + return js::HasOwnProperty(cx, obj, id, foundp); RootedNativeObject nativeObj(cx, &obj->as()); RootedShape prop(cx); @@ -3023,7 +2923,7 @@ GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id, RootedObject obj2(cx); RootedShape shape(cx); - if (!LookupPropertyById(cx, obj, id, &obj2, &shape)) + if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &shape)) return false; desc.clear(); diff --git a/js/src/jsapi.h b/js/src/jsapi.h index bfd671587d2a..2743e463289a 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2999,13 +2999,6 @@ JS_HasProperty(JSContext *cx, JS::HandleObject obj, const char *name, bool *foun extern JS_PUBLIC_API(bool) JS_HasPropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *foundp); -extern JS_PUBLIC_API(bool) -JS_LookupProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_LookupPropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleValue vp); - struct JSPropertyDescriptor { JSObject *obj; unsigned attrs; @@ -3281,11 +3274,6 @@ JS_HasUCProperty(JSContext *cx, JS::HandleObject obj, const char16_t *name, size_t namelen, bool *vp); -extern JS_PUBLIC_API(bool) -JS_LookupUCProperty(JSContext *cx, JS::HandleObject obj, - const char16_t *name, size_t namelen, - JS::MutableHandleValue vp); - extern JS_PUBLIC_API(bool) JS_GetUCProperty(JSContext *cx, JS::HandleObject obj, const char16_t *name, size_t namelen, @@ -3354,9 +3342,6 @@ JS_AlreadyHasOwnElement(JSContext *cx, JS::HandleObject obj, uint32_t index, boo extern JS_PUBLIC_API(bool) JS_HasElement(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *foundp); -extern JS_PUBLIC_API(bool) -JS_LookupElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp); - extern JS_PUBLIC_API(bool) JS_GetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp); diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index ce80dfda395c..e0accbbeb2c6 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -529,10 +529,10 @@ js::ReportUsageError(JSContext *cx, HandleObject callee, const char *msg) MOZ_ASSERT(shape->hasDefaultGetter()); RootedValue usage(cx); - if (!JS_LookupProperty(cx, callee, "usage", &usage)) + if (!JS_GetProperty(cx, callee, "usage", &usage)) return; - if (usage.isUndefined()) { + if (!usage.isString()) { JS_ReportError(cx, "%s", msg); } else { JSString *str = usage.toString(); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 2885f8e7ee8f..a7c889ac5e90 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4567,10 +4567,10 @@ static bool PrintHelp(JSContext *cx, HandleObject obj) { RootedValue usage(cx); - if (!JS_LookupProperty(cx, obj, "usage", &usage)) + if (!JS_GetProperty(cx, obj, "usage", &usage)) return false; RootedValue help(cx); - if (!JS_LookupProperty(cx, obj, "help", &help)) + if (!JS_GetProperty(cx, obj, "help", &help)) return false; if (usage.isUndefined() || help.isUndefined()) @@ -4595,7 +4595,7 @@ Help(JSContext *cx, unsigned argc, jsval *vp) for (size_t i = 0; i < ida.length(); i++) { RootedValue v(cx); RootedId id(cx, ida[i]); - if (!JS_LookupPropertyById(cx, global, id, &v)) + if (!JS_GetPropertyById(cx, global, id, &v)) return false; if (v.isPrimitive()) { JS_ReportError(cx, "primitive arg"); From 8960d9ef9ff075b247f27c7808b7b005d00eb4f2 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Wed, 17 Dec 2014 00:28:39 +0100 Subject: [PATCH 096/130] Bug 1094176 - Remove lookup API from browser. r=bholley --- dom/base/nsDOMClassInfo.cpp | 30 +++++++++++++-------------- dom/bindings/Codegen.py | 4 ++-- dom/xbl/nsXBLProtoImpl.cpp | 7 ++----- ipc/ril/Ril.cpp | 9 +++----- js/ipc/WrapperOwner.cpp | 2 +- js/xpconnect/src/XPCInlines.h | 7 ++----- js/xpconnect/wrappers/AccessCheck.cpp | 14 ++++++++++--- 7 files changed, 36 insertions(+), 37 deletions(-) diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 147abb23c1b5..dc00d5a983fa 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -1026,17 +1026,17 @@ nsDOMClassInfo::Resolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JS::Rooted global(cx, ::JS_GetGlobalForObject(cx, obj)); - JS::Rooted val(cx); - if (!::JS_LookupProperty(cx, global, mData->mName, &val)) { + JS::Rooted desc(cx); + if (!JS_GetPropertyDescriptor(cx, global, mData->mName, &desc)) { return NS_ERROR_UNEXPECTED; } - if (!val.isPrimitive()) { + if (desc.object() && !desc.hasGetterOrSetter() && desc.value().isObject()) { // If val is not an (non-null) object there either is no // constructor for this class, or someone messed with // window.classname, just fall through and let the JS engine // return the Object constructor. - if (!::JS_DefinePropertyById(cx, obj, id, val, + if (!::JS_DefinePropertyById(cx, obj, id, desc.value(), JSPROP_ENUMERATE, JS_STUBGETTER, JS_STUBSETTER)) { return NS_ERROR_UNEXPECTED; @@ -1620,16 +1620,16 @@ nsDOMConstructor::HasInstance(nsIXPConnectWrappedNative *wrapper, if (!name_struct) { // This isn't a normal DOM object, see if this constructor lives on its // prototype chain. - JS::Rooted val(cx); - if (!JS_GetProperty(cx, obj, "prototype", &val)) { + JS::Rooted desc(cx); + if (!JS_GetPropertyDescriptor(cx, obj, "prototype", &desc)) { return NS_ERROR_UNEXPECTED; } - if (val.isPrimitive()) { + if (!desc.object() || desc.hasGetterOrSetter() || !desc.value().isObject()) { return NS_OK; } - JS::Rooted dot_prototype(cx, val.toObjectOrNull()); + JS::Rooted dot_prototype(cx, &desc.value().toObject()); JS::Rooted proto(cx, dom_obj); for (;;) { @@ -1933,19 +1933,19 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx, if (class_parent_name) { JSAutoCompartment ac(cx, winobj); - JS::Rooted val(cx); - if (!JS_LookupProperty(cx, winobj, CutPrefix(class_parent_name), &val)) { + JS::Rooted desc(cx); + if (!JS_GetPropertyDescriptor(cx, winobj, CutPrefix(class_parent_name), &desc)) { return NS_ERROR_UNEXPECTED; } - if (val.isObject()) { - JS::Rooted obj(cx, &val.toObject()); - if (!JS_LookupProperty(cx, obj, "prototype", &val)) { + if (desc.object() && !desc.hasGetterOrSetter() && desc.value().isObject()) { + JS::Rooted obj(cx, &desc.value().toObject()); + if (!JS_GetPropertyDescriptor(cx, obj, "prototype", &desc)) { return NS_ERROR_UNEXPECTED; } - if (val.isObject()) { - proto = &val.toObject(); + if (desc.object() && !desc.hasGetterOrSetter() && desc.value().isObject()) { + proto = &desc.value().toObject(); } } } diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 3397c0ba81b2..a7d61d94d6f6 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -7681,9 +7681,9 @@ class CGEnumerateHook(CGAbstractBindingMethod): if (rv.Failed()) { return ThrowMethodFailedWithDetails(cx, rv, "%s", "enumerate"); } - JS::Rooted dummy(cx); + bool dummy; for (uint32_t i = 0; i < names.Length(); ++i) { - if (!JS_LookupUCProperty(cx, obj, names[i].get(), names[i].Length(), &dummy)) { + if (!JS_HasUCProperty(cx, obj, names[i].get(), names[i].Length(), &dummy)) { return false; } } diff --git a/dom/xbl/nsXBLProtoImpl.cpp b/dom/xbl/nsXBLProtoImpl.cpp index 6b1a110174e6..acb0a8587b63 100644 --- a/dom/xbl/nsXBLProtoImpl.cpp +++ b/dom/xbl/nsXBLProtoImpl.cpp @@ -321,12 +321,9 @@ bool nsXBLProtoImpl::ResolveAllFields(JSContext *cx, JS::Handle obj) const { for (nsXBLProtoImplField* f = mFields; f; f = f->GetNext()) { - // Using OBJ_LOOKUP_PROPERTY is a pain, since what we have is a - // char16_t* for the property name. Let's just use the public API and - // all. nsDependentString name(f->GetName()); - JS::Rooted dummy(cx); - if (!::JS_LookupUCProperty(cx, obj, name.get(), name.Length(), &dummy)) { + bool dummy; + if (!::JS_HasUCProperty(cx, obj, name.get(), name.Length(), &dummy)) { return false; } } diff --git a/ipc/ril/Ril.cpp b/ipc/ril/Ril.cpp index bd602df558e6..9c75988ee820 100644 --- a/ipc/ril/Ril.cpp +++ b/ipc/ril/Ril.cpp @@ -148,17 +148,14 @@ ConnectWorkerToRIL::RunTask(JSContext *aCx) JS::Rooted workerGlobal(aCx, JS::CurrentGlobalOrNull(aCx)); // Check whether |postRILMessage| has been defined. No one but this class - // should ever define |postRILMessage| in a RIL worker, so we call to - // |JS_LookupProperty| instead of |JS_GetProperty| here. + // should ever define |postRILMessage| in a RIL worker. JS::Rooted val(aCx); - if (!JS_LookupProperty(aCx, workerGlobal, "postRILMessage", &val)) { + if (!JS_GetProperty(aCx, workerGlobal, "postRILMessage", &val)) { JS_ReportPendingException(aCx); return false; } - // |JS_LookupProperty| could still return JS_TRUE with an "undefined" - // |postRILMessage|, so we have to make sure that with an additional call - // to |JS_TypeOfValue|. + // Make sure that |postRILMessage| is a function. if (JSTYPE_FUNCTION == JS_TypeOfValue(aCx, val)) { return true; } diff --git a/js/ipc/WrapperOwner.cpp b/js/ipc/WrapperOwner.cpp index b701fecdba3e..71b27e59a5c9 100644 --- a/js/ipc/WrapperOwner.cpp +++ b/js/ipc/WrapperOwner.cpp @@ -336,7 +336,7 @@ CPOWToString(JSContext *cx, unsigned argc, Value *vp) CallArgs args = CallArgsFromVp(argc, vp); RootedObject callee(cx, &args.callee()); RootedValue cpowValue(cx); - if (!JS_LookupProperty(cx, callee, "__cpow__", &cpowValue)) + if (!JS_GetProperty(cx, callee, "__cpow__", &cpowValue)) return false; if (!cpowValue.isObject() || !IsCPOW(&cpowValue.toObject())) { diff --git a/js/xpconnect/src/XPCInlines.h b/js/xpconnect/src/XPCInlines.h index f6f28a4a64c2..6cb3800de3bf 100644 --- a/js/xpconnect/src/XPCInlines.h +++ b/js/xpconnect/src/XPCInlines.h @@ -545,12 +545,9 @@ XPCWrappedNative::SweepTearOffs() inline bool xpc_ForcePropertyResolve(JSContext* cx, JS::HandleObject obj, jsid idArg) { - JS::RootedValue prop(cx); JS::RootedId id(cx, idArg); - - if (!JS_LookupPropertyById(cx, obj, id, &prop)) - return false; - return true; + bool dummy; + return JS_HasPropertyById(cx, obj, id, &dummy); } inline jsid diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp index 944142278060..7cd922a4c41f 100644 --- a/js/xpconnect/wrappers/AccessCheck.cpp +++ b/js/xpconnect/wrappers/AccessCheck.cpp @@ -328,10 +328,19 @@ ExposedPropertiesOnly::check(JSContext *cx, HandleObject wrapper, HandleId id, W if (id == JSID_VOID) return true; - RootedValue exposedProps(cx); - if (!JS_LookupPropertyById(cx, wrappedObject, exposedPropsId, &exposedProps)) + Rooted desc(cx); + if (!JS_GetPropertyDescriptorById(cx, wrappedObject, exposedPropsId, &desc)) return false; + if (!desc.object()) + return false; + + if (desc.hasGetterOrSetter()) { + EnterAndThrow(cx, wrapper, "__exposedProps__ must be a value property"); + return false; + } + + RootedValue exposedProps(cx, desc.value()); if (exposedProps.isNullOrUndefined()) return false; @@ -349,7 +358,6 @@ ExposedPropertiesOnly::check(JSContext *cx, HandleObject wrapper, HandleId id, W Access access = NO_ACCESS; - Rooted desc(cx); if (!JS_GetPropertyDescriptorById(cx, hallpass, id, &desc)) { return false; // Error } From 9725dd6a7042e0bd202f56c24c073ba59357c7c8 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Fri, 12 Dec 2014 11:39:01 -0800 Subject: [PATCH 097/130] Bug 952863, Part 1: Require ECDHE for TLS False Start, r=keeler --HG-- extra : rebase_source : d983e440de5be7c097a3e0f4afe0de805c540919 --- security/manager/ssl/src/nsNSSCallbacks.cpp | 36 ++------------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/security/manager/ssl/src/nsNSSCallbacks.cpp b/security/manager/ssl/src/nsNSSCallbacks.cpp index 326ef8b4226d..3d9e59ba8084 100644 --- a/security/manager/ssl/src/nsNSSCallbacks.cpp +++ b/security/manager/ssl/src/nsNSSCallbacks.cpp @@ -41,9 +41,6 @@ namespace { // These bits are numbered so that the least subtle issues have higher values. // This should make it easier for us to interpret the results. const uint32_t NPN_NOT_NEGOTIATED = 64; -const uint32_t KEA_NOT_FORWARD_SECRET = 32; -const uint32_t KEA_NOT_SAME_AS_EXPECTED = 16; -const uint32_t KEA_NOT_ALLOWED = 8; const uint32_t POSSIBLE_VERSION_DOWNGRADE = 4; const uint32_t POSSIBLE_CIPHER_SUITE_DOWNGRADE = 2; const uint32_t KEA_NOT_SUPPORTED = 1; @@ -971,43 +968,14 @@ CanFalseStartCallback(PRFileDesc* fd, void* client_data, PRBool *canFalseStart) reasonsForNotFalseStarting |= POSSIBLE_VERSION_DOWNGRADE; } - // never do false start without one of these key exchange algorithms - if (cipherInfo.keaType != ssl_kea_rsa && - cipherInfo.keaType != ssl_kea_dh && - cipherInfo.keaType != ssl_kea_ecdh) { + // See bug 952863 for why ECDHE is allowed, but DHE (and RSA) are not. + if (cipherInfo.keaType != ssl_kea_ecdh) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - " "unsupported KEA %d\n", fd, static_cast(cipherInfo.keaType))); reasonsForNotFalseStarting |= KEA_NOT_SUPPORTED; } - // XXX: This assumes that all TLS_DH_* and TLS_ECDH_* cipher suites - // are disabled. - if (cipherInfo.keaType != ssl_kea_ecdh && - cipherInfo.keaType != ssl_kea_dh) { - if (helpers.mFalseStartRequireForwardSecrecy) { - PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, - ("CanFalseStartCallback [%p] failed - KEA used is %d, but " - "require-forward-secrecy configured.\n", fd, - static_cast(cipherInfo.keaType))); - reasonsForNotFalseStarting |= KEA_NOT_FORWARD_SECRET; - } else if (cipherInfo.keaType == ssl_kea_rsa) { - // Make sure we've seen the same kea from this host in the past, to limit - // the potential for downgrade attacks. - int16_t expected = infoObject->GetKEAExpected(); - if (cipherInfo.keaType != expected) { - PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, - ("CanFalseStartCallback [%p] failed - " - "KEA used is %d, expected %d\n", fd, - static_cast(cipherInfo.keaType), - static_cast(expected))); - reasonsForNotFalseStarting |= KEA_NOT_SAME_AS_EXPECTED; - } - } else { - reasonsForNotFalseStarting |= KEA_NOT_ALLOWED; - } - } - // Prevent downgrade attacks on the symmetric cipher. We do not allow CBC // mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt // design. See bug 1109766 for more details. From 72643b84e6de12c5ad407f1008b4b7a26cee972d Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Thu, 30 Oct 2014 16:48:31 -0700 Subject: [PATCH 098/130] Bug 1111392: Add tests for malformed name constraints where there are no names of the constrained type, r=keeler --HG-- extra : rebase_source : 048619553c7725eee1cb73df64faae8c8890c995 --- security/pkix/test/gtest/pkixnames_tests.cpp | 34 ++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/security/pkix/test/gtest/pkixnames_tests.cpp b/security/pkix/test/gtest/pkixnames_tests.cpp index cb89a4b89215..fdf83883e264 100644 --- a/security/pkix/test/gtest/pkixnames_tests.cpp +++ b/security/pkix/test/gtest/pkixnames_tests.cpp @@ -1716,6 +1716,40 @@ GeneralSubtree(const ByteString& base) static const NameConstraintParams NAME_CONSTRAINT_PARAMS[] = { + ///////////////////////////////////////////////////////////////////////////// + // XXX: Malformed name constraints for supported types of names are ignored + // when there are no names of that type to constrain. + { ByteString(), NO_SAN, + GeneralSubtree(DNSName("!")), + Success, Success + }, + { // DirectoryName constraints are an exception, because *every* certificate + // has at least one DirectoryName (tbsCertificate.subject). + ByteString(), NO_SAN, + GeneralSubtree(Name(ByteString(reinterpret_cast("!"), 1))), + Result::ERROR_BAD_DER, Result::ERROR_BAD_DER + }, + { ByteString(), NO_SAN, + GeneralSubtree(IPAddress(ipv4_constraint_truncated_bytes)), + Success, Success + }, + { ByteString(), NO_SAN, + GeneralSubtree(IPAddress(ipv4_constraint_overlong_bytes)), + Success, Success + }, + { ByteString(), NO_SAN, + GeneralSubtree(IPAddress(ipv6_constraint_truncated_bytes)), + Success, Success + }, + { ByteString(), NO_SAN, + GeneralSubtree(IPAddress(ipv6_constraint_overlong_bytes)), + Success, Success + }, + { ByteString(), NO_SAN, + GeneralSubtree(RFC822Name("!")), + Success, Success + }, + ///////////////////////////////////////////////////////////////////////////// // Edge cases of name constraint absolute vs. relative and subdomain matching // that are not clearly explained in RFC 5280. (See the long comment above From 13bd8b32e9068a27dd5de9a366dba7f8fa7abd70 Mon Sep 17 00:00:00 2001 From: Monica Chew Date: Fri, 7 Nov 2014 07:12:37 -0800 Subject: [PATCH 099/130] Bug 1032414: Always return failure in OnStopRequest on network error (r=gcp) --- .../nsUrlClassifierStreamUpdater.cpp | 35 ++++++++++++---- .../tests/unit/head_urlclassifier.js | 3 +- .../tests/unit/test_streamupdater.js | 40 +++++++++---------- 3 files changed, 50 insertions(+), 28 deletions(-) diff --git a/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp b/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp index 19493857ba1f..0a903360f544 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.cpp @@ -340,14 +340,19 @@ NS_IMETHODIMP nsUrlClassifierStreamUpdater::StreamFinished(nsresult status, uint32_t requestedDelay) { + // We are a service and may not be reset with Init between calls, so reset + // mBeganStream manually. + mBeganStream = false; LOG(("nsUrlClassifierStreamUpdater::StreamFinished [%x, %d]", status, requestedDelay)); if (NS_FAILED(status) || mPendingUpdates.Length() == 0) { // We're done. + LOG(("nsUrlClassifierStreamUpdater::Done [this=%p]", this)); mDBService->FinishUpdate(); return NS_OK; } // Wait the requested amount of time before starting a new stream. + // This appears to be a duplicate timer (see bug 1110891) nsresult rv; mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); if (NS_SUCCEEDED(rv)) { @@ -378,7 +383,12 @@ nsUrlClassifierStreamUpdater::UpdateSuccess(uint32_t requestedTimeout) nsAutoCString strTimeout; strTimeout.AppendInt(requestedTimeout); if (successCallback) { + LOG(("nsUrlClassifierStreamUpdater::UpdateSuccess callback [this=%p]", + this)); successCallback->HandleEvent(strTimeout); + } else { + LOG(("nsUrlClassifierStreamUpdater::UpdateSuccess skipping callback [this=%p]", + this)); } // Now fetch the next request LOG(("stream updater: calling into fetch next request")); @@ -452,19 +462,20 @@ nsUrlClassifierStreamUpdater::OnStartRequest(nsIRequest *request, nsCOMPtr httpChannel = do_QueryInterface(request); if (httpChannel) { rv = httpChannel->GetStatus(&status); + LOG(("nsUrlClassifierStreamUpdater::OnStartRequest (status=%x, this=%p)", + status, this)); NS_ENSURE_SUCCESS(rv, rv); - if (NS_ERROR_CONNECTION_REFUSED == status || - NS_ERROR_NET_TIMEOUT == status) { + if (NS_FAILED(status)) { // Assume we're overloading the server and trigger backoff. downloadError = true; - } - - if (NS_SUCCEEDED(status)) { + } else { bool succeeded = false; rv = httpChannel->GetRequestSucceeded(&succeeded); NS_ENSURE_SUCCESS(rv, rv); + LOG(("nsUrlClassifierStreamUpdater::OnStartRequest (%s)", succeeded ? + "succeeded" : "failed")); if (!succeeded) { // 404 or other error, pass error status back LOG(("HTTP request returned failure code.")); @@ -481,11 +492,13 @@ nsUrlClassifierStreamUpdater::OnStartRequest(nsIRequest *request, } if (downloadError) { + LOG(("nsUrlClassifierStreamUpdater::Download error [this=%p]", this)); mDownloadErrorCallback->HandleEvent(strStatus); mDownloadError = true; status = NS_ERROR_ABORT; } else if (NS_SUCCEEDED(status)) { mBeganStream = true; + LOG(("nsUrlClassifierStreamUpdater::Beginning stream [this=%p]", this)); rv = mDBService->BeginStream(mStreamTable); NS_ENSURE_SUCCESS(rv, rv); } @@ -528,7 +541,8 @@ nsUrlClassifierStreamUpdater::OnStopRequest(nsIRequest *request, nsISupports* co if (!mDBService) return NS_ERROR_NOT_INITIALIZED; - LOG(("OnStopRequest (status %x)", aStatus)); + LOG(("OnStopRequest (status %x, beganStream %s, this=%p)", aStatus, + mBeganStream ? "true" : "false", this)); nsresult rv; @@ -536,10 +550,12 @@ nsUrlClassifierStreamUpdater::OnStopRequest(nsIRequest *request, nsISupports* co // Success, finish this stream and move on to the next. rv = mDBService->FinishStream(); } else if (mBeganStream) { + LOG(("OnStopRequest::Canceling update [this=%p]", this)); // We began this stream and couldn't finish it. We have to cancel the // update, it's not in a consistent state. rv = mDBService->CancelUpdate(); } else { + LOG(("OnStopRequest::Finishing update [this=%p]", this)); // The fetch failed, but we didn't start the stream (probably a // server or connection error). We can commit what we've applied // so far, and request again later. @@ -548,7 +564,12 @@ nsUrlClassifierStreamUpdater::OnStopRequest(nsIRequest *request, nsISupports* co mChannel = nullptr; - return rv; + // If the fetch failed, return the network status rather than NS_OK, the + // result of finishing a possibly-empty update + if (NS_SUCCEEDED(aStatus)) { + return rv; + } + return aStatus; } /////////////////////////////////////////////////////////////////////////////// diff --git a/toolkit/components/url-classifier/tests/unit/head_urlclassifier.js b/toolkit/components/url-classifier/tests/unit/head_urlclassifier.js index 69c249640bec..69ecf2fda691 100644 --- a/toolkit/components/url-classifier/tests/unit/head_urlclassifier.js +++ b/toolkit/components/url-classifier/tests/unit/head_urlclassifier.js @@ -176,8 +176,9 @@ function doErrorUpdate(tables, success, failure) { function doStreamUpdate(updateText, success, failure, downloadFailure) { var dataUpdate = "data:," + encodeURIComponent(updateText); - if (!downloadFailure) + if (!downloadFailure) { downloadFailure = failure; + } streamUpdater.downloadUpdates("test-phish-simple,test-malware-simple", "", dataUpdate, success, failure, downloadFailure); diff --git a/toolkit/components/url-classifier/tests/unit/test_streamupdater.js b/toolkit/components/url-classifier/tests/unit/test_streamupdater.js index c377a8c67e58..9ba73a17e053 100644 --- a/toolkit/components/url-classifier/tests/unit/test_streamupdater.js +++ b/toolkit/components/url-classifier/tests/unit/test_streamupdater.js @@ -7,6 +7,8 @@ function doTest(updates, assertions, expectError) } } +// Never use the same URLs for multiple tests, because we aren't guaranteed +// to reset the database between tests. function testFillDb() { var add1Urls = [ "zaz.com/a", "yxz.com/c" ]; @@ -27,9 +29,9 @@ function testFillDb() { } function testSimpleForward() { - var add1Urls = [ "foo.com/a", "bar.com/c" ]; - var add2Urls = [ "foo.com/b" ]; - var add3Urls = [ "bar.com/d" ]; + var add1Urls = [ "foo-simple.com/a", "bar-simple.com/c" ]; + var add2Urls = [ "foo-simple.com/b" ]; + var add3Urls = [ "bar-simple.com/d" ]; var update = "n:1000\n"; update += "i:test-phish-simple\n"; @@ -60,8 +62,8 @@ function testSimpleForward() { // Make sure that a nested forward (a forward within a forward) causes // the update to fail. function testNestedForward() { - var add1Urls = [ "foo.com/a", "bar.com/c" ]; - var add2Urls = [ "foo.com/b" ]; + var add1Urls = [ "foo-nested.com/a", "bar-nested.com/c" ]; + var add2Urls = [ "foo-nested.com/b" ]; var update = "n:1000\n"; update += "i:test-phish-simple\n"; @@ -91,46 +93,44 @@ function testNestedForward() { // An invalid URL forward causes the update to fail. function testInvalidUrlForward() { - var add1Urls = [ "foo.com/a", "bar.com/c" ]; + var add1Urls = [ "foo-invalid.com/a", "bar-invalid.com/c" ]; var update = buildPhishingUpdate( [{ "chunkNum" : 1, "urls" : add1Urls }]); update += "u:asdf://blah/blah\n"; // invalid URL scheme - // The first part of the update should have succeeded. - + // add1Urls is present, but that is an artifact of the way we do the test. var assertions = { - "tableData" : "test-phish-simple;a:1", + "tableData" : "", "urlsExist" : add1Urls }; - doTest([update], assertions, false); + doTest([update], assertions, true); } // A failed network request causes the update to fail. function testErrorUrlForward() { - var add1Urls = [ "foo.com/a", "bar.com/c" ]; + var add1Urls = [ "foo-forward.com/a", "bar-forward.com/c" ]; var update = buildPhishingUpdate( [{ "chunkNum" : 1, "urls" : add1Urls }]); update += "u:http://test.invalid/asdf/asdf\n"; // invalid URL scheme - // The first part of the update should have succeeded - + // add1Urls is present, but that is an artifact of the way we do the test. var assertions = { - "tableData" : "test-phish-simple;a:1", + "tableData" : "", "urlsExist" : add1Urls }; - doTest([update], assertions, false); + doTest([update], assertions, true); } function testMultipleTables() { - var add1Urls = [ "foo.com/a", "bar.com/c" ]; - var add2Urls = [ "foo.com/b" ]; - var add3Urls = [ "bar.com/d" ]; + var add1Urls = [ "foo-multiple.com/a", "bar-multiple.com/c" ]; + var add2Urls = [ "foo-multiple.com/b" ]; + var add3Urls = [ "bar-multiple.com/d" ]; var update = "n:1000\n"; update += "i:test-phish-simple\n"; @@ -179,7 +179,7 @@ QueryInterface: function(iid) // Tests a database reset request. function testReset() { - var addUrls1 = [ "foo.com/a", "foo.com/b" ]; + var addUrls1 = [ "foo-reset.com/a", "foo-reset.com/b" ]; var update1 = buildPhishingUpdate( [ { "chunkNum" : 1, @@ -188,7 +188,7 @@ function testReset() { var update2 = "n:1000\nr:pleasereset\n"; - var addUrls3 = [ "bar.com/a", "bar.com/b" ]; + var addUrls3 = [ "bar-reset.com/a", "bar-reset.com/b" ]; var update3 = buildPhishingUpdate( [ { "chunkNum" : 3, From 0ddcff51a2d1a420b2d2488fd65b5d2d55d85381 Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Mon, 24 Nov 2014 12:05:45 -0800 Subject: [PATCH 100/130] Bug 1068349 - IPC message handlers that return false cause the child process to crash without a crash report. r=ted. --HG-- extra : rebase_source : a754391d6c41de7de82c3c697b684a7ceae9fff7 extra : amend_source : a9e1ba42ca02a69fe16265461f4bac3fdc3bf758 --- dom/ipc/ContentParent.cpp | 44 ++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index aacf4b449445..aa77f89bd4cd 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -213,6 +213,10 @@ static const char* sClipboardTextFlavors[] = { kUnicodeMime }; using base::ChildPrivileges; using base::KillProcess; + +#ifdef MOZ_CRASHREPORTER +using namespace CrashReporter; +#endif using namespace mozilla::dom::bluetooth; using namespace mozilla::dom::cellbroadcast; using namespace mozilla::dom::devicestorage; @@ -1774,7 +1778,16 @@ ContentParent::ActorDestroy(ActorDestroyReason why) NS_ConvertUTF16toUTF8(mAppManifestURL)); } - crashReporter->GenerateCrashReport(this, nullptr); + if (mCalledKillHard) { + // We killed the child with KillHard, so two minidumps should already + // exist - one for the content process, and one for the browser process. + // The "main" minidump of this crash report is the content processes, + // and we use GenerateChildData to annotate our crash report with + // information about the child process. + crashReporter->GenerateChildData(nullptr); + } else { + crashReporter->GenerateCrashReport(this, nullptr); + } nsAutoString dumpID(crashReporter->ChildDumpID()); props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID); @@ -3049,10 +3062,31 @@ ContentParent::KillHard() } mCalledKillHard = true; mForceKillTask = nullptr; - // This ensures the process is eventually killed, but doesn't - // immediately KILLITWITHFIRE because we want to get a minidump if - // possible. After a timeout though, the process is forceably - // killed. + +#ifdef MOZ_CRASHREPORTER + if (ManagedPCrashReporterParent().Length() > 0) { + CrashReporterParent* crashReporter = + static_cast(ManagedPCrashReporterParent()[0]); + + // We're about to kill the child process associated with this + // ContentParent. Something has gone wrong to get us here, + // so we generate a minidump to be potentially submitted in + // a crash report. ContentParent::ActorDestroy is where the + // actual report gets generated, once the child process has + // finally died. + if (crashReporter->GeneratePairedMinidump(this)) { + // GeneratePairedMinidump created two minidumps for us - the main + // one is for the content process we're about to kill, and the other + // one is for the main browser process. That second one is the extra + // minidump tagging along, so we have to tell the crash reporter that + // it exists and is being appended. + nsAutoCString additionalDumps("browser"); + crashReporter->AnnotateCrashReport( + NS_LITERAL_CSTRING("additional_minidumps"), + additionalDumps); + } + } +#endif if (!KillProcess(OtherProcess(), 1, false)) { NS_WARNING("failed to kill subprocess!"); } From 69a6c5091b6ca0a473461f46391e9a7404d577e5 Mon Sep 17 00:00:00 2001 From: Gavin Sharp Date: Mon, 8 Dec 2014 13:54:17 -0800 Subject: [PATCH 101/130] Bug 1108627: market-specific search defaults broke default engine behavior for Fennec, so make it desktop Firefox-only, r=dolske --- browser/app/profile/firefox.js | 2 ++ toolkit/components/search/nsSearchService.js | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 3c04d2df4262..c99a1032ef06 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -404,6 +404,8 @@ pref("browser.search.order.1", "chrome://browser-region/locale/re pref("browser.search.order.2", "chrome://browser-region/locale/region.properties"); pref("browser.search.order.3", "chrome://browser-region/locale/region.properties"); +// Market-specific search defaults (US market only) +pref("browser.search.geoSpecificDefaults", true); pref("browser.search.defaultenginename.US", "data:text/plain,browser.search.defaultenginename.US=Yahoo"); pref("browser.search.order.US.1", "data:text/plain,browser.search.order.US.1=Yahoo"); pref("browser.search.order.US.2", "data:text/plain,browser.search.order.US.2=Google"); diff --git a/toolkit/components/search/nsSearchService.js b/toolkit/components/search/nsSearchService.js index ceb59ff122fd..775e1af1e96f 100644 --- a/toolkit/components/search/nsSearchService.js +++ b/toolkit/components/search/nsSearchService.js @@ -404,6 +404,15 @@ loadListener.prototype = { // Hacky method that tries to determine if this user is in a US geography, and // using an en-US build. function getIsUS() { + let geoSpecificDefaults = false; + try { + geoSpecificDefaults = Services.prefs.getBoolPref("browser.search.geoSpecificDefaults"); + } catch(e) {} + + if (!geoSpecificDefaults) { + return false; + } + // If we've set the pref before, just return that result. let cachePref = "browser.search.isUS"; try { From ee96576d7be98e1c51ef8c60a8027455e0edbf03 Mon Sep 17 00:00:00 2001 From: Dan Glastonbury Date: Tue, 16 Dec 2014 15:20:15 +1000 Subject: [PATCH 102/130] Bug 1048747 - [WebGL2] Implement uniform block/buffer. r=jgilbert, r=smaug --HG-- extra : rebase_source : 0ac73b719bf63b216bc593959385d162a4e8b0cd extra : source : 63eebe8ca90770461267b8a365392db8e091da55 --- dom/canvas/WebGL2Context.h | 25 +- dom/canvas/WebGL2ContextUniforms.cpp | 306 +++++++++++++++++++---- dom/webidl/WebGL2RenderingContext.webidl | 8 +- 3 files changed, 287 insertions(+), 52 deletions(-) diff --git a/dom/canvas/WebGL2Context.h b/dom/canvas/WebGL2Context.h index 55baf3aa1b1c..41eb93b52ccb 100644 --- a/dom/canvas/WebGL2Context.h +++ b/dom/canvas/WebGL2Context.h @@ -14,6 +14,10 @@ class WebGLSampler; class WebGLSync; class WebGLTransformFeedback; class WebGLVertexArrayObject; +namespace dom { +class OwningUnsignedLongOrUint32ArrayOrBoolean; +class OwningWebGLBufferOrLongLong; +} class WebGL2Context : public WebGLContext @@ -231,14 +235,23 @@ public: void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer); void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, GLintptr offset, GLsizeiptr size); */ - void GetIndexedParameter(JSContext*, GLenum target, GLuint index, JS::MutableHandleValue retval); - void GetUniformIndices(WebGLProgram* program, const dom::Sequence& uniformNames, dom::Nullable< nsTArray >& retval); - void GetActiveUniforms(WebGLProgram* program, const dom::Sequence& uniformIndices, GLenum pname, + void GetIndexedParameter(GLenum target, GLuint index, + dom::Nullable& retval); + void GetUniformIndices(WebGLProgram* program, + const dom::Sequence& uniformNames, + dom::Nullable< nsTArray >& retval); + void GetActiveUniforms(WebGLProgram* program, + const dom::Sequence& uniformIndices, GLenum pname, dom::Nullable< nsTArray >& retval); GLuint GetUniformBlockIndex(WebGLProgram* program, const nsAString& uniformBlockName); - void GetActiveUniformBlockParameter(JSContext*, WebGLProgram* program, GLuint uniformBlockIndex, GLenum pname, JS::MutableHandleValue retval); - void GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBlockIndex, dom::DOMString& retval); - void UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); + void GetActiveUniformBlockParameter(JSContext*, WebGLProgram* program, + GLuint uniformBlockIndex, GLenum pname, + dom::Nullable& retval, + ErrorResult& rv); + void GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBlockIndex, + nsAString& retval); + void UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockIndex, + GLuint uniformBlockBinding); // ------------------------------------------------------------------------- diff --git a/dom/canvas/WebGL2ContextUniforms.cpp b/dom/canvas/WebGL2ContextUniforms.cpp index b803bddf6c78..6f9e80b18f9e 100644 --- a/dom/canvas/WebGL2ContextUniforms.cpp +++ b/dom/canvas/WebGL2ContextUniforms.cpp @@ -5,8 +5,11 @@ #include "WebGL2Context.h" #include "GLContext.h" +#include "WebGLContext.h" +#include "WebGLProgram.h" #include "WebGLVertexArray.h" #include "WebGLVertexAttribData.h" +#include "mozilla/dom/WebGL2RenderingContextBinding.h" using namespace mozilla; using namespace mozilla::dom; @@ -30,38 +33,39 @@ GLfloat PuntToFloat(GLuint u) } bool -WebGL2Context::ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) +WebGL2Context::ValidateAttribPointerType(bool integerMode, GLenum type, + GLsizei* out_alignment, const char* info) { - MOZ_ASSERT(alignment); + MOZ_ASSERT(out_alignment); switch (type) { case LOCAL_GL_BYTE: case LOCAL_GL_UNSIGNED_BYTE: - *alignment = 1; + *out_alignment = 1; return true; case LOCAL_GL_SHORT: case LOCAL_GL_UNSIGNED_SHORT: - *alignment = 2; + *out_alignment = 2; return true; case LOCAL_GL_INT: case LOCAL_GL_UNSIGNED_INT: - *alignment = 4; + *out_alignment = 4; return true; } if (!integerMode) { switch (type) { case LOCAL_GL_HALF_FLOAT: - *alignment = 2; + *out_alignment = 2; return true; case LOCAL_GL_FLOAT: case LOCAL_GL_FIXED: case LOCAL_GL_INT_2_10_10_10_REV: case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV: - *alignment = 4; + *out_alignment = 4; return true; } } @@ -74,7 +78,8 @@ WebGL2Context::ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* // Uniforms and attributes void -WebGL2Context::VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset) +WebGL2Context::VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, + GLintptr offset) { if (IsContextLost()) return; @@ -82,8 +87,11 @@ WebGL2Context::VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsiz if (!ValidateAttribIndex(index, "vertexAttribIPointer")) return; - if (!ValidateAttribPointer(true, index, size, type, LOCAL_GL_FALSE, stride, offset, "vertexAttribIPointer")) + if (!ValidateAttribPointer(true, index, size, type, LOCAL_GL_FALSE, stride, offset, + "vertexAttribIPointer")) + { return; + } MOZ_ASSERT(mBoundVertexArray); mBoundVertexArray->EnsureAttrib(index); @@ -123,103 +131,120 @@ WebGL2Context::Uniform3ui(WebGLUniformLocation* location, GLuint v0, GLuint v1, } void -WebGL2Context::Uniform4ui(WebGLUniformLocation* location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +WebGL2Context::Uniform4ui(WebGLUniformLocation* location, GLuint v0, GLuint v1, + GLuint v2, GLuint v3) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::Uniform1uiv(WebGLUniformLocation* location, const dom::Sequence& value) +WebGL2Context::Uniform1uiv(WebGLUniformLocation* location, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::Uniform2uiv(WebGLUniformLocation* location, const dom::Sequence& value) +WebGL2Context::Uniform2uiv(WebGLUniformLocation* location, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::Uniform3uiv(WebGLUniformLocation* location, const dom::Sequence& value) +WebGL2Context::Uniform3uiv(WebGLUniformLocation* location, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::Uniform4uiv(WebGLUniformLocation* location, const dom::Sequence& value) +WebGL2Context::Uniform4uiv(WebGLUniformLocation* location, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix2x3fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value) +WebGL2Context::UniformMatrix2x3fv(WebGLUniformLocation* location, bool transpose, + const dom::Float32Array& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix2x3fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence& value) +WebGL2Context::UniformMatrix2x3fv(WebGLUniformLocation* location, bool transpose, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix3x2fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value) +WebGL2Context::UniformMatrix3x2fv(WebGLUniformLocation* location, bool transpose, + const dom::Float32Array& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix3x2fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence& value) +WebGL2Context::UniformMatrix3x2fv(WebGLUniformLocation* location, bool transpose, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix2x4fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value) +WebGL2Context::UniformMatrix2x4fv(WebGLUniformLocation* location, bool transpose, + const dom::Float32Array& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix2x4fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence& value) +WebGL2Context::UniformMatrix2x4fv(WebGLUniformLocation* location, bool transpose, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix4x2fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value) +WebGL2Context::UniformMatrix4x2fv(WebGLUniformLocation* location, bool transpose, + const dom::Float32Array& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix4x2fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence& value) +WebGL2Context::UniformMatrix4x2fv(WebGLUniformLocation* location, bool transpose, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix3x4fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value) +WebGL2Context::UniformMatrix3x4fv(WebGLUniformLocation* location, bool transpose, + const dom::Float32Array& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix3x4fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence& value) +WebGL2Context::UniformMatrix3x4fv(WebGLUniformLocation* location, bool transpose, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value) +WebGL2Context::UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, + const dom::Float32Array& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence& value) +WebGL2Context::UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } @@ -309,13 +334,51 @@ WebGL2Context::VertexAttribI4uiv(GLuint index, const dom::Sequence& v) // TODO(djg): Implemented in WebGLContext /* void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer); - void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, GLintptr offset, GLsizeiptr size); + void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, + GLintptr offset, GLsizeiptr size); */ +/* This doesn't belong here. It's part of state querying */ void -WebGL2Context::GetIndexedParameter(JSContext*, GLenum target, GLuint index, JS::MutableHandleValue retval) +WebGL2Context::GetIndexedParameter(GLenum target, GLuint index, + dom::Nullable& retval) { - MOZ_CRASH("Not Implemented."); + retval.SetNull(); + if (IsContextLost()) + return; + + GLint64 data = 0; + + MakeContextCurrent(); + + switch (target) { + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + if (index >= mGLMaxTransformFeedbackSeparateAttribs) + return ErrorInvalidValue("getIndexedParameter: index should be less than " + "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS"); + + retval.SetValue().SetAsWebGLBuffer() = + mBoundTransformFeedbackBuffers[index].get(); + return; + + case LOCAL_GL_UNIFORM_BUFFER_BINDING: + if (index >= mGLMaxUniformBufferBindings) + return ErrorInvalidValue("getIndexedParameter: index should be than " + "MAX_UNIFORM_BUFFER_BINDINGS"); + + retval.SetValue().SetAsWebGLBuffer() = mBoundUniformBuffers[index].get(); + return; + + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_START: + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + case LOCAL_GL_UNIFORM_BUFFER_START: + case LOCAL_GL_UNIFORM_BUFFER_SIZE: + gl->fGetInteger64i_v(target, index, &data); + retval.SetValue().SetAsLongLong() = data; + return; + } + + ErrorInvalidEnumInfo("getIndexedParameter: target", target); } void @@ -323,7 +386,32 @@ WebGL2Context::GetUniformIndices(WebGLProgram* program, const dom::Sequence& uniformNames, dom::Nullable< nsTArray >& retval) { - MOZ_CRASH("Not Implemented."); + retval.SetNull(); + if (IsContextLost()) + return; + + if (!ValidateObject("getUniformIndices: program", program)) + return; + + if (!uniformNames.Length()) + return; + + GLuint progname = program->GLName(); + size_t count = uniformNames.Length(); + nsTArray& arr = retval.SetValue(); + + MakeContextCurrent(); + + for (size_t n = 0; n < count; n++) { + NS_LossyConvertUTF16toASCII name(uniformNames[n]); + // const GLchar* glname = name.get(); + const GLchar* glname = nullptr; + name.BeginReading(glname); + + GLuint index = 0; + gl->fGetUniformIndices(progname, 1, &glname, &index); + arr.AppendElement(index); + } } void @@ -332,32 +420,162 @@ WebGL2Context::GetActiveUniforms(WebGLProgram* program, GLenum pname, dom::Nullable< nsTArray >& retval) { - MOZ_CRASH("Not Implemented."); + retval.SetNull(); + if (IsContextLost()) + return; + + if (!ValidateObject("getActiveUniforms: program", program)) + return; + + size_t count = uniformIndices.Length(); + if (!count) + return; + + GLuint progname = program->GLName(); + nsTArray& arr = retval.SetValue(); + arr.SetLength(count); + + MakeContextCurrent(); + gl->fGetActiveUniformsiv(progname, count, uniformIndices.Elements(), pname, + arr.Elements()); } GLuint -WebGL2Context::GetUniformBlockIndex(WebGLProgram* program, const nsAString& uniformBlockName) +WebGL2Context::GetUniformBlockIndex(WebGLProgram* program, + const nsAString& uniformBlockName) { - MOZ_CRASH("Not Implemented."); - return 0; + if (IsContextLost()) + return 0; + + if (!ValidateObject("getUniformBlockIndex: program", program)) + return 0; + + if (!ValidateGLSLVariableName(uniformBlockName, "getUniformBlockIndex")) + return 0; + + NS_LossyConvertUTF16toASCII cname(uniformBlockName); + nsCString mappedName; + program->MapIdentifier(cname, &mappedName); + + GLuint progname = program->GLName(); + + MakeContextCurrent(); + return gl->fGetUniformBlockIndex(progname, mappedName.get()); +} + +static bool +GetUniformBlockActiveUniforms(gl::GLContext* gl, JSContext* cx, + WebGL2Context* owner, GLuint progname, + GLuint uniformBlockIndex, + JS::MutableHandleObject out_array) +{ + GLint length = 0; + gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex, + LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &length); + JS::RootedObject obj(cx, Uint32Array::Create(cx, owner, length, nullptr)); + if (!obj) + return false; + + Uint32Array result; + DebugOnly inited = result.Init(obj); + MOZ_ASSERT(inited); + result.ComputeLengthAndData(); + gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex, + LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, + (GLint*) result.Data()); + + out_array.set(obj); + return true; } void -WebGL2Context::GetActiveUniformBlockParameter(JSContext*, WebGLProgram* program, +WebGL2Context::GetActiveUniformBlockParameter(JSContext* cx, WebGLProgram* program, GLuint uniformBlockIndex, GLenum pname, - JS::MutableHandleValue retval) + Nullable& retval, + ErrorResult& rv) { - MOZ_CRASH("Not Implemented."); + retval.SetNull(); + if (IsContextLost()) + return; + + if (!ValidateObject("getActiveUniformBlockParameter: program", program)) + return; + + GLuint progname = program->GLName(); + GLint param = 0; + + MakeContextCurrent(); + + switch(pname) { + case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: + case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: + gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex, pname, ¶m); + retval.SetValue().SetAsBoolean() = (param != 0); + return; + + case LOCAL_GL_UNIFORM_BLOCK_BINDING: + case LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE: + case LOCAL_GL_UNIFORM_BLOCK_NAME_LENGTH: + case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: + gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex, pname, ¶m); + retval.SetValue().SetAsUnsignedLong() = param; + return; + + case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: + JS::RootedObject array(cx); + if (!GetUniformBlockActiveUniforms(gl, cx, this, progname, uniformBlockIndex, + &array)) + { + rv = NS_ERROR_OUT_OF_MEMORY; + return; + } + + DebugOnly inited = retval.SetValue().SetAsUint32Array().Init(array); + MOZ_ASSERT(inited); + + return; + } + + ErrorInvalidEnumInfo("getActiveUniformBlockParameter: parameter", pname); } -void -WebGL2Context::GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBlockIndex, dom::DOMString& retval) -{ - MOZ_CRASH("Not Implemented."); -} +#define WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH 256 void -WebGL2Context::UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) +WebGL2Context::GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBlockIndex, + nsAString& retval) { - MOZ_CRASH("Not Implemented."); + if (IsContextLost()) + return; + + if (!ValidateObject("getActiveUniformBlockName: program", program)) + return; + + GLuint progname = program->GLName(); + GLchar nameBuffer[WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH]; + GLsizei length = 0; + + MakeContextCurrent(); + gl->fGetActiveUniformBlockName(progname, uniformBlockIndex, + WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH, &length, + nameBuffer); + retval.Assign(NS_ConvertASCIItoUTF16(nsDependentCString(nameBuffer))); +} + +#undef WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH + +void +WebGL2Context::UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockIndex, + GLuint uniformBlockBinding) +{ + if (IsContextLost()) + return; + + if (!ValidateObject("uniformBlockBinding: program", program)) + return; + + GLuint progname = program->GLName(); + + MakeContextCurrent(); + gl->fUniformBlockBinding(progname, uniformBlockIndex, uniformBlockBinding); } diff --git a/dom/webidl/WebGL2RenderingContext.webidl b/dom/webidl/WebGL2RenderingContext.webidl index b981883d7146..93719a627a51 100644 --- a/dom/webidl/WebGL2RenderingContext.webidl +++ b/dom/webidl/WebGL2RenderingContext.webidl @@ -454,11 +454,15 @@ interface WebGL2RenderingContext : WebGLRenderingContext /* Uniform Buffer Objects and Transform Feedback Buffers */ void bindBufferBase(GLenum target, GLuint index, WebGLBuffer? buffer); void bindBufferRange(GLenum target, GLuint index, WebGLBuffer? buffer, GLintptr offset, GLsizeiptr size); - any getIndexedParameter(GLenum target, GLuint index); + // Return from getIndexedParameter is WebGLBuffer or GLintptr or GLsizeiptr) but + // GLintptr and GLsizeiptr are the same underlying type of long long, so only specify + // GLintptr here, otherwise interface generator returns error. + (WebGLBuffer or GLintptr)? getIndexedParameter(GLenum target, GLuint index); sequence? getUniformIndices(WebGLProgram? program, sequence uniformNames); sequence? getActiveUniforms(WebGLProgram? program, sequence uniformIndices, GLenum pname); GLuint getUniformBlockIndex(WebGLProgram? program, DOMString uniformBlockName); - any getActiveUniformBlockParameter(WebGLProgram? program, GLuint uniformBlockIndex, GLenum pname); + [Throws] + (GLuint or Uint32Array or GLboolean)? getActiveUniformBlockParameter(WebGLProgram? program, GLuint uniformBlockIndex, GLenum pname); DOMString? getActiveUniformBlockName(WebGLProgram? program, GLuint uniformBlockIndex); void uniformBlockBinding(WebGLProgram? program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); From 1cc829126d0b25d79c261ff209974b6df98ac12c Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Tue, 16 Dec 2014 15:44:15 -0800 Subject: [PATCH 103/130] Backed out changeset 50d264e4ffa4 (bug 1052123) for android/linux reftest failures --- layout/generic/nsFrameState.cpp | 1 - layout/generic/nsFrameStateBits.h | 9 ----- layout/generic/nsRubyBaseContainerFrame.cpp | 32 ++--------------- layout/generic/nsRubyTextFrame.cpp | 34 ------------------ layout/generic/nsRubyTextFrame.h | 9 ----- .../reftests/css-ruby/autohiding-1-ref.html | 14 -------- layout/reftests/css-ruby/autohiding-1.html | 14 -------- .../reftests/css-ruby/autohiding-2-ref.html | 26 -------------- layout/reftests/css-ruby/autohiding-2.html | 36 ------------------- .../reftests/css-ruby/autohiding-3-ref.html | 17 --------- layout/reftests/css-ruby/autohiding-3.html | 17 --------- layout/reftests/css-ruby/reftest.list | 3 -- 12 files changed, 3 insertions(+), 209 deletions(-) delete mode 100644 layout/reftests/css-ruby/autohiding-1-ref.html delete mode 100644 layout/reftests/css-ruby/autohiding-1.html delete mode 100644 layout/reftests/css-ruby/autohiding-2-ref.html delete mode 100644 layout/reftests/css-ruby/autohiding-2.html delete mode 100644 layout/reftests/css-ruby/autohiding-3-ref.html delete mode 100644 layout/reftests/css-ruby/autohiding-3.html diff --git a/layout/generic/nsFrameState.cpp b/layout/generic/nsFrameState.cpp index 6a58ac2e5853..61ee67d442bf 100644 --- a/layout/generic/nsFrameState.cpp +++ b/layout/generic/nsFrameState.cpp @@ -17,7 +17,6 @@ #include "nsImageFrame.h" #include "nsInlineFrame.h" #include "nsPlaceholderFrame.h" -#include "nsRubyTextFrame.h" #include "nsSVGContainerFrame.h" #include "nsTableCellFrame.h" #include "nsTableRowFrame.h" diff --git a/layout/generic/nsFrameStateBits.h b/layout/generic/nsFrameStateBits.h index ebe65fb40fed..e2c647c833e7 100644 --- a/layout/generic/nsFrameStateBits.h +++ b/layout/generic/nsFrameStateBits.h @@ -512,15 +512,6 @@ FRAME_STATE_GROUP(Inline, nsInlineFrame) FRAME_STATE_BIT(Inline, 21, NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) FRAME_STATE_BIT(Inline, 22, NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST) FRAME_STATE_BIT(Inline, 23, NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST) -// nsRubyTextFrame inherits from nsInlineFrame - - -// == Frame state bits that apply to ruby text frames ========================= - -FRAME_STATE_GROUP(RubyText, nsRubyTextFrame) - -// inherits from nsInlineFrame -FRAME_STATE_BIT(RubyText, 24, NS_RUBY_TEXT_FRAME_AUTOHIDE) // == Frame state bits that apply to placeholder frames ======================= diff --git a/layout/generic/nsRubyBaseContainerFrame.cpp b/layout/generic/nsRubyBaseContainerFrame.cpp index 123a4cc82efb..01e3b623e8ed 100644 --- a/layout/generic/nsRubyBaseContainerFrame.cpp +++ b/layout/generic/nsRubyBaseContainerFrame.cpp @@ -7,7 +7,6 @@ /* rendering object for CSS "display: ruby-base-container" */ #include "nsRubyBaseContainerFrame.h" -#include "nsContentUtils.h" #include "nsLineLayout.h" #include "nsPresContext.h" #include "nsStyleContext.h" @@ -524,40 +523,15 @@ nsRubyBaseContainerFrame::ReflowOnePair(nsPresContext* aPresContext, nscoord istart = aReflowState.mLineLayout->GetCurrentICoord(); nscoord pairISize = 0; - nsAutoString baseText; - if (aBaseFrame) { - if (!nsContentUtils::GetNodeTextContent(aBaseFrame->GetContent(), - true, baseText)) { - NS_RUNTIMEABORT("OOM"); - } - } - // Reflow text frames for (uint32_t i = 0; i < rtcCount; i++) { - nsIFrame* textFrame = aTextFrames[i]; - if (textFrame) { - MOZ_ASSERT(textFrame->GetType() == nsGkAtoms::rubyTextFrame); - nsAutoString annotationText; - if (!nsContentUtils::GetNodeTextContent(textFrame->GetContent(), - true, annotationText)) { - NS_RUNTIMEABORT("OOM"); - } - // Per CSS Ruby spec, the content comparison for auto-hiding - // takes place prior to white spaces collapsing (white-space) - // and text transformation (text-transform), and ignores elements - // (considers only the textContent of the boxes). Which means - // using the content tree text comparison is correct. - if (annotationText.Equals(baseText)) { - textFrame->AddStateBits(NS_RUBY_TEXT_FRAME_AUTOHIDE); - } else { - textFrame->RemoveStateBits(NS_RUBY_TEXT_FRAME_AUTOHIDE); - } - + if (aTextFrames[i]) { + MOZ_ASSERT(aTextFrames[i]->GetType() == nsGkAtoms::rubyTextFrame); nsReflowStatus reflowStatus; nsHTMLReflowMetrics metrics(*aReflowStates[i]); bool pushedFrame; - aReflowStates[i]->mLineLayout->ReflowFrame(textFrame, reflowStatus, + aReflowStates[i]->mLineLayout->ReflowFrame(aTextFrames[i], reflowStatus, &metrics, pushedFrame); if (NS_INLINE_IS_BREAK(reflowStatus)) { // If any breaking occurs when reflowing a ruby text frame, diff --git a/layout/generic/nsRubyTextFrame.cpp b/layout/generic/nsRubyTextFrame.cpp index 707a9c01ab51..c71686241f87 100644 --- a/layout/generic/nsRubyTextFrame.cpp +++ b/layout/generic/nsRubyTextFrame.cpp @@ -60,37 +60,3 @@ nsRubyTextFrame::IsFrameOfType(uint32_t aFlags) const } return nsRubyTextFrameSuper::IsFrameOfType(aFlags); } - - -/* virtual */ void -nsRubyTextFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, - const nsRect& aDirtyRect, - const nsDisplayListSet& aLists) -{ - if (GetStateBits() & NS_RUBY_TEXT_FRAME_AUTOHIDE) { - return; - } - - nsRubyTextFrameSuper::BuildDisplayList(aBuilder, aDirtyRect, aLists); -} - -/* virtual */ void -nsRubyTextFrame::Reflow(nsPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - // Even if we want to hide this frame, we have to reflow it first. - // If we leave it dirty, changes to its content will never be - // propagated to the ancestors, then it won't be displayed even if - // the content is no longer the same, until next reflow triggered by - // some other change. In general, we always reflow all the frames we - // created. There might be other problems if we don't do that. - nsRubyTextFrameSuper::Reflow(aPresContext, aDesiredSize, - aReflowState, aStatus); - - if (GetStateBits() & NS_RUBY_TEXT_FRAME_AUTOHIDE) { - aDesiredSize.ClearSize(); - aDesiredSize.SetOverflowAreasToDesiredBounds(); - } -} diff --git a/layout/generic/nsRubyTextFrame.h b/layout/generic/nsRubyTextFrame.h index 287f970b6b65..f08a05db18b9 100644 --- a/layout/generic/nsRubyTextFrame.h +++ b/layout/generic/nsRubyTextFrame.h @@ -35,15 +35,6 @@ public: virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; #endif - virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, - const nsRect& aDirtyRect, - const nsDisplayListSet& aLists) MOZ_OVERRIDE; - - virtual void Reflow(nsPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, - nsReflowStatus& aStatus) MOZ_OVERRIDE; - protected: friend nsContainerFrame* NS_NewRubyTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); diff --git a/layout/reftests/css-ruby/autohiding-1-ref.html b/layout/reftests/css-ruby/autohiding-1-ref.html deleted file mode 100644 index 12f15a2e879b..000000000000 --- a/layout/reftests/css-ruby/autohiding-1-ref.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - Bug 1052123 - Autohide ruby annotations which are identical to their bases - - - - - - - - - diff --git a/layout/reftests/css-ruby/autohiding-1.html b/layout/reftests/css-ruby/autohiding-1.html deleted file mode 100644 index 9c6ecfaaa34c..000000000000 --- a/layout/reftests/css-ruby/autohiding-1.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - Bug 1052123 - Autohide ruby annotations which are identical to their bases - - - - - - - - - diff --git a/layout/reftests/css-ruby/autohiding-2-ref.html b/layout/reftests/css-ruby/autohiding-2-ref.html deleted file mode 100644 index e389154bb661..000000000000 --- a/layout/reftests/css-ruby/autohiding-2-ref.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Bug 1052123 - Autohide ruby annotations which are identical to their bases - - - -

- - ri -

-

- ri - -

-

- - -

-

- - -

- - diff --git a/layout/reftests/css-ruby/autohiding-2.html b/layout/reftests/css-ruby/autohiding-2.html deleted file mode 100644 index b05a87f658ec..000000000000 --- a/layout/reftests/css-ruby/autohiding-2.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - Bug 1052123 - Autohide ruby annotations which are identical to their bases - - - - -

- - -

-

- - -

-

- - ri -

-

- ri - -

- - diff --git a/layout/reftests/css-ruby/autohiding-3-ref.html b/layout/reftests/css-ruby/autohiding-3-ref.html deleted file mode 100644 index 70549f0477bb..000000000000 --- a/layout/reftests/css-ruby/autohiding-3-ref.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Bug 1052123 - Autohide ruby annotations which are identical to their bases - - - - - - - - - - diff --git a/layout/reftests/css-ruby/autohiding-3.html b/layout/reftests/css-ruby/autohiding-3.html deleted file mode 100644 index 1a39171877b7..000000000000 --- a/layout/reftests/css-ruby/autohiding-3.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Bug 1052123 - Autohide ruby annotations which are identical to their bases - - - - - - - - - - diff --git a/layout/reftests/css-ruby/reftest.list b/layout/reftests/css-ruby/reftest.list index b260f64c65d5..bb2ee6087571 100644 --- a/layout/reftests/css-ruby/reftest.list +++ b/layout/reftests/css-ruby/reftest.list @@ -1,8 +1,5 @@ default-preferences pref(layout.css.ruby.enabled,true) -== autohiding-1.html autohiding-1-ref.html -== autohiding-2.html autohiding-2-ref.html -== autohiding-3.html autohiding-3-ref.html == box-generation-1.html box-generation-1-ref.html == box-generation-2.html box-generation-2-ref.html == box-generation-3.html box-generation-3-ref.html From ce47600bf5cf31652b41e8f9831f1d8c665ae45c Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 16 Dec 2014 18:55:08 -0500 Subject: [PATCH 104/130] Debugging patch for bug 1074744: request the complete log --- toolkit/content/tests/widgets/videocontrols_direction_test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/toolkit/content/tests/widgets/videocontrols_direction_test.js b/toolkit/content/tests/widgets/videocontrols_direction_test.js index 842e859dc8ed..1a64d0096543 100644 --- a/toolkit/content/tests/widgets/videocontrols_direction_test.js +++ b/toolkit/content/tests/widgets/videocontrols_direction_test.js @@ -86,6 +86,7 @@ function runTest(index) { } SimpleTest.waitForExplicitFinish(); +SimpleTest.requestCompleteLog(); window.addEventListener("load", function() { SpecialPowers.pushPrefEnv({"set": [["media.cache_size", 40000]]}, function(){ runTest(0); }); From 60eb32a82cb93f7b4eeb0319ea550778f656cc36 Mon Sep 17 00:00:00 2001 From: Guilherme Goncalves Date: Wed, 17 Dec 2014 09:14:48 +0900 Subject: [PATCH 105/130] Bug 1094275 - Update the in-tree copy of jemalloc3 to commit b4acf73. r=glandium --- configure.in | 2 +- js/src/devtools/rootAnalysis/annotations.js | 2 + memory/build/mozjemalloc_compat.c | 9 +- ...verwrite-VERSION-on-a-git-repository.patch | 68 + ...test-to-detect-whether-to-use-a-cons.patch | 340 --- ...nstead-of-LLU-for-unsigned-long-long.patch | 46 - ...ompat-s-C99-headers-with-MSVC-versio.patch | 1224 ---------- ..._builtin_ffsl-if-ffsl-is-unavailable.patch | 354 --- ...Check-for-__builtin_ffsl-before-ffsl.patch | 225 -- memory/jemalloc/0006-Fix-clang-warnings.patch | 93 - ...lt-purgeable-zone-is-after-the-defau.patch | 59 - .../0008-Allow-to-build-with-clang-cl.patch | 22 - ...rom-cfghdrs_in-cfgoutputs_in-and-cfg.patch | 225 -- memory/jemalloc/moz.build | 2 + memory/jemalloc/src/INSTALL | 131 +- memory/jemalloc/src/Makefile.in | 61 +- memory/jemalloc/src/VERSION | 2 +- memory/jemalloc/src/bin/pprof | 416 ++-- memory/jemalloc/src/config.guess | 192 +- memory/jemalloc/src/config.sub | 22 +- memory/jemalloc/src/configure | 786 ++++--- memory/jemalloc/src/configure.ac | 390 ++-- memory/jemalloc/src/doc/jemalloc.xml.in | 782 ++++--- .../src/include/jemalloc/internal/arena.h | 547 ++--- .../src/include/jemalloc/internal/atomic.h | 73 +- .../src/include/jemalloc/internal/base.h | 2 +- .../src/include/jemalloc/internal/bitmap.h | 54 +- .../src/include/jemalloc/internal/chunk.h | 12 +- .../src/include/jemalloc/internal/chunk_dss.h | 3 +- .../include/jemalloc/internal/chunk_mmap.h | 2 +- .../src/include/jemalloc/internal/ckh.h | 8 +- .../src/include/jemalloc/internal/ctl.h | 6 +- .../src/include/jemalloc/internal/extent.h | 5 +- .../src/include/jemalloc/internal/hash.h | 13 +- .../src/include/jemalloc/internal/huge.h | 29 +- .../jemalloc/internal/jemalloc_internal.h.in | 765 ++++--- .../internal/jemalloc_internal_decls.h | 60 + .../internal/jemalloc_internal_defs.h.in | 63 +- .../internal/jemalloc_internal_macros.h | 6 + .../src/include/jemalloc/internal/mutex.h | 2 +- .../jemalloc/internal/private_symbols.txt | 208 +- .../src/include/jemalloc/internal/prng.h | 2 +- .../src/include/jemalloc/internal/prof.h | 659 +++--- .../src/include/jemalloc/internal/ql.h | 4 +- .../src/include/jemalloc/internal/qr.h | 6 +- .../include/jemalloc/internal/quarantine.h | 21 +- .../src/include/jemalloc/internal/rb.h | 24 +- .../include/jemalloc/internal/size_classes.sh | 284 ++- .../src/include/jemalloc/internal/stats.h | 44 +- .../src/include/jemalloc/internal/tcache.h | 210 +- .../src/include/jemalloc/internal/tsd.h | 539 +++-- .../src/include/jemalloc/internal/util.h | 88 +- .../src/include/jemalloc/internal/valgrind.h | 112 + .../jemalloc/src/include/jemalloc/jemalloc.sh | 2 +- .../src/include/jemalloc/jemalloc_defs.h.in | 3 - .../src/include/jemalloc/jemalloc_macros.h.in | 20 +- .../src/include/jemalloc/jemalloc_protos.h.in | 22 +- .../include/jemalloc/jemalloc_typedefs.h.in | 2 + .../src/include/msvc_compat/C99/stdbool.h | 2 + memory/jemalloc/src/jemalloc.pc.in | 11 + memory/jemalloc/src/src/arena.c | 1825 ++++++++------- memory/jemalloc/src/src/base.c | 19 +- memory/jemalloc/src/src/bitmap.c | 18 +- memory/jemalloc/src/src/chunk.c | 233 +- memory/jemalloc/src/src/chunk_dss.c | 34 +- memory/jemalloc/src/src/chunk_mmap.c | 13 +- memory/jemalloc/src/src/ckh.c | 52 +- memory/jemalloc/src/src/ctl.c | 860 ++++--- memory/jemalloc/src/src/extent.c | 4 +- memory/jemalloc/src/src/huge.c | 462 ++-- memory/jemalloc/src/src/jemalloc.c | 1718 ++++++++------ memory/jemalloc/src/src/prof.c | 1747 +++++++++----- memory/jemalloc/src/src/quarantine.c | 129 +- memory/jemalloc/src/src/rtree.c | 6 +- memory/jemalloc/src/src/stats.c | 301 ++- memory/jemalloc/src/src/tcache.c | 156 +- memory/jemalloc/src/src/tsd.c | 57 +- memory/jemalloc/src/src/util.c | 14 +- memory/jemalloc/src/src/valgrind.c | 34 + memory/jemalloc/src/src/zone.c | 14 +- .../jemalloc/src/test/include/test/btalloc.h | 31 + .../src/test/include/test/jemalloc_test.h.in | 3 + .../test/include/test/jemalloc_test_defs.h.in | 6 +- memory/jemalloc/src/test/include/test/math.h | 2 +- memory/jemalloc/src/test/include/test/test.h | 386 ++-- memory/jemalloc/src/test/include/test/thd.h | 2 +- memory/jemalloc/src/test/include/test/timer.h | 13 + .../src/test/integration/MALLOCX_ARENA.c | 21 +- memory/jemalloc/src/test/integration/allocm.c | 107 - memory/jemalloc/src/test/integration/chunk.c | 59 + memory/jemalloc/src/test/integration/mremap.c | 45 - .../jemalloc/src/test/integration/rallocm.c | 111 - .../jemalloc/src/test/integration/rallocx.c | 8 +- .../jemalloc/src/test/integration/sdallocx.c | 57 + memory/jemalloc/src/test/src/SFMT.c | 22 +- memory/jemalloc/src/test/src/btalloc.c | 8 + memory/jemalloc/src/test/src/btalloc_0.c | 3 + memory/jemalloc/src/test/src/btalloc_1.c | 3 + memory/jemalloc/src/test/src/mtx.c | 4 + memory/jemalloc/src/test/src/test.c | 19 +- memory/jemalloc/src/test/src/thd.c | 6 +- memory/jemalloc/src/test/src/timer.c | 57 + memory/jemalloc/src/test/stress/microbench.c | 181 ++ memory/jemalloc/src/test/unit/SFMT.c | 2000 ++++++++--------- memory/jemalloc/src/test/unit/atomic.c | 97 + memory/jemalloc/src/test/unit/bitmap.c | 16 +- memory/jemalloc/src/test/unit/ckh.c | 46 +- memory/jemalloc/src/test/unit/hash.c | 4 +- memory/jemalloc/src/test/unit/junk.c | 88 +- memory/jemalloc/src/test/unit/junk_alloc.c | 3 + memory/jemalloc/src/test/unit/junk_free.c | 3 + memory/jemalloc/src/test/unit/lg_chunk.c | 26 + memory/jemalloc/src/test/unit/mallctl.c | 71 +- memory/jemalloc/src/test/unit/math.c | 6 + memory/jemalloc/src/test/unit/mq.c | 3 +- memory/jemalloc/src/test/unit/prof_accum.c | 9 +- memory/jemalloc/src/test/unit/prof_accum.h | 35 - memory/jemalloc/src/test/unit/prof_accum_a.c | 3 - memory/jemalloc/src/test/unit/prof_accum_b.c | 3 - memory/jemalloc/src/test/unit/prof_active.c | 136 ++ memory/jemalloc/src/test/unit/prof_reset.c | 236 ++ .../jemalloc/src/test/unit/prof_thread_name.c | 129 ++ memory/jemalloc/src/test/unit/rb.c | 7 +- memory/jemalloc/src/test/unit/rtree.c | 8 +- memory/jemalloc/src/test/unit/stats.c | 128 +- memory/jemalloc/src/test/unit/tsd.c | 42 +- memory/jemalloc/src/test/unit/util.c | 86 +- memory/jemalloc/update.sh | 12 +- memory/jemalloc/upstream.info | 2 +- 129 files changed, 11347 insertions(+), 10068 deletions(-) create mode 100644 memory/jemalloc/0001-Dont-overwrite-VERSION-on-a-git-repository.patch delete mode 100644 memory/jemalloc/0001-Use-a-configure-test-to-detect-whether-to-use-a-cons.patch delete mode 100644 memory/jemalloc/0002-Use-ULL-prefix-instead-of-LLU-for-unsigned-long-long.patch delete mode 100644 memory/jemalloc/0003-Don-t-use-msvc_compat-s-C99-headers-with-MSVC-versio.patch delete mode 100644 memory/jemalloc/0004-Try-to-use-__builtin_ffsl-if-ffsl-is-unavailable.patch delete mode 100644 memory/jemalloc/0005-Check-for-__builtin_ffsl-before-ffsl.patch delete mode 100644 memory/jemalloc/0006-Fix-clang-warnings.patch delete mode 100644 memory/jemalloc/0007-Ensure-the-default-purgeable-zone-is-after-the-defau.patch delete mode 100644 memory/jemalloc/0008-Allow-to-build-with-clang-cl.patch delete mode 100644 memory/jemalloc/0009-Remove-srcroot-from-cfghdrs_in-cfgoutputs_in-and-cfg.patch create mode 100644 memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_decls.h create mode 100644 memory/jemalloc/src/include/jemalloc/internal/valgrind.h create mode 100644 memory/jemalloc/src/include/jemalloc/jemalloc_typedefs.h.in create mode 100644 memory/jemalloc/src/jemalloc.pc.in create mode 100644 memory/jemalloc/src/src/valgrind.c create mode 100644 memory/jemalloc/src/test/include/test/btalloc.h create mode 100644 memory/jemalloc/src/test/include/test/timer.h delete mode 100644 memory/jemalloc/src/test/integration/allocm.c create mode 100644 memory/jemalloc/src/test/integration/chunk.c delete mode 100644 memory/jemalloc/src/test/integration/mremap.c delete mode 100644 memory/jemalloc/src/test/integration/rallocm.c create mode 100644 memory/jemalloc/src/test/integration/sdallocx.c create mode 100644 memory/jemalloc/src/test/src/btalloc.c create mode 100644 memory/jemalloc/src/test/src/btalloc_0.c create mode 100644 memory/jemalloc/src/test/src/btalloc_1.c create mode 100644 memory/jemalloc/src/test/src/timer.c create mode 100644 memory/jemalloc/src/test/stress/microbench.c create mode 100644 memory/jemalloc/src/test/unit/atomic.c create mode 100644 memory/jemalloc/src/test/unit/junk_alloc.c create mode 100644 memory/jemalloc/src/test/unit/junk_free.c create mode 100644 memory/jemalloc/src/test/unit/lg_chunk.c delete mode 100644 memory/jemalloc/src/test/unit/prof_accum.h delete mode 100644 memory/jemalloc/src/test/unit/prof_accum_a.c delete mode 100644 memory/jemalloc/src/test/unit/prof_accum_b.c create mode 100644 memory/jemalloc/src/test/unit/prof_active.c create mode 100644 memory/jemalloc/src/test/unit/prof_reset.c create mode 100644 memory/jemalloc/src/test/unit/prof_thread_name.c diff --git a/configure.in b/configure.in index 81d1f6431cc1..1d0eb48c14b2 100644 --- a/configure.in +++ b/configure.in @@ -9063,7 +9063,7 @@ esac # Run jemalloc configure script if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC3" -o -n "$MOZ_REPLACE_MALLOC"; then - ac_configure_args="--build=$build --host=$target --enable-stats --with-jemalloc-prefix=je_" + ac_configure_args="--build=$build --host=$target --enable-stats --with-jemalloc-prefix=je_ --disable-valgrind" if test -n "$MOZ_REPLACE_MALLOC"; then # When using replace_malloc, we always want memalign and valloc exported from jemalloc. ac_configure_args="$ac_configure_args ac_cv_func_memalign=yes" diff --git a/js/src/devtools/rootAnalysis/annotations.js b/js/src/devtools/rootAnalysis/annotations.js index 31fe350266e8..69e55c101375 100644 --- a/js/src/devtools/rootAnalysis/annotations.js +++ b/js/src/devtools/rootAnalysis/annotations.js @@ -8,6 +8,8 @@ var ignoreIndirectCalls = { "aMallocSizeOf" : true, "_malloc_message" : true, "je_malloc_message" : true, + "chunk_dalloc" : true, + "chunk_alloc" : true, "__conv" : true, "__convf" : true, "prerrortable.c:callback_newtable" : true, diff --git a/memory/build/mozjemalloc_compat.c b/memory/build/mozjemalloc_compat.c index 70265a727124..55b47243a20f 100644 --- a/memory/build/mozjemalloc_compat.c +++ b/memory/build/mozjemalloc_compat.c @@ -21,7 +21,7 @@ je_(mallctlnametomib)(const char *name, size_t *mibp, size_t *miblenp); MOZ_IMPORT_API int je_(mallctlbymib)(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen); MOZ_IMPORT_API int -je_(nallocm)(size_t *rsize, size_t size, int flags); +je_(nallocx)(size_t size, int flags); #else # include "jemalloc/jemalloc.h" @@ -50,15 +50,12 @@ je_(nallocm)(size_t *rsize, size_t size, int flags); MOZ_MEMORY_API size_t malloc_good_size_impl(size_t size) { - size_t ret; - /* je_nallocm crashes when given a size of 0. As + /* je_nallocx crashes when given a size of 0. As * malloc_usable_size(malloc(0)) and malloc_usable_size(malloc(1)) * return the same value, use a size of 1. */ if (size == 0) size = 1; - if (!je_(nallocm)(&ret, size, 0)) - return ret; - return size; + return je_(nallocx)(size, 0); } MOZ_JEMALLOC_API void diff --git a/memory/jemalloc/0001-Dont-overwrite-VERSION-on-a-git-repository.patch b/memory/jemalloc/0001-Dont-overwrite-VERSION-on-a-git-repository.patch new file mode 100644 index 000000000000..34f445327db2 --- /dev/null +++ b/memory/jemalloc/0001-Dont-overwrite-VERSION-on-a-git-repository.patch @@ -0,0 +1,68 @@ +diff --git a/configure b/configure +--- a/configure ++++ b/configure +@@ -6662,28 +6662,6 @@ fi + + + +-if test "x`git rev-parse --is-inside-work-tree 2>/dev/null`" = "xtrue" ; then +- rm -f "${srcroot}VERSION" +- for pattern in '[0-9].[0-9].[0-9]' '[0-9].[0-9].[0-9][0-9]' \ +- '[0-9].[0-9][0-9].[0-9]' '[0-9].[0-9][0-9].[0-9][0-9]' \ +- '[0-9][0-9].[0-9].[0-9]' '[0-9][0-9].[0-9].[0-9][0-9]' \ +- '[0-9][0-9].[0-9][0-9].[0-9]' \ +- '[0-9][0-9].[0-9][0-9].[0-9][0-9]'; do +- if test ! -e "${srcroot}VERSION" ; then +- git describe --long --abbrev=40 --match="${pattern}" > "${srcroot}VERSION.tmp" 2>/dev/null +- if test $? -eq 0 ; then +- mv "${srcroot}VERSION.tmp" "${srcroot}VERSION" +- break +- fi +- fi +- done +-fi +-rm -f "${srcroot}VERSION.tmp" +-if test ! -e "${srcroot}VERSION" ; then +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Missing VERSION file, and unable to generate it; creating bogus VERSION" >&5 +-$as_echo "Missing VERSION file, and unable to generate it; creating bogus VERSION" >&6; } +- echo "0.0.0-0-g0000000000000000000000000000000000000000" > "${srcroot}VERSION" +-fi + jemalloc_version=`cat "${srcroot}VERSION"` + jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print $1}'` + jemalloc_version_minor=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print $2}'` +diff --git a/configure.ac b/configure.ac +--- a/configure.ac ++++ b/configure.ac +@@ -1055,32 +1055,6 @@ dnl ============================================================================ + dnl jemalloc configuration. + dnl + +-dnl Set VERSION if source directory is inside a git repository. +-if test "x`git rev-parse --is-inside-work-tree 2>/dev/null`" = "xtrue" ; then +- dnl Pattern globs aren't powerful enough to match both single- and +- dnl double-digit version numbers, so iterate over patterns to support up to +- dnl version 99.99.99 without any accidental matches. +- rm -f "${srcroot}VERSION" +- for pattern in ['[0-9].[0-9].[0-9]' '[0-9].[0-9].[0-9][0-9]' \ +- '[0-9].[0-9][0-9].[0-9]' '[0-9].[0-9][0-9].[0-9][0-9]' \ +- '[0-9][0-9].[0-9].[0-9]' '[0-9][0-9].[0-9].[0-9][0-9]' \ +- '[0-9][0-9].[0-9][0-9].[0-9]' \ +- '[0-9][0-9].[0-9][0-9].[0-9][0-9]']; do +- if test ! -e "${srcroot}VERSION" ; then +- git describe --long --abbrev=40 --match="${pattern}" > "${srcroot}VERSION.tmp" 2>/dev/null +- if test $? -eq 0 ; then +- mv "${srcroot}VERSION.tmp" "${srcroot}VERSION" +- break +- fi +- fi +- done +-fi +-rm -f "${srcroot}VERSION.tmp" +-if test ! -e "${srcroot}VERSION" ; then +- AC_MSG_RESULT( +- [Missing VERSION file, and unable to generate it; creating bogus VERSION]) +- echo "0.0.0-0-g0000000000000000000000000000000000000000" > "${srcroot}VERSION" +-fi + jemalloc_version=`cat "${srcroot}VERSION"` + jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]1}'` + jemalloc_version_minor=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]2}'` diff --git a/memory/jemalloc/0001-Use-a-configure-test-to-detect-whether-to-use-a-cons.patch b/memory/jemalloc/0001-Use-a-configure-test-to-detect-whether-to-use-a-cons.patch deleted file mode 100644 index cec109f34ebe..000000000000 --- a/memory/jemalloc/0001-Use-a-configure-test-to-detect-whether-to-use-a-cons.patch +++ /dev/null @@ -1,340 +0,0 @@ -diff --git a/configure b/configure ---- a/configure -+++ b/configure -@@ -1905,83 +1905,16 @@ fi - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - - } # ac_fn_c_try_link - --# ac_fn_c_check_func LINENO FUNC VAR --# ---------------------------------- --# Tests whether FUNC exists, setting the cache variable VAR accordingly --ac_fn_c_check_func () --{ -- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack -- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 --$as_echo_n "checking for $2... " >&6; } --if eval \${$3+:} false; then : -- $as_echo_n "(cached) " >&6 --else -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext --/* end confdefs.h. */ --/* Define $2 to an innocuous variant, in case declares $2. -- For example, HP-UX 11i declares gettimeofday. */ --#define $2 innocuous_$2 -- --/* System header to define __stub macros and hopefully few prototypes, -- which can conflict with char $2 (); below. -- Prefer to if __STDC__ is defined, since -- exists even on freestanding compilers. */ -- --#ifdef __STDC__ --# include --#else --# include --#endif -- --#undef $2 -- --/* Override any GCC internal prototype to avoid an error. -- Use char because int might match the return type of a GCC -- builtin and then its argument prototype would still apply. */ --#ifdef __cplusplus --extern "C" --#endif --char $2 (); --/* The GNU C library defines this for functions which it implements -- to always fail with ENOSYS. Some functions are actually named -- something starting with __ and the normal name is an alias. */ --#if defined __stub_$2 || defined __stub___$2 --choke me --#endif -- --int --main () --{ --return $2 (); -- ; -- return 0; --} --_ACEOF --if ac_fn_c_try_link "$LINENO"; then : -- eval "$3=yes" --else -- eval "$3=no" --fi --rm -f core conftest.err conftest.$ac_objext \ -- conftest$ac_exeext conftest.$ac_ext --fi --eval ac_res=\$$3 -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 --$as_echo "$ac_res" >&6; } -- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno -- --} # ac_fn_c_check_func -- - # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES - # ------------------------------------------------------- - # Tests whether HEADER exists, giving a warning if it cannot be compiled using - # the include files in INCLUDES and setting the cache variable VAR - # accordingly. - ac_fn_c_check_header_mongrel () - { - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack -@@ -2059,16 +1992,83 @@ fi - eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 - $as_echo "$ac_res" >&6; } - fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - - } # ac_fn_c_check_header_mongrel - -+# ac_fn_c_check_func LINENO FUNC VAR -+# ---------------------------------- -+# Tests whether FUNC exists, setting the cache variable VAR accordingly -+ac_fn_c_check_func () -+{ -+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack -+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -+$as_echo_n "checking for $2... " >&6; } -+if eval \${$3+:} false; then : -+ $as_echo_n "(cached) " >&6 -+else -+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+/* Define $2 to an innocuous variant, in case declares $2. -+ For example, HP-UX 11i declares gettimeofday. */ -+#define $2 innocuous_$2 -+ -+/* System header to define __stub macros and hopefully few prototypes, -+ which can conflict with char $2 (); below. -+ Prefer to if __STDC__ is defined, since -+ exists even on freestanding compilers. */ -+ -+#ifdef __STDC__ -+# include -+#else -+# include -+#endif -+ -+#undef $2 -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char $2 (); -+/* The GNU C library defines this for functions which it implements -+ to always fail with ENOSYS. Some functions are actually named -+ something starting with __ and the normal name is an alias. */ -+#if defined __stub_$2 || defined __stub___$2 -+choke me -+#endif -+ -+int -+main () -+{ -+return $2 (); -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_link "$LINENO"; then : -+ eval "$3=yes" -+else -+ eval "$3=no" -+fi -+rm -f core conftest.err conftest.$ac_objext \ -+ conftest$ac_exeext conftest.$ac_ext -+fi -+eval ac_res=\$$3 -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -+$as_echo "$ac_res" >&6; } -+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno -+ -+} # ac_fn_c_check_func -+ - # ac_fn_c_check_type LINENO TYPE VAR INCLUDES - # ------------------------------------------- - # Tests whether TYPE exists after having included INCLUDES, setting cache - # variable VAR accordingly. - ac_fn_c_check_type () - { - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -@@ -4817,17 +4817,16 @@ esac - AR=$ac_ct_AR - fi - else - AR="$ac_cv_prog_AR" - fi - - - default_munmap="1" --JEMALLOC_USABLE_SIZE_CONST="const" - case "${host}" in - *-*-darwin*) - CFLAGS="$CFLAGS" - abi="macho" - $as_echo "#define JEMALLOC_PURGE_MADVISE_FREE " >>confdefs.h - - RPATH="" - LD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" -@@ -4850,17 +4849,16 @@ case "${host}" in - CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" - abi="elf" - $as_echo "#define JEMALLOC_HAS_ALLOCA_H 1" >>confdefs.h - - $as_echo "#define JEMALLOC_PURGE_MADVISE_DONTNEED " >>confdefs.h - - $as_echo "#define JEMALLOC_THREADED_INIT " >>confdefs.h - -- JEMALLOC_USABLE_SIZE_CONST="" - default_munmap="0" - ;; - *-*-netbsd*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking ABI" >&5 - $as_echo_n "checking ABI... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #ifdef __ELF__ -@@ -4930,16 +4928,60 @@ rm -f core conftest.err conftest.$ac_obj - PIC_CFLAGS="" - ;; - *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: Unsupported operating system: ${host}" >&5 - $as_echo "Unsupported operating system: ${host}" >&6; } - abi="elf" - ;; - esac -+ -+JEMALLOC_USABLE_SIZE_CONST=const -+for ac_header in malloc.h -+do : -+ ac_fn_c_check_header_mongrel "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default" -+if test "x$ac_cv_header_malloc_h" = xyes; then : -+ cat >>confdefs.h <<_ACEOF -+#define HAVE_MALLOC_H 1 -+_ACEOF -+ -+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether malloc_usable_size definition can use const argument" >&5 -+$as_echo_n "checking whether malloc_usable_size definition can use const argument... " >&6; } -+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+#include -+ #include -+ size_t malloc_usable_size(const void *ptr); -+ -+int -+main () -+{ -+ -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_compile "$LINENO"; then : -+ -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -+$as_echo "yes" >&6; } -+ -+else -+ -+ JEMALLOC_USABLE_SIZE_CONST= -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+$as_echo "no" >&6; } -+ -+fi -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+ -+fi -+ -+done -+ - cat >>confdefs.h <<_ACEOF - #define JEMALLOC_USABLE_SIZE_CONST $JEMALLOC_USABLE_SIZE_CONST - _ACEOF - - - - - -diff --git a/configure.ac b/configure.ac ---- a/configure.ac -+++ b/configure.ac -@@ -253,17 +253,16 @@ AC_PROG_AR - dnl Platform-specific settings. abi and RPATH can probably be determined - dnl programmatically, but doing so is error-prone, which makes it generally - dnl not worth the trouble. - dnl - dnl Define cpp macros in CPPFLAGS, rather than doing AC_DEFINE(macro), since the - dnl definitions need to be seen before any headers are included, which is a pain - dnl to make happen otherwise. - default_munmap="1" --JEMALLOC_USABLE_SIZE_CONST="const" - case "${host}" in - *-*-darwin*) - CFLAGS="$CFLAGS" - abi="macho" - AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) - RPATH="" - LD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" - so="dylib" -@@ -281,17 +280,16 @@ case "${host}" in - ;; - *-*-linux*) - CFLAGS="$CFLAGS" - CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" - abi="elf" - AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) - AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED], [ ]) - AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) -- JEMALLOC_USABLE_SIZE_CONST="" - default_munmap="0" - ;; - *-*-netbsd*) - AC_MSG_CHECKING([ABI]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#ifdef __ELF__ - /* ELF */ - #else -@@ -346,16 +344,32 @@ case "${host}" in - SOREV="${so}" - PIC_CFLAGS="" - ;; - *) - AC_MSG_RESULT([Unsupported operating system: ${host}]) - abi="elf" - ;; - esac -+ -+JEMALLOC_USABLE_SIZE_CONST=const -+AC_CHECK_HEADERS([malloc.h], [ -+ AC_MSG_CHECKING([whether malloc_usable_size definition can use const argument]) -+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM( -+ [#include -+ #include -+ size_t malloc_usable_size(const void *ptr); -+ ], -+ [])],[ -+ AC_MSG_RESULT([yes]) -+ ],[ -+ JEMALLOC_USABLE_SIZE_CONST= -+ AC_MSG_RESULT([no]) -+ ]) -+]) - AC_DEFINE_UNQUOTED([JEMALLOC_USABLE_SIZE_CONST], [$JEMALLOC_USABLE_SIZE_CONST]) - AC_SUBST([abi]) - AC_SUBST([RPATH]) - AC_SUBST([LD_PRELOAD_VAR]) - AC_SUBST([so]) - AC_SUBST([importlib]) - AC_SUBST([o]) - AC_SUBST([a]) diff --git a/memory/jemalloc/0002-Use-ULL-prefix-instead-of-LLU-for-unsigned-long-long.patch b/memory/jemalloc/0002-Use-ULL-prefix-instead-of-LLU-for-unsigned-long-long.patch deleted file mode 100644 index 81bda505e4f9..000000000000 --- a/memory/jemalloc/0002-Use-ULL-prefix-instead-of-LLU-for-unsigned-long-long.patch +++ /dev/null @@ -1,46 +0,0 @@ -diff --git a/include/jemalloc/internal/hash.h b/include/jemalloc/internal/hash.h ---- a/include/jemalloc/internal/hash.h -+++ b/include/jemalloc/internal/hash.h -@@ -71,19 +71,19 @@ hash_fmix_32(uint32_t h) - return (h); - } - - JEMALLOC_INLINE uint64_t - hash_fmix_64(uint64_t k) - { - - k ^= k >> 33; -- k *= QU(0xff51afd7ed558ccdLLU); -+ k *= QU(0xff51afd7ed558ccdULL); - k ^= k >> 33; -- k *= QU(0xc4ceb9fe1a85ec53LLU); -+ k *= QU(0xc4ceb9fe1a85ec53ULL); - k ^= k >> 33; - - return (k); - } - - JEMALLOC_INLINE uint32_t - hash_x86_32(const void *key, int len, uint32_t seed) - { -@@ -242,18 +242,18 @@ hash_x64_128(const void *key, const int - uint64_t r_out[2]) - { - const uint8_t *data = (const uint8_t *) key; - const int nblocks = len / 16; - - uint64_t h1 = seed; - uint64_t h2 = seed; - -- const uint64_t c1 = QU(0x87c37b91114253d5LLU); -- const uint64_t c2 = QU(0x4cf5ad432745937fLLU); -+ const uint64_t c1 = QU(0x87c37b91114253d5ULL); -+ const uint64_t c2 = QU(0x4cf5ad432745937fULL); - - /* body */ - { - const uint64_t *blocks = (const uint64_t *) (data); - int i; - - for (i = 0; i < nblocks; i++) { - uint64_t k1 = hash_get_block_64(blocks, i*2 + 0); diff --git a/memory/jemalloc/0003-Don-t-use-msvc_compat-s-C99-headers-with-MSVC-versio.patch b/memory/jemalloc/0003-Don-t-use-msvc_compat-s-C99-headers-with-MSVC-versio.patch deleted file mode 100644 index aef2e6960755..000000000000 --- a/memory/jemalloc/0003-Don-t-use-msvc_compat-s-C99-headers-with-MSVC-versio.patch +++ /dev/null @@ -1,1224 +0,0 @@ -diff -r 1da44232e82e -r 73d73a2ae3ad configure ---- a/configure Wed May 21 14:41:51 2014 -0700 -+++ b/configure Thu May 29 16:35:25 2014 +0900 -@@ -4333,16 +4333,20 @@ fi - - if test "x${ac_cv_big_endian}" = "x1" ; then - cat >>confdefs.h <<_ACEOF - #define JEMALLOC_BIG_ENDIAN - _ACEOF - - fi - -+if test "x${je_cv_msvc}" = "xyes" -a "x${ac_cv_header_inttypes_h}" = "xno"; then -+ CPPFLAGS="$CPPFLAGS -I${srcroot}/include/msvc_compat/C99" -+fi -+ - # The cast to long int works around a bug in the HP C Compiler - # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects - # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. - # This bug is HP SR number 8606223364. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 - $as_echo_n "checking size of void *... " >&6; } - if ${ac_cv_sizeof_void_p+:} false; then : - $as_echo_n "(cached) " >&6 -diff -r 1da44232e82e -r 73d73a2ae3ad configure.ac ---- a/configure.ac Wed May 21 14:41:51 2014 -0700 -+++ b/configure.ac Thu May 29 16:35:25 2014 +0900 -@@ -150,16 +150,20 @@ if test "x$EXTRA_CFLAGS" != "x" ; then - fi - AC_PROG_CPP - - AC_C_BIGENDIAN([ac_cv_big_endian=1], [ac_cv_big_endian=0]) - if test "x${ac_cv_big_endian}" = "x1" ; then - AC_DEFINE_UNQUOTED([JEMALLOC_BIG_ENDIAN], [ ]) - fi - -+if test "x${je_cv_msvc}" = "xyes" -a "x${ac_cv_header_inttypes_h}" = "xno"; then -+ CPPFLAGS="$CPPFLAGS -I${srcroot}/include/msvc_compat/C99" -+fi -+ - AC_CHECK_SIZEOF([void *]) - if test "x${ac_cv_sizeof_void_p}" = "x8" ; then - LG_SIZEOF_PTR=3 - elif test "x${ac_cv_sizeof_void_p}" = "x4" ; then - LG_SIZEOF_PTR=2 - else - AC_MSG_ERROR([Unsupported pointer size: ${ac_cv_sizeof_void_p}]) - fi -diff -r 1da44232e82e -r 73d73a2ae3ad include/msvc_compat/C99/inttypes.h ---- /dev/null Thu Jan 01 00:00:00 1970 +0000 -+++ b/include/msvc_compat/C99/inttypes.h Thu May 29 16:35:25 2014 +0900 -@@ -0,0 +1,313 @@ -+// ISO C9x compliant inttypes.h for Microsoft Visual Studio -+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -+// -+// Copyright (c) 2006 Alexander Chemeris -+// -+// Redistribution and use in source and binary forms, with or without -+// modification, are permitted provided that the following conditions are met: -+// -+// 1. Redistributions of source code must retain the above copyright notice, -+// this list of conditions and the following disclaimer. -+// -+// 2. Redistributions in binary form must reproduce the above copyright -+// notice, this list of conditions and the following disclaimer in the -+// documentation and/or other materials provided with the distribution. -+// -+// 3. The name of the author may be used to endorse or promote products -+// derived from this software without specific prior written permission. -+// -+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+// -+/////////////////////////////////////////////////////////////////////////////// -+ -+#ifndef _MSC_VER // [ -+#error "Use this header only with Microsoft Visual C++ compilers!" -+#endif // _MSC_VER ] -+ -+#ifndef _MSC_INTTYPES_H_ // [ -+#define _MSC_INTTYPES_H_ -+ -+#if _MSC_VER > 1000 -+#pragma once -+#endif -+ -+#include "stdint.h" -+ -+// 7.8 Format conversion of integer types -+ -+typedef struct { -+ intmax_t quot; -+ intmax_t rem; -+} imaxdiv_t; -+ -+// 7.8.1 Macros for format specifiers -+ -+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 -+ -+#ifdef _WIN64 -+# define __PRI64_PREFIX "l" -+# define __PRIPTR_PREFIX "l" -+#else -+# define __PRI64_PREFIX "ll" -+# define __PRIPTR_PREFIX -+#endif -+ -+// The fprintf macros for signed integers are: -+#define PRId8 "d" -+#define PRIi8 "i" -+#define PRIdLEAST8 "d" -+#define PRIiLEAST8 "i" -+#define PRIdFAST8 "d" -+#define PRIiFAST8 "i" -+ -+#define PRId16 "hd" -+#define PRIi16 "hi" -+#define PRIdLEAST16 "hd" -+#define PRIiLEAST16 "hi" -+#define PRIdFAST16 "hd" -+#define PRIiFAST16 "hi" -+ -+#define PRId32 "d" -+#define PRIi32 "i" -+#define PRIdLEAST32 "d" -+#define PRIiLEAST32 "i" -+#define PRIdFAST32 "d" -+#define PRIiFAST32 "i" -+ -+#define PRId64 __PRI64_PREFIX "d" -+#define PRIi64 __PRI64_PREFIX "i" -+#define PRIdLEAST64 __PRI64_PREFIX "d" -+#define PRIiLEAST64 __PRI64_PREFIX "i" -+#define PRIdFAST64 __PRI64_PREFIX "d" -+#define PRIiFAST64 __PRI64_PREFIX "i" -+ -+#define PRIdMAX __PRI64_PREFIX "d" -+#define PRIiMAX __PRI64_PREFIX "i" -+ -+#define PRIdPTR __PRIPTR_PREFIX "d" -+#define PRIiPTR __PRIPTR_PREFIX "i" -+ -+// The fprintf macros for unsigned integers are: -+#define PRIo8 "o" -+#define PRIu8 "u" -+#define PRIx8 "x" -+#define PRIX8 "X" -+#define PRIoLEAST8 "o" -+#define PRIuLEAST8 "u" -+#define PRIxLEAST8 "x" -+#define PRIXLEAST8 "X" -+#define PRIoFAST8 "o" -+#define PRIuFAST8 "u" -+#define PRIxFAST8 "x" -+#define PRIXFAST8 "X" -+ -+#define PRIo16 "ho" -+#define PRIu16 "hu" -+#define PRIx16 "hx" -+#define PRIX16 "hX" -+#define PRIoLEAST16 "ho" -+#define PRIuLEAST16 "hu" -+#define PRIxLEAST16 "hx" -+#define PRIXLEAST16 "hX" -+#define PRIoFAST16 "ho" -+#define PRIuFAST16 "hu" -+#define PRIxFAST16 "hx" -+#define PRIXFAST16 "hX" -+ -+#define PRIo32 "o" -+#define PRIu32 "u" -+#define PRIx32 "x" -+#define PRIX32 "X" -+#define PRIoLEAST32 "o" -+#define PRIuLEAST32 "u" -+#define PRIxLEAST32 "x" -+#define PRIXLEAST32 "X" -+#define PRIoFAST32 "o" -+#define PRIuFAST32 "u" -+#define PRIxFAST32 "x" -+#define PRIXFAST32 "X" -+ -+#define PRIo64 __PRI64_PREFIX "o" -+#define PRIu64 __PRI64_PREFIX "u" -+#define PRIx64 __PRI64_PREFIX "x" -+#define PRIX64 __PRI64_PREFIX "X" -+#define PRIoLEAST64 __PRI64_PREFIX "o" -+#define PRIuLEAST64 __PRI64_PREFIX "u" -+#define PRIxLEAST64 __PRI64_PREFIX "x" -+#define PRIXLEAST64 __PRI64_PREFIX "X" -+#define PRIoFAST64 __PRI64_PREFIX "o" -+#define PRIuFAST64 __PRI64_PREFIX "u" -+#define PRIxFAST64 __PRI64_PREFIX "x" -+#define PRIXFAST64 __PRI64_PREFIX "X" -+ -+#define PRIoMAX __PRI64_PREFIX "o" -+#define PRIuMAX __PRI64_PREFIX "u" -+#define PRIxMAX __PRI64_PREFIX "x" -+#define PRIXMAX __PRI64_PREFIX "X" -+ -+#define PRIoPTR __PRIPTR_PREFIX "o" -+#define PRIuPTR __PRIPTR_PREFIX "u" -+#define PRIxPTR __PRIPTR_PREFIX "x" -+#define PRIXPTR __PRIPTR_PREFIX "X" -+ -+// The fscanf macros for signed integers are: -+#define SCNd8 "d" -+#define SCNi8 "i" -+#define SCNdLEAST8 "d" -+#define SCNiLEAST8 "i" -+#define SCNdFAST8 "d" -+#define SCNiFAST8 "i" -+ -+#define SCNd16 "hd" -+#define SCNi16 "hi" -+#define SCNdLEAST16 "hd" -+#define SCNiLEAST16 "hi" -+#define SCNdFAST16 "hd" -+#define SCNiFAST16 "hi" -+ -+#define SCNd32 "ld" -+#define SCNi32 "li" -+#define SCNdLEAST32 "ld" -+#define SCNiLEAST32 "li" -+#define SCNdFAST32 "ld" -+#define SCNiFAST32 "li" -+ -+#define SCNd64 "I64d" -+#define SCNi64 "I64i" -+#define SCNdLEAST64 "I64d" -+#define SCNiLEAST64 "I64i" -+#define SCNdFAST64 "I64d" -+#define SCNiFAST64 "I64i" -+ -+#define SCNdMAX "I64d" -+#define SCNiMAX "I64i" -+ -+#ifdef _WIN64 // [ -+# define SCNdPTR "I64d" -+# define SCNiPTR "I64i" -+#else // _WIN64 ][ -+# define SCNdPTR "ld" -+# define SCNiPTR "li" -+#endif // _WIN64 ] -+ -+// The fscanf macros for unsigned integers are: -+#define SCNo8 "o" -+#define SCNu8 "u" -+#define SCNx8 "x" -+#define SCNX8 "X" -+#define SCNoLEAST8 "o" -+#define SCNuLEAST8 "u" -+#define SCNxLEAST8 "x" -+#define SCNXLEAST8 "X" -+#define SCNoFAST8 "o" -+#define SCNuFAST8 "u" -+#define SCNxFAST8 "x" -+#define SCNXFAST8 "X" -+ -+#define SCNo16 "ho" -+#define SCNu16 "hu" -+#define SCNx16 "hx" -+#define SCNX16 "hX" -+#define SCNoLEAST16 "ho" -+#define SCNuLEAST16 "hu" -+#define SCNxLEAST16 "hx" -+#define SCNXLEAST16 "hX" -+#define SCNoFAST16 "ho" -+#define SCNuFAST16 "hu" -+#define SCNxFAST16 "hx" -+#define SCNXFAST16 "hX" -+ -+#define SCNo32 "lo" -+#define SCNu32 "lu" -+#define SCNx32 "lx" -+#define SCNX32 "lX" -+#define SCNoLEAST32 "lo" -+#define SCNuLEAST32 "lu" -+#define SCNxLEAST32 "lx" -+#define SCNXLEAST32 "lX" -+#define SCNoFAST32 "lo" -+#define SCNuFAST32 "lu" -+#define SCNxFAST32 "lx" -+#define SCNXFAST32 "lX" -+ -+#define SCNo64 "I64o" -+#define SCNu64 "I64u" -+#define SCNx64 "I64x" -+#define SCNX64 "I64X" -+#define SCNoLEAST64 "I64o" -+#define SCNuLEAST64 "I64u" -+#define SCNxLEAST64 "I64x" -+#define SCNXLEAST64 "I64X" -+#define SCNoFAST64 "I64o" -+#define SCNuFAST64 "I64u" -+#define SCNxFAST64 "I64x" -+#define SCNXFAST64 "I64X" -+ -+#define SCNoMAX "I64o" -+#define SCNuMAX "I64u" -+#define SCNxMAX "I64x" -+#define SCNXMAX "I64X" -+ -+#ifdef _WIN64 // [ -+# define SCNoPTR "I64o" -+# define SCNuPTR "I64u" -+# define SCNxPTR "I64x" -+# define SCNXPTR "I64X" -+#else // _WIN64 ][ -+# define SCNoPTR "lo" -+# define SCNuPTR "lu" -+# define SCNxPTR "lx" -+# define SCNXPTR "lX" -+#endif // _WIN64 ] -+ -+#endif // __STDC_FORMAT_MACROS ] -+ -+// 7.8.2 Functions for greatest-width integer types -+ -+// 7.8.2.1 The imaxabs function -+#define imaxabs _abs64 -+ -+// 7.8.2.2 The imaxdiv function -+ -+// This is modified version of div() function from Microsoft's div.c found -+// in %MSVC.NET%\crt\src\div.c -+#ifdef STATIC_IMAXDIV // [ -+static -+#else // STATIC_IMAXDIV ][ -+_inline -+#endif // STATIC_IMAXDIV ] -+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) -+{ -+ imaxdiv_t result; -+ -+ result.quot = numer / denom; -+ result.rem = numer % denom; -+ -+ if (numer < 0 && result.rem > 0) { -+ // did division wrong; must fix up -+ ++result.quot; -+ result.rem -= denom; -+ } -+ -+ return result; -+} -+ -+// 7.8.2.3 The strtoimax and strtoumax functions -+#define strtoimax _strtoi64 -+#define strtoumax _strtoui64 -+ -+// 7.8.2.4 The wcstoimax and wcstoumax functions -+#define wcstoimax _wcstoi64 -+#define wcstoumax _wcstoui64 -+ -+ -+#endif // _MSC_INTTYPES_H_ ] -diff -r 1da44232e82e -r 73d73a2ae3ad include/msvc_compat/C99/stdbool.h ---- /dev/null Thu Jan 01 00:00:00 1970 +0000 -+++ b/include/msvc_compat/C99/stdbool.h Thu May 29 16:35:25 2014 +0900 -@@ -0,0 +1,16 @@ -+#ifndef stdbool_h -+#define stdbool_h -+ -+#include -+ -+/* MSVC doesn't define _Bool or bool in C, but does have BOOL */ -+/* Note this doesn't pass autoconf's test because (bool) 0.5 != true */ -+typedef BOOL _Bool; -+ -+#define bool _Bool -+#define true 1 -+#define false 0 -+ -+#define __bool_true_false_are_defined 1 -+ -+#endif /* stdbool_h */ -diff -r 1da44232e82e -r 73d73a2ae3ad include/msvc_compat/C99/stdint.h ---- /dev/null Thu Jan 01 00:00:00 1970 +0000 -+++ b/include/msvc_compat/C99/stdint.h Thu May 29 16:35:25 2014 +0900 -@@ -0,0 +1,247 @@ -+// ISO C9x compliant stdint.h for Microsoft Visual Studio -+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -+// -+// Copyright (c) 2006-2008 Alexander Chemeris -+// -+// Redistribution and use in source and binary forms, with or without -+// modification, are permitted provided that the following conditions are met: -+// -+// 1. Redistributions of source code must retain the above copyright notice, -+// this list of conditions and the following disclaimer. -+// -+// 2. Redistributions in binary form must reproduce the above copyright -+// notice, this list of conditions and the following disclaimer in the -+// documentation and/or other materials provided with the distribution. -+// -+// 3. The name of the author may be used to endorse or promote products -+// derived from this software without specific prior written permission. -+// -+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+// -+/////////////////////////////////////////////////////////////////////////////// -+ -+#ifndef _MSC_VER // [ -+#error "Use this header only with Microsoft Visual C++ compilers!" -+#endif // _MSC_VER ] -+ -+#ifndef _MSC_STDINT_H_ // [ -+#define _MSC_STDINT_H_ -+ -+#if _MSC_VER > 1000 -+#pragma once -+#endif -+ -+#include -+ -+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when -+// compiling for ARM we should wrap include with 'extern "C++" {}' -+// or compiler give many errors like this: -+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed -+#ifdef __cplusplus -+extern "C" { -+#endif -+# include -+#ifdef __cplusplus -+} -+#endif -+ -+// Define _W64 macros to mark types changing their size, like intptr_t. -+#ifndef _W64 -+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 -+# define _W64 __w64 -+# else -+# define _W64 -+# endif -+#endif -+ -+ -+// 7.18.1 Integer types -+ -+// 7.18.1.1 Exact-width integer types -+ -+// Visual Studio 6 and Embedded Visual C++ 4 doesn't -+// realize that, e.g. char has the same size as __int8 -+// so we give up on __intX for them. -+#if (_MSC_VER < 1300) -+ typedef signed char int8_t; -+ typedef signed short int16_t; -+ typedef signed int int32_t; -+ typedef unsigned char uint8_t; -+ typedef unsigned short uint16_t; -+ typedef unsigned int uint32_t; -+#else -+ typedef signed __int8 int8_t; -+ typedef signed __int16 int16_t; -+ typedef signed __int32 int32_t; -+ typedef unsigned __int8 uint8_t; -+ typedef unsigned __int16 uint16_t; -+ typedef unsigned __int32 uint32_t; -+#endif -+typedef signed __int64 int64_t; -+typedef unsigned __int64 uint64_t; -+ -+ -+// 7.18.1.2 Minimum-width integer types -+typedef int8_t int_least8_t; -+typedef int16_t int_least16_t; -+typedef int32_t int_least32_t; -+typedef int64_t int_least64_t; -+typedef uint8_t uint_least8_t; -+typedef uint16_t uint_least16_t; -+typedef uint32_t uint_least32_t; -+typedef uint64_t uint_least64_t; -+ -+// 7.18.1.3 Fastest minimum-width integer types -+typedef int8_t int_fast8_t; -+typedef int16_t int_fast16_t; -+typedef int32_t int_fast32_t; -+typedef int64_t int_fast64_t; -+typedef uint8_t uint_fast8_t; -+typedef uint16_t uint_fast16_t; -+typedef uint32_t uint_fast32_t; -+typedef uint64_t uint_fast64_t; -+ -+// 7.18.1.4 Integer types capable of holding object pointers -+#ifdef _WIN64 // [ -+ typedef signed __int64 intptr_t; -+ typedef unsigned __int64 uintptr_t; -+#else // _WIN64 ][ -+ typedef _W64 signed int intptr_t; -+ typedef _W64 unsigned int uintptr_t; -+#endif // _WIN64 ] -+ -+// 7.18.1.5 Greatest-width integer types -+typedef int64_t intmax_t; -+typedef uint64_t uintmax_t; -+ -+ -+// 7.18.2 Limits of specified-width integer types -+ -+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 -+ -+// 7.18.2.1 Limits of exact-width integer types -+#define INT8_MIN ((int8_t)_I8_MIN) -+#define INT8_MAX _I8_MAX -+#define INT16_MIN ((int16_t)_I16_MIN) -+#define INT16_MAX _I16_MAX -+#define INT32_MIN ((int32_t)_I32_MIN) -+#define INT32_MAX _I32_MAX -+#define INT64_MIN ((int64_t)_I64_MIN) -+#define INT64_MAX _I64_MAX -+#define UINT8_MAX _UI8_MAX -+#define UINT16_MAX _UI16_MAX -+#define UINT32_MAX _UI32_MAX -+#define UINT64_MAX _UI64_MAX -+ -+// 7.18.2.2 Limits of minimum-width integer types -+#define INT_LEAST8_MIN INT8_MIN -+#define INT_LEAST8_MAX INT8_MAX -+#define INT_LEAST16_MIN INT16_MIN -+#define INT_LEAST16_MAX INT16_MAX -+#define INT_LEAST32_MIN INT32_MIN -+#define INT_LEAST32_MAX INT32_MAX -+#define INT_LEAST64_MIN INT64_MIN -+#define INT_LEAST64_MAX INT64_MAX -+#define UINT_LEAST8_MAX UINT8_MAX -+#define UINT_LEAST16_MAX UINT16_MAX -+#define UINT_LEAST32_MAX UINT32_MAX -+#define UINT_LEAST64_MAX UINT64_MAX -+ -+// 7.18.2.3 Limits of fastest minimum-width integer types -+#define INT_FAST8_MIN INT8_MIN -+#define INT_FAST8_MAX INT8_MAX -+#define INT_FAST16_MIN INT16_MIN -+#define INT_FAST16_MAX INT16_MAX -+#define INT_FAST32_MIN INT32_MIN -+#define INT_FAST32_MAX INT32_MAX -+#define INT_FAST64_MIN INT64_MIN -+#define INT_FAST64_MAX INT64_MAX -+#define UINT_FAST8_MAX UINT8_MAX -+#define UINT_FAST16_MAX UINT16_MAX -+#define UINT_FAST32_MAX UINT32_MAX -+#define UINT_FAST64_MAX UINT64_MAX -+ -+// 7.18.2.4 Limits of integer types capable of holding object pointers -+#ifdef _WIN64 // [ -+# define INTPTR_MIN INT64_MIN -+# define INTPTR_MAX INT64_MAX -+# define UINTPTR_MAX UINT64_MAX -+#else // _WIN64 ][ -+# define INTPTR_MIN INT32_MIN -+# define INTPTR_MAX INT32_MAX -+# define UINTPTR_MAX UINT32_MAX -+#endif // _WIN64 ] -+ -+// 7.18.2.5 Limits of greatest-width integer types -+#define INTMAX_MIN INT64_MIN -+#define INTMAX_MAX INT64_MAX -+#define UINTMAX_MAX UINT64_MAX -+ -+// 7.18.3 Limits of other integer types -+ -+#ifdef _WIN64 // [ -+# define PTRDIFF_MIN _I64_MIN -+# define PTRDIFF_MAX _I64_MAX -+#else // _WIN64 ][ -+# define PTRDIFF_MIN _I32_MIN -+# define PTRDIFF_MAX _I32_MAX -+#endif // _WIN64 ] -+ -+#define SIG_ATOMIC_MIN INT_MIN -+#define SIG_ATOMIC_MAX INT_MAX -+ -+#ifndef SIZE_MAX // [ -+# ifdef _WIN64 // [ -+# define SIZE_MAX _UI64_MAX -+# else // _WIN64 ][ -+# define SIZE_MAX _UI32_MAX -+# endif // _WIN64 ] -+#endif // SIZE_MAX ] -+ -+// WCHAR_MIN and WCHAR_MAX are also defined in -+#ifndef WCHAR_MIN // [ -+# define WCHAR_MIN 0 -+#endif // WCHAR_MIN ] -+#ifndef WCHAR_MAX // [ -+# define WCHAR_MAX _UI16_MAX -+#endif // WCHAR_MAX ] -+ -+#define WINT_MIN 0 -+#define WINT_MAX _UI16_MAX -+ -+#endif // __STDC_LIMIT_MACROS ] -+ -+ -+// 7.18.4 Limits of other integer types -+ -+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 -+ -+// 7.18.4.1 Macros for minimum-width integer constants -+ -+#define INT8_C(val) val##i8 -+#define INT16_C(val) val##i16 -+#define INT32_C(val) val##i32 -+#define INT64_C(val) val##i64 -+ -+#define UINT8_C(val) val##ui8 -+#define UINT16_C(val) val##ui16 -+#define UINT32_C(val) val##ui32 -+#define UINT64_C(val) val##ui64 -+ -+// 7.18.4.2 Macros for greatest-width integer constants -+#define INTMAX_C INT64_C -+#define UINTMAX_C UINT64_C -+ -+#endif // __STDC_CONSTANT_MACROS ] -+ -+ -+#endif // _MSC_STDINT_H_ ] -diff -r 1da44232e82e -r 73d73a2ae3ad include/msvc_compat/inttypes.h ---- a/include/msvc_compat/inttypes.h Wed May 21 14:41:51 2014 -0700 -+++ /dev/null Thu Jan 01 00:00:00 1970 +0000 -@@ -1,313 +0,0 @@ --// ISO C9x compliant inttypes.h for Microsoft Visual Studio --// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 --// --// Copyright (c) 2006 Alexander Chemeris --// --// Redistribution and use in source and binary forms, with or without --// modification, are permitted provided that the following conditions are met: --// --// 1. Redistributions of source code must retain the above copyright notice, --// this list of conditions and the following disclaimer. --// --// 2. Redistributions in binary form must reproduce the above copyright --// notice, this list of conditions and the following disclaimer in the --// documentation and/or other materials provided with the distribution. --// --// 3. The name of the author may be used to endorse or promote products --// derived from this software without specific prior written permission. --// --// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED --// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --// --/////////////////////////////////////////////////////////////////////////////// -- --#ifndef _MSC_VER // [ --#error "Use this header only with Microsoft Visual C++ compilers!" --#endif // _MSC_VER ] -- --#ifndef _MSC_INTTYPES_H_ // [ --#define _MSC_INTTYPES_H_ -- --#if _MSC_VER > 1000 --#pragma once --#endif -- --#include "stdint.h" -- --// 7.8 Format conversion of integer types -- --typedef struct { -- intmax_t quot; -- intmax_t rem; --} imaxdiv_t; -- --// 7.8.1 Macros for format specifiers -- --#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 -- --#ifdef _WIN64 --# define __PRI64_PREFIX "l" --# define __PRIPTR_PREFIX "l" --#else --# define __PRI64_PREFIX "ll" --# define __PRIPTR_PREFIX --#endif -- --// The fprintf macros for signed integers are: --#define PRId8 "d" --#define PRIi8 "i" --#define PRIdLEAST8 "d" --#define PRIiLEAST8 "i" --#define PRIdFAST8 "d" --#define PRIiFAST8 "i" -- --#define PRId16 "hd" --#define PRIi16 "hi" --#define PRIdLEAST16 "hd" --#define PRIiLEAST16 "hi" --#define PRIdFAST16 "hd" --#define PRIiFAST16 "hi" -- --#define PRId32 "d" --#define PRIi32 "i" --#define PRIdLEAST32 "d" --#define PRIiLEAST32 "i" --#define PRIdFAST32 "d" --#define PRIiFAST32 "i" -- --#define PRId64 __PRI64_PREFIX "d" --#define PRIi64 __PRI64_PREFIX "i" --#define PRIdLEAST64 __PRI64_PREFIX "d" --#define PRIiLEAST64 __PRI64_PREFIX "i" --#define PRIdFAST64 __PRI64_PREFIX "d" --#define PRIiFAST64 __PRI64_PREFIX "i" -- --#define PRIdMAX __PRI64_PREFIX "d" --#define PRIiMAX __PRI64_PREFIX "i" -- --#define PRIdPTR __PRIPTR_PREFIX "d" --#define PRIiPTR __PRIPTR_PREFIX "i" -- --// The fprintf macros for unsigned integers are: --#define PRIo8 "o" --#define PRIu8 "u" --#define PRIx8 "x" --#define PRIX8 "X" --#define PRIoLEAST8 "o" --#define PRIuLEAST8 "u" --#define PRIxLEAST8 "x" --#define PRIXLEAST8 "X" --#define PRIoFAST8 "o" --#define PRIuFAST8 "u" --#define PRIxFAST8 "x" --#define PRIXFAST8 "X" -- --#define PRIo16 "ho" --#define PRIu16 "hu" --#define PRIx16 "hx" --#define PRIX16 "hX" --#define PRIoLEAST16 "ho" --#define PRIuLEAST16 "hu" --#define PRIxLEAST16 "hx" --#define PRIXLEAST16 "hX" --#define PRIoFAST16 "ho" --#define PRIuFAST16 "hu" --#define PRIxFAST16 "hx" --#define PRIXFAST16 "hX" -- --#define PRIo32 "o" --#define PRIu32 "u" --#define PRIx32 "x" --#define PRIX32 "X" --#define PRIoLEAST32 "o" --#define PRIuLEAST32 "u" --#define PRIxLEAST32 "x" --#define PRIXLEAST32 "X" --#define PRIoFAST32 "o" --#define PRIuFAST32 "u" --#define PRIxFAST32 "x" --#define PRIXFAST32 "X" -- --#define PRIo64 __PRI64_PREFIX "o" --#define PRIu64 __PRI64_PREFIX "u" --#define PRIx64 __PRI64_PREFIX "x" --#define PRIX64 __PRI64_PREFIX "X" --#define PRIoLEAST64 __PRI64_PREFIX "o" --#define PRIuLEAST64 __PRI64_PREFIX "u" --#define PRIxLEAST64 __PRI64_PREFIX "x" --#define PRIXLEAST64 __PRI64_PREFIX "X" --#define PRIoFAST64 __PRI64_PREFIX "o" --#define PRIuFAST64 __PRI64_PREFIX "u" --#define PRIxFAST64 __PRI64_PREFIX "x" --#define PRIXFAST64 __PRI64_PREFIX "X" -- --#define PRIoMAX __PRI64_PREFIX "o" --#define PRIuMAX __PRI64_PREFIX "u" --#define PRIxMAX __PRI64_PREFIX "x" --#define PRIXMAX __PRI64_PREFIX "X" -- --#define PRIoPTR __PRIPTR_PREFIX "o" --#define PRIuPTR __PRIPTR_PREFIX "u" --#define PRIxPTR __PRIPTR_PREFIX "x" --#define PRIXPTR __PRIPTR_PREFIX "X" -- --// The fscanf macros for signed integers are: --#define SCNd8 "d" --#define SCNi8 "i" --#define SCNdLEAST8 "d" --#define SCNiLEAST8 "i" --#define SCNdFAST8 "d" --#define SCNiFAST8 "i" -- --#define SCNd16 "hd" --#define SCNi16 "hi" --#define SCNdLEAST16 "hd" --#define SCNiLEAST16 "hi" --#define SCNdFAST16 "hd" --#define SCNiFAST16 "hi" -- --#define SCNd32 "ld" --#define SCNi32 "li" --#define SCNdLEAST32 "ld" --#define SCNiLEAST32 "li" --#define SCNdFAST32 "ld" --#define SCNiFAST32 "li" -- --#define SCNd64 "I64d" --#define SCNi64 "I64i" --#define SCNdLEAST64 "I64d" --#define SCNiLEAST64 "I64i" --#define SCNdFAST64 "I64d" --#define SCNiFAST64 "I64i" -- --#define SCNdMAX "I64d" --#define SCNiMAX "I64i" -- --#ifdef _WIN64 // [ --# define SCNdPTR "I64d" --# define SCNiPTR "I64i" --#else // _WIN64 ][ --# define SCNdPTR "ld" --# define SCNiPTR "li" --#endif // _WIN64 ] -- --// The fscanf macros for unsigned integers are: --#define SCNo8 "o" --#define SCNu8 "u" --#define SCNx8 "x" --#define SCNX8 "X" --#define SCNoLEAST8 "o" --#define SCNuLEAST8 "u" --#define SCNxLEAST8 "x" --#define SCNXLEAST8 "X" --#define SCNoFAST8 "o" --#define SCNuFAST8 "u" --#define SCNxFAST8 "x" --#define SCNXFAST8 "X" -- --#define SCNo16 "ho" --#define SCNu16 "hu" --#define SCNx16 "hx" --#define SCNX16 "hX" --#define SCNoLEAST16 "ho" --#define SCNuLEAST16 "hu" --#define SCNxLEAST16 "hx" --#define SCNXLEAST16 "hX" --#define SCNoFAST16 "ho" --#define SCNuFAST16 "hu" --#define SCNxFAST16 "hx" --#define SCNXFAST16 "hX" -- --#define SCNo32 "lo" --#define SCNu32 "lu" --#define SCNx32 "lx" --#define SCNX32 "lX" --#define SCNoLEAST32 "lo" --#define SCNuLEAST32 "lu" --#define SCNxLEAST32 "lx" --#define SCNXLEAST32 "lX" --#define SCNoFAST32 "lo" --#define SCNuFAST32 "lu" --#define SCNxFAST32 "lx" --#define SCNXFAST32 "lX" -- --#define SCNo64 "I64o" --#define SCNu64 "I64u" --#define SCNx64 "I64x" --#define SCNX64 "I64X" --#define SCNoLEAST64 "I64o" --#define SCNuLEAST64 "I64u" --#define SCNxLEAST64 "I64x" --#define SCNXLEAST64 "I64X" --#define SCNoFAST64 "I64o" --#define SCNuFAST64 "I64u" --#define SCNxFAST64 "I64x" --#define SCNXFAST64 "I64X" -- --#define SCNoMAX "I64o" --#define SCNuMAX "I64u" --#define SCNxMAX "I64x" --#define SCNXMAX "I64X" -- --#ifdef _WIN64 // [ --# define SCNoPTR "I64o" --# define SCNuPTR "I64u" --# define SCNxPTR "I64x" --# define SCNXPTR "I64X" --#else // _WIN64 ][ --# define SCNoPTR "lo" --# define SCNuPTR "lu" --# define SCNxPTR "lx" --# define SCNXPTR "lX" --#endif // _WIN64 ] -- --#endif // __STDC_FORMAT_MACROS ] -- --// 7.8.2 Functions for greatest-width integer types -- --// 7.8.2.1 The imaxabs function --#define imaxabs _abs64 -- --// 7.8.2.2 The imaxdiv function -- --// This is modified version of div() function from Microsoft's div.c found --// in %MSVC.NET%\crt\src\div.c --#ifdef STATIC_IMAXDIV // [ --static --#else // STATIC_IMAXDIV ][ --_inline --#endif // STATIC_IMAXDIV ] --imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) --{ -- imaxdiv_t result; -- -- result.quot = numer / denom; -- result.rem = numer % denom; -- -- if (numer < 0 && result.rem > 0) { -- // did division wrong; must fix up -- ++result.quot; -- result.rem -= denom; -- } -- -- return result; --} -- --// 7.8.2.3 The strtoimax and strtoumax functions --#define strtoimax _strtoi64 --#define strtoumax _strtoui64 -- --// 7.8.2.4 The wcstoimax and wcstoumax functions --#define wcstoimax _wcstoi64 --#define wcstoumax _wcstoui64 -- -- --#endif // _MSC_INTTYPES_H_ ] -diff -r 1da44232e82e -r 73d73a2ae3ad include/msvc_compat/stdbool.h ---- a/include/msvc_compat/stdbool.h Wed May 21 14:41:51 2014 -0700 -+++ /dev/null Thu Jan 01 00:00:00 1970 +0000 -@@ -1,16 +0,0 @@ --#ifndef stdbool_h --#define stdbool_h -- --#include -- --/* MSVC doesn't define _Bool or bool in C, but does have BOOL */ --/* Note this doesn't pass autoconf's test because (bool) 0.5 != true */ --typedef BOOL _Bool; -- --#define bool _Bool --#define true 1 --#define false 0 -- --#define __bool_true_false_are_defined 1 -- --#endif /* stdbool_h */ -diff -r 1da44232e82e -r 73d73a2ae3ad include/msvc_compat/stdint.h ---- a/include/msvc_compat/stdint.h Wed May 21 14:41:51 2014 -0700 -+++ /dev/null Thu Jan 01 00:00:00 1970 +0000 -@@ -1,247 +0,0 @@ --// ISO C9x compliant stdint.h for Microsoft Visual Studio --// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 --// --// Copyright (c) 2006-2008 Alexander Chemeris --// --// Redistribution and use in source and binary forms, with or without --// modification, are permitted provided that the following conditions are met: --// --// 1. Redistributions of source code must retain the above copyright notice, --// this list of conditions and the following disclaimer. --// --// 2. Redistributions in binary form must reproduce the above copyright --// notice, this list of conditions and the following disclaimer in the --// documentation and/or other materials provided with the distribution. --// --// 3. The name of the author may be used to endorse or promote products --// derived from this software without specific prior written permission. --// --// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED --// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --// --/////////////////////////////////////////////////////////////////////////////// -- --#ifndef _MSC_VER // [ --#error "Use this header only with Microsoft Visual C++ compilers!" --#endif // _MSC_VER ] -- --#ifndef _MSC_STDINT_H_ // [ --#define _MSC_STDINT_H_ -- --#if _MSC_VER > 1000 --#pragma once --#endif -- --#include -- --// For Visual Studio 6 in C++ mode and for many Visual Studio versions when --// compiling for ARM we should wrap include with 'extern "C++" {}' --// or compiler give many errors like this: --// error C2733: second C linkage of overloaded function 'wmemchr' not allowed --#ifdef __cplusplus --extern "C" { --#endif --# include --#ifdef __cplusplus --} --#endif -- --// Define _W64 macros to mark types changing their size, like intptr_t. --#ifndef _W64 --# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 --# define _W64 __w64 --# else --# define _W64 --# endif --#endif -- -- --// 7.18.1 Integer types -- --// 7.18.1.1 Exact-width integer types -- --// Visual Studio 6 and Embedded Visual C++ 4 doesn't --// realize that, e.g. char has the same size as __int8 --// so we give up on __intX for them. --#if (_MSC_VER < 1300) -- typedef signed char int8_t; -- typedef signed short int16_t; -- typedef signed int int32_t; -- typedef unsigned char uint8_t; -- typedef unsigned short uint16_t; -- typedef unsigned int uint32_t; --#else -- typedef signed __int8 int8_t; -- typedef signed __int16 int16_t; -- typedef signed __int32 int32_t; -- typedef unsigned __int8 uint8_t; -- typedef unsigned __int16 uint16_t; -- typedef unsigned __int32 uint32_t; --#endif --typedef signed __int64 int64_t; --typedef unsigned __int64 uint64_t; -- -- --// 7.18.1.2 Minimum-width integer types --typedef int8_t int_least8_t; --typedef int16_t int_least16_t; --typedef int32_t int_least32_t; --typedef int64_t int_least64_t; --typedef uint8_t uint_least8_t; --typedef uint16_t uint_least16_t; --typedef uint32_t uint_least32_t; --typedef uint64_t uint_least64_t; -- --// 7.18.1.3 Fastest minimum-width integer types --typedef int8_t int_fast8_t; --typedef int16_t int_fast16_t; --typedef int32_t int_fast32_t; --typedef int64_t int_fast64_t; --typedef uint8_t uint_fast8_t; --typedef uint16_t uint_fast16_t; --typedef uint32_t uint_fast32_t; --typedef uint64_t uint_fast64_t; -- --// 7.18.1.4 Integer types capable of holding object pointers --#ifdef _WIN64 // [ -- typedef signed __int64 intptr_t; -- typedef unsigned __int64 uintptr_t; --#else // _WIN64 ][ -- typedef _W64 signed int intptr_t; -- typedef _W64 unsigned int uintptr_t; --#endif // _WIN64 ] -- --// 7.18.1.5 Greatest-width integer types --typedef int64_t intmax_t; --typedef uint64_t uintmax_t; -- -- --// 7.18.2 Limits of specified-width integer types -- --#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 -- --// 7.18.2.1 Limits of exact-width integer types --#define INT8_MIN ((int8_t)_I8_MIN) --#define INT8_MAX _I8_MAX --#define INT16_MIN ((int16_t)_I16_MIN) --#define INT16_MAX _I16_MAX --#define INT32_MIN ((int32_t)_I32_MIN) --#define INT32_MAX _I32_MAX --#define INT64_MIN ((int64_t)_I64_MIN) --#define INT64_MAX _I64_MAX --#define UINT8_MAX _UI8_MAX --#define UINT16_MAX _UI16_MAX --#define UINT32_MAX _UI32_MAX --#define UINT64_MAX _UI64_MAX -- --// 7.18.2.2 Limits of minimum-width integer types --#define INT_LEAST8_MIN INT8_MIN --#define INT_LEAST8_MAX INT8_MAX --#define INT_LEAST16_MIN INT16_MIN --#define INT_LEAST16_MAX INT16_MAX --#define INT_LEAST32_MIN INT32_MIN --#define INT_LEAST32_MAX INT32_MAX --#define INT_LEAST64_MIN INT64_MIN --#define INT_LEAST64_MAX INT64_MAX --#define UINT_LEAST8_MAX UINT8_MAX --#define UINT_LEAST16_MAX UINT16_MAX --#define UINT_LEAST32_MAX UINT32_MAX --#define UINT_LEAST64_MAX UINT64_MAX -- --// 7.18.2.3 Limits of fastest minimum-width integer types --#define INT_FAST8_MIN INT8_MIN --#define INT_FAST8_MAX INT8_MAX --#define INT_FAST16_MIN INT16_MIN --#define INT_FAST16_MAX INT16_MAX --#define INT_FAST32_MIN INT32_MIN --#define INT_FAST32_MAX INT32_MAX --#define INT_FAST64_MIN INT64_MIN --#define INT_FAST64_MAX INT64_MAX --#define UINT_FAST8_MAX UINT8_MAX --#define UINT_FAST16_MAX UINT16_MAX --#define UINT_FAST32_MAX UINT32_MAX --#define UINT_FAST64_MAX UINT64_MAX -- --// 7.18.2.4 Limits of integer types capable of holding object pointers --#ifdef _WIN64 // [ --# define INTPTR_MIN INT64_MIN --# define INTPTR_MAX INT64_MAX --# define UINTPTR_MAX UINT64_MAX --#else // _WIN64 ][ --# define INTPTR_MIN INT32_MIN --# define INTPTR_MAX INT32_MAX --# define UINTPTR_MAX UINT32_MAX --#endif // _WIN64 ] -- --// 7.18.2.5 Limits of greatest-width integer types --#define INTMAX_MIN INT64_MIN --#define INTMAX_MAX INT64_MAX --#define UINTMAX_MAX UINT64_MAX -- --// 7.18.3 Limits of other integer types -- --#ifdef _WIN64 // [ --# define PTRDIFF_MIN _I64_MIN --# define PTRDIFF_MAX _I64_MAX --#else // _WIN64 ][ --# define PTRDIFF_MIN _I32_MIN --# define PTRDIFF_MAX _I32_MAX --#endif // _WIN64 ] -- --#define SIG_ATOMIC_MIN INT_MIN --#define SIG_ATOMIC_MAX INT_MAX -- --#ifndef SIZE_MAX // [ --# ifdef _WIN64 // [ --# define SIZE_MAX _UI64_MAX --# else // _WIN64 ][ --# define SIZE_MAX _UI32_MAX --# endif // _WIN64 ] --#endif // SIZE_MAX ] -- --// WCHAR_MIN and WCHAR_MAX are also defined in --#ifndef WCHAR_MIN // [ --# define WCHAR_MIN 0 --#endif // WCHAR_MIN ] --#ifndef WCHAR_MAX // [ --# define WCHAR_MAX _UI16_MAX --#endif // WCHAR_MAX ] -- --#define WINT_MIN 0 --#define WINT_MAX _UI16_MAX -- --#endif // __STDC_LIMIT_MACROS ] -- -- --// 7.18.4 Limits of other integer types -- --#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 -- --// 7.18.4.1 Macros for minimum-width integer constants -- --#define INT8_C(val) val##i8 --#define INT16_C(val) val##i16 --#define INT32_C(val) val##i32 --#define INT64_C(val) val##i64 -- --#define UINT8_C(val) val##ui8 --#define UINT16_C(val) val##ui16 --#define UINT32_C(val) val##ui32 --#define UINT64_C(val) val##ui64 -- --// 7.18.4.2 Macros for greatest-width integer constants --#define INTMAX_C INT64_C --#define UINTMAX_C UINT64_C -- --#endif // __STDC_CONSTANT_MACROS ] -- -- --#endif // _MSC_STDINT_H_ ] diff --git a/memory/jemalloc/0004-Try-to-use-__builtin_ffsl-if-ffsl-is-unavailable.patch b/memory/jemalloc/0004-Try-to-use-__builtin_ffsl-if-ffsl-is-unavailable.patch deleted file mode 100644 index 5df2f8c7fc2e..000000000000 --- a/memory/jemalloc/0004-Try-to-use-__builtin_ffsl-if-ffsl-is-unavailable.patch +++ /dev/null @@ -1,354 +0,0 @@ -diff --git a/configure b/configure ---- a/configure -+++ b/configure -@@ -6940,18 +6940,67 @@ else - je_cv_function_ffsl=no - fi - rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_function_ffsl" >&5 - $as_echo "$je_cv_function_ffsl" >&6; } - --if test "x${je_cv_function_ffsl}" != "xyes" ; then -- as_fn_error $? "Cannot build without ffsl(3)" "$LINENO" 5 -+if test "x${je_cv_function_ffsl}" == "xyes" ; then -+ $as_echo "#define JEMALLOC_INTERNAL_FFSL ffsl" >>confdefs.h -+ -+ $as_echo "#define JEMALLOC_INTERNAL_FFS ffs" >>confdefs.h -+ -+else -+ -+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program using __builtin_ffsl is compilable" >&5 -+$as_echo_n "checking whether a program using __builtin_ffsl is compilable... " >&6; } -+if ${je_cv_gcc_builtin_ffsl+:} false; then : -+ $as_echo_n "(cached) " >&6 -+else -+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+ -+ #include -+ #include -+ #include -+ -+int -+main () -+{ -+ -+ { -+ int rv = __builtin_ffsl(0x08); -+ printf("%d\n", rv); -+ } -+ -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_link "$LINENO"; then : -+ je_cv_gcc_builtin_ffsl=yes -+else -+ je_cv_gcc_builtin_ffsl=no -+fi -+rm -f core conftest.err conftest.$ac_objext \ -+ conftest$ac_exeext conftest.$ac_ext -+fi -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_gcc_builtin_ffsl" >&5 -+$as_echo "$je_cv_gcc_builtin_ffsl" >&6; } -+ -+ if test "x${je_cv_gcc_builtin_ffsl}" == "xyes" ; then -+ $as_echo "#define JEMALLOC_INTERNAL_FFSL __builtin_ffsl" >>confdefs.h -+ -+ $as_echo "#define JEMALLOC_INTERNAL_FFS __builtin_ffs" >>confdefs.h -+ -+ else -+ as_fn_error $? "Cannot build without ffsl(3) or __builtin_ffsl()" "$LINENO" 5 -+ fi - fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether atomic(9) is compilable" >&5 - $as_echo_n "checking whether atomic(9) is compilable... " >&6; } - if ${je_cv_atomic9+:} false; then : - $as_echo_n "(cached) " >&6 -diff --git a/configure.ac b/configure.ac ---- a/configure.ac -+++ b/configure.ac -@@ -1160,31 +1160,51 @@ fi - AC_SUBST([enable_tls]) - if test "x${enable_tls}" = "x1" ; then - AC_DEFINE_UNQUOTED([JEMALLOC_TLS], [ ]) - elif test "x${force_tls}" = "x1" ; then - AC_MSG_ERROR([Failed to configure TLS, which is mandatory for correct function]) - fi - - dnl ============================================================================ --dnl Check for ffsl(3), and fail if not found. This function exists on all --dnl platforms that jemalloc currently has a chance of functioning on without --dnl modification. -+dnl Check for ffsl(3), then __builtin_ffsl(), and fail if neither are found. -+dnl One of those two functions should (theoretically) exist on all platforms -+dnl that jemalloc currently has a chance of functioning on without modification. -+dnl We additionally assume ffs() or __builtin_ffs() are defined if -+dnl ffsl() or __builtin_ffsl() are defined, respectively. - JE_COMPILABLE([a program using ffsl], [ - #include - #include - #include - ], [ - { - int rv = ffsl(0x08); - printf("%d\n", rv); - } - ], [je_cv_function_ffsl]) --if test "x${je_cv_function_ffsl}" != "xyes" ; then -- AC_MSG_ERROR([Cannot build without ffsl(3)]) -+if test "x${je_cv_function_ffsl}" == "xyes" ; then -+ AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [ffsl]) -+ AC_DEFINE([JEMALLOC_INTERNAL_FFS], [ffs]) -+else -+ JE_COMPILABLE([a program using __builtin_ffsl], [ -+ #include -+ #include -+ #include -+ ], [ -+ { -+ int rv = __builtin_ffsl(0x08); -+ printf("%d\n", rv); -+ } -+ ], [je_cv_gcc_builtin_ffsl]) -+ if test "x${je_cv_gcc_builtin_ffsl}" == "xyes" ; then -+ AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [__builtin_ffsl]) -+ AC_DEFINE([JEMALLOC_INTERNAL_FFS], [__builtin_ffs]) -+ else -+ AC_MSG_ERROR([Cannot build without ffsl(3) or __builtin_ffsl()]) -+ fi - fi - - dnl ============================================================================ - dnl Check for atomic(9) operations as provided on FreeBSD. - - JE_COMPILABLE([atomic(9)], [ - #include - #include -diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h ---- a/include/jemalloc/internal/arena.h -+++ b/include/jemalloc/internal/arena.h -@@ -810,17 +810,17 @@ arena_run_regind(arena_run_t *run, arena - * Avoid doing division with a variable divisor if possible. Using - * actual division here can reduce allocator throughput by over 20%! - */ - diff = (unsigned)((uintptr_t)ptr - (uintptr_t)run - - bin_info->reg0_offset); - - /* Rescale (factor powers of 2 out of the numerator and denominator). */ - interval = bin_info->reg_interval; -- shift = ffs(interval) - 1; -+ shift = jemalloc_ffs(interval) - 1; - diff >>= shift; - interval >>= shift; - - if (interval == 1) { - /* The divisor was a power of 2. */ - regind = diff; - } else { - /* -diff --git a/include/jemalloc/internal/bitmap.h b/include/jemalloc/internal/bitmap.h ---- a/include/jemalloc/internal/bitmap.h -+++ b/include/jemalloc/internal/bitmap.h -@@ -125,21 +125,21 @@ bitmap_sfu(bitmap_t *bitmap, const bitma - size_t bit; - bitmap_t g; - unsigned i; - - assert(bitmap_full(bitmap, binfo) == false); - - i = binfo->nlevels - 1; - g = bitmap[binfo->levels[i].group_offset]; -- bit = ffsl(g) - 1; -+ bit = jemalloc_ffsl(g) - 1; - while (i > 0) { - i--; - g = bitmap[binfo->levels[i].group_offset + bit]; -- bit = (bit << LG_BITMAP_GROUP_NBITS) + (ffsl(g) - 1); -+ bit = (bit << LG_BITMAP_GROUP_NBITS) + (jemalloc_ffsl(g) - 1); - } - - bitmap_set(bitmap, binfo, bit); - return (bit); - } - - JEMALLOC_INLINE void - bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) -diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in ---- a/include/jemalloc/internal/jemalloc_internal.h.in -+++ b/include/jemalloc/internal/jemalloc_internal.h.in -@@ -9,21 +9,23 @@ - # define EPERM ERROR_WRITE_FAULT - # define EFAULT ERROR_INVALID_ADDRESS - # define ENOMEM ERROR_NOT_ENOUGH_MEMORY - # undef ERANGE - # define ERANGE ERROR_INVALID_DATA - #else - # include - # include --# include --# if !defined(SYS_write) && defined(__NR_write) --# define SYS_write __NR_write -+# if !defined(__pnacl__) && !defined(__native_client__) -+# include -+# if !defined(SYS_write) && defined(__NR_write) -+# define SYS_write __NR_write -+# endif -+# include - # endif --# include - # include - # include - #endif - #include - - #include - #ifndef SIZE_T_MAX - # define SIZE_T_MAX SIZE_MAX -@@ -275,16 +277,19 @@ static const bool config_ivsalloc = - # define LG_QUANTUM 4 - # endif - # ifdef __SH4__ - # define LG_QUANTUM 4 - # endif - # ifdef __tile__ - # define LG_QUANTUM 4 - # endif -+# ifdef __le32__ -+# define LG_QUANTUM 4 -+# endif - # ifndef LG_QUANTUM - # error "No LG_QUANTUM definition for architecture; specify via CPPFLAGS" - # endif - #endif - - #define QUANTUM ((size_t)(1U << LG_QUANTUM)) - #define QUANTUM_MASK (QUANTUM - 1) - -diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in ---- a/include/jemalloc/internal/jemalloc_internal_defs.h.in -+++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in -@@ -153,16 +153,23 @@ - * memory map holes, much like munmap(2) does. - */ - #undef JEMALLOC_MREMAP - - /* TLS is used to map arenas and magazine caches to threads. */ - #undef JEMALLOC_TLS - - /* -+ * ffs()/ffsl() functions to use for bitmapping. Don't use these directly; -+ * instead, use jemalloc_ffs() or jemalloc_ffsl() from util.h. -+ */ -+#undef JEMALLOC_INTERNAL_FFSL -+#undef JEMALLOC_INTERNAL_FFS -+ -+/* - * JEMALLOC_IVSALLOC enables ivsalloc(), which verifies that pointers reside - * within jemalloc-owned chunks before dereferencing them. - */ - #undef JEMALLOC_IVSALLOC - - /* - * Darwin (OS X) uses zones to work around Mach-O symbol override shortcomings. - */ -diff --git a/include/jemalloc/internal/util.h b/include/jemalloc/internal/util.h ---- a/include/jemalloc/internal/util.h -+++ b/include/jemalloc/internal/util.h -@@ -104,22 +104,44 @@ void malloc_cprintf(void (*write)(void * - void malloc_printf(const char *format, ...) - JEMALLOC_ATTR(format(printf, 1, 2)); - - #endif /* JEMALLOC_H_EXTERNS */ - /******************************************************************************/ - #ifdef JEMALLOC_H_INLINES - - #ifndef JEMALLOC_ENABLE_INLINE -+int jemalloc_ffsl(long bitmap); -+int jemalloc_ffs(int bitmap); - size_t pow2_ceil(size_t x); - void set_errno(int errnum); - int get_errno(void); - #endif - - #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_UTIL_C_)) -+ -+/* Sanity check: */ -+#if !defined(JEMALLOC_INTERNAL_FFSL) || !defined(JEMALLOC_INTERNAL_FFS) -+# error Both JEMALLOC_INTERNAL_FFSL && JEMALLOC_INTERNAL_FFS should have been defined by configure -+#endif -+ -+JEMALLOC_ALWAYS_INLINE int -+jemalloc_ffsl(long bitmap) -+{ -+ -+ return (JEMALLOC_INTERNAL_FFSL(bitmap)); -+} -+ -+JEMALLOC_ALWAYS_INLINE int -+jemalloc_ffs(int bitmap) -+{ -+ -+ return (JEMALLOC_INTERNAL_FFS(bitmap)); -+} -+ - /* Compute the smallest power of 2 that is >= x. */ - JEMALLOC_INLINE size_t - pow2_ceil(size_t x) - { - - x--; - x |= x >> 1; - x |= x >> 2; -diff --git a/src/arena.c b/src/arena.c ---- a/src/arena.c -+++ b/src/arena.c -@@ -2378,17 +2378,17 @@ bin_info_run_size_calc(arena_bin_info_t - /* - * Determine redzone size based on minimum alignment and minimum - * redzone size. Add padding to the end of the run if it is needed to - * align the regions. The padding allows each redzone to be half the - * minimum alignment; without the padding, each redzone would have to - * be twice as large in order to maintain alignment. - */ - if (config_fill && opt_redzone) { -- size_t align_min = ZU(1) << (ffs(bin_info->reg_size) - 1); -+ size_t align_min = ZU(1) << (jemalloc_ffs(bin_info->reg_size) - 1); - if (align_min <= REDZONE_MINSIZE) { - bin_info->redzone_size = REDZONE_MINSIZE; - pad_size = 0; - } else { - bin_info->redzone_size = align_min >> 1; - pad_size = bin_info->redzone_size; - } - } else { -diff --git a/src/rtree.c b/src/rtree.c ---- a/src/rtree.c -+++ b/src/rtree.c -@@ -4,18 +4,18 @@ - rtree_t * - rtree_new(unsigned bits, rtree_alloc_t *alloc, rtree_dalloc_t *dalloc) - { - rtree_t *ret; - unsigned bits_per_level, bits_in_leaf, height, i; - - assert(bits > 0 && bits <= (sizeof(uintptr_t) << 3)); - -- bits_per_level = ffs(pow2_ceil((RTREE_NODESIZE / sizeof(void *)))) - 1; -- bits_in_leaf = ffs(pow2_ceil((RTREE_NODESIZE / sizeof(uint8_t)))) - 1; -+ bits_per_level = jemalloc_ffs(pow2_ceil((RTREE_NODESIZE / sizeof(void *)))) - 1; -+ bits_in_leaf = jemalloc_ffs(pow2_ceil((RTREE_NODESIZE / sizeof(uint8_t)))) - 1; - if (bits > bits_in_leaf) { - height = 1 + (bits - bits_in_leaf) / bits_per_level; - if ((height-1) * bits_per_level + bits_in_leaf != bits) - height++; - } else { - height = 1; - } - assert((height-1) * bits_per_level + bits_in_leaf >= bits); diff --git a/memory/jemalloc/0005-Check-for-__builtin_ffsl-before-ffsl.patch b/memory/jemalloc/0005-Check-for-__builtin_ffsl-before-ffsl.patch deleted file mode 100644 index 3348d6a588d6..000000000000 --- a/memory/jemalloc/0005-Check-for-__builtin_ffsl-before-ffsl.patch +++ /dev/null @@ -1,225 +0,0 @@ -diff --git a/configure b/configure ---- a/configure -+++ b/configure -@@ -6904,27 +6904,70 @@ if test "x${enable_tls}" = "x1" ; then - #define JEMALLOC_TLS - _ACEOF - - elif test "x${force_tls}" = "x1" ; then - as_fn_error $? "Failed to configure TLS, which is mandatory for correct function" "$LINENO" 5 - fi - - -+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program using __builtin_ffsl is compilable" >&5 -+$as_echo_n "checking whether a program using __builtin_ffsl is compilable... " >&6; } -+if ${je_cv_gcc_builtin_ffsl+:} false; then : -+ $as_echo_n "(cached) " >&6 -+else -+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+ -+#include -+#include -+#include -+ -+int -+main () -+{ -+ -+ { -+ int rv = __builtin_ffsl(0x08); -+ printf("%d\n", rv); -+ } -+ -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_link "$LINENO"; then : -+ je_cv_gcc_builtin_ffsl=yes -+else -+ je_cv_gcc_builtin_ffsl=no -+fi -+rm -f core conftest.err conftest.$ac_objext \ -+ conftest$ac_exeext conftest.$ac_ext -+fi -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_gcc_builtin_ffsl" >&5 -+$as_echo "$je_cv_gcc_builtin_ffsl" >&6; } -+ -+if test "x${je_cv_gcc_builtin_ffsl}" == "xyes" ; then -+ $as_echo "#define JEMALLOC_INTERNAL_FFSL __builtin_ffsl" >>confdefs.h -+ -+ $as_echo "#define JEMALLOC_INTERNAL_FFS __builtin_ffs" >>confdefs.h -+ -+else -+ - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program using ffsl is compilable" >&5 - $as_echo_n "checking whether a program using ffsl is compilable... " >&6; } - if ${je_cv_function_ffsl+:} false; then : - $as_echo_n "(cached) " >&6 - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - --#include --#include --#include -+ #include -+ #include -+ #include - - int - main () - { - - { - int rv = ffsl(0x08); - printf("%d\n", rv); -@@ -6940,71 +6983,29 @@ else - je_cv_function_ffsl=no - fi - rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_function_ffsl" >&5 - $as_echo "$je_cv_function_ffsl" >&6; } - --if test "x${je_cv_function_ffsl}" == "xyes" ; then -- $as_echo "#define JEMALLOC_INTERNAL_FFSL ffsl" >>confdefs.h -- -- $as_echo "#define JEMALLOC_INTERNAL_FFS ffs" >>confdefs.h -- --else -- --{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program using __builtin_ffsl is compilable" >&5 --$as_echo_n "checking whether a program using __builtin_ffsl is compilable... " >&6; } --if ${je_cv_gcc_builtin_ffsl+:} false; then : -- $as_echo_n "(cached) " >&6 --else -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext --/* end confdefs.h. */ -- -- #include -- #include -- #include -- --int --main () --{ -- -- { -- int rv = __builtin_ffsl(0x08); -- printf("%d\n", rv); -- } -- -- ; -- return 0; --} --_ACEOF --if ac_fn_c_try_link "$LINENO"; then : -- je_cv_gcc_builtin_ffsl=yes --else -- je_cv_gcc_builtin_ffsl=no --fi --rm -f core conftest.err conftest.$ac_objext \ -- conftest$ac_exeext conftest.$ac_ext --fi --{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_gcc_builtin_ffsl" >&5 --$as_echo "$je_cv_gcc_builtin_ffsl" >&6; } -- -- if test "x${je_cv_gcc_builtin_ffsl}" == "xyes" ; then -- $as_echo "#define JEMALLOC_INTERNAL_FFSL __builtin_ffsl" >>confdefs.h -- -- $as_echo "#define JEMALLOC_INTERNAL_FFS __builtin_ffs" >>confdefs.h -+ if test "x${je_cv_function_ffsl}" == "xyes" ; then -+ $as_echo "#define JEMALLOC_INTERNAL_FFSL ffsl" >>confdefs.h -+ -+ $as_echo "#define JEMALLOC_INTERNAL_FFS ffs" >>confdefs.h - - else - as_fn_error $? "Cannot build without ffsl(3) or __builtin_ffsl()" "$LINENO" 5 - fi - fi - - - -+ - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether atomic(9) is compilable" >&5 - $as_echo_n "checking whether atomic(9) is compilable... " >&6; } - if ${je_cv_atomic9+:} false; then : - $as_echo_n "(cached) " >&6 - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -diff --git a/configure.ac b/configure.ac ---- a/configure.ac -+++ b/configure.ac -@@ -1160,53 +1160,54 @@ fi - AC_SUBST([enable_tls]) - if test "x${enable_tls}" = "x1" ; then - AC_DEFINE_UNQUOTED([JEMALLOC_TLS], [ ]) - elif test "x${force_tls}" = "x1" ; then - AC_MSG_ERROR([Failed to configure TLS, which is mandatory for correct function]) - fi - - dnl ============================================================================ --dnl Check for ffsl(3), then __builtin_ffsl(), and fail if neither are found. -+dnl Check for __builtin_ffsl(), then ffsl(3), and fail if neither are found. - dnl One of those two functions should (theoretically) exist on all platforms - dnl that jemalloc currently has a chance of functioning on without modification. - dnl We additionally assume ffs() or __builtin_ffs() are defined if - dnl ffsl() or __builtin_ffsl() are defined, respectively. --JE_COMPILABLE([a program using ffsl], [ -+JE_COMPILABLE([a program using __builtin_ffsl], [ - #include - #include - #include - ], [ - { -- int rv = ffsl(0x08); -+ int rv = __builtin_ffsl(0x08); - printf("%d\n", rv); - } --], [je_cv_function_ffsl]) --if test "x${je_cv_function_ffsl}" == "xyes" ; then -- AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [ffsl]) -- AC_DEFINE([JEMALLOC_INTERNAL_FFS], [ffs]) -+], [je_cv_gcc_builtin_ffsl]) -+if test "x${je_cv_gcc_builtin_ffsl}" == "xyes" ; then -+ AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [__builtin_ffsl]) -+ AC_DEFINE([JEMALLOC_INTERNAL_FFS], [__builtin_ffs]) - else -- JE_COMPILABLE([a program using __builtin_ffsl], [ -+ JE_COMPILABLE([a program using ffsl], [ - #include - #include - #include - ], [ - { -- int rv = __builtin_ffsl(0x08); -+ int rv = ffsl(0x08); - printf("%d\n", rv); - } -- ], [je_cv_gcc_builtin_ffsl]) -- if test "x${je_cv_gcc_builtin_ffsl}" == "xyes" ; then -- AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [__builtin_ffsl]) -- AC_DEFINE([JEMALLOC_INTERNAL_FFS], [__builtin_ffs]) -+ ], [je_cv_function_ffsl]) -+ if test "x${je_cv_function_ffsl}" == "xyes" ; then -+ AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [ffsl]) -+ AC_DEFINE([JEMALLOC_INTERNAL_FFS], [ffs]) - else - AC_MSG_ERROR([Cannot build without ffsl(3) or __builtin_ffsl()]) - fi - fi - -+ - dnl ============================================================================ - dnl Check for atomic(9) operations as provided on FreeBSD. - - JE_COMPILABLE([atomic(9)], [ - #include - #include - #include - ], [ diff --git a/memory/jemalloc/0006-Fix-clang-warnings.patch b/memory/jemalloc/0006-Fix-clang-warnings.patch deleted file mode 100644 index 33cd9fdbdb11..000000000000 --- a/memory/jemalloc/0006-Fix-clang-warnings.patch +++ /dev/null @@ -1,93 +0,0 @@ -diff --git a/src/prof.c b/src/prof.c ---- a/src/prof.c -+++ b/src/prof.c -@@ -1057,25 +1057,25 @@ label_open_close_error: - prof_dump_ctx_cleanup(ctx.p, &ctx_ql); - malloc_mutex_unlock(&prof_dump_mtx); - return (true); - } - - #define DUMP_FILENAME_BUFSIZE (PATH_MAX + 1) - #define VSEQ_INVALID UINT64_C(0xffffffffffffffff) - static void --prof_dump_filename(char *filename, char v, int64_t vseq) -+prof_dump_filename(char *filename, char v, uint64_t vseq) - { - - cassert(config_prof); - - if (vseq != VSEQ_INVALID) { - /* "...v.heap" */ - malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE, -- "%s.%d.%"PRIu64".%c%"PRId64".heap", -+ "%s.%d.%"PRIu64".%c%"PRIu64".heap", - opt_prof_prefix, (int)getpid(), prof_dump_seq, v, vseq); - } else { - /* "....heap" */ - malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE, - "%s.%d.%"PRIu64".%c.heap", - opt_prof_prefix, (int)getpid(), prof_dump_seq, v); - } - prof_dump_seq++; -diff --git a/src/util.c b/src/util.c ---- a/src/util.c -+++ b/src/util.c -@@ -95,17 +95,17 @@ buferror(int err, char *buf, size_t bufl - return (strerror_r(err, buf, buflen)); - #endif - } - - uintmax_t - malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base) - { - uintmax_t ret, digit; -- int b; -+ unsigned b; - bool neg; - const char *p, *ns; - - p = nptr; - if (base < 0 || base == 1 || base > 36) { - ns = p; - set_errno(EINVAL); - ret = UINTMAX_MAX; -@@ -376,17 +376,19 @@ malloc_vsnprintf(char *str, size_t size, - val = va_arg(ap, ssize_t); \ - break; \ - case 'z' | 0x80: \ - val = va_arg(ap, size_t); \ - break; \ - case 'p': /* Synthetic; used for %p. */ \ - val = va_arg(ap, uintptr_t); \ - break; \ -- default: not_reached(); \ -+ default: \ -+ not_reached(); \ -+ val = 0; \ - } \ - } while (0) - - i = 0; - f = format; - while (true) { - switch (*f) { - case '\0': goto label_out; -@@ -543,17 +545,17 @@ malloc_vsnprintf(char *str, size_t size, - buf[1] = '\0'; - APPEND_PADDED_S(buf, 1, width, left_justify); - f++; - break; - } case 's': - assert(len == '?' || len == 'l'); - assert_not_implemented(len != 'l'); - s = va_arg(ap, char *); -- slen = (prec < 0) ? strlen(s) : prec; -+ slen = (prec < 0) ? strlen(s) : (size_t)prec; - APPEND_PADDED_S(s, slen, width, left_justify); - f++; - break; - case 'p': { - uintmax_t val; - char buf[X2S_BUFSIZE]; - - GET_ARG_NUMERIC(val, 'p'); diff --git a/memory/jemalloc/0007-Ensure-the-default-purgeable-zone-is-after-the-defau.patch b/memory/jemalloc/0007-Ensure-the-default-purgeable-zone-is-after-the-defau.patch deleted file mode 100644 index 2801cfe58745..000000000000 --- a/memory/jemalloc/0007-Ensure-the-default-purgeable-zone-is-after-the-defau.patch +++ /dev/null @@ -1,59 +0,0 @@ -diff --git a/src/zone.c b/src/zone.c -index e0302ef..a722287 100644 ---- a/src/zone.c -+++ b/src/zone.c -@@ -176,6 +176,7 @@ register_zone(void) - * register jemalloc's. - */ - malloc_zone_t *default_zone = malloc_default_zone(); -+ malloc_zone_t *purgeable_zone = NULL; - if (!default_zone->zone_name || - strcmp(default_zone->zone_name, "DefaultMallocZone") != 0) { - return; -@@ -237,22 +238,37 @@ register_zone(void) - * run time. - */ - if (malloc_default_purgeable_zone != NULL) -- malloc_default_purgeable_zone(); -+ purgeable_zone = malloc_default_purgeable_zone(); - - /* Register the custom zone. At this point it won't be the default. */ - malloc_zone_register(&zone); - -- /* -- * Unregister and reregister the default zone. On OSX >= 10.6, -- * unregistering takes the last registered zone and places it at the -- * location of the specified zone. Unregistering the default zone thus -- * makes the last registered one the default. On OSX < 10.6, -- * unregistering shifts all registered zones. The first registered zone -- * then becomes the default. -- */ - do { - default_zone = malloc_default_zone(); -+ /* -+ * Unregister and reregister the default zone. On OSX >= 10.6, -+ * unregistering takes the last registered zone and places it -+ * at the location of the specified zone. Unregistering the -+ * default zone thus makes the last registered one the default. -+ * On OSX < 10.6, unregistering shifts all registered zones. -+ * The first registered zone then becomes the default. -+ */ - malloc_zone_unregister(default_zone); - malloc_zone_register(default_zone); -+ /* -+ * On OSX 10.6, having the default purgeable zone appear before -+ * the default zone makes some things crash because it thinks it -+ * owns the default zone allocated pointers. We thus unregister/ -+ * re-register it in order to ensure it's always after the -+ * default zone. On OSX < 10.6, there is no purgeable zone, so -+ * this does nothing. On OSX >= 10.6, unregistering replaces the -+ * purgeable zone with the last registered zone above, i.e the -+ * default zone. Registering it again then puts it at the end, -+ * obviously after the default zone. -+ */ -+ if (purgeable_zone) { -+ malloc_zone_unregister(purgeable_zone); -+ malloc_zone_register(purgeable_zone); -+ } - } while (malloc_default_zone() != &zone); - } diff --git a/memory/jemalloc/0008-Allow-to-build-with-clang-cl.patch b/memory/jemalloc/0008-Allow-to-build-with-clang-cl.patch deleted file mode 100644 index 09865d3a3b7d..000000000000 --- a/memory/jemalloc/0008-Allow-to-build-with-clang-cl.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/include/msvc_compat/C99/stdbool.h b/include/msvc_compat/C99/stdbool.h ---- a/include/msvc_compat/C99/stdbool.h -+++ b/include/msvc_compat/C99/stdbool.h -@@ -1,16 +1,18 @@ - #ifndef stdbool_h - #define stdbool_h - - #include - - /* MSVC doesn't define _Bool or bool in C, but does have BOOL */ - /* Note this doesn't pass autoconf's test because (bool) 0.5 != true */ -+#ifndef __clang__ - typedef BOOL _Bool; -+#endif - - #define bool _Bool - #define true 1 - #define false 0 - - #define __bool_true_false_are_defined 1 - - #endif /* stdbool_h */ diff --git a/memory/jemalloc/0009-Remove-srcroot-from-cfghdrs_in-cfgoutputs_in-and-cfg.patch b/memory/jemalloc/0009-Remove-srcroot-from-cfghdrs_in-cfgoutputs_in-and-cfg.patch deleted file mode 100644 index 45624205232d..000000000000 --- a/memory/jemalloc/0009-Remove-srcroot-from-cfghdrs_in-cfgoutputs_in-and-cfg.patch +++ /dev/null @@ -1,225 +0,0 @@ -diff --git a/Makefile.in b/Makefile.in ---- a/Makefile.in -+++ b/Makefile.in -@@ -37,19 +37,19 @@ EXE := @exe@ - LIBPREFIX := @libprefix@ - REV := @rev@ - install_suffix := @install_suffix@ - ABI := @abi@ - XSLTPROC := @XSLTPROC@ - AUTOCONF := @AUTOCONF@ - _RPATH = @RPATH@ - RPATH = $(if $(1),$(call _RPATH,$(1))) --cfghdrs_in := @cfghdrs_in@ -+cfghdrs_in := $(addprefix $(srcroot),@cfghdrs_in@) - cfghdrs_out := @cfghdrs_out@ --cfgoutputs_in := @cfgoutputs_in@ -+cfgoutputs_in := $(addprefix $(srcroot),@cfgoutputs_in@) - cfgoutputs_out := @cfgoutputs_out@ - enable_autogen := @enable_autogen@ - enable_code_coverage := @enable_code_coverage@ - enable_experimental := @enable_experimental@ - enable_zone_allocator := @enable_zone_allocator@ - DSO_LDFLAGS = @DSO_LDFLAGS@ - SOREV = @SOREV@ - PIC_CFLAGS = @PIC_CFLAGS@ -diff --git a/configure b/configure ---- a/configure -+++ b/configure -@@ -5654,25 +5654,25 @@ else - fi - - install_suffix="$INSTALL_SUFFIX" - - - je_="je_" - - --cfgoutputs_in="${srcroot}Makefile.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}doc/html.xsl.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}doc/manpages.xsl.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}doc/jemalloc.xml.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}include/jemalloc/jemalloc_macros.h.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}include/jemalloc/jemalloc_protos.h.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}include/jemalloc/internal/jemalloc_internal.h.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}test/test.sh.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}test/include/test/jemalloc_test.h.in" -+cfgoutputs_in="Makefile.in" -+cfgoutputs_in="${cfgoutputs_in} doc/html.xsl.in" -+cfgoutputs_in="${cfgoutputs_in} doc/manpages.xsl.in" -+cfgoutputs_in="${cfgoutputs_in} doc/jemalloc.xml.in" -+cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_macros.h.in" -+cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_protos.h.in" -+cfgoutputs_in="${cfgoutputs_in} include/jemalloc/internal/jemalloc_internal.h.in" -+cfgoutputs_in="${cfgoutputs_in} test/test.sh.in" -+cfgoutputs_in="${cfgoutputs_in} test/include/test/jemalloc_test.h.in" - - cfgoutputs_out="Makefile" - cfgoutputs_out="${cfgoutputs_out} doc/html.xsl" - cfgoutputs_out="${cfgoutputs_out} doc/manpages.xsl" - cfgoutputs_out="${cfgoutputs_out} doc/jemalloc.xml" - cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_macros.h" - cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_protos.h" - cfgoutputs_out="${cfgoutputs_out} include/jemalloc/internal/jemalloc_internal.h" -@@ -5684,28 +5684,28 @@ cfgoutputs_tup="${cfgoutputs_tup} doc/ht - cfgoutputs_tup="${cfgoutputs_tup} doc/manpages.xsl:doc/manpages.xsl.in" - cfgoutputs_tup="${cfgoutputs_tup} doc/jemalloc.xml:doc/jemalloc.xml.in" - cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_macros.h:include/jemalloc/jemalloc_macros.h.in" - cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_protos.h:include/jemalloc/jemalloc_protos.h.in" - cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/internal/jemalloc_internal.h" - cfgoutputs_tup="${cfgoutputs_tup} test/test.sh:test/test.sh.in" - cfgoutputs_tup="${cfgoutputs_tup} test/include/test/jemalloc_test.h:test/include/test/jemalloc_test.h.in" - --cfghdrs_in="${srcroot}include/jemalloc/jemalloc_defs.h.in" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/jemalloc_internal_defs.h.in" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/private_namespace.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/private_unnamespace.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/private_symbols.txt" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/public_namespace.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/public_unnamespace.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/size_classes.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/jemalloc_rename.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/jemalloc_mangle.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/jemalloc.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}test/include/test/jemalloc_test_defs.h.in" -+cfghdrs_in="include/jemalloc/jemalloc_defs.h.in" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/jemalloc_internal_defs.h.in" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_namespace.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_unnamespace.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_symbols.txt" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_namespace.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_unnamespace.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/size_classes.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_rename.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_mangle.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc.sh" -+cfghdrs_in="${cfghdrs_in} test/include/test/jemalloc_test_defs.h.in" - - cfghdrs_out="include/jemalloc/jemalloc_defs.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc${install_suffix}.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_namespace.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_unnamespace.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_symbols.txt" - cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_namespace.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_unnamespace.h" -@@ -5713,18 +5713,18 @@ cfghdrs_out="${cfghdrs_out} include/jema - cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_protos_jet.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_rename.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle_jet.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/jemalloc_internal_defs.h" - cfghdrs_out="${cfghdrs_out} test/include/test/jemalloc_test_defs.h" - - cfghdrs_tup="include/jemalloc/jemalloc_defs.h:include/jemalloc/jemalloc_defs.h.in" --cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:${srcroot}include/jemalloc/internal/jemalloc_internal_defs.h.in" --cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:${srcroot}test/include/test/jemalloc_test_defs.h.in" -+cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:include/jemalloc/internal/jemalloc_internal_defs.h.in" -+cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:test/include/test/jemalloc_test_defs.h.in" - - # Check whether --enable-cc-silence was given. - if test "${enable_cc_silence+set}" = set; then : - enableval=$enable_cc_silence; if test "x$enable_cc_silence" = "xno" ; then - enable_cc_silence="0" - else - enable_cc_silence="1" - fi -diff --git a/configure.ac b/configure.ac ---- a/configure.ac -+++ b/configure.ac -@@ -546,25 +546,25 @@ AC_ARG_WITH([install_suffix], - install_suffix="$INSTALL_SUFFIX" - AC_SUBST([install_suffix]) - - dnl Substitute @je_@ in jemalloc_protos.h.in, primarily to make generation of - dnl jemalloc_protos_jet.h easy. - je_="je_" - AC_SUBST([je_]) - --cfgoutputs_in="${srcroot}Makefile.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}doc/html.xsl.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}doc/manpages.xsl.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}doc/jemalloc.xml.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}include/jemalloc/jemalloc_macros.h.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}include/jemalloc/jemalloc_protos.h.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}include/jemalloc/internal/jemalloc_internal.h.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}test/test.sh.in" --cfgoutputs_in="${cfgoutputs_in} ${srcroot}test/include/test/jemalloc_test.h.in" -+cfgoutputs_in="Makefile.in" -+cfgoutputs_in="${cfgoutputs_in} doc/html.xsl.in" -+cfgoutputs_in="${cfgoutputs_in} doc/manpages.xsl.in" -+cfgoutputs_in="${cfgoutputs_in} doc/jemalloc.xml.in" -+cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_macros.h.in" -+cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_protos.h.in" -+cfgoutputs_in="${cfgoutputs_in} include/jemalloc/internal/jemalloc_internal.h.in" -+cfgoutputs_in="${cfgoutputs_in} test/test.sh.in" -+cfgoutputs_in="${cfgoutputs_in} test/include/test/jemalloc_test.h.in" - - cfgoutputs_out="Makefile" - cfgoutputs_out="${cfgoutputs_out} doc/html.xsl" - cfgoutputs_out="${cfgoutputs_out} doc/manpages.xsl" - cfgoutputs_out="${cfgoutputs_out} doc/jemalloc.xml" - cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_macros.h" - cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_protos.h" - cfgoutputs_out="${cfgoutputs_out} include/jemalloc/internal/jemalloc_internal.h" -@@ -576,28 +576,28 @@ cfgoutputs_tup="${cfgoutputs_tup} doc/ht - cfgoutputs_tup="${cfgoutputs_tup} doc/manpages.xsl:doc/manpages.xsl.in" - cfgoutputs_tup="${cfgoutputs_tup} doc/jemalloc.xml:doc/jemalloc.xml.in" - cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_macros.h:include/jemalloc/jemalloc_macros.h.in" - cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_protos.h:include/jemalloc/jemalloc_protos.h.in" - cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/internal/jemalloc_internal.h" - cfgoutputs_tup="${cfgoutputs_tup} test/test.sh:test/test.sh.in" - cfgoutputs_tup="${cfgoutputs_tup} test/include/test/jemalloc_test.h:test/include/test/jemalloc_test.h.in" - --cfghdrs_in="${srcroot}include/jemalloc/jemalloc_defs.h.in" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/jemalloc_internal_defs.h.in" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/private_namespace.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/private_unnamespace.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/private_symbols.txt" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/public_namespace.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/public_unnamespace.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/internal/size_classes.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/jemalloc_rename.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/jemalloc_mangle.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}include/jemalloc/jemalloc.sh" --cfghdrs_in="${cfghdrs_in} ${srcroot}test/include/test/jemalloc_test_defs.h.in" -+cfghdrs_in="include/jemalloc/jemalloc_defs.h.in" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/jemalloc_internal_defs.h.in" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_namespace.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_unnamespace.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_symbols.txt" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_namespace.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_unnamespace.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/size_classes.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_rename.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_mangle.sh" -+cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc.sh" -+cfghdrs_in="${cfghdrs_in} test/include/test/jemalloc_test_defs.h.in" - - cfghdrs_out="include/jemalloc/jemalloc_defs.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc${install_suffix}.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_namespace.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_unnamespace.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_symbols.txt" - cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_namespace.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_unnamespace.h" -@@ -605,18 +605,18 @@ cfghdrs_out="${cfghdrs_out} include/jema - cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_protos_jet.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_rename.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle_jet.h" - cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/jemalloc_internal_defs.h" - cfghdrs_out="${cfghdrs_out} test/include/test/jemalloc_test_defs.h" - - cfghdrs_tup="include/jemalloc/jemalloc_defs.h:include/jemalloc/jemalloc_defs.h.in" --cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:${srcroot}include/jemalloc/internal/jemalloc_internal_defs.h.in" --cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:${srcroot}test/include/test/jemalloc_test_defs.h.in" -+cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:include/jemalloc/internal/jemalloc_internal_defs.h.in" -+cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:test/include/test/jemalloc_test_defs.h.in" - - dnl Do not silence irrelevant compiler warnings by default, since enabling this - dnl option incurs a performance penalty. - AC_ARG_ENABLE([cc-silence], - [AS_HELP_STRING([--enable-cc-silence], - [Silence irrelevant compiler warnings])], - [if test "x$enable_cc_silence" = "xno" ; then - enable_cc_silence="0" diff --git a/memory/jemalloc/moz.build b/memory/jemalloc/moz.build index 1ec3f80b79c1..d9cfa0e99dfb 100644 --- a/memory/jemalloc/moz.build +++ b/memory/jemalloc/moz.build @@ -27,6 +27,8 @@ SOURCES += [ 'src/src/tcache.c', 'src/src/tsd.c', 'src/src/util.c', + # FIXME do we ever want valgrind.c? + # 'src/src/valgrind.c', ] # Only OSX needs the zone allocation implementation, diff --git a/memory/jemalloc/src/INSTALL b/memory/jemalloc/src/INSTALL index 841704d2a08d..b8459a813ced 100644 --- a/memory/jemalloc/src/INSTALL +++ b/memory/jemalloc/src/INSTALL @@ -1,10 +1,23 @@ -Building and installing jemalloc can be as simple as typing the following while -in the root directory of the source tree: +Building and installing a packaged release of jemalloc can be as simple as +typing the following while in the root directory of the source tree: ./configure make make install +If building from unpackaged developer sources, the simplest command sequence +that might work is: + + ./autogen.sh + make dist + make + make install + +Note that documentation is not built by the default target because doing so +would create a dependency on xsltproc in packaged releases, hence the +requirement to either run 'make dist' or avoid installing docs via the various +install_* targets documented below. + === Advanced configuration ===================================================== The 'configure' script supports numerous options that allow control of which @@ -56,7 +69,7 @@ any of the following arguments (not a definitive list) to 'configure': replace the "malloc", "calloc", etc. symbols. --without-export - Don't export public APIs. This can be useful when building jemalloc as a + Don't export public APIs. This can be useful when building jemalloc as a static library, or to avoid exporting public APIs when using the zone allocator on OSX. @@ -71,10 +84,10 @@ any of the following arguments (not a definitive list) to 'configure': versions of jemalloc can coexist in the same installation directory. For example, libjemalloc.so.0 becomes libjemalloc.so.0. ---enable-cc-silence - Enable code that silences non-useful compiler warnings. This is helpful - when trying to tell serious warnings from those due to compiler - limitations, but it potentially incurs a performance penalty. +--disable-cc-silence + Disable code that silences non-useful compiler warnings. This is mainly + useful during development when auditing the set of warnings that are being + silenced. --enable-debug Enable assertions and validation code. This incurs a substantial @@ -96,7 +109,7 @@ any of the following arguments (not a definitive list) to 'configure': --enable-ivsalloc Enable validation code, which verifies that pointers reside within - jemalloc-owned chunks before dereferencing them. This incurs a substantial + jemalloc-owned chunks before dereferencing them. This incurs a substantial performance hit. --disable-stats @@ -132,12 +145,6 @@ any of the following arguments (not a definitive list) to 'configure': released in bulk, thus reducing the total number of mutex operations. See the "opt.tcache" option for usage details. ---enable-mremap - Enable huge realloc() via mremap(2). mremap() is disabled by default - because the flavor used is specific to Linux, which has a quirk in its - virtual memory allocation algorithm that causes semi-permanent VM map holes - under normal jemalloc operation. - --disable-munmap Disable virtual memory deallocation via munmap(2); instead keep track of the virtual memory for later use. munmap() is disabled by default (i.e. @@ -145,10 +152,6 @@ any of the following arguments (not a definitive list) to 'configure': memory allocation algorithm that causes semi-permanent VM map holes under normal jemalloc operation. ---enable-dss - Enable support for page allocation/deallocation via sbrk(2), in addition to - mmap(2). - --disable-fill Disable support for junk/zero filling of memory, quarantine, and redzones. See the "opt.junk", "opt.zero", "opt.quarantine", and "opt.redzone" option @@ -157,11 +160,8 @@ any of the following arguments (not a definitive list) to 'configure': --disable-valgrind Disable support for Valgrind. ---disable-experimental - Disable support for the experimental API (*allocm()). - --disable-zone-allocator - Disable zone allocator for Darwin. This means jemalloc won't be hooked as + Disable zone allocator for Darwin. This means jemalloc won't be hooked as the default allocator on OSX/iOS. --enable-utrace @@ -189,6 +189,93 @@ any of the following arguments (not a definitive list) to 'configure': Specify where to find DocBook XSL stylesheets when building the documentation. +--with-lg-page= + Specify the base 2 log of the system page size. This option is only useful + when cross compiling, since the configure script automatically determines + the host's page size by default. + +--with-lg-page-sizes= + Specify the comma-separated base 2 logs of the page sizes to support. This + option may be useful when cross-compiling in combination with + --with-lg-page, but its primary use case is for integration with FreeBSD's + libc, wherein jemalloc is embedded. + +--with-lg-size-class-group= + Specify the base 2 log of how many size classes to use for each doubling in + size. By default jemalloc uses =2, which results in + e.g. the following size classes: + + [...], 64, + 80, 96, 112, 128, + 160, [...] + + =3 results in e.g. the following size classes: + + [...], 64, + 72, 80, 88, 96, 104, 112, 120, 128, + 144, [...] + + The minimal =0 causes jemalloc to only provide size + classes that are powers of 2: + + [...], + 64, + 128, + 256, + [...] + + An implementation detail currently limits the total number of small size + classes to 255, and a compilation error will result if the + you specify cannot be supported. The limit is + roughly =4, depending on page size. + +--with-lg-quantum= + Specify the base 2 log of the minimum allocation alignment. jemalloc needs + to know the minimum alignment that meets the following C standard + requirement (quoted from the April 12, 2011 draft of the C11 standard): + + The pointer returned if the allocation succeeds is suitably aligned so + that it may be assigned to a pointer to any type of object with a + fundamental alignment requirement and then used to access such an object + or an array of such objects in the space allocated [...] + + This setting is architecture-specific, and although jemalloc includes known + safe values for the most commonly used modern architectures, there is a + wrinkle related to GNU libc (glibc) that may impact your choice of + . On most modern architectures, this mandates 16-byte alignment + (=4), but the glibc developers chose not to meet this + requirement for performance reasons. An old discussion can be found at + https://sourceware.org/bugzilla/show_bug.cgi?id=206 . Unlike glibc, + jemalloc does follow the C standard by default (caveat: jemalloc + technically cheats if --with-lg-tiny-min is smaller than + --with-lg-quantum), but the fact that Linux systems already work around + this allocator noncompliance means that it is generally safe in practice to + let jemalloc's minimum alignment follow glibc's lead. If you specify + --with-lg-quantum=3 during configuration, jemalloc will provide additional + size classes that are not 16-byte-aligned (24, 40, and 56, assuming + --with-lg-size-class-group=2). + +--with-lg-tiny-min= + Specify the base 2 log of the minimum tiny size class to support. Tiny + size classes are powers of 2 less than the quantum, and are only + incorporated if is less than (see + --with-lg-quantum). Tiny size classes technically violate the C standard + requirement for minimum alignment, and crashes could conceivably result if + the compiler were to generate instructions that made alignment assumptions, + both because illegal instruction traps could result, and because accesses + could straddle page boundaries and cause segmentation faults due to + accessing unmapped addresses. + + The default of =3 works well in practice even on architectures + that technically require 16-byte alignment, probably for the same reason + --with-lg-quantum=3 works. Smaller tiny size classes can, and will, cause + crashes (see https://bugzilla.mozilla.org/show_bug.cgi?id=691003 for an + example). + + This option is rarely useful, and is mainly provided as documentation of a + subtle implementation detail. If you do use this option, specify a + value in [3, ..., ]. + The following environment variables (not a definitive list) impact configure's behavior: diff --git a/memory/jemalloc/src/Makefile.in b/memory/jemalloc/src/Makefile.in index c9a99579ac16..c268d0025558 100644 --- a/memory/jemalloc/src/Makefile.in +++ b/memory/jemalloc/src/Makefile.in @@ -48,7 +48,7 @@ cfgoutputs_in := $(addprefix $(srcroot),@cfgoutputs_in@) cfgoutputs_out := @cfgoutputs_out@ enable_autogen := @enable_autogen@ enable_code_coverage := @enable_code_coverage@ -enable_experimental := @enable_experimental@ +enable_valgrind := @enable_valgrind@ enable_zone_allocator := @enable_zone_allocator@ DSO_LDFLAGS = @DSO_LDFLAGS@ SOREV = @SOREV@ @@ -83,6 +83,9 @@ C_SRCS := $(srcroot)src/jemalloc.c $(srcroot)src/arena.c \ $(srcroot)src/mb.c $(srcroot)src/mutex.c $(srcroot)src/prof.c \ $(srcroot)src/quarantine.c $(srcroot)src/rtree.c $(srcroot)src/stats.c \ $(srcroot)src/tcache.c $(srcroot)src/util.c $(srcroot)src/tsd.c +ifeq ($(enable_valgrind), 1) +C_SRCS += $(srcroot)src/valgrind.c +endif ifeq ($(enable_zone_allocator), 1) C_SRCS += $(srcroot)src/zone.c endif @@ -98,26 +101,36 @@ DSOS := $(objroot)lib/$(LIBJEMALLOC).$(SOREV) ifneq ($(SOREV),$(SO)) DSOS += $(objroot)lib/$(LIBJEMALLOC).$(SO) endif +PC := $(objroot)jemalloc.pc MAN3 := $(objroot)doc/jemalloc$(install_suffix).3 DOCS_XML := $(objroot)doc/jemalloc$(install_suffix).xml DOCS_HTML := $(DOCS_XML:$(objroot)%.xml=$(srcroot)%.html) DOCS_MAN3 := $(DOCS_XML:$(objroot)%.xml=$(srcroot)%.3) DOCS := $(DOCS_HTML) $(DOCS_MAN3) -C_TESTLIB_SRCS := $(srcroot)test/src/math.c $(srcroot)test/src/mtx.c \ - $(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \ - $(srcroot)test/src/thd.c +C_TESTLIB_SRCS := $(srcroot)test/src/btalloc.c $(srcroot)test/src/btalloc_0.c \ + $(srcroot)test/src/btalloc_1.c $(srcroot)test/src/math.c \ + $(srcroot)test/src/mtx.c $(srcroot)test/src/SFMT.c \ + $(srcroot)test/src/test.c $(srcroot)test/src/thd.c \ + $(srcroot)test/src/timer.c C_UTIL_INTEGRATION_SRCS := $(srcroot)src/util.c -TESTS_UNIT := $(srcroot)test/unit/bitmap.c \ +TESTS_UNIT := $(srcroot)test/unit/atomic.c \ + $(srcroot)test/unit/bitmap.c \ $(srcroot)test/unit/ckh.c \ $(srcroot)test/unit/hash.c \ $(srcroot)test/unit/junk.c \ + $(srcroot)test/unit/junk_alloc.c \ + $(srcroot)test/unit/junk_free.c \ + $(srcroot)test/unit/lg_chunk.c \ $(srcroot)test/unit/mallctl.c \ $(srcroot)test/unit/math.c \ $(srcroot)test/unit/mq.c \ $(srcroot)test/unit/mtx.c \ $(srcroot)test/unit/prof_accum.c \ + $(srcroot)test/unit/prof_active.c \ $(srcroot)test/unit/prof_gdump.c \ $(srcroot)test/unit/prof_idump.c \ + $(srcroot)test/unit/prof_reset.c \ + $(srcroot)test/unit/prof_thread_name.c \ $(srcroot)test/unit/ql.c \ $(srcroot)test/unit/qr.c \ $(srcroot)test/unit/quarantine.c \ @@ -128,23 +141,18 @@ TESTS_UNIT := $(srcroot)test/unit/bitmap.c \ $(srcroot)test/unit/tsd.c \ $(srcroot)test/unit/util.c \ $(srcroot)test/unit/zero.c -TESTS_UNIT_AUX := $(srcroot)test/unit/prof_accum_a.c \ - $(srcroot)test/unit/prof_accum_b.c TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \ $(srcroot)test/integration/allocated.c \ + $(srcroot)test/integration/sdallocx.c \ $(srcroot)test/integration/mallocx.c \ - $(srcroot)test/integration/mremap.c \ + $(srcroot)test/integration/MALLOCX_ARENA.c \ $(srcroot)test/integration/posix_memalign.c \ $(srcroot)test/integration/rallocx.c \ $(srcroot)test/integration/thread_arena.c \ $(srcroot)test/integration/thread_tcache_enabled.c \ - $(srcroot)test/integration/xallocx.c -ifeq ($(enable_experimental), 1) -TESTS_INTEGRATION += $(srcroot)test/integration/allocm.c \ - $(srcroot)test/integration/MALLOCX_ARENA.c \ - $(srcroot)test/integration/rallocm.c -endif -TESTS_STRESS := + $(srcroot)test/integration/xallocx.c \ + $(srcroot)test/integration/chunk.c +TESTS_STRESS := $(srcroot)test/stress/microbench.c TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_STRESS) C_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.$(O)) @@ -157,10 +165,9 @@ C_TESTLIB_STRESS_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.stress.$(O)) C_TESTLIB_OBJS := $(C_TESTLIB_UNIT_OBJS) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(C_TESTLIB_STRESS_OBJS) TESTS_UNIT_OBJS := $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%.$(O)) -TESTS_UNIT_AUX_OBJS := $(TESTS_UNIT_AUX:$(srcroot)%.c=$(objroot)%.$(O)) TESTS_INTEGRATION_OBJS := $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%.$(O)) TESTS_STRESS_OBJS := $(TESTS_STRESS:$(srcroot)%.c=$(objroot)%.$(O)) -TESTS_OBJS := $(TESTS_UNIT_OBJS) $(TESTS_UNIT_AUX_OBJS) $(TESTS_INTEGRATION_OBJS) $(TESTS_STRESS_OBJS) +TESTS_OBJS := $(TESTS_UNIT_OBJS) $(TESTS_INTEGRATION_OBJS) $(TESTS_STRESS_OBJS) .PHONY: all dist build_doc_html build_doc_man build_doc .PHONY: install_bin install_include install_lib @@ -209,18 +216,12 @@ $(C_TESTLIB_STRESS_OBJS): $(objroot)test/src/%.stress.$(O): $(srcroot)test/src/% $(C_TESTLIB_STRESS_OBJS): CPPFLAGS += -DJEMALLOC_STRESS_TEST -DJEMALLOC_STRESS_TESTLIB $(C_TESTLIB_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include $(TESTS_UNIT_OBJS): CPPFLAGS += -DJEMALLOC_UNIT_TEST -$(TESTS_UNIT_AUX_OBJS): CPPFLAGS += -DJEMALLOC_UNIT_TEST -define make-unit-link-dep -$(1): TESTS_UNIT_LINK_OBJS += $(2) -$(1): $(2) -endef -$(foreach test, $(TESTS_UNIT:$(srcroot)test/unit/%.c=$(objroot)test/unit/%$(EXE)), $(eval $(call make-unit-link-dep,$(test),$(filter $(test:%=%_a.$(O)) $(test:%=%_b.$(O)),$(TESTS_UNIT_AUX_OBJS))))) $(TESTS_INTEGRATION_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_TEST $(TESTS_STRESS_OBJS): CPPFLAGS += -DJEMALLOC_STRESS_TEST $(TESTS_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.c $(TESTS_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include ifneq ($(IMPORTLIB),$(SO)) -$(C_OBJS): CPPFLAGS += -DDLLEXPORT +$(C_OBJS) $(C_JET_OBJS): CPPFLAGS += -DDLLEXPORT endif ifndef CC_MM @@ -229,7 +230,7 @@ HEADER_DIRS = $(srcroot)include/jemalloc/internal \ $(objroot)include/jemalloc $(objroot)include/jemalloc/internal HEADERS = $(wildcard $(foreach dir,$(HEADER_DIRS),$(dir)/*.h)) $(C_OBJS) $(C_PIC_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): $(HEADERS) -$(TESTS_OBJS): $(objroot)test/unit/jemalloc_test.h +$(TESTS_OBJS): $(objroot)test/include/test/jemalloc_test.h endif $(C_OBJS) $(C_PIC_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): %.$(O): @@ -301,7 +302,14 @@ install_lib_static: $(STATIC_LIBS) install -m 755 $$l $(LIBDIR); \ done -install_lib: install_lib_shared install_lib_static +install_lib_pc: $(PC) + install -d $(LIBDIR)/pkgconfig + @for l in $(PC); do \ + echo "install -m 644 $$l $(LIBDIR)/pkgconfig"; \ + install -m 644 $$l $(LIBDIR)/pkgconfig; \ +done + +install_lib: install_lib_shared install_lib_static install_lib_pc install_doc_html: install -d $(DATADIR)/doc/jemalloc$(install_suffix) @@ -400,7 +408,6 @@ clean: rm -f $(objroot)*.gcov.* distclean: clean - rm -rf $(objroot)autom4te.cache rm -f $(objroot)bin/jemalloc.sh rm -f $(objroot)config.log rm -f $(objroot)config.status diff --git a/memory/jemalloc/src/VERSION b/memory/jemalloc/src/VERSION index dace31ba7b6a..b69b0ae0f104 100644 --- a/memory/jemalloc/src/VERSION +++ b/memory/jemalloc/src/VERSION @@ -1 +1 @@ -3.6.0-0-g46c0af68bd248b04df75e4f92d5fb804c3d75340 +3.6.0-204-gb4acf7300a4ca3423ca36fe227e9bc2e23f25b9f diff --git a/memory/jemalloc/src/bin/pprof b/memory/jemalloc/src/bin/pprof index a309943c1cb9..df503aea9383 100755 --- a/memory/jemalloc/src/bin/pprof +++ b/memory/jemalloc/src/bin/pprof @@ -2,11 +2,11 @@ # Copyright (c) 1998-2007, Google Inc. # All rights reserved. -# +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: -# +# # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above @@ -16,7 +16,7 @@ # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. -# +# # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -223,6 +223,7 @@ Call-graph Options: --edgefraction= Hide edges below *total [default=.001] --maxdegree= Max incoming/outgoing edges per node [default=8] --focus= Focus on nodes matching + --thread= Show profile for thread --ignore= Ignore nodes matching --scale= Set GV scaling [default=0] --heapcheck Make nodes with non-0 object counts @@ -332,6 +333,7 @@ sub Init() { $main::opt_edgefraction = 0.001; $main::opt_maxdegree = 8; $main::opt_focus = ''; + $main::opt_thread = undef; $main::opt_ignore = ''; $main::opt_scale = 0; $main::opt_heapcheck = 0; @@ -402,6 +404,7 @@ sub Init() { "edgefraction=f" => \$main::opt_edgefraction, "maxdegree=i" => \$main::opt_maxdegree, "focus=s" => \$main::opt_focus, + "thread=s" => \$main::opt_thread, "ignore=s" => \$main::opt_ignore, "scale=i" => \$main::opt_scale, "heapcheck" => \$main::opt_heapcheck, @@ -562,6 +565,86 @@ sub Init() { } } +sub FilterAndPrint { + my ($profile, $symbols, $libs, $thread) = @_; + + # Get total data in profile + my $total = TotalProfile($profile); + + # Remove uniniteresting stack items + $profile = RemoveUninterestingFrames($symbols, $profile); + + # Focus? + if ($main::opt_focus ne '') { + $profile = FocusProfile($symbols, $profile, $main::opt_focus); + } + + # Ignore? + if ($main::opt_ignore ne '') { + $profile = IgnoreProfile($symbols, $profile, $main::opt_ignore); + } + + my $calls = ExtractCalls($symbols, $profile); + + # Reduce profiles to required output granularity, and also clean + # each stack trace so a given entry exists at most once. + my $reduced = ReduceProfile($symbols, $profile); + + # Get derived profiles + my $flat = FlatProfile($reduced); + my $cumulative = CumulativeProfile($reduced); + + # Print + if (!$main::opt_interactive) { + if ($main::opt_disasm) { + PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm); + } elsif ($main::opt_list) { + PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0); + } elsif ($main::opt_text) { + # Make sure the output is empty when have nothing to report + # (only matters when --heapcheck is given but we must be + # compatible with old branches that did not pass --heapcheck always): + if ($total != 0) { + printf("Total%s: %s %s\n", + (defined($thread) ? " (t$thread)" : ""), + Unparse($total), Units()); + } + PrintText($symbols, $flat, $cumulative, -1); + } elsif ($main::opt_raw) { + PrintSymbolizedProfile($symbols, $profile, $main::prog); + } elsif ($main::opt_callgrind) { + PrintCallgrind($calls); + } else { + if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) { + if ($main::opt_gv) { + RunGV(TempName($main::next_tmpfile, "ps"), ""); + } elsif ($main::opt_evince) { + RunEvince(TempName($main::next_tmpfile, "pdf"), ""); + } elsif ($main::opt_web) { + my $tmp = TempName($main::next_tmpfile, "svg"); + RunWeb($tmp); + # The command we run might hand the file name off + # to an already running browser instance and then exit. + # Normally, we'd remove $tmp on exit (right now), + # but fork a child to remove $tmp a little later, so that the + # browser has time to load it first. + delete $main::tempnames{$tmp}; + if (fork() == 0) { + sleep 5; + unlink($tmp); + exit(0); + } + } + } else { + cleanup(); + exit(1); + } + } + } else { + InteractiveMode($profile, $symbols, $libs, $total); + } +} + sub Main() { Init(); $main::collected_profile = undef; @@ -605,9 +688,6 @@ sub Main() { $symbol_map = MergeSymbols($symbol_map, $base->{symbols}); } - # Get total data in profile - my $total = TotalProfile($profile); - # Collect symbols my $symbols; if ($main::use_symbolized_profile) { @@ -622,75 +702,17 @@ sub Main() { $symbols = ExtractSymbols($libs, $pcs); } - # Remove uniniteresting stack items - $profile = RemoveUninterestingFrames($symbols, $profile); - - # Focus? - if ($main::opt_focus ne '') { - $profile = FocusProfile($symbols, $profile, $main::opt_focus); + if (!defined($main::opt_thread)) { + FilterAndPrint($profile, $symbols, $libs); } - - # Ignore? - if ($main::opt_ignore ne '') { - $profile = IgnoreProfile($symbols, $profile, $main::opt_ignore); - } - - my $calls = ExtractCalls($symbols, $profile); - - # Reduce profiles to required output granularity, and also clean - # each stack trace so a given entry exists at most once. - my $reduced = ReduceProfile($symbols, $profile); - - # Get derived profiles - my $flat = FlatProfile($reduced); - my $cumulative = CumulativeProfile($reduced); - - # Print - if (!$main::opt_interactive) { - if ($main::opt_disasm) { - PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm); - } elsif ($main::opt_list) { - PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0); - } elsif ($main::opt_text) { - # Make sure the output is empty when have nothing to report - # (only matters when --heapcheck is given but we must be - # compatible with old branches that did not pass --heapcheck always): - if ($total != 0) { - printf("Total: %s %s\n", Unparse($total), Units()); - } - PrintText($symbols, $flat, $cumulative, -1); - } elsif ($main::opt_raw) { - PrintSymbolizedProfile($symbols, $profile, $main::prog); - } elsif ($main::opt_callgrind) { - PrintCallgrind($calls); - } else { - if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) { - if ($main::opt_gv) { - RunGV(TempName($main::next_tmpfile, "ps"), ""); - } elsif ($main::opt_evince) { - RunEvince(TempName($main::next_tmpfile, "pdf"), ""); - } elsif ($main::opt_web) { - my $tmp = TempName($main::next_tmpfile, "svg"); - RunWeb($tmp); - # The command we run might hand the file name off - # to an already running browser instance and then exit. - # Normally, we'd remove $tmp on exit (right now), - # but fork a child to remove $tmp a little later, so that the - # browser has time to load it first. - delete $main::tempnames{$tmp}; - if (fork() == 0) { - sleep 5; - unlink($tmp); - exit(0); - } - } - } else { - cleanup(); - exit(1); + if (defined($data->{threads})) { + foreach my $thread (sort { $a <=> $b } keys(%{$data->{threads}})) { + if (defined($main::opt_thread) && + ($main::opt_thread eq '*' || $main::opt_thread == $thread)) { + my $thread_profile = $data->{threads}{$thread}; + FilterAndPrint($thread_profile, $symbols, $libs, $thread); } } - } else { - InteractiveMode($profile, $symbols, $libs, $total); } cleanup(); @@ -1683,23 +1705,23 @@ sub PrintSource { HtmlPrintNumber($c2), UnparseAddress($offset, $e->[0]), CleanDisassembly($e->[3])); - + # Append the most specific source line associated with this instruction if (length($dis) < 80) { $dis .= (' ' x (80 - length($dis))) }; $dis = HtmlEscape($dis); my $f = $e->[5]; my $l = $e->[6]; if ($f ne $last_dis_filename) { - $dis .= sprintf("%s:%d", + $dis .= sprintf("%s:%d", HtmlEscape(CleanFileName($f)), $l); } elsif ($l ne $last_dis_linenum) { # De-emphasize the unchanged file name portion $dis .= sprintf("%s" . - ":%d", + ":%d", HtmlEscape(CleanFileName($f)), $l); } else { # De-emphasize the entire location - $dis .= sprintf("%s:%d", + $dis .= sprintf("%s:%d", HtmlEscape(CleanFileName($f)), $l); } $last_dis_filename = $f; @@ -1788,8 +1810,8 @@ sub PrintSource { if (defined($dis) && $dis ne '') { $asm = "" . $dis . ""; } - my $source_class = (($n1 + $n2 > 0) - ? "livesrc" + my $source_class = (($n1 + $n2 > 0) + ? "livesrc" : (($asm ne "") ? "deadsrc" : "nop")); printf $output ( "%5d " . @@ -2811,9 +2833,15 @@ sub RemoveUninterestingFrames { 'free', 'memalign', 'posix_memalign', + 'aligned_alloc', 'pvalloc', 'valloc', 'realloc', + 'mallocx', # jemalloc + 'rallocx', # jemalloc + 'xallocx', # jemalloc + 'dallocx', # jemalloc + 'sdallocx', # jemalloc 'tc_calloc', 'tc_cfree', 'tc_malloc', @@ -2923,6 +2951,10 @@ sub RemoveUninterestingFrames { if (exists($symbols->{$a})) { my $func = $symbols->{$a}->[0]; if ($skip{$func} || ($func =~ m/$skip_regexp/)) { + # Throw away the portion of the backtrace seen so far, under the + # assumption that previous frames were for functions internal to the + # allocator. + @path = (); next; } } @@ -3680,6 +3712,7 @@ sub IsSymbolizedProfileFile { # $result->{version} Version number of profile file # $result->{period} Sampling period (in microseconds) # $result->{profile} Profile object +# $result->{threads} Map of thread IDs to profile objects # $result->{map} Memory map info from profile # $result->{pcs} Hash of all PC values seen, key is hex address sub ReadProfile { @@ -3728,6 +3761,9 @@ sub ReadProfile { } elsif ($header =~ m/^heap profile:/) { $main::profile_type = 'heap'; $result = ReadHeapProfile($prog, *PROFILE, $header); + } elsif ($header =~ m/^heap/) { + $main::profile_type = 'heap'; + $result = ReadThreadedHeapProfile($prog, $fname, $header); } elsif ($header =~ m/^--- *$contention_marker/o) { $main::profile_type = 'contention'; $result = ReadSynchProfile($prog, *PROFILE); @@ -3870,11 +3906,7 @@ sub ReadCPUProfile { return $r; } -sub ReadHeapProfile { - my $prog = shift; - local *PROFILE = shift; - my $header = shift; - +sub HeapProfileIndex { my $index = 1; if ($main::opt_inuse_space) { $index = 1; @@ -3885,6 +3917,84 @@ sub ReadHeapProfile { } elsif ($main::opt_alloc_objects) { $index = 2; } + return $index; +} + +sub ReadMappedLibraries { + my $fh = shift; + my $map = ""; + # Read the /proc/self/maps data + while (<$fh>) { + s/\r//g; # turn windows-looking lines into unix-looking lines + $map .= $_; + } + return $map; +} + +sub ReadMemoryMap { + my $fh = shift; + my $map = ""; + # Read /proc/self/maps data as formatted by DumpAddressMap() + my $buildvar = ""; + while () { + s/\r//g; # turn windows-looking lines into unix-looking lines + # Parse "build=
" specification if supplied + if (m/^\s*build=(.*)\n/) { + $buildvar = $1; + } + + # Expand "$build" variable if available + $_ =~ s/\$build\b/$buildvar/g; + + $map .= $_; + } + return $map; +} + +sub AdjustSamples { + my ($sample_adjustment, $sampling_algorithm, $n1, $s1, $n2, $s2) = @_; + if ($sample_adjustment) { + if ($sampling_algorithm == 2) { + # Remote-heap version 2 + # The sampling frequency is the rate of a Poisson process. + # This means that the probability of sampling an allocation of + # size X with sampling rate Y is 1 - exp(-X/Y) + if ($n1 != 0) { + my $ratio = (($s1*1.0)/$n1)/($sample_adjustment); + my $scale_factor = 1/(1 - exp(-$ratio)); + $n1 *= $scale_factor; + $s1 *= $scale_factor; + } + if ($n2 != 0) { + my $ratio = (($s2*1.0)/$n2)/($sample_adjustment); + my $scale_factor = 1/(1 - exp(-$ratio)); + $n2 *= $scale_factor; + $s2 *= $scale_factor; + } + } else { + # Remote-heap version 1 + my $ratio; + $ratio = (($s1*1.0)/$n1)/($sample_adjustment); + if ($ratio < 1) { + $n1 /= $ratio; + $s1 /= $ratio; + } + $ratio = (($s2*1.0)/$n2)/($sample_adjustment); + if ($ratio < 1) { + $n2 /= $ratio; + $s2 /= $ratio; + } + } + } + return ($n1, $s1, $n2, $s2); +} + +sub ReadHeapProfile { + my $prog = shift; + local *PROFILE = shift; + my $header = shift; + + my $index = HeapProfileIndex(); # Find the type of this profile. The header line looks like: # heap profile: 1246: 8800744 [ 1246: 8800744] @ /266053 @@ -3974,29 +4084,12 @@ sub ReadHeapProfile { while () { s/\r//g; # turn windows-looking lines into unix-looking lines if (/^MAPPED_LIBRARIES:/) { - # Read the /proc/self/maps data - while () { - s/\r//g; # turn windows-looking lines into unix-looking lines - $map .= $_; - } + $map .= ReadMappedLibraries(*PROFILE); last; } if (/^--- Memory map:/) { - # Read /proc/self/maps data as formatted by DumpAddressMap() - my $buildvar = ""; - while () { - s/\r//g; # turn windows-looking lines into unix-looking lines - # Parse "build=" specification if supplied - if (m/^\s*build=(.*)\n/) { - $buildvar = $1; - } - - # Expand "$build" variable if available - $_ =~ s/\$build\b/$buildvar/g; - - $map .= $_; - } + $map .= ReadMemoryMap(*PROFILE); last; } @@ -4007,42 +4100,8 @@ sub ReadHeapProfile { if (m/^\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]\s+@\s+(.*)$/) { my $stack = $5; my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4); - - if ($sample_adjustment) { - if ($sampling_algorithm == 2) { - # Remote-heap version 2 - # The sampling frequency is the rate of a Poisson process. - # This means that the probability of sampling an allocation of - # size X with sampling rate Y is 1 - exp(-X/Y) - if ($n1 != 0) { - my $ratio = (($s1*1.0)/$n1)/($sample_adjustment); - my $scale_factor = 1/(1 - exp(-$ratio)); - $n1 *= $scale_factor; - $s1 *= $scale_factor; - } - if ($n2 != 0) { - my $ratio = (($s2*1.0)/$n2)/($sample_adjustment); - my $scale_factor = 1/(1 - exp(-$ratio)); - $n2 *= $scale_factor; - $s2 *= $scale_factor; - } - } else { - # Remote-heap version 1 - my $ratio; - $ratio = (($s1*1.0)/$n1)/($sample_adjustment); - if ($ratio < 1) { - $n1 /= $ratio; - $s1 /= $ratio; - } - $ratio = (($s2*1.0)/$n2)/($sample_adjustment); - if ($ratio < 1) { - $n2 /= $ratio; - $s2 /= $ratio; - } - } - } - - my @counts = ($n1, $s1, $n2, $s2); + my @counts = AdjustSamples($sample_adjustment, $sampling_algorithm, + $n1, $s1, $n2, $s2); AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]); } } @@ -4056,6 +4115,83 @@ sub ReadHeapProfile { return $r; } +sub ReadThreadedHeapProfile { + my ($prog, $fname, $header) = @_; + + my $index = HeapProfileIndex(); + my $sampling_algorithm = 0; + my $sample_adjustment = 0; + chomp($header); + my $type = "unknown"; + # Assuming a very specific type of header for now. + if ($header =~ m"^heap_v2/(\d+)") { + $type = "_v2"; + $sampling_algorithm = 2; + $sample_adjustment = int($1); + } + if ($type ne "_v2" || !defined($sample_adjustment)) { + die "Threaded heap profiles require v2 sampling with a sample rate\n"; + } + + my $profile = {}; + my $thread_profiles = {}; + my $pcs = {}; + my $map = ""; + my $stack = ""; + + while () { + s/\r//g; + if (/^MAPPED_LIBRARIES:/) { + $map .= ReadMappedLibraries(*PROFILE); + last; + } + + if (/^--- Memory map:/) { + $map .= ReadMemoryMap(*PROFILE); + last; + } + + # Read entry of the form: + # @ a1 a2 ... an + # t*: : [: ] + # t1: : [: ] + # ... + # tn: : [: ] + s/^\s*//; + s/\s*$//; + if (m/^@\s+(.*)$/) { + $stack = $1; + } elsif (m/^\s*(t(\*|\d+)):\s+(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]$/) { + if ($stack eq "") { + # Still in the header, so this is just a per-thread summary. + next; + } + my $thread = $2; + my ($n1, $s1, $n2, $s2) = ($3, $4, $5, $6); + my @counts = AdjustSamples($sample_adjustment, $sampling_algorithm, + $n1, $s1, $n2, $s2); + if ($thread eq "*") { + AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]); + } else { + if (!exists($thread_profiles->{$thread})) { + $thread_profiles->{$thread} = {}; + } + AddEntries($thread_profiles->{$thread}, $pcs, + FixCallerAddresses($stack), $counts[$index]); + } + } + } + + my $r = {}; + $r->{version} = "heap"; + $r->{period} = 1; + $r->{profile} = $profile; + $r->{threads} = $thread_profiles; + $r->{libs} = ParseLibraries($prog, $map, $pcs); + $r->{pcs} = $pcs; + return $r; +} + sub ReadSynchProfile { my $prog = shift; local *PROFILE = shift; @@ -4747,7 +4883,7 @@ sub MapToSymbols { } } } - + # Prepend to accumulated symbols for pcstr # (so that caller comes before callee) my $sym = $symbols->{$pcstr}; @@ -4941,7 +5077,7 @@ sub ConfigureTool { my $dirname = $`; # this is everything up to and including the last slash if (-x "$dirname$tool") { $path = "$dirname$tool"; - } else { + } else { $path = $tool; } } diff --git a/memory/jemalloc/src/config.guess b/memory/jemalloc/src/config.guess index b79252d6b103..1f5c50c0d152 100755 --- a/memory/jemalloc/src/config.guess +++ b/memory/jemalloc/src/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2013 Free Software Foundation, Inc. +# Copyright 1992-2014 Free Software Foundation, Inc. -timestamp='2013-06-10' +timestamp='2014-03-23' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2013 Free Software Foundation, Inc. +Copyright 1992-2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -149,7 +149,7 @@ Linux|GNU|GNU/*) LIBC=gnu #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac @@ -826,7 +826,7 @@ EOF *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; - i*:MSYS*:*) + *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) @@ -969,10 +969,10 @@ EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; - or1k:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} exit ;; - or32:Linux:*:*) + or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) @@ -1260,16 +1260,26 @@ EOF if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then - if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - case $UNAME_PROCESSOR in - i386) UNAME_PROCESSOR=x86_64 ;; - powerpc) UNAME_PROCESSOR=powerpc64 ;; - esac + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; @@ -1361,154 +1371,6 @@ EOF exit ;; esac -eval $set_cc_for_build -cat >$dummy.c < -# include -#endif -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (__arm) && defined (__acorn) && defined (__unix) - printf ("arm-acorn-riscix\n"); exit (0); -#endif - -#if defined (hp300) && !defined (hpux) - printf ("m68k-hp-bsd\n"); exit (0); -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); - -#endif - -#if defined (vax) -# if !defined (ultrix) -# include -# if defined (BSD) -# if BSD == 43 - printf ("vax-dec-bsd4.3\n"); exit (0); -# else -# if BSD == 199006 - printf ("vax-dec-bsd4.3reno\n"); exit (0); -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# endif -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# else - printf ("vax-dec-ultrix\n"); exit (0); -# endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - -# Apollos put the system type in the environment. - -test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } - -# Convex versions that predate uname can use getsysinfo(1) - -if [ -x /usr/convex/getsysinfo ] -then - case `getsysinfo -f cpu_type` in - c1*) - echo c1-convex-bsd - exit ;; - c2*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - c34*) - echo c34-convex-bsd - exit ;; - c38*) - echo c38-convex-bsd - exit ;; - c4*) - echo c4-convex-bsd - exit ;; - esac -fi - cat >&2 <." version="\ GNU config.sub ($timestamp) -Copyright 1992-2013 Free Software Foundation, Inc. +Copyright 1992-2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -283,8 +283,10 @@ case $basic_machine in | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ @@ -296,8 +298,7 @@ case $basic_machine in | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ - | open8 \ - | or1k | or32 \ + | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ @@ -402,8 +403,10 @@ case $basic_machine in | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ @@ -415,6 +418,7 @@ case $basic_machine in | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ + | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ @@ -1376,7 +1380,7 @@ case $os in | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1400,6 +1404,9 @@ case $os in -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; + # Apple iOS + -ios*) + ;; -linux-dietlibc) os=-linux-dietlibc ;; @@ -1594,9 +1601,6 @@ case $basic_machine in mips*-*) os=-elf ;; - or1k-*) - os=-elf - ;; or32-*) os=-coff ;; diff --git a/memory/jemalloc/src/configure b/memory/jemalloc/src/configure index e1dc2c594022..0811648d8236 100755 --- a/memory/jemalloc/src/configure +++ b/memory/jemalloc/src/configure @@ -638,9 +638,7 @@ enable_xmalloc enable_valgrind enable_utrace enable_fill -enable_dss enable_munmap -enable_mremap enable_tcache enable_prof enable_stats @@ -649,7 +647,6 @@ je_ install_suffix private_namespace enable_code_coverage -enable_experimental AUTOCONF LD RANLIB @@ -753,7 +750,6 @@ enable_option_checking with_xslroot with_rpath enable_autogen -enable_experimental enable_code_coverage with_mangling with_jemalloc_prefix @@ -770,13 +766,16 @@ with_static_libunwind enable_prof_libgcc enable_prof_gcc enable_tcache -enable_mremap enable_munmap -enable_dss enable_fill enable_utrace enable_valgrind enable_xmalloc +with_lg_tiny_min +with_lg_quantum +with_lg_page +with_lg_page_sizes +with_lg_size_class_group enable_lazy_lock enable_tls enable_zone_allocator @@ -1402,9 +1401,8 @@ Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-autogen Automatically regenerate configure output - --disable-experimental Disable support for the experimental API --enable-code-coverage Enable code coverage - --enable-cc-silence Silence irrelevant compiler warnings + --disable-cc-silence Do not silence irrelevant compiler warnings --enable-debug Build debugging code (implies --enable-ivsalloc) --enable-ivsalloc Validate pointers passed through the public API --disable-stats Disable statistics calculation/reporting @@ -1413,9 +1411,7 @@ Optional Features: --disable-prof-libgcc Do not use libgcc for backtracing --disable-prof-gcc Do not use gcc intrinsics for backtracing --disable-tcache Disable per thread caches - --enable-mremap Enable mremap(2) for huge realloc() --disable-munmap Disable VM deallocation via munmap(2) - --enable-dss Enable allocation from DSS --disable-fill Disable support for junk/zero filling, quarantine, and redzones --enable-utrace Enable utrace(2)-based tracing @@ -1442,6 +1438,16 @@ Optional Packages: --with-static-libunwind= Path to static libunwind library; use rather than dynamically linking + --with-lg-tiny-min= + Base 2 log of minimum tiny size class to support + --with-lg-quantum= + Base 2 log of minimum allocation alignment + --with-lg-page= + Base 2 log of system page size + --with-lg-page-sizes= + Base 2 logs of system page sizes to support + --with-lg-size-class-group= + Base 2 log of size classes per doubling Some influential environment variables: CC C compiler command @@ -2476,7 +2482,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -rev=1 +rev=2 srcroot=$srcdir @@ -3669,7 +3675,43 @@ $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CPPFLAGS="$CPPFLAGS -I${srcroot}/include/msvc_compat" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -FS" >&5 +$as_echo_n "checking whether compiler supports -FS... " >&6; } +TCFLAGS="${CFLAGS}" +if test "x${CFLAGS}" = "x" ; then + CFLAGS="-FS" +else + CFLAGS="${CFLAGS} -FS" +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +int +main () +{ + + return 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + je_cv_cflags_appended=-FS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + je_cv_cflags_appended= + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CFLAGS="${TCFLAGS}" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + CPPFLAGS="$CPPFLAGS -I${srcdir}/include/msvc_compat" fi fi if test "x$EXTRA_CFLAGS" != "x" ; then @@ -4339,7 +4381,7 @@ _ACEOF fi if test "x${je_cv_msvc}" = "xyes" -a "x${ac_cv_header_inttypes_h}" = "xno"; then - CPPFLAGS="$CPPFLAGS -I${srcroot}/include/msvc_compat/C99" + CPPFLAGS="$CPPFLAGS -I${srcdir}/include/msvc_compat/C99" fi # The cast to long int works around a bug in the HP C Compiler @@ -4626,9 +4668,10 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac CPU_SPINWAIT="" case "${host_cpu}" in - i[345]86) - ;; i686|x86_64) + if ${je_cv_pause+:} false; then : + $as_echo_n "(cached) " >&6 +else { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pause instruction is compilable" >&5 $as_echo_n "checking whether pause instruction is compilable... " >&6; } @@ -4657,45 +4700,11 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_pause" >&5 $as_echo "$je_cv_pause" >&6; } +fi + if test "x${je_cv_pause}" = "xyes" ; then CPU_SPINWAIT='__asm__ volatile("pause")' fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether SSE2 intrinsics is compilable" >&5 -$as_echo_n "checking whether SSE2 intrinsics is compilable... " >&6; } -if ${je_cv_sse2+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - je_cv_sse2=yes -else - je_cv_sse2=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_sse2" >&5 -$as_echo "$je_cv_sse2" >&6; } - - if test "x${je_cv_sse2}" = "xyes" ; then - cat >>confdefs.h <<_ACEOF -#define HAVE_SSE2 -_ACEOF - - fi ;; powerpc) cat >>confdefs.h <<_ACEOF @@ -4827,7 +4836,7 @@ fi default_munmap="1" case "${host}" in - *-*-darwin*) + *-*-darwin* | *-*-ios*) CFLAGS="$CFLAGS" abi="macho" $as_echo "#define JEMALLOC_PURGE_MADVISE_FREE " >>confdefs.h @@ -4847,6 +4856,12 @@ case "${host}" in $as_echo "#define JEMALLOC_PURGE_MADVISE_FREE " >>confdefs.h force_lazy_lock="1" + ;; + *-*-dragonfly*) + CFLAGS="$CFLAGS" + abi="elf" + $as_echo "#define JEMALLOC_PURGE_MADVISE_FREE " >>confdefs.h + ;; *-*-linux*) CFLAGS="$CFLAGS" @@ -4907,7 +4922,7 @@ $as_echo "$abi" >&6; } fi abi="xcoff" ;; - *-*-mingw*) + *-*-mingw* | *-*-cygwin*) abi="pecoff" force_tls="0" RPATH="" @@ -5125,7 +5140,7 @@ int main () { static __thread int - __attribute__((tls_model("initial-exec"))) foo; + __attribute__((tls_model("initial-exec"), unused)) foo; foo = 0; ; return 0; @@ -5449,7 +5464,7 @@ fi -public_syms="malloc_conf malloc_message malloc calloc posix_memalign aligned_alloc realloc free mallocx rallocx xallocx sallocx dallocx nallocx mallctl mallctlnametomib mallctlbymib malloc_stats_print malloc_usable_size" +public_syms="malloc_conf malloc_message malloc calloc posix_memalign aligned_alloc realloc free mallocx rallocx xallocx sallocx dallocx sdallocx nallocx mallctl mallctlnametomib mallctlbymib malloc_stats_print malloc_usable_size" ac_fn_c_check_func "$LINENO" "memalign" "ac_cv_func_memalign" if test "x$ac_cv_func_memalign" = xyes; then : @@ -5466,26 +5481,6 @@ if test "x$ac_cv_func_valloc" = xyes; then : fi -# Check whether --enable-experimental was given. -if test "${enable_experimental+set}" = set; then : - enableval=$enable_experimental; if test "x$enable_experimental" = "xno" ; then - enable_experimental="0" -else - enable_experimental="1" -fi - -else - enable_experimental="1" - -fi - -if test "x$enable_experimental" = "x1" ; then - $as_echo "#define JEMALLOC_EXPERIMENTAL " >>confdefs.h - - public_syms="${public_syms} allocm dallocm nallocm rallocm sallocm" -fi - - GCOV_FLAGS= # Check whether --enable-code-coverage was given. if test "${enable_code_coverage+set}" = set; then : @@ -5660,31 +5655,37 @@ je_="je_" cfgoutputs_in="Makefile.in" +cfgoutputs_in="${cfgoutputs_in} jemalloc.pc.in" cfgoutputs_in="${cfgoutputs_in} doc/html.xsl.in" cfgoutputs_in="${cfgoutputs_in} doc/manpages.xsl.in" cfgoutputs_in="${cfgoutputs_in} doc/jemalloc.xml.in" cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_macros.h.in" cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_protos.h.in" +cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_typedefs.h.in" cfgoutputs_in="${cfgoutputs_in} include/jemalloc/internal/jemalloc_internal.h.in" cfgoutputs_in="${cfgoutputs_in} test/test.sh.in" cfgoutputs_in="${cfgoutputs_in} test/include/test/jemalloc_test.h.in" cfgoutputs_out="Makefile" +cfgoutputs_out="${cfgoutputs_out} jemalloc.pc" cfgoutputs_out="${cfgoutputs_out} doc/html.xsl" cfgoutputs_out="${cfgoutputs_out} doc/manpages.xsl" cfgoutputs_out="${cfgoutputs_out} doc/jemalloc.xml" cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_macros.h" cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_protos.h" +cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_typedefs.h" cfgoutputs_out="${cfgoutputs_out} include/jemalloc/internal/jemalloc_internal.h" cfgoutputs_out="${cfgoutputs_out} test/test.sh" cfgoutputs_out="${cfgoutputs_out} test/include/test/jemalloc_test.h" cfgoutputs_tup="Makefile" +cfgoutputs_tup="${cfgoutputs_tup} jemalloc.pc:jemalloc.pc.in" cfgoutputs_tup="${cfgoutputs_tup} doc/html.xsl:doc/html.xsl.in" cfgoutputs_tup="${cfgoutputs_tup} doc/manpages.xsl:doc/manpages.xsl.in" cfgoutputs_tup="${cfgoutputs_tup} doc/jemalloc.xml:doc/jemalloc.xml.in" cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_macros.h:include/jemalloc/jemalloc_macros.h.in" cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_protos.h:include/jemalloc/jemalloc_protos.h.in" +cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_typedefs.h:include/jemalloc/jemalloc_typedefs.h.in" cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/internal/jemalloc_internal.h" cfgoutputs_tup="${cfgoutputs_tup} test/test.sh:test/test.sh.in" cfgoutputs_tup="${cfgoutputs_tup} test/include/test/jemalloc_test.h:test/include/test/jemalloc_test.h.in" @@ -5730,7 +5731,7 @@ else fi else - enable_cc_silence="0" + enable_cc_silence="1" fi @@ -6015,9 +6016,9 @@ fi done if test "x$LUNWIND" = "x-lunwind" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for backtrace in -lunwind" >&5 -$as_echo_n "checking for backtrace in -lunwind... " >&6; } -if ${ac_cv_lib_unwind_backtrace+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unw_backtrace in -lunwind" >&5 +$as_echo_n "checking for unw_backtrace in -lunwind... " >&6; } +if ${ac_cv_lib_unwind_unw_backtrace+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -6031,27 +6032,27 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char backtrace (); +char unw_backtrace (); int main () { -return backtrace (); +return unw_backtrace (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_unwind_backtrace=yes + ac_cv_lib_unwind_unw_backtrace=yes else - ac_cv_lib_unwind_backtrace=no + ac_cv_lib_unwind_unw_backtrace=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_unwind_backtrace" >&5 -$as_echo "$ac_cv_lib_unwind_backtrace" >&6; } -if test "x$ac_cv_lib_unwind_backtrace" = xyes; then : +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_unwind_unw_backtrace" >&5 +$as_echo "$ac_cv_lib_unwind_unw_backtrace" >&6; } +if test "x$ac_cv_lib_unwind_unw_backtrace" = xyes; then : LIBS="$LIBS $LUNWIND" else enable_prof_libunwind="0" @@ -6214,11 +6215,6 @@ $as_echo_n "checking configured backtracing method... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $backtrace_method" >&5 $as_echo "$backtrace_method" >&6; } if test "x$enable_prof" = "x1" ; then - if test "x${force_tls}" = "x0" ; then - as_fn_error $? "Heap profiling requires TLS" "$LINENO" 5; - fi - force_tls="1" - if test "x$abi" != "xpecoff"; then LIBS="$LIBS -lm" fi @@ -6247,63 +6243,6 @@ if test "x$enable_tcache" = "x1" ; then fi -# Check whether --enable-mremap was given. -if test "${enable_mremap+set}" = set; then : - enableval=$enable_mremap; if test "x$enable_mremap" = "xno" ; then - enable_mremap="0" -else - enable_mremap="1" -fi - -else - enable_mremap="0" - -fi - -if test "x$enable_mremap" = "x1" ; then - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mremap(...MREMAP_FIXED...) is compilable" >&5 -$as_echo_n "checking whether mremap(...MREMAP_FIXED...) is compilable... " >&6; } -if ${je_cv_mremap_fixed+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#define _GNU_SOURCE -#include - -int -main () -{ - -void *p = mremap((void *)0, 0, 0, MREMAP_MAYMOVE|MREMAP_FIXED, (void *)0); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - je_cv_mremap_fixed=yes -else - je_cv_mremap_fixed=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_mremap_fixed" >&5 -$as_echo "$je_cv_mremap_fixed" >&6; } - - if test "x${je_cv_mremap_fixed}" = "xno" ; then - enable_mremap="0" - fi -fi -if test "x$enable_mremap" = "x1" ; then - $as_echo "#define JEMALLOC_MREMAP " >>confdefs.h - -fi - - # Check whether --enable-munmap was given. if test "${enable_munmap+set}" = set; then : enableval=$enable_munmap; if test "x$enable_munmap" = "xno" ; then @@ -6323,19 +6262,7 @@ if test "x$enable_munmap" = "x1" ; then fi -# Check whether --enable-dss was given. -if test "${enable_dss+set}" = set; then : - enableval=$enable_dss; if test "x$enable_dss" = "xno" ; then - enable_dss="0" -else - enable_dss="1" -fi - -else - enable_dss="0" - -fi - +have_dss="1" ac_fn_c_check_func "$LINENO" "sbrk" "ac_cv_func_sbrk" if test "x$ac_cv_func_sbrk" = xyes; then : have_sbrk="1" @@ -6344,24 +6271,20 @@ else fi if test "x$have_sbrk" = "x1" ; then - if test "x$sbrk_deprecated" == "x1" ; then + if test "x$sbrk_deprecated" = "x1" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling dss allocation because sbrk is deprecated" >&5 $as_echo "Disabling dss allocation because sbrk is deprecated" >&6; } - enable_dss="0" - else - $as_echo "#define JEMALLOC_HAVE_SBRK " >>confdefs.h - + have_dss="0" fi else - enable_dss="0" + have_dss="0" fi -if test "x$enable_dss" = "x1" ; then +if test "x$have_dss" = "x1" ; then $as_echo "#define JEMALLOC_DSS " >>confdefs.h fi - # Check whether --enable-fill was given. if test "${enable_fill+set}" = set; then : enableval=$enable_fill; if test "x$enable_fill" = "xno" ; then @@ -6517,16 +6440,140 @@ if test "x$enable_xmalloc" = "x1" ; then fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking STATIC_PAGE_SHIFT" >&5 -$as_echo_n "checking STATIC_PAGE_SHIFT... " >&6; } -if ${je_cv_static_page_shift+:} false; then : + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program using __builtin_ffsl is compilable" >&5 +$as_echo_n "checking whether a program using __builtin_ffsl is compilable... " >&6; } +if ${je_cv_gcc_builtin_ffsl+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include + +int +main () +{ + + { + int rv = __builtin_ffsl(0x08); + printf("%d\n", rv); + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + je_cv_gcc_builtin_ffsl=yes +else + je_cv_gcc_builtin_ffsl=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_gcc_builtin_ffsl" >&5 +$as_echo "$je_cv_gcc_builtin_ffsl" >&6; } + +if test "x${je_cv_gcc_builtin_ffsl}" = "xyes" ; then + $as_echo "#define JEMALLOC_INTERNAL_FFSL __builtin_ffsl" >>confdefs.h + + $as_echo "#define JEMALLOC_INTERNAL_FFS __builtin_ffs" >>confdefs.h + +else + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program using ffsl is compilable" >&5 +$as_echo_n "checking whether a program using ffsl is compilable... " >&6; } +if ${je_cv_function_ffsl+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + #include + +int +main () +{ + + { + int rv = ffsl(0x08); + printf("%d\n", rv); + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + je_cv_function_ffsl=yes +else + je_cv_function_ffsl=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_function_ffsl" >&5 +$as_echo "$je_cv_function_ffsl" >&6; } + + if test "x${je_cv_function_ffsl}" = "xyes" ; then + $as_echo "#define JEMALLOC_INTERNAL_FFSL ffsl" >>confdefs.h + + $as_echo "#define JEMALLOC_INTERNAL_FFS ffs" >>confdefs.h + + else + as_fn_error $? "Cannot build without ffsl(3) or __builtin_ffsl()" "$LINENO" 5 + fi +fi + + +# Check whether --with-lg_tiny_min was given. +if test "${with_lg_tiny_min+set}" = set; then : + withval=$with_lg_tiny_min; LG_TINY_MIN="$with_lg_tiny_min" +else + LG_TINY_MIN="3" +fi + +cat >>confdefs.h <<_ACEOF +#define LG_TINY_MIN $LG_TINY_MIN +_ACEOF + + + +# Check whether --with-lg_quantum was given. +if test "${with_lg_quantum+set}" = set; then : + withval=$with_lg_quantum; LG_QUANTA="$with_lg_quantum" +else + LG_QUANTA="3 4" +fi + +if test "x$with_lg_quantum" != "x" ; then + cat >>confdefs.h <<_ACEOF +#define LG_QUANTUM $with_lg_quantum +_ACEOF + +fi + + +# Check whether --with-lg_page was given. +if test "${with_lg_page+set}" = set; then : + withval=$with_lg_page; LG_PAGE="$with_lg_page" +else + LG_PAGE="detect" +fi + +if test "x$LG_PAGE" == "xdetect"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking LG_PAGE" >&5 +$as_echo_n "checking LG_PAGE... " >&6; } +if ${je_cv_lg_page+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run test program while cross compiling -See \`config.log' for more details" "$LINENO" 5; } + je_cv_lg_page=12 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6556,7 +6603,7 @@ main () if (result == -1) { return 1; } - result = ffsl(result) - 1; + result = JEMALLOC_INTERNAL_FFSL(result) - 1; f = fopen("conftest.out", "w"); if (f == NULL) { @@ -6572,32 +6619,50 @@ main () } _ACEOF if ac_fn_c_try_run "$LINENO"; then : - je_cv_static_page_shift=`cat conftest.out` + je_cv_lg_page=`cat conftest.out` else - je_cv_static_page_shift=undefined + je_cv_lg_page=undefined fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_static_page_shift" >&5 -$as_echo "$je_cv_static_page_shift" >&6; } - -if test "x$je_cv_static_page_shift" != "xundefined"; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_lg_page" >&5 +$as_echo "$je_cv_lg_page" >&6; } +fi +if test "x${je_cv_lg_page}" != "x" ; then + LG_PAGE="${je_cv_lg_page}" +fi +if test "x${LG_PAGE}" != "xundefined" ; then cat >>confdefs.h <<_ACEOF -#define STATIC_PAGE_SHIFT $je_cv_static_page_shift +#define LG_PAGE $LG_PAGE _ACEOF else - as_fn_error $? "cannot determine value for STATIC_PAGE_SHIFT" "$LINENO" 5 + as_fn_error $? "cannot determine value for LG_PAGE" "$LINENO" 5 fi -if test -d "${srcroot}.git" ; then - git describe --long --abbrev=40 > ${srcroot}VERSION +# Check whether --with-lg_page_sizes was given. +if test "${with_lg_page_sizes+set}" = set; then : + withval=$with_lg_page_sizes; LG_PAGE_SIZES="$with_lg_page_sizes" +else + LG_PAGE_SIZES="$LG_PAGE" fi -jemalloc_version=`cat ${srcroot}VERSION` + + + +# Check whether --with-lg_size_class_group was given. +if test "${with_lg_size_class_group+set}" = set; then : + withval=$with_lg_size_class_group; LG_SIZE_CLASS_GROUP="$with_lg_size_class_group" +else + LG_SIZE_CLASS_GROUP="2" +fi + + + +jemalloc_version=`cat "${srcroot}VERSION"` jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print $1}'` jemalloc_version_minor=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print $2}'` jemalloc_version_bugfix=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print $3}'` @@ -6729,6 +6794,32 @@ fi CPPFLAGS="$CPPFLAGS -D_REENTRANT" +ac_fn_c_check_func "$LINENO" "secure_getenv" "ac_cv_func_secure_getenv" +if test "x$ac_cv_func_secure_getenv" = xyes; then : + have_secure_getenv="1" +else + have_secure_getenv="0" + +fi + +if test "x$have_secure_getenv" = "x1" ; then + $as_echo "#define JEMALLOC_HAVE_SECURE_GETENV " >>confdefs.h + +fi + +ac_fn_c_check_func "$LINENO" "issetugid" "ac_cv_func_issetugid" +if test "x$ac_cv_func_issetugid" = xyes; then : + have_issetugid="1" +else + have_issetugid="0" + +fi + +if test "x$have_issetugid" = "x1" ; then + $as_echo "#define JEMALLOC_HAVE_ISSETUGID " >>confdefs.h + +fi + ac_fn_c_check_func "$LINENO" "_malloc_thread_cleanup" "ac_cv_func__malloc_thread_cleanup" if test "x$ac_cv_func__malloc_thread_cleanup" = xyes; then : have__malloc_thread_cleanup="1" @@ -6909,95 +7000,51 @@ elif test "x${force_tls}" = "x1" ; then fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program using __builtin_ffsl is compilable" >&5 -$as_echo_n "checking whether a program using __builtin_ffsl is compilable... " >&6; } -if ${je_cv_gcc_builtin_ffsl+:} false; then : + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C11 atomics is compilable" >&5 +$as_echo_n "checking whether C11 atomics is compilable... " >&6; } +if ${je_cv_c11atomics+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -#include +#include +#if (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__) +#include +#else +#error Atomics not available +#endif int main () { - { - int rv = __builtin_ffsl(0x08); - printf("%d\n", rv); - } + uint64_t *p = (uint64_t *)0; + uint64_t x = 1; + volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; + uint64_t r = atomic_fetch_add(a, x) + x; + return (r == 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - je_cv_gcc_builtin_ffsl=yes + je_cv_c11atomics=yes else - je_cv_gcc_builtin_ffsl=no + je_cv_c11atomics=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_gcc_builtin_ffsl" >&5 -$as_echo "$je_cv_gcc_builtin_ffsl" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_c11atomics" >&5 +$as_echo "$je_cv_c11atomics" >&6; } -if test "x${je_cv_gcc_builtin_ffsl}" == "xyes" ; then - $as_echo "#define JEMALLOC_INTERNAL_FFSL __builtin_ffsl" >>confdefs.h +if test "x${je_cv_c11atomics}" = "xyes" ; then + $as_echo "#define JEMALLOC_C11ATOMICS 1" >>confdefs.h - $as_echo "#define JEMALLOC_INTERNAL_FFS __builtin_ffs" >>confdefs.h - -else - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program using ffsl is compilable" >&5 -$as_echo_n "checking whether a program using ffsl is compilable... " >&6; } -if ${je_cv_function_ffsl+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - #include - #include - -int -main () -{ - - { - int rv = ffsl(0x08); - printf("%d\n", rv); - } - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - je_cv_function_ffsl=yes -else - je_cv_function_ffsl=no fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_function_ffsl" >&5 -$as_echo "$je_cv_function_ffsl" >&6; } - - if test "x${je_cv_function_ffsl}" == "xyes" ; then - $as_echo "#define JEMALLOC_INTERNAL_FFSL ffsl" >>confdefs.h - - $as_echo "#define JEMALLOC_INTERNAL_FFS ffs" >>confdefs.h - - else - as_fn_error $? "Cannot build without ffsl(3) or __builtin_ffsl()" "$LINENO" 5 - fi -fi - @@ -7098,6 +7145,46 @@ fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether madvise(2) is compilable" >&5 +$as_echo_n "checking whether madvise(2) is compilable... " >&6; } +if ${je_cv_madvise+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +int +main () +{ + + { + madvise((void *)0, 0, 0); + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + je_cv_madvise=yes +else + je_cv_madvise=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_madvise" >&5 +$as_echo "$je_cv_madvise" >&6; } + +if test "x${je_cv_madvise}" = "xyes" ; then + $as_echo "#define JEMALLOC_HAVE_MADVISE " >>confdefs.h + +fi + + + if test "x${je_cv_atomic9}" != "xyes" -a "x${je_cv_osatomic}" != "xyes" ; then @@ -7193,6 +7280,48 @@ $as_echo "$je_cv_sync_compare_and_swap_8" >&6; } fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_clz" >&5 +$as_echo_n "checking for __builtin_clz... " >&6; } +if ${je_cv_builtin_clz+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + { + unsigned x = 0; + int y = __builtin_clz(x); + } + { + unsigned long x = 0; + int y = __builtin_clzl(x); + } + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + je_cv_builtin_clz=yes +else + je_cv_builtin_clz=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_builtin_clz" >&5 +$as_echo "$je_cv_builtin_clz" >&6; } + +if test "x${je_cv_builtin_clz}" = "xyes" ; then + $as_echo "#define JEMALLOC_HAVE_BUILTIN_CLZ " >>confdefs.h + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Darwin OSSpin*() is compilable" >&5 $as_echo_n "checking whether Darwin OSSpin*() is compilable... " >&6; } @@ -7271,7 +7400,7 @@ $as_echo_n "checking malloc zone version... " >&6; } int main () { -static foo[sizeof(malloc_zone_t) == sizeof(void *) * 14 ? 1 : -1] +static int foo[sizeof(malloc_zone_t) == sizeof(void *) * 14 ? 1 : -1] ; return 0; @@ -7287,7 +7416,7 @@ else int main () { -static foo[sizeof(malloc_zone_t) == sizeof(void *) * 15 ? 1 : -1] +static int foo[sizeof(malloc_zone_t) == sizeof(void *) * 15 ? 1 : -1] ; return 0; @@ -7303,7 +7432,7 @@ else int main () { -static foo[sizeof(malloc_zone_t) == sizeof(void *) * 16 ? 1 : -1] +static int foo[sizeof(malloc_zone_t) == sizeof(void *) * 16 ? 1 : -1] ; return 0; @@ -7317,7 +7446,7 @@ if ac_fn_c_try_compile "$LINENO"; then : int main () { -static foo[sizeof(malloc_introspection_t) == sizeof(void *) * 9 ? 1 : -1] +static int foo[sizeof(malloc_introspection_t) == sizeof(void *) * 9 ? 1 : -1] ; return 0; @@ -7333,7 +7462,7 @@ else int main () { -static foo[sizeof(malloc_introspection_t) == sizeof(void *) * 13 ? 1 : -1] +static int foo[sizeof(malloc_introspection_t) == sizeof(void *) * 13 ? 1 : -1] ; return 0; @@ -7356,7 +7485,7 @@ else int main () { -static foo[sizeof(malloc_zone_t) == sizeof(void *) * 17 ? 1 : -1] +static int foo[sizeof(malloc_zone_t) == sizeof(void *) * 17 ? 1 : -1] ; return 0; @@ -7372,7 +7501,7 @@ else int main () { -static foo[sizeof(malloc_zone_t) > sizeof(void *) * 17 ? 1 : -1] +static int foo[sizeof(malloc_zone_t) > sizeof(void *) * 17 ? 1 : -1] ; return 0; @@ -7412,6 +7541,131 @@ _ACEOF fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether glibc malloc hook is compilable" >&5 +$as_echo_n "checking whether glibc malloc hook is compilable... " >&6; } +if ${je_cv_glibc_malloc_hook+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +extern void (* __free_hook)(void *ptr); +extern void *(* __malloc_hook)(size_t size); +extern void *(* __realloc_hook)(void *ptr, size_t size); + +int +main () +{ + + void *ptr = 0L; + if (__malloc_hook) ptr = __malloc_hook(1); + if (__realloc_hook) ptr = __realloc_hook(ptr, 2); + if (__free_hook && ptr) __free_hook(ptr); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + je_cv_glibc_malloc_hook=yes +else + je_cv_glibc_malloc_hook=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_glibc_malloc_hook" >&5 +$as_echo "$je_cv_glibc_malloc_hook" >&6; } + +if test "x${je_cv_glibc_malloc_hook}" = "xyes" ; then + $as_echo "#define JEMALLOC_GLIBC_MALLOC_HOOK " >>confdefs.h + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether glibc memalign hook is compilable" >&5 +$as_echo_n "checking whether glibc memalign hook is compilable... " >&6; } +if ${je_cv_glibc_memalign_hook+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +extern void *(* __memalign_hook)(size_t alignment, size_t size); + +int +main () +{ + + void *ptr = 0L; + if (__memalign_hook) ptr = __memalign_hook(16, 7); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + je_cv_glibc_memalign_hook=yes +else + je_cv_glibc_memalign_hook=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_glibc_memalign_hook" >&5 +$as_echo "$je_cv_glibc_memalign_hook" >&6; } + +if test "x${je_cv_glibc_memalign_hook}" = "xyes" ; then + $as_echo "#define JEMALLOC_GLIBC_MEMALIGN_HOOK " >>confdefs.h + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads adaptive mutexes is compilable" >&5 +$as_echo_n "checking whether pthreads adaptive mutexes is compilable... " >&6; } +if ${je_cv_pthread_mutex_adaptive_np+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +int +main () +{ + + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); + pthread_mutexattr_destroy(&attr); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + je_cv_pthread_mutex_adaptive_np=yes +else + je_cv_pthread_mutex_adaptive_np=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $je_cv_pthread_mutex_adaptive_np" >&5 +$as_echo "$je_cv_pthread_mutex_adaptive_np" >&6; } + +if test "x${je_cv_pthread_mutex_adaptive_np}" = "xyes" ; then + $as_echo "#define JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP " >>confdefs.h + +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 $as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } if ${ac_cv_header_stdbool_h+:} false; then : @@ -8256,6 +8510,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 srcdir="${srcdir}" objroot="${objroot}" + LG_QUANTA="${LG_QUANTA}" + LG_TINY_MIN=${LG_TINY_MIN} + LG_PAGE_SIZES="${LG_PAGE_SIZES}" + LG_SIZE_CLASS_GROUP=${LG_SIZE_CLASS_GROUP} srcdir="${srcdir}" @@ -8891,7 +9149,7 @@ $as_echo "$as_me: executing $ac_file commands" >&6;} ;; "include/jemalloc/internal/size_classes.h":C) mkdir -p "${objroot}include/jemalloc/internal" - "${srcdir}/include/jemalloc/internal/size_classes.sh" > "${objroot}include/jemalloc/internal/size_classes.h" + "${srcdir}/include/jemalloc/internal/size_classes.sh" "${LG_QUANTA}" ${LG_TINY_MIN} "${LG_PAGE_SIZES}" ${LG_SIZE_CLASS_GROUP} > "${objroot}include/jemalloc/internal/size_classes.h" ;; "include/jemalloc/jemalloc_protos_jet.h":C) mkdir -p "${objroot}include/jemalloc" @@ -9016,8 +9274,6 @@ $as_echo " : ${JEMALLOC_PRIVATE_NAMESPACE}" >&6; } $as_echo "install_suffix : ${install_suffix}" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: autogen : ${enable_autogen}" >&5 $as_echo "autogen : ${enable_autogen}" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: experimental : ${enable_experimental}" >&5 -$as_echo "experimental : ${enable_experimental}" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: cc-silence : ${enable_cc_silence}" >&5 $as_echo "cc-silence : ${enable_cc_silence}" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: debug : ${enable_debug}" >&5 @@ -9044,12 +9300,8 @@ $as_echo "utrace : ${enable_utrace}" >&6; } $as_echo "valgrind : ${enable_valgrind}" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: xmalloc : ${enable_xmalloc}" >&5 $as_echo "xmalloc : ${enable_xmalloc}" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: mremap : ${enable_mremap}" >&5 -$as_echo "mremap : ${enable_mremap}" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: munmap : ${enable_munmap}" >&5 $as_echo "munmap : ${enable_munmap}" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: dss : ${enable_dss}" >&5 -$as_echo "dss : ${enable_dss}" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: lazy_lock : ${enable_lazy_lock}" >&5 $as_echo "lazy_lock : ${enable_lazy_lock}" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: tls : ${enable_tls}" >&5 diff --git a/memory/jemalloc/src/configure.ac b/memory/jemalloc/src/configure.ac index dca1cdb0bea5..871d8eb5d161 100644 --- a/memory/jemalloc/src/configure.ac +++ b/memory/jemalloc/src/configure.ac @@ -44,7 +44,7 @@ AC_CACHE_CHECK([whether $1 is compilable], dnl ============================================================================ dnl Library revision. -rev=1 +rev=2 AC_SUBST([rev]) srcroot=$srcdir @@ -141,7 +141,8 @@ if test "x$CFLAGS" = "x" ; then JE_CFLAGS_APPEND([-Zi]) JE_CFLAGS_APPEND([-MT]) JE_CFLAGS_APPEND([-W3]) - CPPFLAGS="$CPPFLAGS -I${srcroot}/include/msvc_compat" + JE_CFLAGS_APPEND([-FS]) + CPPFLAGS="$CPPFLAGS -I${srcdir}/include/msvc_compat" fi fi dnl Append EXTRA_CFLAGS to CFLAGS, if defined. @@ -156,7 +157,7 @@ if test "x${ac_cv_big_endian}" = "x1" ; then fi if test "x${je_cv_msvc}" = "xyes" -a "x${ac_cv_header_inttypes_h}" = "xno"; then - CPPFLAGS="$CPPFLAGS -I${srcroot}/include/msvc_compat/C99" + CPPFLAGS="$CPPFLAGS -I${srcdir}/include/msvc_compat/C99" fi AC_CHECK_SIZEOF([void *]) @@ -205,23 +206,14 @@ AC_CANONICAL_HOST dnl CPU-specific settings. CPU_SPINWAIT="" case "${host_cpu}" in - i[[345]]86) - ;; i686|x86_64) - JE_COMPILABLE([pause instruction], [], - [[__asm__ volatile("pause"); return 0;]], - [je_cv_pause]) + AC_CACHE_VAL([je_cv_pause], + [JE_COMPILABLE([pause instruction], [], + [[__asm__ volatile("pause"); return 0;]], + [je_cv_pause])]) if test "x${je_cv_pause}" = "xyes" ; then CPU_SPINWAIT='__asm__ volatile("pause")' fi - dnl emmintrin.h fails to compile unless MMX, SSE, and SSE2 are - dnl supported. - JE_COMPILABLE([SSE2 intrinsics], [ -#include -], [], [je_cv_sse2]) - if test "x${je_cv_sse2}" = "xyes" ; then - AC_DEFINE_UNQUOTED([HAVE_SSE2], [ ]) - fi ;; powerpc) AC_DEFINE_UNQUOTED([HAVE_ALTIVEC], [ ]) @@ -263,7 +255,7 @@ dnl definitions need to be seen before any headers are included, which is a pain dnl to make happen otherwise. default_munmap="1" case "${host}" in - *-*-darwin*) + *-*-darwin* | *-*-ios*) CFLAGS="$CFLAGS" abi="macho" AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) @@ -282,6 +274,11 @@ case "${host}" in AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) force_lazy_lock="1" ;; + *-*-dragonfly*) + CFLAGS="$CFLAGS" + abi="elf" + AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) + ;; *-*-linux*) CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" @@ -324,7 +321,7 @@ case "${host}" in fi abi="xcoff" ;; - *-*-mingw*) + *-*-mingw* | *-*-cygwin*) abi="pecoff" force_tls="0" RPATH="" @@ -405,7 +402,7 @@ SAVED_CFLAGS="${CFLAGS}" JE_CFLAGS_APPEND([-Werror]) JE_COMPILABLE([tls_model attribute], [], [static __thread int - __attribute__((tls_model("initial-exec"))) foo; + __attribute__((tls_model("initial-exec"), unused)) foo; foo = 0;], [je_cv_tls_model]) CFLAGS="${SAVED_CFLAGS}" @@ -446,7 +443,7 @@ AC_PROG_RANLIB AC_PATH_PROG([LD], [ld], [false], [$PATH]) AC_PATH_PROG([AUTOCONF], [autoconf], [false], [$PATH]) -public_syms="malloc_conf malloc_message malloc calloc posix_memalign aligned_alloc realloc free mallocx rallocx xallocx sallocx dallocx nallocx mallctl mallctlnametomib mallctlbymib malloc_stats_print malloc_usable_size" +public_syms="malloc_conf malloc_message malloc calloc posix_memalign aligned_alloc realloc free mallocx rallocx xallocx sallocx dallocx sdallocx nallocx mallctl mallctlnametomib mallctlbymib malloc_stats_print malloc_usable_size" dnl Check for allocator-related functions that should be wrapped. AC_CHECK_FUNC([memalign], @@ -456,24 +453,6 @@ AC_CHECK_FUNC([valloc], [AC_DEFINE([JEMALLOC_OVERRIDE_VALLOC], [ ]) public_syms="${public_syms} valloc"]) -dnl Support the experimental API by default. -AC_ARG_ENABLE([experimental], - [AS_HELP_STRING([--disable-experimental], - [Disable support for the experimental API])], -[if test "x$enable_experimental" = "xno" ; then - enable_experimental="0" -else - enable_experimental="1" -fi -], -[enable_experimental="1"] -) -if test "x$enable_experimental" = "x1" ; then - AC_DEFINE([JEMALLOC_EXPERIMENTAL], [ ]) - public_syms="${public_syms} allocm dallocm nallocm rallocm sallocm" -fi -AC_SUBST([enable_experimental]) - dnl Do not compute test code coverage by default. GCOV_FLAGS= AC_ARG_ENABLE([code-coverage], @@ -552,31 +531,37 @@ je_="je_" AC_SUBST([je_]) cfgoutputs_in="Makefile.in" +cfgoutputs_in="${cfgoutputs_in} jemalloc.pc.in" cfgoutputs_in="${cfgoutputs_in} doc/html.xsl.in" cfgoutputs_in="${cfgoutputs_in} doc/manpages.xsl.in" cfgoutputs_in="${cfgoutputs_in} doc/jemalloc.xml.in" cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_macros.h.in" cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_protos.h.in" +cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_typedefs.h.in" cfgoutputs_in="${cfgoutputs_in} include/jemalloc/internal/jemalloc_internal.h.in" cfgoutputs_in="${cfgoutputs_in} test/test.sh.in" cfgoutputs_in="${cfgoutputs_in} test/include/test/jemalloc_test.h.in" cfgoutputs_out="Makefile" +cfgoutputs_out="${cfgoutputs_out} jemalloc.pc" cfgoutputs_out="${cfgoutputs_out} doc/html.xsl" cfgoutputs_out="${cfgoutputs_out} doc/manpages.xsl" cfgoutputs_out="${cfgoutputs_out} doc/jemalloc.xml" cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_macros.h" cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_protos.h" +cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_typedefs.h" cfgoutputs_out="${cfgoutputs_out} include/jemalloc/internal/jemalloc_internal.h" cfgoutputs_out="${cfgoutputs_out} test/test.sh" cfgoutputs_out="${cfgoutputs_out} test/include/test/jemalloc_test.h" cfgoutputs_tup="Makefile" +cfgoutputs_tup="${cfgoutputs_tup} jemalloc.pc:jemalloc.pc.in" cfgoutputs_tup="${cfgoutputs_tup} doc/html.xsl:doc/html.xsl.in" cfgoutputs_tup="${cfgoutputs_tup} doc/manpages.xsl:doc/manpages.xsl.in" cfgoutputs_tup="${cfgoutputs_tup} doc/jemalloc.xml:doc/jemalloc.xml.in" cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_macros.h:include/jemalloc/jemalloc_macros.h.in" cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_protos.h:include/jemalloc/jemalloc_protos.h.in" +cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_typedefs.h:include/jemalloc/jemalloc_typedefs.h.in" cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/internal/jemalloc_internal.h" cfgoutputs_tup="${cfgoutputs_tup} test/test.sh:test/test.sh.in" cfgoutputs_tup="${cfgoutputs_tup} test/include/test/jemalloc_test.h:test/include/test/jemalloc_test.h.in" @@ -613,18 +598,17 @@ cfghdrs_tup="include/jemalloc/jemalloc_defs.h:include/jemalloc/jemalloc_defs.h.i cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:include/jemalloc/internal/jemalloc_internal_defs.h.in" cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:test/include/test/jemalloc_test_defs.h.in" -dnl Do not silence irrelevant compiler warnings by default, since enabling this -dnl option incurs a performance penalty. +dnl Silence irrelevant compiler warnings by default. AC_ARG_ENABLE([cc-silence], - [AS_HELP_STRING([--enable-cc-silence], - [Silence irrelevant compiler warnings])], + [AS_HELP_STRING([--disable-cc-silence], + [Do not silence irrelevant compiler warnings])], [if test "x$enable_cc_silence" = "xno" ; then enable_cc_silence="0" else enable_cc_silence="1" fi ], -[enable_cc_silence="0"] +[enable_cc_silence="1"] ) if test "x$enable_cc_silence" = "x1" ; then AC_DEFINE([JEMALLOC_CC_SILENCE], [ ]) @@ -739,7 +723,7 @@ fi, if test "x$backtrace_method" = "x" -a "x$enable_prof_libunwind" = "x1" ; then AC_CHECK_HEADERS([libunwind.h], , [enable_prof_libunwind="0"]) if test "x$LUNWIND" = "x-lunwind" ; then - AC_CHECK_LIB([unwind], [backtrace], [LIBS="$LIBS $LUNWIND"], + AC_CHECK_LIB([unwind], [unw_backtrace], [LIBS="$LIBS $LUNWIND"], [enable_prof_libunwind="0"]) else LIBS="$LIBS $LUNWIND" @@ -800,11 +784,6 @@ fi AC_MSG_CHECKING([configured backtracing method]) AC_MSG_RESULT([$backtrace_method]) if test "x$enable_prof" = "x1" ; then - if test "x${force_tls}" = "x0" ; then - AC_MSG_ERROR([Heap profiling requires TLS]); - fi - force_tls="1" - if test "x$abi" != "xpecoff"; then dnl Heap profiling uses the log(3) function. LIBS="$LIBS -lm" @@ -830,33 +809,6 @@ if test "x$enable_tcache" = "x1" ; then fi AC_SUBST([enable_tcache]) -dnl Disable mremap() for huge realloc() by default. -AC_ARG_ENABLE([mremap], - [AS_HELP_STRING([--enable-mremap], [Enable mremap(2) for huge realloc()])], -[if test "x$enable_mremap" = "xno" ; then - enable_mremap="0" -else - enable_mremap="1" -fi -], -[enable_mremap="0"] -) -if test "x$enable_mremap" = "x1" ; then - JE_COMPILABLE([mremap(...MREMAP_FIXED...)], [ -#define _GNU_SOURCE -#include -], [ -void *p = mremap((void *)0, 0, 0, MREMAP_MAYMOVE|MREMAP_FIXED, (void *)0); -], [je_cv_mremap_fixed]) - if test "x${je_cv_mremap_fixed}" = "xno" ; then - enable_mremap="0" - fi -fi -if test "x$enable_mremap" = "x1" ; then - AC_DEFINE([JEMALLOC_MREMAP], [ ]) -fi -AC_SUBST([enable_mremap]) - dnl Enable VM deallocation via munmap() by default. AC_ARG_ENABLE([munmap], [AS_HELP_STRING([--disable-munmap], [Disable VM deallocation via munmap(2)])], @@ -873,34 +825,22 @@ if test "x$enable_munmap" = "x1" ; then fi AC_SUBST([enable_munmap]) -dnl Do not enable allocation from DSS by default. -AC_ARG_ENABLE([dss], - [AS_HELP_STRING([--enable-dss], [Enable allocation from DSS])], -[if test "x$enable_dss" = "xno" ; then - enable_dss="0" -else - enable_dss="1" -fi -], -[enable_dss="0"] -) +dnl Enable allocation from DSS if supported by the OS. +have_dss="1" dnl Check whether the BSD/SUSv1 sbrk() exists. If not, disable DSS support. AC_CHECK_FUNC([sbrk], [have_sbrk="1"], [have_sbrk="0"]) if test "x$have_sbrk" = "x1" ; then - if test "x$sbrk_deprecated" == "x1" ; then + if test "x$sbrk_deprecated" = "x1" ; then AC_MSG_RESULT([Disabling dss allocation because sbrk is deprecated]) - enable_dss="0" - else - AC_DEFINE([JEMALLOC_HAVE_SBRK], [ ]) + have_dss="0" fi else - enable_dss="0" + have_dss="0" fi -if test "x$enable_dss" = "x1" ; then +if test "x$have_dss" = "x1" ; then AC_DEFINE([JEMALLOC_DSS], [ ]) fi -AC_SUBST([enable_dss]) dnl Support the junk/zero filling option by default. AC_ARG_ENABLE([fill], @@ -992,8 +932,66 @@ if test "x$enable_xmalloc" = "x1" ; then fi AC_SUBST([enable_xmalloc]) -AC_CACHE_CHECK([STATIC_PAGE_SHIFT], - [je_cv_static_page_shift], +dnl ============================================================================ +dnl Check for __builtin_ffsl(), then ffsl(3), and fail if neither are found. +dnl One of those two functions should (theoretically) exist on all platforms +dnl that jemalloc currently has a chance of functioning on without modification. +dnl We additionally assume ffs() or __builtin_ffs() are defined if +dnl ffsl() or __builtin_ffsl() are defined, respectively. +JE_COMPILABLE([a program using __builtin_ffsl], [ +#include +#include +#include +], [ + { + int rv = __builtin_ffsl(0x08); + printf("%d\n", rv); + } +], [je_cv_gcc_builtin_ffsl]) +if test "x${je_cv_gcc_builtin_ffsl}" = "xyes" ; then + AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [__builtin_ffsl]) + AC_DEFINE([JEMALLOC_INTERNAL_FFS], [__builtin_ffs]) +else + JE_COMPILABLE([a program using ffsl], [ + #include + #include + #include + ], [ + { + int rv = ffsl(0x08); + printf("%d\n", rv); + } + ], [je_cv_function_ffsl]) + if test "x${je_cv_function_ffsl}" = "xyes" ; then + AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [ffsl]) + AC_DEFINE([JEMALLOC_INTERNAL_FFS], [ffs]) + else + AC_MSG_ERROR([Cannot build without ffsl(3) or __builtin_ffsl()]) + fi +fi + +AC_ARG_WITH([lg_tiny_min], + [AS_HELP_STRING([--with-lg-tiny-min=], + [Base 2 log of minimum tiny size class to support])], + [LG_TINY_MIN="$with_lg_tiny_min"], + [LG_TINY_MIN="3"]) +AC_DEFINE_UNQUOTED([LG_TINY_MIN], [$LG_TINY_MIN]) + +AC_ARG_WITH([lg_quantum], + [AS_HELP_STRING([--with-lg-quantum=], + [Base 2 log of minimum allocation alignment])], + [LG_QUANTA="$with_lg_quantum"], + [LG_QUANTA="3 4"]) +if test "x$with_lg_quantum" != "x" ; then + AC_DEFINE_UNQUOTED([LG_QUANTUM], [$with_lg_quantum]) +fi + +AC_ARG_WITH([lg_page], + [AS_HELP_STRING([--with-lg-page=], [Base 2 log of system page size])], + [LG_PAGE="$with_lg_page"], [LG_PAGE="detect"]) +if test "x$LG_PAGE" == "xdetect"; then + AC_CACHE_CHECK([LG_PAGE], + [je_cv_lg_page], AC_RUN_IFELSE([AC_LANG_PROGRAM( [[ #include @@ -1018,7 +1016,7 @@ AC_CACHE_CHECK([STATIC_PAGE_SHIFT], if (result == -1) { return 1; } - result = ffsl(result) - 1; + result = JEMALLOC_INTERNAL_FFSL(result) - 1; f = fopen("conftest.out", "w"); if (f == NULL) { @@ -1029,24 +1027,35 @@ AC_CACHE_CHECK([STATIC_PAGE_SHIFT], return 0; ]])], - [je_cv_static_page_shift=`cat conftest.out`], - [je_cv_static_page_shift=undefined])) - -if test "x$je_cv_static_page_shift" != "xundefined"; then - AC_DEFINE_UNQUOTED([STATIC_PAGE_SHIFT], [$je_cv_static_page_shift]) -else - AC_MSG_ERROR([cannot determine value for STATIC_PAGE_SHIFT]) + [je_cv_lg_page=`cat conftest.out`], + [je_cv_lg_page=undefined], + [je_cv_lg_page=12])) fi +if test "x${je_cv_lg_page}" != "x" ; then + LG_PAGE="${je_cv_lg_page}" +fi +if test "x${LG_PAGE}" != "xundefined" ; then + AC_DEFINE_UNQUOTED([LG_PAGE], [$LG_PAGE]) +else + AC_MSG_ERROR([cannot determine value for LG_PAGE]) +fi + +AC_ARG_WITH([lg_page_sizes], + [AS_HELP_STRING([--with-lg-page-sizes=], + [Base 2 logs of system page sizes to support])], + [LG_PAGE_SIZES="$with_lg_page_sizes"], [LG_PAGE_SIZES="$LG_PAGE"]) + +AC_ARG_WITH([lg_size_class_group], + [AS_HELP_STRING([--with-lg-size-class-group=], + [Base 2 log of size classes per doubling])], + [LG_SIZE_CLASS_GROUP="$with_lg_size_class_group"], + [LG_SIZE_CLASS_GROUP="2"]) dnl ============================================================================ dnl jemalloc configuration. dnl -dnl Set VERSION if source directory has an embedded git repository. -if test -d "${srcroot}.git" ; then - git describe --long --abbrev=40 > ${srcroot}VERSION -fi -jemalloc_version=`cat ${srcroot}VERSION` +jemalloc_version=`cat "${srcroot}VERSION"` jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]1}'` jemalloc_version_minor=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]2}'` jemalloc_version_bugfix=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]3}'` @@ -1073,6 +1082,24 @@ fi CPPFLAGS="$CPPFLAGS -D_REENTRANT" +dnl Check if the GNU-specific secure_getenv function exists. +AC_CHECK_FUNC([secure_getenv], + [have_secure_getenv="1"], + [have_secure_getenv="0"] + ) +if test "x$have_secure_getenv" = "x1" ; then + AC_DEFINE([JEMALLOC_HAVE_SECURE_GETENV], [ ]) +fi + +dnl Check if the Solaris/BSD issetugid function exists. +AC_CHECK_FUNC([issetugid], + [have_issetugid="1"], + [have_issetugid="0"] + ) +if test "x$have_issetugid" = "x1" ; then + AC_DEFINE([JEMALLOC_HAVE_ISSETUGID], [ ]) +fi + dnl Check whether the BSD-specific _malloc_thread_cleanup() exists. If so, use dnl it rather than pthreads TSD cleanup functions to support cleanup during dnl thread exit, in order to avoid pthreads library recursion during @@ -1165,43 +1192,25 @@ elif test "x${force_tls}" = "x1" ; then fi dnl ============================================================================ -dnl Check for __builtin_ffsl(), then ffsl(3), and fail if neither are found. -dnl One of those two functions should (theoretically) exist on all platforms -dnl that jemalloc currently has a chance of functioning on without modification. -dnl We additionally assume ffs() or __builtin_ffs() are defined if -dnl ffsl() or __builtin_ffsl() are defined, respectively. -JE_COMPILABLE([a program using __builtin_ffsl], [ -#include -#include -#include -], [ - { - int rv = __builtin_ffsl(0x08); - printf("%d\n", rv); - } -], [je_cv_gcc_builtin_ffsl]) -if test "x${je_cv_gcc_builtin_ffsl}" == "xyes" ; then - AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [__builtin_ffsl]) - AC_DEFINE([JEMALLOC_INTERNAL_FFS], [__builtin_ffs]) -else - JE_COMPILABLE([a program using ffsl], [ - #include - #include - #include - ], [ - { - int rv = ffsl(0x08); - printf("%d\n", rv); - } - ], [je_cv_function_ffsl]) - if test "x${je_cv_function_ffsl}" == "xyes" ; then - AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [ffsl]) - AC_DEFINE([JEMALLOC_INTERNAL_FFS], [ffs]) - else - AC_MSG_ERROR([Cannot build without ffsl(3) or __builtin_ffsl()]) - fi -fi +dnl Check for C11 atomics. +JE_COMPILABLE([C11 atomics], [ +#include +#if (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__) +#include +#else +#error Atomics not available +#endif +], [ + uint64_t *p = (uint64_t *)0; + uint64_t x = 1; + volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; + uint64_t r = atomic_fetch_add(a, x) + x; + return (r == 0); +], [je_cv_c11atomics]) +if test "x${je_cv_c11atomics}" = "xyes" ; then + AC_DEFINE([JEMALLOC_C11ATOMICS]) +fi dnl ============================================================================ dnl Check for atomic(9) operations as provided on FreeBSD. @@ -1248,6 +1257,20 @@ if test "x${je_cv_osatomic}" = "xyes" ; then AC_DEFINE([JEMALLOC_OSATOMIC], [ ]) fi +dnl ============================================================================ +dnl Check for madvise(2). + +JE_COMPILABLE([madvise(2)], [ +#include +], [ + { + madvise((void *)0, 0, 0); + } +], [je_cv_madvise]) +if test "x${je_cv_madvise}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_MADVISE], [ ]) +fi + dnl ============================================================================ dnl Check whether __sync_{add,sub}_and_fetch() are available despite dnl __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n macros being undefined. @@ -1282,6 +1305,29 @@ if test "x${je_cv_atomic9}" != "xyes" -a "x${je_cv_osatomic}" != "xyes" ; then JE_SYNC_COMPARE_AND_SWAP_CHECK(64, 8) fi +dnl ============================================================================ +dnl Check for __builtin_clz() and __builtin_clzl(). + +AC_CACHE_CHECK([for __builtin_clz], + [je_cv_builtin_clz], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([], + [ + { + unsigned x = 0; + int y = __builtin_clz(x); + } + { + unsigned long x = 0; + int y = __builtin_clzl(x); + } + ])], + [je_cv_builtin_clz=yes], + [je_cv_builtin_clz=no])]) + +if test "x${je_cv_builtin_clz}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_BUILTIN_CLZ], [ ]) +fi + dnl ============================================================================ dnl Check for spinlock(3) operations as provided on Darwin. @@ -1330,7 +1376,7 @@ if test "x${enable_zone_allocator}" = "x1" ; then AC_DEFUN([JE_ZONE_PROGRAM], [AC_LANG_PROGRAM( [#include ], - [static foo[[sizeof($1) $2 sizeof(void *) * $3 ? 1 : -1]]] + [static int foo[[sizeof($1) $2 sizeof(void *) * $3 ? 1 : -1]]] )]) AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,==,14)],[JEMALLOC_ZONE_VERSION=3],[ @@ -1355,6 +1401,49 @@ if test "x${enable_zone_allocator}" = "x1" ; then AC_DEFINE_UNQUOTED(JEMALLOC_ZONE_VERSION, [$JEMALLOC_ZONE_VERSION]) fi +dnl ============================================================================ +dnl Check for glibc malloc hooks + +JE_COMPILABLE([glibc malloc hook], [ +#include + +extern void (* __free_hook)(void *ptr); +extern void *(* __malloc_hook)(size_t size); +extern void *(* __realloc_hook)(void *ptr, size_t size); +], [ + void *ptr = 0L; + if (__malloc_hook) ptr = __malloc_hook(1); + if (__realloc_hook) ptr = __realloc_hook(ptr, 2); + if (__free_hook && ptr) __free_hook(ptr); +], [je_cv_glibc_malloc_hook]) +if test "x${je_cv_glibc_malloc_hook}" = "xyes" ; then + AC_DEFINE([JEMALLOC_GLIBC_MALLOC_HOOK], [ ]) +fi + +JE_COMPILABLE([glibc memalign hook], [ +#include + +extern void *(* __memalign_hook)(size_t alignment, size_t size); +], [ + void *ptr = 0L; + if (__memalign_hook) ptr = __memalign_hook(16, 7); +], [je_cv_glibc_memalign_hook]) +if test "x${je_cv_glibc_memalign_hook}" = "xyes" ; then + AC_DEFINE([JEMALLOC_GLIBC_MEMALIGN_HOOK], [ ]) +fi + +JE_COMPILABLE([pthreads adaptive mutexes], [ +#include +], [ + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); + pthread_mutexattr_destroy(&attr); +], [je_cv_pthread_mutex_adaptive_np]) +if test "x${je_cv_pthread_mutex_adaptive_np}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP], [ ]) +fi + dnl ============================================================================ dnl Check for typedefs, structures, and compiler characteristics. AC_HEADER_STDBOOL @@ -1415,10 +1504,14 @@ AC_CONFIG_COMMANDS([include/jemalloc/internal/public_unnamespace.h], [ ]) AC_CONFIG_COMMANDS([include/jemalloc/internal/size_classes.h], [ mkdir -p "${objroot}include/jemalloc/internal" - "${srcdir}/include/jemalloc/internal/size_classes.sh" > "${objroot}include/jemalloc/internal/size_classes.h" + "${srcdir}/include/jemalloc/internal/size_classes.sh" "${LG_QUANTA}" ${LG_TINY_MIN} "${LG_PAGE_SIZES}" ${LG_SIZE_CLASS_GROUP} > "${objroot}include/jemalloc/internal/size_classes.h" ], [ srcdir="${srcdir}" objroot="${objroot}" + LG_QUANTA="${LG_QUANTA}" + LG_TINY_MIN=${LG_TINY_MIN} + LG_PAGE_SIZES="${LG_PAGE_SIZES}" + LG_SIZE_CLASS_GROUP=${LG_SIZE_CLASS_GROUP} ]) AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_protos_jet.h], [ mkdir -p "${objroot}include/jemalloc" @@ -1504,7 +1597,6 @@ AC_MSG_RESULT([JEMALLOC_PRIVATE_NAMESPACE]) AC_MSG_RESULT([ : ${JEMALLOC_PRIVATE_NAMESPACE}]) AC_MSG_RESULT([install_suffix : ${install_suffix}]) AC_MSG_RESULT([autogen : ${enable_autogen}]) -AC_MSG_RESULT([experimental : ${enable_experimental}]) AC_MSG_RESULT([cc-silence : ${enable_cc_silence}]) AC_MSG_RESULT([debug : ${enable_debug}]) AC_MSG_RESULT([code-coverage : ${enable_code_coverage}]) @@ -1518,9 +1610,7 @@ AC_MSG_RESULT([fill : ${enable_fill}]) AC_MSG_RESULT([utrace : ${enable_utrace}]) AC_MSG_RESULT([valgrind : ${enable_valgrind}]) AC_MSG_RESULT([xmalloc : ${enable_xmalloc}]) -AC_MSG_RESULT([mremap : ${enable_mremap}]) AC_MSG_RESULT([munmap : ${enable_munmap}]) -AC_MSG_RESULT([dss : ${enable_dss}]) AC_MSG_RESULT([lazy_lock : ${enable_lazy_lock}]) AC_MSG_RESULT([tls : ${enable_tls}]) AC_MSG_RESULT([===============================================================================]) diff --git a/memory/jemalloc/src/doc/jemalloc.xml.in b/memory/jemalloc/src/doc/jemalloc.xml.in index d8e2e711f2c8..0148f0385845 100644 --- a/memory/jemalloc/src/doc/jemalloc.xml.in +++ b/memory/jemalloc/src/doc/jemalloc.xml.in @@ -38,17 +38,13 @@ xallocx sallocx dallocx + sdallocx nallocx mallctl mallctlnametomib mallctlbymib malloc_stats_print malloc_usable_size - allocm - rallocm - sallocm - dallocm - nallocm --> general purpose memory allocation functions @@ -61,8 +57,7 @@ SYNOPSIS - #include <stdlib.h> -#include <jemalloc/jemalloc.h> + #include <jemalloc/jemalloc.h> Standard API @@ -125,6 +120,12 @@ void *ptr int flags + + void sdallocx + void *ptr + size_t size + int flags + size_t nallocx size_t size @@ -172,41 +173,6 @@ const char *malloc_conf; - - Experimental API - - int allocm - void **ptr - size_t *rsize - size_t size - int flags - - - int rallocm - void **ptr - size_t *rsize - size_t size - size_t extra - int flags - - - int sallocm - const void *ptr - size_t *rsize - int flags - - - int dallocm - void *ptr - int flags - - - int nallocm - size_t *rsize - size_t size - int flags - - @@ -229,15 +195,15 @@ The posix_memalign function allocates size bytes of memory such that the - allocation's base address is an even multiple of + allocation's base address is a multiple of alignment, and returns the allocation in the value pointed to by ptr. The requested - alignment must be a power of 2 at least as large - as sizeof(void *). + alignment must be a power of 2 at least as large as + sizeof(void *). The aligned_alloc function allocates size bytes of memory such that the - allocation's base address is an even multiple of + allocation's base address is a multiple of alignment. The requested alignment must be a power of 2. Behavior is undefined if size is not an integral multiple of @@ -268,7 +234,8 @@ rallocx, xallocx, sallocx, - dallocx, and + dallocx, + sdallocx, and nallocx functions all have a flags argument that can be used to specify options. The functions only check the options that are contextually @@ -310,10 +277,10 @@ Use the arena specified by the index a (and by necessity bypass the thread - cache). This macro has no effect for huge regions, nor for regions - that were allocated via an arena other than the one specified. - This macro does not validate that a - specifies an arena index in the valid range. + cache). This macro has no effect for regions that were allocated + via an arena other than the one specified. This macro does not + validate that a specifies an arena index in + the valid range. @@ -352,6 +319,15 @@ memory referenced by ptr to be made available for future allocations. + The sdallocx function is an + extension of dallocx with a + size parameter to allow the caller to pass in the + allocation size as an optimization. The minimum valid input size is the + original requested size of the allocation, and the maximum valid input + size is the corresponding value returned by + nallocx or + sallocx. + The nallocx function allocates no memory, but it performs the same size computation as the mallocx function, and returns the real @@ -430,11 +406,12 @@ for (i = 0; i < nbins; i++) { functions simultaneously. If is specified during configuration, “m” and “a” can be specified to omit merged arena and per arena statistics, respectively; - “b” and “l” can be specified to omit per size - class statistics for bins and large objects, respectively. Unrecognized - characters are silently ignored. Note that thread caching may prevent - some statistics from being completely up to date, since extra locking - would be required to merge counters that track thread cache operations. + “b”, “l”, and “h” can be specified to + omit per size class statistics for bins, large objects, and huge objects, + respectively. Unrecognized characters are silently ignored. Note that + thread caching may prevent some statistics from being completely up to + date, since extra locking would be required to merge counters that track + thread cache operations. The malloc_usable_size function @@ -449,116 +426,6 @@ for (i = 0; i < nbins; i++) { depended on, since such behavior is entirely implementation-dependent. - - Experimental API - The experimental API is subject to change or removal without regard - for backward compatibility. If - is specified during configuration, the experimental API is - omitted. - - The allocm, - rallocm, - sallocm, - dallocm, and - nallocm functions all have a - flags argument that can be used to specify - options. The functions only check the options that are contextually - relevant. Use bitwise or (|) operations to - specify one or more of the following: - - - ALLOCM_LG_ALIGN(la) - - - Align the memory allocation to start at an address - that is a multiple of (1 << - la). This macro does not validate - that la is within the valid - range. - - - ALLOCM_ALIGN(a) - - - Align the memory allocation to start at an address - that is a multiple of a, where - a is a power of two. This macro does not - validate that a is a power of 2. - - - - ALLOCM_ZERO - - Initialize newly allocated memory to contain zero - bytes. In the growing reallocation case, the real size prior to - reallocation defines the boundary between untouched bytes and those - that are initialized to contain zero bytes. If this macro is - absent, newly allocated memory is uninitialized. - - - ALLOCM_NO_MOVE - - For reallocation, fail rather than moving the - object. This constraint can apply to both growth and - shrinkage. - - - ALLOCM_ARENA(a) - - - Use the arena specified by the index - a (and by necessity bypass the thread - cache). This macro has no effect for huge regions, nor for regions - that were allocated via an arena other than the one specified. - This macro does not validate that a - specifies an arena index in the valid range. - - - - - The allocm function allocates at - least size bytes of memory, sets - *ptr to the base address of the allocation, and - sets *rsize to the real size of the allocation if - rsize is not NULL. Behavior - is undefined if size is 0, or - if request size overflows due to size class and/or alignment - constraints. - - The rallocm function resizes the - allocation at *ptr to be at least - size bytes, sets *ptr to - the base address of the allocation if it moved, and sets - *rsize to the real size of the allocation if - rsize is not NULL. If - extra is non-zero, an attempt is made to resize - the allocation to be at least (size + - extra) bytes, though inability to allocate - the extra byte(s) will not by itself result in failure. Behavior is - undefined if size is 0, if - request size overflows due to size class and/or alignment constraints, or - if (size + - extra > - SIZE_T_MAX). - - The sallocm function sets - *rsize to the real size of the allocation. - - The dallocm function causes the - memory referenced by ptr to be made available for - future allocations. - - The nallocm function allocates no - memory, but it performs the same size computation as the - allocm function, and if - rsize is not NULL it sets - *rsize to the real size of the allocation that - would result from the equivalent allocm - function call. Behavior is undefined if size is - 0, or if request size overflows due to size class - and/or alignment constraints. - TUNING @@ -598,8 +465,10 @@ for (i = 0; i < nbins; i++) { 2 to obtain memory, which is suboptimal for several reasons, including race conditions, increased fragmentation, and artificial limitations on maximum usable memory. If - is specified during configuration, this - allocator uses both mmap + sbrk + 2 is supported by the operating + system, this allocator uses both + mmap 2 and sbrk 2, in that order of preference; @@ -632,12 +501,11 @@ for (i = 0; i < nbins; i++) { possible to find metadata for user objects very quickly. User objects are broken into three categories according to size: - small, large, and huge. Small objects are smaller than one page. Large - objects are smaller than the chunk size. Huge objects are a multiple of - the chunk size. Small and large objects are managed by arenas; huge - objects are managed separately in a single data structure that is shared by - all threads. Huge objects are used by applications infrequently enough - that this single data structure is not a scalability issue. + small, large, and huge. Small and large objects are managed entirely by + arenas; huge objects are additionally aggregated in a single data structure + that is shared by all threads. Huge objects are typically used by + applications infrequently enough that this single data structure is not a + scalability issue. Each chunk that is managed by an arena tracks its contents as runs of contiguous pages (unused, backing a set of small objects, or backing one @@ -646,18 +514,18 @@ for (i = 0; i < nbins; i++) { allocations in constant time. Small objects are managed in groups by page runs. Each run maintains - a frontier and free list to track which regions are in use. Allocation - requests that are no more than half the quantum (8 or 16, depending on - architecture) are rounded up to the nearest power of two that is at least - sizeof(double). All other small - object size classes are multiples of the quantum, spaced such that internal - fragmentation is limited to approximately 25% for all but the smallest size - classes. Allocation requests that are larger than the maximum small size - class, but small enough to fit in an arena-managed chunk (see the opt.lg_chunk option), are - rounded up to the nearest run size. Allocation requests that are too large - to fit in an arena-managed chunk are rounded up to the nearest multiple of - the chunk size. + a bitmap to track which regions are in use. Allocation requests that are no + more than half the quantum (8 or 16, depending on architecture) are rounded + up to the nearest power of two that is at least sizeof(double). All other object size + classes are multiples of the quantum, spaced such that there are four size + classes for each doubling in size, which limits internal fragmentation to + approximately 20% for all but the smallest size classes. Small size classes + are smaller than four times the page size, large size classes are smaller + than the chunk size (see the opt.lg_chunk option), and + huge size classes extend from the chunk size up to one size class less than + the full address space size. Allocations are packed tightly together, which can be an issue for multi-threaded applications. If you need to assure that allocations do not @@ -684,13 +552,13 @@ for (i = 0; i < nbins; i++) { - Small + Small lg [8] 16 - [16, 32, 48, ..., 128] + [16, 32, 48, 64, 80, 96, 112, 128] 32 @@ -710,17 +578,77 @@ for (i = 0; i < nbins; i++) { 512 - [2560, 3072, 3584] + [2560, 3072, 3584, 4096] + + + 1 KiB + [5 KiB, 6 KiB, 7 KiB, 8 KiB] + + + 2 KiB + [10 KiB, 12 KiB, 14 KiB] + + + Large + 2 KiB + [16 KiB] - Large 4 KiB - [4 KiB, 8 KiB, 12 KiB, ..., 4072 KiB] + [20 KiB, 24 KiB, 28 KiB, 32 KiB] + + + 8 KiB + [40 KiB, 48 KiB, 54 KiB, 64 KiB] + + + 16 KiB + [80 KiB, 96 KiB, 112 KiB, 128 KiB] + + + 32 KiB + [160 KiB, 192 KiB, 224 KiB, 256 KiB] + + + 64 KiB + [320 KiB, 384 KiB, 448 KiB, 512 KiB] + + + 128 KiB + [640 KiB, 768 KiB, 896 KiB, 1024 KiB] + + + 256 KiB + [1280 KiB, 1536 KiB, 1792 KiB, 2048 KiB] + + + 512 KiB + [2560 KiB, 3072 KiB, 3584 KiB] + + + Huge + 512 KiB + [4 MiB] + + + 1 MiB + [5 MiB, 6 MiB, 7 MiB, 8 MiB] + + + 2 MiB + [10 MiB, 12 MiB, 14 MiB, 16 MiB] - Huge 4 MiB - [4 MiB, 8 MiB, 12 MiB, ...] + [20 MiB, 24 MiB, 28 MiB, 32 MiB] + + + 8 MiB + [40 MiB, 48 MiB, 56 MiB, 64 MiB] + + + ... + ... @@ -775,16 +703,6 @@ for (i = 0; i < nbins; i++) { build configuration. - - - config.dss - (bool) - r- - - was specified during - build configuration. - - config.fill @@ -805,16 +723,6 @@ for (i = 0; i < nbins; i++) { during build configuration. - - - config.mremap - (bool) - r- - - was specified during - build configuration. - - config.munmap @@ -940,10 +848,15 @@ for (i = 0; i < nbins; i++) { 2) allocation precedence as related to mmap 2 allocation. The following - settings are supported: “disabled”, “primary”, - and “secondary”. The default is “secondary” if - config.dss is - true, “disabled” otherwise. + settings are supported if + sbrk + 2 is supported by the operating + system: “disabled”, “primary”, and + “secondary”; otherwise only “disabled” is + supported. The default is “secondary” if + sbrk + 2 is supported by the operating + system; “disabled” otherwise. @@ -1003,26 +916,34 @@ for (i = 0; i < nbins; i++) { is specified during configuration, this has the potential to cause deadlock for a multi-threaded process that exits while one or more threads are executing in the memory allocation - functions. Therefore, this option should only be used with care; it is - primarily intended as a performance tuning aid during application + functions. Furthermore, atexit may + allocate memory during application initialization and then deadlock + internally when jemalloc in turn calls + atexit, so this option is not + univerally usable (though the application can register its own + atexit function with equivalent + functionality). Therefore, this option should only be used with care; + it is primarily intended as a performance tuning aid during application development. This option is disabled by default. opt.junk - (bool) + (const char *) r- [] - Junk filling enabled/disabled. If enabled, each byte - of uninitialized allocated memory will be initialized to - 0xa5. All deallocated memory will be initialized to - 0x5a. This is intended for debugging and will - impact performance negatively. This option is disabled by default - unless is specified during - configuration, in which case it is enabled by default unless running - inside Junk filling. If set to "alloc", each byte of + uninitialized allocated memory will be initialized to + 0xa5. If set to "free", all deallocated memory will + be initialized to 0x5a. If set to "true", both + allocated and deallocated memory will be initialized, and if set to + "false", junk filling be disabled entirely. This is intended for + debugging and will impact performance negatively. This option is + "false" by default unless is specified + during configuration, in which case it is "true" by default unless + running inside Valgrind. @@ -1076,9 +997,8 @@ for (i = 0; i < nbins; i++) { Zero filling enabled/disabled. If enabled, each byte of uninitialized allocated memory will be initialized to 0. Note that this initialization only happens once for each byte, so - realloc, - rallocx and - rallocm calls do not zero memory that + realloc and + rallocx calls do not zero memory that was previously allocated. This is intended for debugging and will impact performance negatively. This option is disabled by default. @@ -1097,19 +1017,6 @@ for (i = 0; i < nbins; i++) { is disabled by default. - - - opt.valgrind - (bool) - r- - [] - - Valgrind - support enabled/disabled. This option is vestigal because jemalloc - auto-detects whether it is running inside Valgrind. This option is - disabled by default, unless running inside Valgrind. - - opt.xmalloc @@ -1146,7 +1053,8 @@ malloc_conf = "xmalloc:true";]]> linkend="opt.lg_tcache_max">opt.lg_tcache_max option for related tuning information. This option is enabled by default unless running inside Valgrind. + url="http://valgrind.org/">Valgrind, in which case it is + forcefully disabled. @@ -1219,10 +1127,25 @@ malloc_conf = "xmalloc:true";]]> This option is enabled by default. + + + opt.prof_thread_active_init + (bool) + r- + [] + + Initial setting for thread.prof.active + in newly created threads. The initial setting for newly created threads + can also be changed during execution via the prof.thread_active_init + mallctl. This option is enabled by default. + + opt.lg_prof_sample - (ssize_t) + (size_t) r- [] @@ -1299,7 +1222,13 @@ malloc_conf = "xmalloc:true";]]> <prefix>.<pid>.<seq>.f.heap, where <prefix> is controlled by the opt.prof_prefix - option. This option is enabled by default. + option. Note that atexit may allocate + memory during application initialization and then deadlock internally + when jemalloc in turn calls atexit, so + this option is not univerally usable (though the application can + register its own atexit function with + equivalent functionality). This option is disabled by + default. @@ -1418,10 +1347,48 @@ malloc_conf = "xmalloc:true";]]> the developer may find manual flushing useful. + + + thread.prof.name + (const char *) + r- or + -w + [] + + Get/set the descriptive name associated with the calling + thread in memory profile dumps. An internal copy of the name string is + created, so the input string need not be maintained after this interface + completes execution. The output string of this interface should be + copied for non-ephemeral uses, because multiple implementation details + can cause asynchronous string deallocation. Furthermore, each + invocation of this interface can only read or write; simultaneous + read/write is not supported due to string lifetime limitations. The + name string must nil-terminated and comprised only of characters in the + sets recognized + by isgraph + 3 and + isblank + 3. + + + + + thread.prof.active + (bool) + rw + [] + + Control whether sampling is currently active for the + calling thread. This is an activation mechanism in addition to prof.active; both must + be active for the calling thread to sample. This flag is enabled by + default. + + arena.<i>.purge - (unsigned) + (void) -- Purge unused dirty pages for arena <i>, or for @@ -1439,14 +1406,80 @@ malloc_conf = "xmalloc:true";]]> Set the precedence of dss allocation as related to mmap allocation for arena <i>, or for all arenas if <i> equals arenas.narenas. Note - that even during huge allocation this setting is read from the arena - that would be chosen for small or large allocation so that applications - can depend on consistent dss versus mmap allocation regardless of - allocation size. See opt.dss for supported - settings. - + linkend="arenas.narenas">arenas.narenas. See + opt.dss for supported + settings. + + + + + arena.<i>.chunk.alloc + (chunk_alloc_t *) + rw + + Get or set the chunk allocation function for arena + <i>. If setting, the chunk deallocation function should + also be set via + arena.<i>.chunk.dalloc to a companion + function that knows how to deallocate the chunks. + + typedef void *(chunk_alloc_t) + void *chunk + size_t size + size_t alignment + bool *zero + unsigned arena_ind + + A chunk allocation function conforms to the chunk_alloc_t + type and upon success returns a pointer to size + bytes of memory on behalf of arena arena_ind such + that the chunk's base address is a multiple of + alignment, as well as setting + *zero to indicate whether the chunk is zeroed. + Upon error the function returns NULL and leaves + *zero unmodified. The + size parameter is always a multiple of the chunk + size. The alignment parameter is always a power + of two at least as large as the chunk size. Zeroing is mandatory if + *zero is true upon function entry. If + chunk is not NULL, the + returned pointer must be chunk or + NULL if it could not be allocated. + + Note that replacing the default chunk allocation function makes + the arena's arena.<i>.dss + setting irrelevant. + + + + + arena.<i>.chunk.dalloc + (chunk_dalloc_t *) + rw + + Get or set the chunk deallocation function for arena + <i>. If setting, the chunk deallocation function must + be capable of deallocating all extant chunks associated with arena + <i>, usually by passing unknown chunks to the deallocation + function that was replaced. In practice, it is feasible to control + allocation for arenas created via arenas.extend such + that all chunks originate from an application-supplied chunk allocator + (by setting custom chunk allocation/deallocation functions just after + arena creation), but the automatically created arenas may have already + created chunks prior to the application having an opportunity to take + over chunk allocation. + + typedef void (chunk_dalloc_t) + void *chunk + size_t size + unsigned arena_ind + + A chunk deallocation function conforms to the + chunk_dalloc_t type and deallocates a + chunk of given size on + behalf of arena arena_ind. @@ -1548,7 +1581,7 @@ malloc_conf = "xmalloc:true";]]> arenas.nlruns - (size_t) + (unsigned) r- Total number of large size classes. @@ -1564,14 +1597,23 @@ malloc_conf = "xmalloc:true";]]> class. - + - arenas.purge + arenas.nhchunks (unsigned) - -w + r- - Purge unused dirty pages for the specified arena, or - for all arenas if none is specified. + Total number of huge size classes. + + + + + arenas.hchunks.<i>.size + (size_t) + r- + + Maximum size supported by this huge size + class. @@ -1584,6 +1626,20 @@ malloc_conf = "xmalloc:true";]]> and returning the new arena index. + + + prof.thread_active_init + (bool) + rw + [] + + Control the initial setting for thread.prof.active + in newly created threads. See the opt.prof_thread_active_init + option for additional information. + + prof.active @@ -1594,8 +1650,9 @@ malloc_conf = "xmalloc:true";]]> Control whether sampling is currently active. See the opt.prof_active - option for additional information. - + option for additional information, as well as the interrelated thread.prof.active + mallctl. @@ -1614,6 +1671,33 @@ malloc_conf = "xmalloc:true";]]> option. + + + prof.reset + (size_t) + -w + [] + + Reset all memory profile statistics, and optionally + update the sample rate (see opt.lg_prof_sample + and prof.lg_sample). + + + + + + prof.lg_sample + (size_t) + r- + [] + + Get the current sample rate (see opt.lg_prof_sample). + + + prof.interval @@ -1637,9 +1721,8 @@ malloc_conf = "xmalloc:true";]]> Pointer to a counter that contains an approximate count of the current number of bytes in active pages. The estimate may be - high, but never low, because each arena rounds up to the nearest - multiple of the chunk size when computing its contribution to the - counter. Note that the epoch mallctl has no bearing on this counter. Furthermore, counter consistency is maintained via atomic operations, so it is necessary to use an atomic operation in @@ -1721,39 +1804,6 @@ malloc_conf = "xmalloc:true";]]> - - - stats.huge.allocated - (size_t) - r- - [] - - Number of bytes currently allocated by huge objects. - - - - - - stats.huge.nmalloc - (uint64_t) - r- - [] - - Cumulative number of huge allocation requests. - - - - - - stats.huge.ndalloc - (uint64_t) - r- - [] - - Cumulative number of huge deallocation requests. - - - stats.arenas.<i>.dss @@ -1930,15 +1980,48 @@ malloc_conf = "xmalloc:true";]]> - + - stats.arenas.<i>.bins.<j>.allocated + stats.arenas.<i>.huge.allocated (size_t) r- [] - Current number of bytes allocated by - bin. + Number of bytes currently allocated by huge objects. + + + + + + stats.arenas.<i>.huge.nmalloc + (uint64_t) + r- + [] + + Cumulative number of huge allocation requests served + directly by the arena. + + + + + stats.arenas.<i>.huge.ndalloc + (uint64_t) + r- + [] + + Cumulative number of huge deallocation requests served + directly by the arena. + + + + + stats.arenas.<i>.huge.nrequests + (uint64_t) + r- + [] + + Cumulative number of huge allocation requests. + @@ -1974,6 +2057,17 @@ malloc_conf = "xmalloc:true";]]> requests. + + + stats.arenas.<i>.bins.<j>.curregs + (size_t) + r- + [] + + Current number of regions for this size + class. + + stats.arenas.<i>.bins.<j>.nfills @@ -2068,6 +2162,50 @@ malloc_conf = "xmalloc:true";]]> Current number of runs for this size class. + + + + stats.arenas.<i>.hchunks.<j>.nmalloc + (uint64_t) + r- + [] + + Cumulative number of allocation requests for this size + class served directly by the arena. + + + + + stats.arenas.<i>.hchunks.<j>.ndalloc + (uint64_t) + r- + [] + + Cumulative number of deallocation requests for this + size class served directly by the arena. + + + + + stats.arenas.<i>.hchunks.<j>.nrequests + (uint64_t) + r- + [] + + Cumulative number of allocation requests for this size + class. + + + + + stats.arenas.<i>.hchunks.<j>.curhchunks + (size_t) + r- + [] + + Current number of huge allocations for this size class. + + @@ -2253,42 +2391,6 @@ malloc_conf = "xmalloc:true";]]> returns the usable size of the allocation pointed to by ptr. - - Experimental API - The allocm, - rallocm, - sallocm, - dallocm, and - nallocm functions return - ALLOCM_SUCCESS on success; otherwise they return an - error value. The allocm, - rallocm, and - nallocm functions will fail if: - - - ALLOCM_ERR_OOM - - Out of memory. Insufficient contiguous memory was - available to service the allocation request. The - allocm function additionally sets - *ptr to NULL, whereas - the rallocm function leaves - *ptr unmodified. - - - The rallocm function will also - fail if: - - - ALLOCM_ERR_NOT_MOVED - - ALLOCM_NO_MOVE was specified, - but the reallocation request could not be serviced without moving - the object. - - - - ENVIRONMENT diff --git a/memory/jemalloc/src/include/jemalloc/internal/arena.h b/memory/jemalloc/src/include/jemalloc/internal/arena.h index 996566a6edf7..1e190234267b 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/arena.h +++ b/memory/jemalloc/src/include/jemalloc/internal/arena.h @@ -1,30 +1,10 @@ /******************************************************************************/ #ifdef JEMALLOC_H_TYPES -/* - * RUN_MAX_OVRHD indicates maximum desired run header overhead. Runs are sized - * as small as possible such that this setting is still honored, without - * violating other constraints. The goal is to make runs as small as possible - * without exceeding a per run external fragmentation threshold. - * - * We use binary fixed point math for overhead computations, where the binary - * point is implicitly RUN_BFP bits to the left. - * - * Note that it is possible to set RUN_MAX_OVRHD low enough that it cannot be - * honored for some/all object sizes, since when heap profiling is enabled - * there is one pointer of header overhead per object (plus a constant). This - * constraint is relaxed (ignored) for runs that are so small that the - * per-region overhead is greater than: - * - * (RUN_MAX_OVRHD / (reg_interval << (3+RUN_BFP)) - */ -#define RUN_BFP 12 -/* \/ Implicit binary fixed point. */ -#define RUN_MAX_OVRHD 0x0000003dU -#define RUN_MAX_OVRHD_RELAX 0x00001800U +#define LARGE_MINCLASS (ZU(1) << LG_LARGE_MINCLASS) /* Maximum number of regions in one run. */ -#define LG_RUN_MAXREGS 11 +#define LG_RUN_MAXREGS (LG_PAGE - LG_TINY_MIN) #define RUN_MAXREGS (1U << LG_RUN_MAXREGS) /* @@ -43,9 +23,10 @@ */ #define LG_DIRTY_MULT_DEFAULT 3 -typedef struct arena_chunk_map_s arena_chunk_map_t; -typedef struct arena_chunk_s arena_chunk_t; typedef struct arena_run_s arena_run_t; +typedef struct arena_chunk_map_bits_s arena_chunk_map_bits_t; +typedef struct arena_chunk_map_misc_s arena_chunk_map_misc_t; +typedef struct arena_chunk_s arena_chunk_t; typedef struct arena_bin_info_s arena_bin_info_t; typedef struct arena_bin_s arena_bin_t; typedef struct arena_s arena_t; @@ -54,41 +35,19 @@ typedef struct arena_s arena_t; /******************************************************************************/ #ifdef JEMALLOC_H_STRUCTS +struct arena_run_s { + /* Index of bin this run is associated with. */ + index_t binind; + + /* Number of free regions in run. */ + unsigned nfree; + + /* Per region allocated/deallocated bitmap. */ + bitmap_t bitmap[BITMAP_GROUPS_MAX]; +}; + /* Each element of the chunk map corresponds to one page within the chunk. */ -struct arena_chunk_map_s { -#ifndef JEMALLOC_PROF - /* - * Overlay prof_ctx in order to allow it to be referenced by dead code. - * Such antics aren't warranted for per arena data structures, but - * chunk map overhead accounts for a percentage of memory, rather than - * being just a fixed cost. - */ - union { -#endif - union { - /* - * Linkage for run trees. There are two disjoint uses: - * - * 1) arena_t's runs_avail tree. - * 2) arena_run_t conceptually uses this linkage for in-use - * non-full runs, rather than directly embedding linkage. - */ - rb_node(arena_chunk_map_t) rb_link; - /* - * List of runs currently in purgatory. arena_chunk_purge() - * temporarily allocates runs that contain dirty pages while - * purging, so that other threads cannot use the runs while the - * purging thread is operating without the arena lock held. - */ - ql_elm(arena_chunk_map_t) ql_link; - } u; - - /* Profile counters, used for large object runs. */ - prof_ctx_t *prof_ctx; -#ifndef JEMALLOC_PROF - }; /* union { ... }; */ -#endif - +struct arena_chunk_map_bits_s { /* * Run address (or size) and various flags are stored together. The bit * layout looks like (assuming 32-bit system): @@ -110,7 +69,6 @@ struct arena_chunk_map_s { * p : run page offset * s : run size * n : binind for size class; large objects set these to BININD_INVALID - * except for promoted allocations (see prof_promote) * x : don't care * - : 0 * + : 1 @@ -137,11 +95,15 @@ struct arena_chunk_map_s { * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx * -------- -------- ----++++ ++++D-LA * - * Large (sampled, size <= PAGE): + * Large (sampled, size <= LARGE_MINCLASS): * ssssssss ssssssss ssssnnnn nnnnD-LA + * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx + * -------- -------- ----++++ ++++D-LA * - * Large (not sampled, size == PAGE): + * Large (not sampled, size == LARGE_MINCLASS): * ssssssss ssssssss ssss++++ ++++D-LA + * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx + * -------- -------- ----++++ ++++D-LA */ size_t bits; #define CHUNK_MAP_BININD_SHIFT 4 @@ -156,52 +118,49 @@ struct arena_chunk_map_s { #define CHUNK_MAP_ALLOCATED ((size_t)0x1U) #define CHUNK_MAP_KEY CHUNK_MAP_ALLOCATED }; -typedef rb_tree(arena_chunk_map_t) arena_avail_tree_t; -typedef rb_tree(arena_chunk_map_t) arena_run_tree_t; -typedef ql_head(arena_chunk_map_t) arena_chunk_mapelms_t; + +/* + * Each arena_chunk_map_misc_t corresponds to one page within the chunk, just + * like arena_chunk_map_bits_t. Two separate arrays are stored within each + * chunk header in order to improve cache locality. + */ +struct arena_chunk_map_misc_s { + /* + * Linkage for run trees. There are two disjoint uses: + * + * 1) arena_t's runs_avail tree. + * 2) arena_run_t conceptually uses this linkage for in-use non-full + * runs, rather than directly embedding linkage. + */ + rb_node(arena_chunk_map_misc_t) rb_link; + + union { + /* Linkage for list of dirty runs. */ + ql_elm(arena_chunk_map_misc_t) dr_link; + + /* Profile counters, used for large object runs. */ + prof_tctx_t *prof_tctx; + + /* Small region run metadata. */ + arena_run_t run; + }; +}; +typedef rb_tree(arena_chunk_map_misc_t) arena_avail_tree_t; +typedef rb_tree(arena_chunk_map_misc_t) arena_run_tree_t; +typedef ql_head(arena_chunk_map_misc_t) arena_chunk_miscelms_t; /* Arena chunk header. */ struct arena_chunk_s { /* Arena that owns the chunk. */ arena_t *arena; - /* Linkage for tree of arena chunks that contain dirty runs. */ - rb_node(arena_chunk_t) dirty_link; - - /* Number of dirty pages. */ - size_t ndirty; - - /* Number of available runs. */ - size_t nruns_avail; - - /* - * Number of available run adjacencies that purging could coalesce. - * Clean and dirty available runs are not coalesced, which causes - * virtual memory fragmentation. The ratio of - * (nruns_avail-nruns_adjac):nruns_adjac is used for tracking this - * fragmentation. - */ - size_t nruns_adjac; - /* * Map of pages within chunk that keeps track of free/large/small. The * first map_bias entries are omitted, since the chunk header does not * need to be tracked in the map. This omission saves a header page * for common chunk sizes (e.g. 4 MiB). */ - arena_chunk_map_t map[1]; /* Dynamically sized. */ -}; -typedef rb_tree(arena_chunk_t) arena_chunk_tree_t; - -struct arena_run_s { - /* Bin this run is associated with. */ - arena_bin_t *bin; - - /* Index of next region that has never been allocated, or nregs. */ - uint32_t nextind; - - /* Number of free regions in run. */ - unsigned nfree; + arena_chunk_map_bits_t map_bits[1]; /* Dynamically sized. */ }; /* @@ -212,12 +171,7 @@ struct arena_run_s { * Each run has the following layout: * * /--------------------\ - * | arena_run_t header | - * | ... | - * bitmap_offset | bitmap | - * | ... | - * ctx0_offset | ctx map | - * | ... | + * | pad? | * |--------------------| * | redzone | * reg0_offset | region 0 | @@ -258,24 +212,12 @@ struct arena_bin_info_s { /* Total number of regions in a run for this bin's size class. */ uint32_t nregs; - /* - * Offset of first bitmap_t element in a run header for this bin's size - * class. - */ - uint32_t bitmap_offset; - /* * Metadata used to manipulate bitmaps for runs associated with this * bin. */ bitmap_info_t bitmap_info; - /* - * Offset of first (prof_ctx_t *) in a run header for this bin's size - * class, or 0 if (config_prof == false || opt_prof == false). - */ - uint32_t ctx0_offset; - /* Offset of first region in a run for this bin's size class. */ uint32_t reg0_offset; }; @@ -321,8 +263,7 @@ struct arena_s { /* * There are three classes of arena operations from a locking * perspective: - * 1) Thread asssignment (modifies nthreads) is protected by - * arenas_lock. + * 1) Thread assignment (modifies nthreads) is protected by arenas_lock. * 2) Bin-related operations are protected by bin locks. * 3) Chunk- and run-related operations are protected by this mutex. */ @@ -339,9 +280,6 @@ struct arena_s { dss_prec_t dss_prec; - /* Tree of dirty-page-containing chunks this arena manages. */ - arena_chunk_tree_t chunks_dirty; - /* * In order to avoid rapid chunk allocation/deallocation when an arena * oscillates right on the cusp of needing a new chunk, cache the most @@ -354,7 +292,7 @@ struct arena_s { */ arena_chunk_t *spare; - /* Number of pages in active runs. */ + /* Number of pages in active runs and huge regions. */ size_t nactive; /* @@ -365,20 +303,21 @@ struct arena_s { */ size_t ndirty; - /* - * Approximate number of pages being purged. It is possible for - * multiple threads to purge dirty pages concurrently, and they use - * npurgatory to indicate the total number of pages all threads are - * attempting to purge. - */ - size_t npurgatory; - /* * Size/address-ordered trees of this arena's available runs. The trees * are used for first-best-fit run allocation. */ arena_avail_tree_t runs_avail; + /* List of dirty runs this arena manages. */ + arena_chunk_miscelms_t runs_dirty; + + /* + * User-configurable chunk allocation and deallocation functions. + */ + chunk_alloc_t *chunk_alloc; + chunk_dalloc_t *chunk_dalloc; + /* bins is used to store trees of free regions. */ arena_bin_t bins[NBINS]; }; @@ -388,22 +327,28 @@ struct arena_s { #ifdef JEMALLOC_H_EXTERNS extern ssize_t opt_lg_dirty_mult; -/* - * small_size2bin is a compact lookup table that rounds request sizes up to - * size classes. In order to reduce cache footprint, the table is compressed, - * and all accesses are via the SMALL_SIZE2BIN macro. - */ -extern uint8_t const small_size2bin[]; -#define SMALL_SIZE2BIN(s) (small_size2bin[(s-1) >> LG_TINY_MIN]) extern arena_bin_info_t arena_bin_info[NBINS]; -/* Number of large size classes. */ -#define nlclasses (chunk_npages - map_bias) +extern size_t map_bias; /* Number of arena chunk header pages. */ +extern size_t map_misc_offset; +extern size_t arena_maxrun; /* Max run size for arenas. */ +extern size_t arena_maxclass; /* Max size class for arenas. */ +extern unsigned nlclasses; /* Number of large size classes. */ +extern unsigned nhclasses; /* Number of huge size classes. */ +void *arena_chunk_alloc_huge(arena_t *arena, size_t usize, size_t alignment, + bool *zero); +void arena_chunk_dalloc_huge(arena_t *arena, void *chunk, size_t usize); +void arena_chunk_ralloc_huge_similar(arena_t *arena, void *chunk, + size_t oldsize, size_t usize); +void arena_chunk_ralloc_huge_shrink(arena_t *arena, void *chunk, + size_t oldsize, size_t usize); +bool arena_chunk_ralloc_huge_expand(arena_t *arena, void *chunk, + size_t oldsize, size_t usize, bool *zero); void arena_purge_all(arena_t *arena); void arena_tcache_fill_small(arena_t *arena, tcache_bin_t *tbin, - size_t binind, uint64_t prof_accumbytes); + index_t binind, uint64_t prof_accumbytes); void arena_alloc_junk_small(void *ptr, arena_bin_info_t *bin_info, bool zero); #ifdef JEMALLOC_JET @@ -420,17 +365,19 @@ void *arena_malloc_small(arena_t *arena, size_t size, bool zero); void *arena_malloc_large(arena_t *arena, size_t size, bool zero); void *arena_palloc(arena_t *arena, size_t size, size_t alignment, bool zero); void arena_prof_promoted(const void *ptr, size_t size); -void arena_dalloc_bin_locked(arena_t *arena, arena_chunk_t *chunk, void *ptr, - arena_chunk_map_t *mapelm); +void arena_dalloc_bin_junked_locked(arena_t *arena, arena_chunk_t *chunk, + void *ptr, arena_chunk_map_bits_t *bitselm); void arena_dalloc_bin(arena_t *arena, arena_chunk_t *chunk, void *ptr, - size_t pageind, arena_chunk_map_t *mapelm); + size_t pageind, arena_chunk_map_bits_t *bitselm); void arena_dalloc_small(arena_t *arena, arena_chunk_t *chunk, void *ptr, size_t pageind); #ifdef JEMALLOC_JET typedef void (arena_dalloc_junk_large_t)(void *, size_t); extern arena_dalloc_junk_large_t *arena_dalloc_junk_large; +#else +void arena_dalloc_junk_large(void *ptr, size_t usize); #endif -void arena_dalloc_large_locked(arena_t *arena, arena_chunk_t *chunk, +void arena_dalloc_large_junked_locked(arena_t *arena, arena_chunk_t *chunk, void *ptr); void arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr); #ifdef JEMALLOC_JET @@ -439,15 +386,15 @@ extern arena_ralloc_junk_large_t *arena_ralloc_junk_large; #endif bool arena_ralloc_no_move(void *ptr, size_t oldsize, size_t size, size_t extra, bool zero); -void *arena_ralloc(arena_t *arena, void *ptr, size_t oldsize, size_t size, - size_t extra, size_t alignment, bool zero, bool try_tcache_alloc, - bool try_tcache_dalloc); +void *arena_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, + size_t size, size_t extra, size_t alignment, bool zero, + bool try_tcache_alloc, bool try_tcache_dalloc); dss_prec_t arena_dss_prec_get(arena_t *arena); -void arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec); +bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec); void arena_stats_merge(arena_t *arena, const char **dss, size_t *nactive, size_t *ndirty, arena_stats_t *astats, malloc_bin_stats_t *bstats, - malloc_large_stats_t *lstats); -bool arena_new(arena_t *arena, unsigned ind); + malloc_large_stats_t *lstats, malloc_huge_stats_t *hstats); +arena_t *arena_new(unsigned ind); void arena_boot(void); void arena_prefork(arena_t *arena); void arena_postfork_parent(arena_t *arena); @@ -458,7 +405,13 @@ void arena_postfork_child(arena_t *arena); #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE -arena_chunk_map_t *arena_mapp_get(arena_chunk_t *chunk, size_t pageind); +arena_chunk_map_bits_t *arena_bitselm_get(arena_chunk_t *chunk, + size_t pageind); +arena_chunk_map_misc_t *arena_miscelm_get(arena_chunk_t *chunk, + size_t pageind); +size_t arena_miscelm_to_pageind(arena_chunk_map_misc_t *miscelm); +void *arena_miscelm_to_rpages(arena_chunk_map_misc_t *miscelm); +arena_chunk_map_misc_t *arena_run_to_miscelm(arena_run_t *run); size_t *arena_mapbitsp_get(arena_chunk_t *chunk, size_t pageind); size_t arena_mapbitsp_read(size_t *mapbitsp); size_t arena_mapbits_get(arena_chunk_t *chunk, size_t pageind); @@ -466,7 +419,7 @@ size_t arena_mapbits_unallocated_size_get(arena_chunk_t *chunk, size_t pageind); size_t arena_mapbits_large_size_get(arena_chunk_t *chunk, size_t pageind); size_t arena_mapbits_small_runind_get(arena_chunk_t *chunk, size_t pageind); -size_t arena_mapbits_binind_get(arena_chunk_t *chunk, size_t pageind); +index_t arena_mapbits_binind_get(arena_chunk_t *chunk, size_t pageind); size_t arena_mapbits_dirty_get(arena_chunk_t *chunk, size_t pageind); size_t arena_mapbits_unzeroed_get(arena_chunk_t *chunk, size_t pageind); size_t arena_mapbits_large_get(arena_chunk_t *chunk, size_t pageind); @@ -479,43 +432,91 @@ void arena_mapbits_unallocated_size_set(arena_chunk_t *chunk, size_t pageind, void arena_mapbits_large_set(arena_chunk_t *chunk, size_t pageind, size_t size, size_t flags); void arena_mapbits_large_binind_set(arena_chunk_t *chunk, size_t pageind, - size_t binind); + index_t binind); void arena_mapbits_small_set(arena_chunk_t *chunk, size_t pageind, - size_t runind, size_t binind, size_t flags); + size_t runind, index_t binind, size_t flags); void arena_mapbits_unzeroed_set(arena_chunk_t *chunk, size_t pageind, size_t unzeroed); bool arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes); bool arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes); bool arena_prof_accum(arena_t *arena, uint64_t accumbytes); -size_t arena_ptr_small_binind_get(const void *ptr, size_t mapbits); -size_t arena_bin_index(arena_t *arena, arena_bin_t *bin); +index_t arena_ptr_small_binind_get(const void *ptr, size_t mapbits); +index_t arena_bin_index(arena_t *arena, arena_bin_t *bin); unsigned arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info, const void *ptr); -prof_ctx_t *arena_prof_ctx_get(const void *ptr); -void arena_prof_ctx_set(const void *ptr, size_t usize, prof_ctx_t *ctx); -void *arena_malloc(arena_t *arena, size_t size, bool zero, bool try_tcache); +prof_tctx_t *arena_prof_tctx_get(const void *ptr); +void arena_prof_tctx_set(const void *ptr, prof_tctx_t *tctx); +void *arena_malloc(tsd_t *tsd, arena_t *arena, size_t size, bool zero, + bool try_tcache); size_t arena_salloc(const void *ptr, bool demote); -void arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr, +void arena_dalloc(tsd_t *tsd, arena_chunk_t *chunk, void *ptr, + bool try_tcache); +void arena_sdalloc(tsd_t *tsd, arena_chunk_t *chunk, void *ptr, size_t size, bool try_tcache); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) # ifdef JEMALLOC_ARENA_INLINE_A -JEMALLOC_ALWAYS_INLINE arena_chunk_map_t * -arena_mapp_get(arena_chunk_t *chunk, size_t pageind) +JEMALLOC_ALWAYS_INLINE arena_chunk_map_bits_t * +arena_bitselm_get(arena_chunk_t *chunk, size_t pageind) { assert(pageind >= map_bias); assert(pageind < chunk_npages); - return (&chunk->map[pageind-map_bias]); + return (&chunk->map_bits[pageind-map_bias]); +} + +JEMALLOC_ALWAYS_INLINE arena_chunk_map_misc_t * +arena_miscelm_get(arena_chunk_t *chunk, size_t pageind) +{ + + assert(pageind >= map_bias); + assert(pageind < chunk_npages); + + return ((arena_chunk_map_misc_t *)((uintptr_t)chunk + + (uintptr_t)map_misc_offset) + pageind-map_bias); +} + +JEMALLOC_ALWAYS_INLINE size_t +arena_miscelm_to_pageind(arena_chunk_map_misc_t *miscelm) +{ + arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(miscelm); + size_t pageind = ((uintptr_t)miscelm - ((uintptr_t)chunk + + map_misc_offset)) / sizeof(arena_chunk_map_misc_t) + map_bias; + + assert(pageind >= map_bias); + assert(pageind < chunk_npages); + + return (pageind); +} + +JEMALLOC_ALWAYS_INLINE void * +arena_miscelm_to_rpages(arena_chunk_map_misc_t *miscelm) +{ + arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(miscelm); + size_t pageind = arena_miscelm_to_pageind(miscelm); + + return ((void *)((uintptr_t)chunk + (pageind << LG_PAGE))); +} + +JEMALLOC_ALWAYS_INLINE arena_chunk_map_misc_t * +arena_run_to_miscelm(arena_run_t *run) +{ + arena_chunk_map_misc_t *miscelm = (arena_chunk_map_misc_t + *)((uintptr_t)run - offsetof(arena_chunk_map_misc_t, run)); + + assert(arena_miscelm_to_pageind(miscelm) >= map_bias); + assert(arena_miscelm_to_pageind(miscelm) < chunk_npages); + + return (miscelm); } JEMALLOC_ALWAYS_INLINE size_t * arena_mapbitsp_get(arena_chunk_t *chunk, size_t pageind) { - return (&arena_mapp_get(chunk, pageind)->bits); + return (&arena_bitselm_get(chunk, pageind)->bits); } JEMALLOC_ALWAYS_INLINE size_t @@ -564,11 +565,11 @@ arena_mapbits_small_runind_get(arena_chunk_t *chunk, size_t pageind) return (mapbits >> LG_PAGE); } -JEMALLOC_ALWAYS_INLINE size_t +JEMALLOC_ALWAYS_INLINE index_t arena_mapbits_binind_get(arena_chunk_t *chunk, size_t pageind) { size_t mapbits; - size_t binind; + index_t binind; mapbits = arena_mapbits_get(chunk, pageind); binind = (mapbits & CHUNK_MAP_BININD_MASK) >> CHUNK_MAP_BININD_SHIFT; @@ -660,20 +661,20 @@ arena_mapbits_large_set(arena_chunk_t *chunk, size_t pageind, size_t size, JEMALLOC_ALWAYS_INLINE void arena_mapbits_large_binind_set(arena_chunk_t *chunk, size_t pageind, - size_t binind) + index_t binind) { size_t *mapbitsp = arena_mapbitsp_get(chunk, pageind); size_t mapbits = arena_mapbitsp_read(mapbitsp); assert(binind <= BININD_INVALID); - assert(arena_mapbits_large_size_get(chunk, pageind) == PAGE); + assert(arena_mapbits_large_size_get(chunk, pageind) == LARGE_MINCLASS); arena_mapbitsp_write(mapbitsp, (mapbits & ~CHUNK_MAP_BININD_MASK) | (binind << CHUNK_MAP_BININD_SHIFT)); } JEMALLOC_ALWAYS_INLINE void arena_mapbits_small_set(arena_chunk_t *chunk, size_t pageind, size_t runind, - size_t binind, size_t flags) + index_t binind, size_t flags) { size_t *mapbitsp = arena_mapbitsp_get(chunk, pageind); size_t mapbits = arena_mapbitsp_read(mapbitsp); @@ -719,7 +720,7 @@ arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes) cassert(config_prof); - if (prof_interval == 0) + if (likely(prof_interval == 0)) return (false); return (arena_prof_accum_impl(arena, accumbytes)); } @@ -730,7 +731,7 @@ arena_prof_accum(arena_t *arena, uint64_t accumbytes) cassert(config_prof); - if (prof_interval == 0) + if (likely(prof_interval == 0)) return (false); { @@ -743,10 +744,10 @@ arena_prof_accum(arena_t *arena, uint64_t accumbytes) } } -JEMALLOC_ALWAYS_INLINE size_t +JEMALLOC_ALWAYS_INLINE index_t arena_ptr_small_binind_get(const void *ptr, size_t mapbits) { - size_t binind; + index_t binind; binind = (mapbits & CHUNK_MAP_BININD_MASK) >> CHUNK_MAP_BININD_SHIFT; @@ -755,10 +756,13 @@ arena_ptr_small_binind_get(const void *ptr, size_t mapbits) arena_t *arena; size_t pageind; size_t actual_mapbits; + size_t rpages_ind; arena_run_t *run; arena_bin_t *bin; - size_t actual_binind; + index_t run_binind, actual_binind; arena_bin_info_t *bin_info; + arena_chunk_map_misc_t *miscelm; + void *rpages; assert(binind != BININD_INVALID); assert(binind < NBINS); @@ -769,13 +773,17 @@ arena_ptr_small_binind_get(const void *ptr, size_t mapbits) assert(mapbits == actual_mapbits); assert(arena_mapbits_large_get(chunk, pageind) == 0); assert(arena_mapbits_allocated_get(chunk, pageind) != 0); - run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind - - (actual_mapbits >> LG_PAGE)) << LG_PAGE)); - bin = run->bin; + rpages_ind = pageind - arena_mapbits_small_runind_get(chunk, + pageind); + miscelm = arena_miscelm_get(chunk, rpages_ind); + run = &miscelm->run; + run_binind = run->binind; + bin = &arena->bins[run_binind]; actual_binind = bin - arena->bins; - assert(binind == actual_binind); + assert(run_binind == actual_binind); bin_info = &arena_bin_info[actual_binind]; - assert(((uintptr_t)ptr - ((uintptr_t)run + + rpages = arena_miscelm_to_rpages(miscelm); + assert(((uintptr_t)ptr - ((uintptr_t)rpages + (uintptr_t)bin_info->reg0_offset)) % bin_info->reg_interval == 0); } @@ -785,10 +793,10 @@ arena_ptr_small_binind_get(const void *ptr, size_t mapbits) # endif /* JEMALLOC_ARENA_INLINE_A */ # ifdef JEMALLOC_ARENA_INLINE_B -JEMALLOC_INLINE size_t +JEMALLOC_INLINE index_t arena_bin_index(arena_t *arena, arena_bin_t *bin) { - size_t binind = bin - arena->bins; + index_t binind = bin - arena->bins; assert(binind < NBINS); return (binind); } @@ -798,19 +806,21 @@ arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info, const void *ptr) { unsigned shift, diff, regind; size_t interval; + arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run); + void *rpages = arena_miscelm_to_rpages(miscelm); /* * Freeing a pointer lower than region zero can cause assertion * failure. */ - assert((uintptr_t)ptr >= (uintptr_t)run + + assert((uintptr_t)ptr >= (uintptr_t)rpages + (uintptr_t)bin_info->reg0_offset); /* * Avoid doing division with a variable divisor if possible. Using * actual division here can reduce allocator throughput by over 20%! */ - diff = (unsigned)((uintptr_t)ptr - (uintptr_t)run - + diff = (unsigned)((uintptr_t)ptr - (uintptr_t)rpages - bin_info->reg0_offset); /* Rescale (factor powers of 2 out of the numerator and denominator). */ @@ -850,8 +860,8 @@ arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info, const void *ptr) SIZE_INV(28), SIZE_INV(29), SIZE_INV(30), SIZE_INV(31) }; - if (interval <= ((sizeof(interval_invs) / sizeof(unsigned)) + - 2)) { + if (likely(interval <= ((sizeof(interval_invs) / + sizeof(unsigned)) + 2))) { regind = (diff * interval_invs[interval - 3]) >> SIZE_INV_SHIFT; } else @@ -865,10 +875,10 @@ arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info, const void *ptr) return (regind); } -JEMALLOC_INLINE prof_ctx_t * -arena_prof_ctx_get(const void *ptr) +JEMALLOC_INLINE prof_tctx_t * +arena_prof_tctx_get(const void *ptr) { - prof_ctx_t *ret; + prof_tctx_t *ret; arena_chunk_t *chunk; size_t pageind, mapbits; @@ -880,31 +890,16 @@ arena_prof_ctx_get(const void *ptr) pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; mapbits = arena_mapbits_get(chunk, pageind); assert((mapbits & CHUNK_MAP_ALLOCATED) != 0); - if ((mapbits & CHUNK_MAP_LARGE) == 0) { - if (prof_promote) - ret = (prof_ctx_t *)(uintptr_t)1U; - else { - arena_run_t *run = (arena_run_t *)((uintptr_t)chunk + - (uintptr_t)((pageind - (mapbits >> LG_PAGE)) << - LG_PAGE)); - size_t binind = arena_ptr_small_binind_get(ptr, - mapbits); - arena_bin_info_t *bin_info = &arena_bin_info[binind]; - unsigned regind; - - regind = arena_run_regind(run, bin_info, ptr); - ret = *(prof_ctx_t **)((uintptr_t)run + - bin_info->ctx0_offset + (regind * - sizeof(prof_ctx_t *))); - } - } else - ret = arena_mapp_get(chunk, pageind)->prof_ctx; + if (likely((mapbits & CHUNK_MAP_LARGE) == 0)) + ret = (prof_tctx_t *)(uintptr_t)1U; + else + ret = arena_miscelm_get(chunk, pageind)->prof_tctx; return (ret); } JEMALLOC_INLINE void -arena_prof_ctx_set(const void *ptr, size_t usize, prof_ctx_t *ctx) +arena_prof_tctx_set(const void *ptr, prof_tctx_t *tctx) { arena_chunk_t *chunk; size_t pageind; @@ -917,59 +912,42 @@ arena_prof_ctx_set(const void *ptr, size_t usize, prof_ctx_t *ctx) pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; assert(arena_mapbits_allocated_get(chunk, pageind) != 0); - if (usize > SMALL_MAXCLASS || (prof_promote && - ((uintptr_t)ctx != (uintptr_t)1U || arena_mapbits_large_get(chunk, - pageind) != 0))) { - assert(arena_mapbits_large_get(chunk, pageind) != 0); - arena_mapp_get(chunk, pageind)->prof_ctx = ctx; - } else { - assert(arena_mapbits_large_get(chunk, pageind) == 0); - if (prof_promote == false) { - size_t mapbits = arena_mapbits_get(chunk, pageind); - arena_run_t *run = (arena_run_t *)((uintptr_t)chunk + - (uintptr_t)((pageind - (mapbits >> LG_PAGE)) << - LG_PAGE)); - size_t binind; - arena_bin_info_t *bin_info; - unsigned regind; - - binind = arena_ptr_small_binind_get(ptr, mapbits); - bin_info = &arena_bin_info[binind]; - regind = arena_run_regind(run, bin_info, ptr); - - *((prof_ctx_t **)((uintptr_t)run + - bin_info->ctx0_offset + (regind * sizeof(prof_ctx_t - *)))) = ctx; - } - } + if (unlikely(arena_mapbits_large_get(chunk, pageind) != 0)) + arena_miscelm_get(chunk, pageind)->prof_tctx = tctx; } JEMALLOC_ALWAYS_INLINE void * -arena_malloc(arena_t *arena, size_t size, bool zero, bool try_tcache) +arena_malloc(tsd_t *tsd, arena_t *arena, size_t size, bool zero, + bool try_tcache) { tcache_t *tcache; assert(size != 0); assert(size <= arena_maxclass); - if (size <= SMALL_MAXCLASS) { - if (try_tcache && (tcache = tcache_get(true)) != NULL) + if (likely(size <= SMALL_MAXCLASS)) { + if (likely(try_tcache) && likely((tcache = tcache_get(tsd, + true)) != NULL)) return (tcache_alloc_small(tcache, size, zero)); else { - return (arena_malloc_small(choose_arena(arena), size, - zero)); + arena = arena_choose(tsd, arena); + if (unlikely(arena == NULL)) + return (NULL); + return (arena_malloc_small(arena, size, zero)); } } else { /* * Initialize tcache after checking size in order to avoid * infinite recursion during tcache initialization. */ - if (try_tcache && size <= tcache_maxclass && (tcache = - tcache_get(true)) != NULL) + if (try_tcache && size <= tcache_maxclass && likely((tcache = + tcache_get(tsd, true)) != NULL)) return (tcache_alloc_large(tcache, size, zero)); else { - return (arena_malloc_large(choose_arena(arena), size, - zero)); + arena = arena_choose(tsd, arena); + if (unlikely(arena == NULL)) + return (NULL); + return (arena_malloc_large(arena, size, zero)); } } } @@ -980,7 +958,8 @@ arena_salloc(const void *ptr, bool demote) { size_t ret; arena_chunk_t *chunk; - size_t pageind, binind; + size_t pageind; + index_t binind; assert(ptr != NULL); assert(CHUNK_ADDR2BASE(ptr) != ptr); @@ -989,71 +968,103 @@ arena_salloc(const void *ptr, bool demote) pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; assert(arena_mapbits_allocated_get(chunk, pageind) != 0); binind = arena_mapbits_binind_get(chunk, pageind); - if (binind == BININD_INVALID || (config_prof && demote == false && - prof_promote && arena_mapbits_large_get(chunk, pageind) != 0)) { + if (unlikely(binind == BININD_INVALID || (config_prof && !demote && + arena_mapbits_large_get(chunk, pageind) != 0))) { /* - * Large allocation. In the common case (demote == true), and - * as this is an inline function, most callers will only end up - * looking at binind to determine that ptr is a small - * allocation. + * Large allocation. In the common case (demote), and as this + * is an inline function, most callers will only end up looking + * at binind to determine that ptr is a small allocation. */ assert(((uintptr_t)ptr & PAGE_MASK) == 0); ret = arena_mapbits_large_size_get(chunk, pageind); assert(ret != 0); assert(pageind + (ret>>LG_PAGE) <= chunk_npages); - assert(ret == PAGE || arena_mapbits_large_size_get(chunk, - pageind+(ret>>LG_PAGE)-1) == 0); - assert(binind == arena_mapbits_binind_get(chunk, - pageind+(ret>>LG_PAGE)-1)); assert(arena_mapbits_dirty_get(chunk, pageind) == arena_mapbits_dirty_get(chunk, pageind+(ret>>LG_PAGE)-1)); } else { - /* - * Small allocation (possibly promoted to a large object due to - * prof_promote). - */ + /* Small allocation (possibly promoted to a large object). */ assert(arena_mapbits_large_get(chunk, pageind) != 0 || arena_ptr_small_binind_get(ptr, arena_mapbits_get(chunk, pageind)) == binind); - ret = arena_bin_info[binind].reg_size; + ret = index2size(binind); } return (ret); } JEMALLOC_ALWAYS_INLINE void -arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr, bool try_tcache) +arena_dalloc(tsd_t *tsd, arena_chunk_t *chunk, void *ptr, bool try_tcache) { size_t pageind, mapbits; tcache_t *tcache; - assert(arena != NULL); - assert(chunk->arena == arena); assert(ptr != NULL); assert(CHUNK_ADDR2BASE(ptr) != ptr); pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; mapbits = arena_mapbits_get(chunk, pageind); assert(arena_mapbits_allocated_get(chunk, pageind) != 0); - if ((mapbits & CHUNK_MAP_LARGE) == 0) { + if (likely((mapbits & CHUNK_MAP_LARGE) == 0)) { /* Small allocation. */ - if (try_tcache && (tcache = tcache_get(false)) != NULL) { - size_t binind; - - binind = arena_ptr_small_binind_get(ptr, mapbits); + if (likely(try_tcache) && likely((tcache = tcache_get(tsd, + false)) != NULL)) { + index_t binind = arena_ptr_small_binind_get(ptr, + mapbits); tcache_dalloc_small(tcache, ptr, binind); } else - arena_dalloc_small(arena, chunk, ptr, pageind); + arena_dalloc_small(chunk->arena, chunk, ptr, pageind); } else { size_t size = arena_mapbits_large_size_get(chunk, pageind); assert(((uintptr_t)ptr & PAGE_MASK) == 0); - if (try_tcache && size <= tcache_maxclass && (tcache = - tcache_get(false)) != NULL) { + if (try_tcache && size <= tcache_maxclass && likely((tcache = + tcache_get(tsd, false)) != NULL)) tcache_dalloc_large(tcache, ptr, size); - } else - arena_dalloc_large(arena, chunk, ptr); + else + arena_dalloc_large(chunk->arena, chunk, ptr); + } +} + +JEMALLOC_ALWAYS_INLINE void +arena_sdalloc(tsd_t *tsd, arena_chunk_t *chunk, void *ptr, size_t size, + bool try_tcache) +{ + tcache_t *tcache; + + assert(ptr != NULL); + assert(CHUNK_ADDR2BASE(ptr) != ptr); + + if (config_prof && opt_prof) { + size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; + assert(arena_mapbits_allocated_get(chunk, pageind) != 0); + if (arena_mapbits_large_get(chunk, pageind) != 0) { + /* Make sure to use promoted size, not request size. */ + assert(((uintptr_t)ptr & PAGE_MASK) == 0); + size = arena_mapbits_large_size_get(chunk, pageind); + } + } + assert(s2u(size) == s2u(arena_salloc(ptr, false))); + + if (likely(size <= SMALL_MAXCLASS)) { + /* Small allocation. */ + if (likely(try_tcache) && likely((tcache = tcache_get(tsd, + false)) != NULL)) { + index_t binind = size2index(size); + tcache_dalloc_small(tcache, ptr, binind); + } else { + size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> + LG_PAGE; + arena_dalloc_small(chunk->arena, chunk, ptr, pageind); + } + } else { + assert(((uintptr_t)ptr & PAGE_MASK) == 0); + + if (try_tcache && size <= tcache_maxclass && (tcache = + tcache_get(tsd, false)) != NULL) + tcache_dalloc_large(tcache, ptr, size); + else + arena_dalloc_large(chunk->arena, chunk, ptr); } } # endif /* JEMALLOC_ARENA_INLINE_B */ diff --git a/memory/jemalloc/src/include/jemalloc/internal/atomic.h b/memory/jemalloc/src/include/jemalloc/internal/atomic.h index 11a7b47fe0f9..23ac93ffd1ca 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/atomic.h +++ b/memory/jemalloc/src/include/jemalloc/internal/atomic.h @@ -18,6 +18,17 @@ /******************************************************************************/ #ifdef JEMALLOC_H_INLINES +/* + * All functions return the arithmetic result of the atomic operation. Some + * atomic operation APIs return the value prior to mutation, in which case the + * following functions must redundantly compute the result so that it can be + * returned. These functions are normally inlined, so the extra operations can + * be optimized away if the return values aren't used by the callers. + * + * atomic_add_( *p, x) { return (*p + x); } + * atomic_sub_( *p, x) { return (*p - x); } + */ + #ifndef JEMALLOC_ENABLE_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x); uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x); @@ -47,21 +58,35 @@ atomic_sub_uint64(uint64_t *p, uint64_t x) return (__sync_sub_and_fetch(p, x)); } -#elif (defined(_MSC_VER)) +# elif (defined(_MSC_VER)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) { - return (InterlockedExchangeAdd64(p, x)); + return (InterlockedExchangeAdd64(p, x) + x); } JEMALLOC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x) { - return (InterlockedExchangeAdd64(p, -((int64_t)x))); + return (InterlockedExchangeAdd64(p, -((int64_t)x)) - x); } -#elif (defined(JEMALLOC_OSATOMIC)) +# elif (defined(JEMALLOC_C11ATOMICS)) +JEMALLOC_INLINE uint64_t +atomic_add_uint64(uint64_t *p, uint64_t x) +{ + volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; + return (atomic_fetch_add(a, x) + x); +} + +JEMALLOC_INLINE uint64_t +atomic_sub_uint64(uint64_t *p, uint64_t x) +{ + volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; + return (atomic_fetch_sub(a, x) - x); +} +# elif (defined(JEMALLOC_OSATOMIC)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) { @@ -79,28 +104,31 @@ atomic_sub_uint64(uint64_t *p, uint64_t x) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) { + uint64_t t = x; asm volatile ( "lock; xaddq %0, %1;" - : "+r" (x), "=m" (*p) /* Outputs. */ + : "+r" (t), "=m" (*p) /* Outputs. */ : "m" (*p) /* Inputs. */ ); - return (x); + return (t + x); } JEMALLOC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x) { + uint64_t t; x = (uint64_t)(-(int64_t)x); + t = x; asm volatile ( "lock; xaddq %0, %1;" - : "+r" (x), "=m" (*p) /* Outputs. */ + : "+r" (t), "=m" (*p) /* Outputs. */ : "m" (*p) /* Inputs. */ ); - return (x); + return (t + x); } # elif (defined(JEMALLOC_ATOMIC9)) JEMALLOC_INLINE uint64_t @@ -164,14 +192,28 @@ JEMALLOC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x) { - return (InterlockedExchangeAdd(p, x)); + return (InterlockedExchangeAdd(p, x) + x); } JEMALLOC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x) { - return (InterlockedExchangeAdd(p, -((int32_t)x))); + return (InterlockedExchangeAdd(p, -((int32_t)x)) - x); +} +# elif (defined(JEMALLOC_C11ATOMICS)) +JEMALLOC_INLINE uint32_t +atomic_add_uint32(uint32_t *p, uint32_t x) +{ + volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; + return (atomic_fetch_add(a, x) + x); +} + +JEMALLOC_INLINE uint32_t +atomic_sub_uint32(uint32_t *p, uint32_t x) +{ + volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; + return (atomic_fetch_sub(a, x) - x); } #elif (defined(JEMALLOC_OSATOMIC)) JEMALLOC_INLINE uint32_t @@ -191,28 +233,31 @@ atomic_sub_uint32(uint32_t *p, uint32_t x) JEMALLOC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x) { + uint32_t t = x; asm volatile ( "lock; xaddl %0, %1;" - : "+r" (x), "=m" (*p) /* Outputs. */ + : "+r" (t), "=m" (*p) /* Outputs. */ : "m" (*p) /* Inputs. */ ); - return (x); + return (t + x); } JEMALLOC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x) { + uint32_t t; x = (uint32_t)(-(int32_t)x); + t = x; asm volatile ( "lock; xaddl %0, %1;" - : "+r" (x), "=m" (*p) /* Outputs. */ + : "+r" (t), "=m" (*p) /* Outputs. */ : "m" (*p) /* Inputs. */ ); - return (x); + return (t + x); } #elif (defined(JEMALLOC_ATOMIC9)) JEMALLOC_INLINE uint32_t diff --git a/memory/jemalloc/src/include/jemalloc/internal/base.h b/memory/jemalloc/src/include/jemalloc/internal/base.h index 9cf75ffb0b3c..3fb80b92a987 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/base.h +++ b/memory/jemalloc/src/include/jemalloc/internal/base.h @@ -12,7 +12,7 @@ void *base_alloc(size_t size); void *base_calloc(size_t number, size_t size); extent_node_t *base_node_alloc(void); -void base_node_dealloc(extent_node_t *node); +void base_node_dalloc(extent_node_t *node); bool base_boot(void); void base_prefork(void); void base_postfork_parent(void); diff --git a/memory/jemalloc/src/include/jemalloc/internal/bitmap.h b/memory/jemalloc/src/include/jemalloc/internal/bitmap.h index 6db4ab703d7e..fcc6005c795b 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/bitmap.h +++ b/memory/jemalloc/src/include/jemalloc/internal/bitmap.h @@ -3,6 +3,7 @@ /* Maximum bitmap bit count is 2^LG_BITMAP_MAXBITS. */ #define LG_BITMAP_MAXBITS LG_RUN_MAXREGS +#define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS) typedef struct bitmap_level_s bitmap_level_t; typedef struct bitmap_info_s bitmap_info_t; @@ -14,6 +15,51 @@ typedef unsigned long bitmap_t; #define BITMAP_GROUP_NBITS (ZU(1) << LG_BITMAP_GROUP_NBITS) #define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1) +/* Number of groups required to store a given number of bits. */ +#define BITMAP_BITS2GROUPS(nbits) \ + ((nbits + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS) + +/* + * Number of groups required at a particular level for a given number of bits. + */ +#define BITMAP_GROUPS_L0(nbits) \ + BITMAP_BITS2GROUPS(nbits) +#define BITMAP_GROUPS_L1(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits)) +#define BITMAP_GROUPS_L2(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))) +#define BITMAP_GROUPS_L3(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ + BITMAP_BITS2GROUPS((nbits))))) + +/* + * Assuming the number of levels, number of groups required for a given number + * of bits. + */ +#define BITMAP_GROUPS_1_LEVEL(nbits) \ + BITMAP_GROUPS_L0(nbits) +#define BITMAP_GROUPS_2_LEVEL(nbits) \ + (BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits)) +#define BITMAP_GROUPS_3_LEVEL(nbits) \ + (BITMAP_GROUPS_2_LEVEL(nbits) + BITMAP_GROUPS_L2(nbits)) +#define BITMAP_GROUPS_4_LEVEL(nbits) \ + (BITMAP_GROUPS_3_LEVEL(nbits) + BITMAP_GROUPS_L3(nbits)) + +/* + * Maximum number of groups required to support LG_BITMAP_MAXBITS. + */ +#if LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_1_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2 +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 3 +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_3_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 4 +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_4_LEVEL(BITMAP_MAXBITS) +#else +# error "Unsupported bitmap size" +#endif + /* Maximum number of levels possible. */ #define BITMAP_MAX_LEVELS \ (LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \ @@ -93,7 +139,7 @@ bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) bitmap_t g; assert(bit < binfo->nbits); - assert(bitmap_get(bitmap, binfo, bit) == false); + assert(!bitmap_get(bitmap, binfo, bit)); goff = bit >> LG_BITMAP_GROUP_NBITS; gp = &bitmap[goff]; g = *gp; @@ -126,7 +172,7 @@ bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) bitmap_t g; unsigned i; - assert(bitmap_full(bitmap, binfo) == false); + assert(!bitmap_full(bitmap, binfo)); i = binfo->nlevels - 1; g = bitmap[binfo->levels[i].group_offset]; @@ -158,7 +204,7 @@ bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) assert((g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK))) == 0); g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK); *gp = g; - assert(bitmap_get(bitmap, binfo, bit) == false); + assert(!bitmap_get(bitmap, binfo, bit)); /* Propagate group state transitions up the tree. */ if (propagate) { unsigned i; @@ -172,7 +218,7 @@ bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) == 0); g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK); *gp = g; - if (propagate == false) + if (!propagate) break; } } diff --git a/memory/jemalloc/src/include/jemalloc/internal/chunk.h b/memory/jemalloc/src/include/jemalloc/internal/chunk.h index 87d8700dac8a..764b7aca7902 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/chunk.h +++ b/memory/jemalloc/src/include/jemalloc/internal/chunk.h @@ -40,13 +40,15 @@ extern rtree_t *chunks_rtree; extern size_t chunksize; extern size_t chunksize_mask; /* (chunksize - 1). */ extern size_t chunk_npages; -extern size_t map_bias; /* Number of arena chunk header pages. */ -extern size_t arena_maxclass; /* Max size class for arenas. */ -void *chunk_alloc(size_t size, size_t alignment, bool base, bool *zero, - dss_prec_t dss_prec); +void *chunk_alloc_base(size_t size); +void *chunk_alloc_arena(chunk_alloc_t *chunk_alloc, + chunk_dalloc_t *chunk_dalloc, unsigned arena_ind, void *new_addr, + size_t size, size_t alignment, bool *zero); +void *chunk_alloc_default(void *new_addr, size_t size, size_t alignment, + bool *zero, unsigned arena_ind); void chunk_unmap(void *chunk, size_t size); -void chunk_dealloc(void *chunk, size_t size, bool unmap); +bool chunk_dalloc_default(void *chunk, size_t size, unsigned arena_ind); bool chunk_boot(void); void chunk_prefork(void); void chunk_postfork_parent(void); diff --git a/memory/jemalloc/src/include/jemalloc/internal/chunk_dss.h b/memory/jemalloc/src/include/jemalloc/internal/chunk_dss.h index 4535ce09c09a..09896470fbfc 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/chunk_dss.h +++ b/memory/jemalloc/src/include/jemalloc/internal/chunk_dss.h @@ -23,7 +23,8 @@ extern const char *dss_prec_names[]; dss_prec_t chunk_dss_prec_get(void); bool chunk_dss_prec_set(dss_prec_t dss_prec); -void *chunk_alloc_dss(size_t size, size_t alignment, bool *zero); +void *chunk_alloc_dss(void *new_addr, size_t size, size_t alignment, + bool *zero); bool chunk_in_dss(void *chunk); bool chunk_dss_boot(void); void chunk_dss_prefork(void); diff --git a/memory/jemalloc/src/include/jemalloc/internal/chunk_mmap.h b/memory/jemalloc/src/include/jemalloc/internal/chunk_mmap.h index f24abac75382..c5d5c6c0c7ac 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/chunk_mmap.h +++ b/memory/jemalloc/src/include/jemalloc/internal/chunk_mmap.h @@ -12,7 +12,7 @@ bool pages_purge(void *addr, size_t length); void *chunk_alloc_mmap(size_t size, size_t alignment, bool *zero); -bool chunk_dealloc_mmap(void *chunk, size_t size); +bool chunk_dalloc_mmap(void *chunk, size_t size); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ diff --git a/memory/jemalloc/src/include/jemalloc/internal/ckh.h b/memory/jemalloc/src/include/jemalloc/internal/ckh.h index 58712a6a763e..75c1c979f270 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/ckh.h +++ b/memory/jemalloc/src/include/jemalloc/internal/ckh.h @@ -66,13 +66,13 @@ struct ckh_s { /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS -bool ckh_new(ckh_t *ckh, size_t minitems, ckh_hash_t *hash, +bool ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp); -void ckh_delete(ckh_t *ckh); +void ckh_delete(tsd_t *tsd, ckh_t *ckh); size_t ckh_count(ckh_t *ckh); bool ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data); -bool ckh_insert(ckh_t *ckh, const void *key, const void *data); -bool ckh_remove(ckh_t *ckh, const void *searchkey, void **key, +bool ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data); +bool ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key, void **data); bool ckh_search(ckh_t *ckh, const void *seachkey, void **key, void **data); void ckh_string_hash(const void *key, size_t r_hash[2]); diff --git a/memory/jemalloc/src/include/jemalloc/internal/ctl.h b/memory/jemalloc/src/include/jemalloc/internal/ctl.h index 0ffecc5f2a23..a3e899eaba34 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/ctl.h +++ b/memory/jemalloc/src/include/jemalloc/internal/ctl.h @@ -46,6 +46,7 @@ struct ctl_arena_stats_s { malloc_bin_stats_t bstats[NBINS]; malloc_large_stats_t *lstats; /* nlclasses elements. */ + malloc_huge_stats_t *hstats; /* nhclasses elements. */ }; struct ctl_stats_s { @@ -57,11 +58,6 @@ struct ctl_stats_s { uint64_t total; /* stats_chunks.nchunks */ size_t high; /* stats_chunks.highchunks */ } chunks; - struct { - size_t allocated; /* huge_allocated */ - uint64_t nmalloc; /* huge_nmalloc */ - uint64_t ndalloc; /* huge_ndalloc */ - } huge; unsigned narenas; ctl_arena_stats_t *arenas; /* (narenas + 1) elements. */ }; diff --git a/memory/jemalloc/src/include/jemalloc/internal/extent.h b/memory/jemalloc/src/include/jemalloc/internal/extent.h index ba95ca816bd9..cbfc20a95942 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/extent.h +++ b/memory/jemalloc/src/include/jemalloc/internal/extent.h @@ -16,7 +16,7 @@ struct extent_node_s { rb_node(extent_node_t) link_ad; /* Profile counters, used for huge objects. */ - prof_ctx_t *prof_ctx; + prof_tctx_t *prof_tctx; /* Pointer to the extent that this tree node is responsible for. */ void *addr; @@ -24,6 +24,9 @@ struct extent_node_s { /* Total region size. */ size_t size; + /* Arena from which this extent came, if any. */ + arena_t *arena; + /* True if zero-filled; used by chunk recycling code. */ bool zeroed; }; diff --git a/memory/jemalloc/src/include/jemalloc/internal/hash.h b/memory/jemalloc/src/include/jemalloc/internal/hash.h index f2b3a16c849e..bcead337abc1 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/hash.h +++ b/memory/jemalloc/src/include/jemalloc/internal/hash.h @@ -35,13 +35,14 @@ JEMALLOC_INLINE uint32_t hash_rotl_32(uint32_t x, int8_t r) { - return (x << r) | (x >> (32 - r)); + return ((x << r) | (x >> (32 - r))); } JEMALLOC_INLINE uint64_t hash_rotl_64(uint64_t x, int8_t r) { - return (x << r) | (x >> (64 - r)); + + return ((x << r) | (x >> (64 - r))); } JEMALLOC_INLINE uint32_t @@ -76,9 +77,9 @@ hash_fmix_64(uint64_t k) { k ^= k >> 33; - k *= QU(0xff51afd7ed558ccdULL); + k *= KQU(0xff51afd7ed558ccd); k ^= k >> 33; - k *= QU(0xc4ceb9fe1a85ec53ULL); + k *= KQU(0xc4ceb9fe1a85ec53); k ^= k >> 33; return (k); @@ -247,8 +248,8 @@ hash_x64_128(const void *key, const int len, const uint32_t seed, uint64_t h1 = seed; uint64_t h2 = seed; - const uint64_t c1 = QU(0x87c37b91114253d5ULL); - const uint64_t c2 = QU(0x4cf5ad432745937fULL); + const uint64_t c1 = KQU(0x87c37b91114253d5); + const uint64_t c2 = KQU(0x4cf5ad432745937f); /* body */ { diff --git a/memory/jemalloc/src/include/jemalloc/internal/huge.h b/memory/jemalloc/src/include/jemalloc/internal/huge.h index a2b9c779191f..39d8aa50b653 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/huge.h +++ b/memory/jemalloc/src/include/jemalloc/internal/huge.h @@ -9,30 +9,23 @@ /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS -/* Huge allocation statistics. */ -extern uint64_t huge_nmalloc; -extern uint64_t huge_ndalloc; -extern size_t huge_allocated; - -/* Protects chunk-related data structures. */ -extern malloc_mutex_t huge_mtx; - -void *huge_malloc(size_t size, bool zero, dss_prec_t dss_prec); -void *huge_palloc(size_t size, size_t alignment, bool zero, - dss_prec_t dss_prec); +void *huge_malloc(tsd_t *tsd, arena_t *arena, size_t size, bool zero, + bool try_tcache); +void *huge_palloc(tsd_t *tsd, arena_t *arena, size_t usize, size_t alignment, + bool zero, bool try_tcache); bool huge_ralloc_no_move(void *ptr, size_t oldsize, size_t size, - size_t extra); -void *huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra, - size_t alignment, bool zero, bool try_tcache_dalloc, dss_prec_t dss_prec); + size_t extra, bool zero); +void *huge_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, + size_t size, size_t extra, size_t alignment, bool zero, + bool try_tcache_alloc, bool try_tcache_dalloc); #ifdef JEMALLOC_JET typedef void (huge_dalloc_junk_t)(void *, size_t); extern huge_dalloc_junk_t *huge_dalloc_junk; #endif -void huge_dalloc(void *ptr, bool unmap); +void huge_dalloc(tsd_t *tsd, void *ptr, bool try_tcache); size_t huge_salloc(const void *ptr); -dss_prec_t huge_dss_prec_get(arena_t *arena); -prof_ctx_t *huge_prof_ctx_get(const void *ptr); -void huge_prof_ctx_set(const void *ptr, prof_ctx_t *ctx); +prof_tctx_t *huge_prof_tctx_get(const void *ptr); +void huge_prof_tctx_set(const void *ptr, prof_tctx_t *tctx); bool huge_boot(void); void huge_prefork(void); void huge_postfork_parent(void); diff --git a/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal.h.in b/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal.h.in index 2534255679ec..b7617dfd351f 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal.h.in +++ b/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal.h.in @@ -1,72 +1,13 @@ #ifndef JEMALLOC_INTERNAL_H #define JEMALLOC_INTERNAL_H -#include -#ifdef _WIN32 -# include -# define ENOENT ERROR_PATH_NOT_FOUND -# define EINVAL ERROR_BAD_ARGUMENTS -# define EAGAIN ERROR_OUTOFMEMORY -# define EPERM ERROR_WRITE_FAULT -# define EFAULT ERROR_INVALID_ADDRESS -# define ENOMEM ERROR_NOT_ENOUGH_MEMORY -# undef ERANGE -# define ERANGE ERROR_INVALID_DATA -#else -# include -# include -# if !defined(__pnacl__) && !defined(__native_client__) -# include -# if !defined(SYS_write) && defined(__NR_write) -# define SYS_write __NR_write -# endif -# include -# endif -# include -# include -#endif -#include - -#include -#ifndef SIZE_T_MAX -# define SIZE_T_MAX SIZE_MAX -#endif -#include -#include -#include -#include -#include -#include -#ifndef offsetof -# define offsetof(type, member) ((size_t)&(((type *)NULL)->member)) -#endif -#include -#include -#include -#include -#ifdef _MSC_VER -# include -typedef intptr_t ssize_t; -# define PATH_MAX 1024 -# define STDERR_FILENO 2 -# define __func__ __FUNCTION__ -/* Disable warnings about deprecated system functions */ -# pragma warning(disable: 4996) -#else -# include -#endif -#include #include "jemalloc_internal_defs.h" +#include "jemalloc/internal/jemalloc_internal_decls.h" #ifdef JEMALLOC_UTRACE #include #endif -#ifdef JEMALLOC_VALGRIND -#include -#include -#endif - #define JEMALLOC_NO_DEMANGLE #ifdef JEMALLOC_JET # define JEMALLOC_N(n) jet_##n @@ -87,7 +28,7 @@ static const bool config_debug = false #endif ; -static const bool config_dss = +static const bool have_dss = #ifdef JEMALLOC_DSS true #else @@ -129,13 +70,6 @@ static const bool config_prof_libunwind = false #endif ; -static const bool config_mremap = -#ifdef JEMALLOC_MREMAP - true -#else - false -#endif - ; static const bool config_munmap = #ifdef JEMALLOC_MUNMAP true @@ -193,6 +127,10 @@ static const bool config_ivsalloc = #endif ; +#ifdef JEMALLOC_C11ATOMICS +#include +#endif + #ifdef JEMALLOC_ATOMIC9 #include #endif @@ -231,15 +169,26 @@ static const bool config_ivsalloc = #include "jemalloc/internal/jemalloc_internal_macros.h" +/* Size class index type. */ +typedef unsigned index_t; + +#define MALLOCX_ARENA_MASK ((int)~0xff) #define MALLOCX_LG_ALIGN_MASK ((int)0x3f) -#define ALLOCM_LG_ALIGN_MASK ((int)0x3f) +/* Use MALLOCX_ALIGN_GET() if alignment may not be specified in flags. */ +#define MALLOCX_ALIGN_GET_SPECIFIED(flags) \ + (ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK)) +#define MALLOCX_ALIGN_GET(flags) \ + (MALLOCX_ALIGN_GET_SPECIFIED(flags) & (SIZE_T_MAX-1)) +#define MALLOCX_ZERO_GET(flags) \ + ((bool)(flags & MALLOCX_ZERO)) +#define MALLOCX_ARENA_GET(flags) \ + (((unsigned)(flags >> 8)) - 1) /* Smallest size class to support. */ -#define LG_TINY_MIN 3 #define TINY_MIN (1U << LG_TINY_MIN) /* - * Minimum alignment of allocations is 2^LG_QUANTUM bytes (ignoring tiny size + * Minimum allocation alignment is 2^LG_QUANTUM bytes (ignoring tiny size * classes). */ #ifndef LG_QUANTUM @@ -270,6 +219,9 @@ static const bool config_ivsalloc = # ifdef __mips__ # define LG_QUANTUM 3 # endif +# ifdef __or1k__ +# define LG_QUANTUM 3 +# endif # ifdef __powerpc__ # define LG_QUANTUM 4 # endif @@ -286,7 +238,8 @@ static const bool config_ivsalloc = # define LG_QUANTUM 4 # endif # ifndef LG_QUANTUM -# error "No LG_QUANTUM definition for architecture; specify via CPPFLAGS" +# error "Unknown minimum alignment for architecture; specify via " + "--with-lg-quantum" # endif #endif @@ -326,12 +279,11 @@ static const bool config_ivsalloc = #define CACHELINE_CEILING(s) \ (((s) + CACHELINE_MASK) & ~CACHELINE_MASK) -/* Page size. STATIC_PAGE_SHIFT is determined by the configure script. */ +/* Page size. LG_PAGE is determined by the configure script. */ #ifdef PAGE_MASK # undef PAGE_MASK #endif -#define LG_PAGE STATIC_PAGE_SHIFT -#define PAGE ((size_t)(1U << STATIC_PAGE_SHIFT)) +#define PAGE ((size_t)(1U << LG_PAGE)) #define PAGE_MASK ((size_t)(PAGE - 1)) /* Return the smallest pagesize multiple that is >= s. */ @@ -350,7 +302,7 @@ static const bool config_ivsalloc = #define ALIGNMENT_CEILING(s, alignment) \ (((s) + (alignment - 1)) & (-(alignment))) -/* Declare a variable length array */ +/* Declare a variable-length array. */ #if __STDC_VERSION__ < 199901L # ifdef _MSC_VER # include @@ -363,86 +315,12 @@ static const bool config_ivsalloc = # endif # endif # define VARIABLE_ARRAY(type, name, count) \ - type *name = alloca(sizeof(type) * count) + type *name = alloca(sizeof(type) * (count)) #else -# define VARIABLE_ARRAY(type, name, count) type name[count] -#endif - -#ifdef JEMALLOC_VALGRIND -/* - * The JEMALLOC_VALGRIND_*() macros must be macros rather than functions - * so that when Valgrind reports errors, there are no extra stack frames - * in the backtraces. - * - * The size that is reported to valgrind must be consistent through a chain of - * malloc..realloc..realloc calls. Request size isn't recorded anywhere in - * jemalloc, so it is critical that all callers of these macros provide usize - * rather than request size. As a result, buffer overflow detection is - * technically weakened for the standard API, though it is generally accepted - * practice to consider any extra bytes reported by malloc_usable_size() as - * usable space. - */ -#define JEMALLOC_VALGRIND_MALLOC(cond, ptr, usize, zero) do { \ - if (config_valgrind && opt_valgrind && cond) \ - VALGRIND_MALLOCLIKE_BLOCK(ptr, usize, p2rz(ptr), zero); \ -} while (0) -#define JEMALLOC_VALGRIND_REALLOC(ptr, usize, old_ptr, old_usize, \ - old_rzsize, zero) do { \ - if (config_valgrind && opt_valgrind) { \ - size_t rzsize = p2rz(ptr); \ - \ - if (ptr == old_ptr) { \ - VALGRIND_RESIZEINPLACE_BLOCK(ptr, old_usize, \ - usize, rzsize); \ - if (zero && old_usize < usize) { \ - VALGRIND_MAKE_MEM_DEFINED( \ - (void *)((uintptr_t)ptr + \ - old_usize), usize - old_usize); \ - } \ - } else { \ - if (old_ptr != NULL) { \ - VALGRIND_FREELIKE_BLOCK(old_ptr, \ - old_rzsize); \ - } \ - if (ptr != NULL) { \ - size_t copy_size = (old_usize < usize) \ - ? old_usize : usize; \ - size_t tail_size = usize - copy_size; \ - VALGRIND_MALLOCLIKE_BLOCK(ptr, usize, \ - rzsize, false); \ - if (copy_size > 0) { \ - VALGRIND_MAKE_MEM_DEFINED(ptr, \ - copy_size); \ - } \ - if (zero && tail_size > 0) { \ - VALGRIND_MAKE_MEM_DEFINED( \ - (void *)((uintptr_t)ptr + \ - copy_size), tail_size); \ - } \ - } \ - } \ - } \ -} while (0) -#define JEMALLOC_VALGRIND_FREE(ptr, rzsize) do { \ - if (config_valgrind && opt_valgrind) \ - VALGRIND_FREELIKE_BLOCK(ptr, rzsize); \ -} while (0) -#else -#define RUNNING_ON_VALGRIND ((unsigned)0) -#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ - do {} while (0) -#define VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB) \ - do {} while (0) -#define VALGRIND_FREELIKE_BLOCK(addr, rzB) do {} while (0) -#define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr, _qzz_len) do {} while (0) -#define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr, _qzz_len) do {} while (0) -#define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr, _qzz_len) do {} while (0) -#define JEMALLOC_VALGRIND_MALLOC(cond, ptr, usize, zero) do {} while (0) -#define JEMALLOC_VALGRIND_REALLOC(ptr, usize, old_ptr, old_usize, \ - old_rzsize, zero) do {} while (0) -#define JEMALLOC_VALGRIND_FREE(ptr, rzsize) do {} while (0) +# define VARIABLE_ARRAY(type, name, count) type name[(count)] #endif +#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/prng.h" @@ -469,6 +347,7 @@ static const bool config_ivsalloc = /******************************************************************************/ #define JEMALLOC_H_STRUCTS +#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/prng.h" @@ -477,7 +356,6 @@ static const bool config_ivsalloc = #include "jemalloc/internal/stats.h" #include "jemalloc/internal/ctl.h" #include "jemalloc/internal/mutex.h" -#include "jemalloc/internal/tsd.h" #include "jemalloc/internal/mb.h" #include "jemalloc/internal/bitmap.h" #include "jemalloc/internal/extent.h" @@ -491,54 +369,62 @@ static const bool config_ivsalloc = #include "jemalloc/internal/quarantine.h" #include "jemalloc/internal/prof.h" -typedef struct { - uint64_t allocated; - uint64_t deallocated; -} thread_allocated_t; -/* - * The JEMALLOC_ARG_CONCAT() wrapper is necessary to pass {0, 0} via a cpp macro - * argument. - */ -#define THREAD_ALLOCATED_INITIALIZER JEMALLOC_ARG_CONCAT({0, 0}) +#include "jemalloc/internal/tsd.h" #undef JEMALLOC_H_STRUCTS /******************************************************************************/ #define JEMALLOC_H_EXTERNS extern bool opt_abort; -extern bool opt_junk; +extern const char *opt_junk; +extern bool opt_junk_alloc; +extern bool opt_junk_free; extern size_t opt_quarantine; extern bool opt_redzone; extern bool opt_utrace; -extern bool opt_valgrind; extern bool opt_xmalloc; extern bool opt_zero; extern size_t opt_narenas; +extern bool in_valgrind; + /* Number of CPUs. */ extern unsigned ncpus; -/* Protects arenas initialization (arenas, arenas_total). */ -extern malloc_mutex_t arenas_lock; /* - * Arenas that are used to service external requests. Not all elements of the - * arenas array are necessarily used; arenas are created lazily as needed. - * - * arenas[0..narenas_auto) are used for automatic multiplexing of threads and - * arenas. arenas[narenas_auto..narenas_total) are only used if the application - * takes some action to create them and allocate from them. + * index2size_tab encodes the same information as could be computed (at + * unacceptable cost in some code paths) by index2size_compute(). */ -extern arena_t **arenas; -extern unsigned narenas_total; -extern unsigned narenas_auto; /* Read-only after initialization. */ +extern size_t const index2size_tab[NSIZES]; +/* + * size2index_tab is a compact lookup table that rounds request sizes up to + * size classes. In order to reduce cache footprint, the table is compressed, + * and all accesses are via size2index(). + */ +extern uint8_t const size2index_tab[]; +arena_t *a0get(void); +void *a0malloc(size_t size); +void *a0calloc(size_t num, size_t size); +void a0free(void *ptr); arena_t *arenas_extend(unsigned ind); -void arenas_cleanup(void *arg); -arena_t *choose_arena_hard(void); +arena_t *arena_init(unsigned ind); +unsigned narenas_total_get(void); +arena_t *arena_get_hard(tsd_t *tsd, unsigned ind, bool init_if_missing); +arena_t *arena_choose_hard(tsd_t *tsd); +void arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind); +unsigned arena_nbound(unsigned ind); +void thread_allocated_cleanup(tsd_t *tsd); +void thread_deallocated_cleanup(tsd_t *tsd); +void arena_cleanup(tsd_t *tsd); +void arenas_cache_cleanup(tsd_t *tsd); +void narenas_cache_cleanup(tsd_t *tsd); +void arenas_cache_bypass_cleanup(tsd_t *tsd); void jemalloc_prefork(void); void jemalloc_postfork_parent(void); void jemalloc_postfork_child(void); +#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/prng.h" @@ -547,7 +433,6 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/stats.h" #include "jemalloc/internal/ctl.h" #include "jemalloc/internal/mutex.h" -#include "jemalloc/internal/tsd.h" #include "jemalloc/internal/mb.h" #include "jemalloc/internal/bitmap.h" #include "jemalloc/internal/extent.h" @@ -560,11 +445,13 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/hash.h" #include "jemalloc/internal/quarantine.h" #include "jemalloc/internal/prof.h" +#include "jemalloc/internal/tsd.h" #undef JEMALLOC_H_EXTERNS /******************************************************************************/ #define JEMALLOC_H_INLINES +#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/prng.h" @@ -581,22 +468,150 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/huge.h" #ifndef JEMALLOC_ENABLE_INLINE -malloc_tsd_protos(JEMALLOC_ATTR(unused), arenas, arena_t *) - +index_t size2index_compute(size_t size); +index_t size2index_lookup(size_t size); +index_t size2index(size_t size); +size_t index2size_compute(index_t index); +size_t index2size_lookup(index_t index); +size_t index2size(index_t index); +size_t s2u_compute(size_t size); +size_t s2u_lookup(size_t size); size_t s2u(size_t size); size_t sa2u(size_t size, size_t alignment); -unsigned narenas_total_get(void); -arena_t *choose_arena(arena_t *arena); +arena_t *arena_choose(tsd_t *tsd, arena_t *arena); +arena_t *arena_get(tsd_t *tsd, unsigned ind, bool init_if_missing, + bool refresh_if_missing); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) -/* - * Map of pthread_self() --> arenas[???], used for selecting an arena to use - * for allocations. - */ -malloc_tsd_externs(arenas, arena_t *) -malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, arenas, arena_t *, NULL, - arenas_cleanup) +JEMALLOC_INLINE index_t +size2index_compute(size_t size) +{ + +#if (NTBINS != 0) + if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { + size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; + size_t lg_ceil = lg_floor(pow2_ceil(size)); + return (lg_ceil < lg_tmin ? 0 : lg_ceil - lg_tmin); + } else +#endif + { + size_t x = lg_floor((size<<1)-1); + size_t shift = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM) ? 0 : + x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM); + size_t grp = shift << LG_SIZE_CLASS_GROUP; + + size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) + ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; + + size_t delta_inverse_mask = ZI(-1) << lg_delta; + size_t mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) & + ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); + + size_t index = NTBINS + grp + mod; + return (index); + } +} + +JEMALLOC_ALWAYS_INLINE index_t +size2index_lookup(size_t size) +{ + + assert(size <= LOOKUP_MAXCLASS); + { + size_t ret = ((size_t)(size2index_tab[(size-1) >> + LG_TINY_MIN])); + assert(ret == size2index_compute(size)); + return (ret); + } +} + +JEMALLOC_ALWAYS_INLINE index_t +size2index(size_t size) +{ + + assert(size > 0); + if (likely(size <= LOOKUP_MAXCLASS)) + return (size2index_lookup(size)); + else + return (size2index_compute(size)); +} + +JEMALLOC_INLINE size_t +index2size_compute(index_t index) +{ + +#if (NTBINS > 0) + if (index < NTBINS) + return (ZU(1) << (LG_TINY_MAXCLASS - NTBINS + 1 + index)); + else +#endif + { + size_t reduced_index = index - NTBINS; + size_t grp = reduced_index >> LG_SIZE_CLASS_GROUP; + size_t mod = reduced_index & ((ZU(1) << LG_SIZE_CLASS_GROUP) - + 1); + + size_t grp_size_mask = ~((!!grp)-1); + size_t grp_size = ((ZU(1) << (LG_QUANTUM + + (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask; + + size_t shift = (grp == 0) ? 1 : grp; + size_t lg_delta = shift + (LG_QUANTUM-1); + size_t mod_size = (mod+1) << lg_delta; + + size_t usize = grp_size + mod_size; + return (usize); + } +} + +JEMALLOC_ALWAYS_INLINE size_t +index2size_lookup(index_t index) +{ + size_t ret = (size_t)index2size_tab[index]; + assert(ret == index2size_compute(index)); + return (ret); +} + +JEMALLOC_ALWAYS_INLINE size_t +index2size(index_t index) +{ + + assert(index < NSIZES); + return (index2size_lookup(index)); +} + +JEMALLOC_ALWAYS_INLINE size_t +s2u_compute(size_t size) +{ + +#if (NTBINS > 0) + if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { + size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; + size_t lg_ceil = lg_floor(pow2_ceil(size)); + return (lg_ceil < lg_tmin ? (ZU(1) << lg_tmin) : + (ZU(1) << lg_ceil)); + } else +#endif + { + size_t x = lg_floor((size<<1)-1); + size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) + ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; + size_t delta = ZU(1) << lg_delta; + size_t delta_mask = delta - 1; + size_t usize = (size + delta_mask) & ~delta_mask; + return (usize); + } +} + +JEMALLOC_ALWAYS_INLINE size_t +s2u_lookup(size_t size) +{ + size_t ret = index2size_lookup(size2index_lookup(size)); + + assert(ret == s2u_compute(size)); + return (ret); +} /* * Compute usable size that would result from allocating an object with the @@ -606,11 +621,11 @@ JEMALLOC_ALWAYS_INLINE size_t s2u(size_t size) { - if (size <= SMALL_MAXCLASS) - return (arena_bin_info[SMALL_SIZE2BIN(size)].reg_size); - if (size <= arena_maxclass) - return (PAGE_CEILING(size)); - return (CHUNK_CEILING(size)); + assert(size > 0); + if (likely(size <= LOOKUP_MAXCLASS)) + return (s2u_lookup(size)); + else + return (s2u_compute(size)); } /* @@ -624,108 +639,132 @@ sa2u(size_t size, size_t alignment) assert(alignment != 0 && ((alignment - 1) & alignment) == 0); - /* - * Round size up to the nearest multiple of alignment. - * - * This done, we can take advantage of the fact that for each small - * size class, every object is aligned at the smallest power of two - * that is non-zero in the base two representation of the size. For - * example: - * - * Size | Base 2 | Minimum alignment - * -----+----------+------------------ - * 96 | 1100000 | 32 - * 144 | 10100000 | 32 - * 192 | 11000000 | 64 - */ - usize = ALIGNMENT_CEILING(size, alignment); - /* - * (usize < size) protects against the combination of maximal - * alignment and size greater than maximal alignment. - */ - if (usize < size) { - /* size_t overflow. */ - return (0); + /* Try for a small size class. */ + if (size <= SMALL_MAXCLASS && alignment < PAGE) { + /* + * Round size up to the nearest multiple of alignment. + * + * This done, we can take advantage of the fact that for each + * small size class, every object is aligned at the smallest + * power of two that is non-zero in the base two representation + * of the size. For example: + * + * Size | Base 2 | Minimum alignment + * -----+----------+------------------ + * 96 | 1100000 | 32 + * 144 | 10100000 | 32 + * 192 | 11000000 | 64 + */ + usize = s2u(ALIGNMENT_CEILING(size, alignment)); + if (usize < LARGE_MINCLASS) + return (usize); } - if (usize <= arena_maxclass && alignment <= PAGE) { - if (usize <= SMALL_MAXCLASS) - return (arena_bin_info[SMALL_SIZE2BIN(usize)].reg_size); - return (PAGE_CEILING(usize)); - } else { - size_t run_size; - + /* Try for a large size class. */ + if (likely(size <= arena_maxclass) && likely(alignment < chunksize)) { /* * We can't achieve subpage alignment, so round up alignment - * permanently; it makes later calculations simpler. + * to the minimum that can actually be supported. */ alignment = PAGE_CEILING(alignment); - usize = PAGE_CEILING(size); - /* - * (usize < size) protects against very large sizes within - * PAGE of SIZE_T_MAX. - * - * (usize + alignment < usize) protects against the - * combination of maximal alignment and usize large enough - * to cause overflow. This is similar to the first overflow - * check above, but it needs to be repeated due to the new - * usize value, which may now be *equal* to maximal - * alignment, whereas before we only detected overflow if the - * original size was *greater* than maximal alignment. - */ - if (usize < size || usize + alignment < usize) { - /* size_t overflow. */ - return (0); - } + + /* Make sure result is a large size class. */ + usize = (size <= LARGE_MINCLASS) ? LARGE_MINCLASS : s2u(size); /* * Calculate the size of the over-size run that arena_palloc() * would need to allocate in order to guarantee the alignment. - * If the run wouldn't fit within a chunk, round up to a huge - * allocation size. */ - run_size = usize + alignment - PAGE; - if (run_size <= arena_maxclass) - return (PAGE_CEILING(usize)); - return (CHUNK_CEILING(usize)); + if (usize + alignment - PAGE <= arena_maxrun) + return (usize); } -} -JEMALLOC_INLINE unsigned -narenas_total_get(void) -{ - unsigned narenas; + /* Huge size class. Beware of size_t overflow. */ - malloc_mutex_lock(&arenas_lock); - narenas = narenas_total; - malloc_mutex_unlock(&arenas_lock); + /* + * We can't achieve subchunk alignment, so round up alignment to the + * minimum that can actually be supported. + */ + alignment = CHUNK_CEILING(alignment); + if (alignment == 0) { + /* size_t overflow. */ + return (0); + } - return (narenas); + /* Make sure result is a huge size class. */ + if (size <= chunksize) + usize = chunksize; + else { + usize = s2u(size); + if (usize < size) { + /* size_t overflow. */ + return (0); + } + } + + /* + * Calculate the multi-chunk mapping that huge_palloc() would need in + * order to guarantee the alignment. + */ + if (usize + alignment - PAGE < usize) { + /* size_t overflow. */ + return (0); + } + return (usize); } /* Choose an arena based on a per-thread value. */ JEMALLOC_INLINE arena_t * -choose_arena(arena_t *arena) +arena_choose(tsd_t *tsd, arena_t *arena) { arena_t *ret; if (arena != NULL) return (arena); - if ((ret = *arenas_tsd_get()) == NULL) { - ret = choose_arena_hard(); - assert(ret != NULL); - } + if (unlikely((ret = tsd_arena_get(tsd)) == NULL)) + ret = arena_choose_hard(tsd); return (ret); } + +JEMALLOC_INLINE arena_t * +arena_get(tsd_t *tsd, unsigned ind, bool init_if_missing, + bool refresh_if_missing) +{ + arena_t *arena; + arena_t **arenas_cache = tsd_arenas_cache_get(tsd); + + /* init_if_missing requires refresh_if_missing. */ + assert(!init_if_missing || refresh_if_missing); + + if (unlikely(arenas_cache == NULL)) { + /* arenas_cache hasn't been initialized yet. */ + return (arena_get_hard(tsd, ind, init_if_missing)); + } + if (unlikely(ind >= tsd_narenas_cache_get(tsd))) { + /* + * ind is invalid, cache is old (too small), or arena to be + * initialized. + */ + return (refresh_if_missing ? arena_get_hard(tsd, ind, + init_if_missing) : NULL); + } + arena = arenas_cache[ind]; + if (likely(arena != NULL) || !refresh_if_missing) + return (arena); + if (init_if_missing) + return (arena_get_hard(tsd, ind, init_if_missing)); + else + return (NULL); +} #endif #include "jemalloc/internal/bitmap.h" #include "jemalloc/internal/rtree.h" /* - * Include arena.h twice in order to resolve circular dependencies with - * tcache.h. + * Include portions of arena.h interleaved with tcache.h in order to resolve + * circular dependencies. */ #define JEMALLOC_ARENA_INLINE_A #include "jemalloc/internal/arena.h" @@ -738,72 +777,73 @@ choose_arena(arena_t *arena) #include "jemalloc/internal/quarantine.h" #ifndef JEMALLOC_ENABLE_INLINE -void *imalloct(size_t size, bool try_tcache, arena_t *arena); -void *imalloc(size_t size); -void *icalloct(size_t size, bool try_tcache, arena_t *arena); -void *icalloc(size_t size); -void *ipalloct(size_t usize, size_t alignment, bool zero, bool try_tcache, - arena_t *arena); -void *ipalloc(size_t usize, size_t alignment, bool zero); +void *imalloct(tsd_t *tsd, size_t size, bool try_tcache, arena_t *arena); +void *imalloc(tsd_t *tsd, size_t size); +void *icalloct(tsd_t *tsd, size_t size, bool try_tcache, arena_t *arena); +void *icalloc(tsd_t *tsd, size_t size); +void *ipalloct(tsd_t *tsd, size_t usize, size_t alignment, bool zero, + bool try_tcache, arena_t *arena); +void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero); size_t isalloc(const void *ptr, bool demote); size_t ivsalloc(const void *ptr, bool demote); size_t u2rz(size_t usize); size_t p2rz(const void *ptr); -void idalloct(void *ptr, bool try_tcache); -void idalloc(void *ptr); -void iqalloct(void *ptr, bool try_tcache); -void iqalloc(void *ptr); -void *iralloct_realign(void *ptr, size_t oldsize, size_t size, size_t extra, +void idalloct(tsd_t *tsd, void *ptr, bool try_tcache); +void isdalloct(tsd_t *tsd, void *ptr, size_t size, bool try_tcache); +void idalloc(tsd_t *tsd, void *ptr); +void iqalloc(tsd_t *tsd, void *ptr, bool try_tcache); +void isqalloc(tsd_t *tsd, void *ptr, size_t size, bool try_tcache); +void *iralloct_realign(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, + size_t extra, size_t alignment, bool zero, bool try_tcache_alloc, + bool try_tcache_dalloc, arena_t *arena); +void *iralloct(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, bool try_tcache_alloc, bool try_tcache_dalloc, arena_t *arena); -void *iralloct(void *ptr, size_t size, size_t extra, size_t alignment, - bool zero, bool try_tcache_alloc, bool try_tcache_dalloc, arena_t *arena); -void *iralloc(void *ptr, size_t size, size_t extra, size_t alignment, - bool zero); -bool ixalloc(void *ptr, size_t size, size_t extra, size_t alignment, - bool zero); -malloc_tsd_protos(JEMALLOC_ATTR(unused), thread_allocated, thread_allocated_t) +void *iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, + size_t alignment, bool zero); +bool ixalloc(void *ptr, size_t oldsize, size_t size, size_t extra, + size_t alignment, bool zero); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) JEMALLOC_ALWAYS_INLINE void * -imalloct(size_t size, bool try_tcache, arena_t *arena) +imalloct(tsd_t *tsd, size_t size, bool try_tcache, arena_t *arena) { assert(size != 0); - if (size <= arena_maxclass) - return (arena_malloc(arena, size, false, try_tcache)); + if (likely(size <= arena_maxclass)) + return (arena_malloc(tsd, arena, size, false, try_tcache)); else - return (huge_malloc(size, false, huge_dss_prec_get(arena))); + return (huge_malloc(tsd, arena, size, false, try_tcache)); } JEMALLOC_ALWAYS_INLINE void * -imalloc(size_t size) +imalloc(tsd_t *tsd, size_t size) { - return (imalloct(size, true, NULL)); + return (imalloct(tsd, size, true, NULL)); } JEMALLOC_ALWAYS_INLINE void * -icalloct(size_t size, bool try_tcache, arena_t *arena) +icalloct(tsd_t *tsd, size_t size, bool try_tcache, arena_t *arena) { - if (size <= arena_maxclass) - return (arena_malloc(arena, size, true, try_tcache)); + if (likely(size <= arena_maxclass)) + return (arena_malloc(tsd, arena, size, true, try_tcache)); else - return (huge_malloc(size, true, huge_dss_prec_get(arena))); + return (huge_malloc(tsd, arena, size, true, try_tcache)); } JEMALLOC_ALWAYS_INLINE void * -icalloc(size_t size) +icalloc(tsd_t *tsd, size_t size) { - return (icalloct(size, true, NULL)); + return (icalloct(tsd, size, true, NULL)); } JEMALLOC_ALWAYS_INLINE void * -ipalloct(size_t usize, size_t alignment, bool zero, bool try_tcache, +ipalloct(tsd_t *tsd, size_t usize, size_t alignment, bool zero, bool try_tcache, arena_t *arena) { void *ret; @@ -811,16 +851,20 @@ ipalloct(size_t usize, size_t alignment, bool zero, bool try_tcache, assert(usize != 0); assert(usize == sa2u(usize, alignment)); - if (usize <= arena_maxclass && alignment <= PAGE) - ret = arena_malloc(arena, usize, zero, try_tcache); + if (usize <= SMALL_MAXCLASS && alignment < PAGE) + ret = arena_malloc(tsd, arena, usize, zero, try_tcache); else { - if (usize <= arena_maxclass) { - ret = arena_palloc(choose_arena(arena), usize, - alignment, zero); - } else if (alignment <= chunksize) - ret = huge_malloc(usize, zero, huge_dss_prec_get(arena)); - else - ret = huge_palloc(usize, alignment, zero, huge_dss_prec_get(arena)); + if (likely(usize <= arena_maxclass)) { + arena = arena_choose(tsd, arena); + if (unlikely(arena == NULL)) + return (NULL); + ret = arena_palloc(arena, usize, alignment, zero); + } else if (likely(alignment <= chunksize)) + ret = huge_malloc(tsd, arena, usize, zero, try_tcache); + else { + ret = huge_palloc(tsd, arena, usize, alignment, zero, + try_tcache); + } } assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret); @@ -828,10 +872,10 @@ ipalloct(size_t usize, size_t alignment, bool zero, bool try_tcache, } JEMALLOC_ALWAYS_INLINE void * -ipalloc(size_t usize, size_t alignment, bool zero) +ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero) { - return (ipalloct(usize, alignment, zero, true, NULL)); + return (ipalloct(tsd, usize, alignment, zero, true, NULL)); } /* @@ -847,10 +891,10 @@ isalloc(const void *ptr, bool demote) assert(ptr != NULL); /* Demotion only makes sense if config_prof is true. */ - assert(config_prof || demote == false); + assert(config_prof || !demote); chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (chunk != ptr) + if (likely(chunk != ptr)) ret = arena_salloc(ptr, demote); else ret = huge_salloc(ptr); @@ -875,7 +919,7 @@ u2rz(size_t usize) size_t ret; if (usize <= SMALL_MAXCLASS) { - size_t binind = SMALL_SIZE2BIN(usize); + index_t binind = size2index(usize); ret = arena_bin_info[binind].redzone_size; } else ret = 0; @@ -892,47 +936,64 @@ p2rz(const void *ptr) } JEMALLOC_ALWAYS_INLINE void -idalloct(void *ptr, bool try_tcache) +idalloct(tsd_t *tsd, void *ptr, bool try_tcache) { arena_chunk_t *chunk; assert(ptr != NULL); chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (chunk != ptr) - arena_dalloc(chunk->arena, chunk, ptr, try_tcache); + if (likely(chunk != ptr)) + arena_dalloc(tsd, chunk, ptr, try_tcache); else - huge_dalloc(ptr, true); + huge_dalloc(tsd, ptr, try_tcache); } JEMALLOC_ALWAYS_INLINE void -idalloc(void *ptr) +isdalloct(tsd_t *tsd, void *ptr, size_t size, bool try_tcache) { + arena_chunk_t *chunk; - idalloct(ptr, true); -} + assert(ptr != NULL); -JEMALLOC_ALWAYS_INLINE void -iqalloct(void *ptr, bool try_tcache) -{ - - if (config_fill && opt_quarantine) - quarantine(ptr); + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + if (likely(chunk != ptr)) + arena_sdalloc(tsd, chunk, ptr, size, try_tcache); else - idalloct(ptr, try_tcache); + huge_dalloc(tsd, ptr, try_tcache); } JEMALLOC_ALWAYS_INLINE void -iqalloc(void *ptr) +idalloc(tsd_t *tsd, void *ptr) { - iqalloct(ptr, true); + idalloct(tsd, ptr, true); +} + +JEMALLOC_ALWAYS_INLINE void +iqalloc(tsd_t *tsd, void *ptr, bool try_tcache) +{ + + if (config_fill && unlikely(opt_quarantine)) + quarantine(tsd, ptr); + else + idalloct(tsd, ptr, try_tcache); +} + +JEMALLOC_ALWAYS_INLINE void +isqalloc(tsd_t *tsd, void *ptr, size_t size, bool try_tcache) +{ + + if (config_fill && unlikely(opt_quarantine)) + quarantine(tsd, ptr); + else + isdalloct(tsd, ptr, size, try_tcache); } JEMALLOC_ALWAYS_INLINE void * -iralloct_realign(void *ptr, size_t oldsize, size_t size, size_t extra, - size_t alignment, bool zero, bool try_tcache_alloc, bool try_tcache_dalloc, - arena_t *arena) +iralloct_realign(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, + size_t extra, size_t alignment, bool zero, bool try_tcache_alloc, + bool try_tcache_dalloc, arena_t *arena) { void *p; size_t usize, copysize; @@ -940,7 +1001,7 @@ iralloct_realign(void *ptr, size_t oldsize, size_t size, size_t extra, usize = sa2u(size + extra, alignment); if (usize == 0) return (NULL); - p = ipalloct(usize, alignment, zero, try_tcache_alloc, arena); + p = ipalloct(tsd, usize, alignment, zero, try_tcache_alloc, arena); if (p == NULL) { if (extra == 0) return (NULL); @@ -948,7 +1009,8 @@ iralloct_realign(void *ptr, size_t oldsize, size_t size, size_t extra, usize = sa2u(size, alignment); if (usize == 0) return (NULL); - p = ipalloct(usize, alignment, zero, try_tcache_alloc, arena); + p = ipalloct(tsd, usize, alignment, zero, try_tcache_alloc, + arena); if (p == NULL) return (NULL); } @@ -958,72 +1020,65 @@ iralloct_realign(void *ptr, size_t oldsize, size_t size, size_t extra, */ copysize = (size < oldsize) ? size : oldsize; memcpy(p, ptr, copysize); - iqalloct(ptr, try_tcache_dalloc); + isqalloc(tsd, ptr, oldsize, try_tcache_dalloc); return (p); } JEMALLOC_ALWAYS_INLINE void * -iralloct(void *ptr, size_t size, size_t extra, size_t alignment, bool zero, - bool try_tcache_alloc, bool try_tcache_dalloc, arena_t *arena) +iralloct(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment, + bool zero, bool try_tcache_alloc, bool try_tcache_dalloc, arena_t *arena) { - size_t oldsize; assert(ptr != NULL); assert(size != 0); - oldsize = isalloc(ptr, config_prof); - if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1)) != 0) { /* * Existing object alignment is inadequate; allocate new space * and copy. */ - return (iralloct_realign(ptr, oldsize, size, extra, alignment, + return (iralloct_realign(tsd, ptr, oldsize, size, 0, alignment, zero, try_tcache_alloc, try_tcache_dalloc, arena)); } - if (size + extra <= arena_maxclass) { - return (arena_ralloc(arena, ptr, oldsize, size, extra, - alignment, zero, try_tcache_alloc, - try_tcache_dalloc)); + if (likely(size <= arena_maxclass)) { + return (arena_ralloc(tsd, arena, ptr, oldsize, size, 0, + alignment, zero, try_tcache_alloc, try_tcache_dalloc)); } else { - return (huge_ralloc(ptr, oldsize, size, extra, - alignment, zero, try_tcache_dalloc, huge_dss_prec_get(arena))); + return (huge_ralloc(tsd, arena, ptr, oldsize, size, 0, + alignment, zero, try_tcache_alloc, try_tcache_dalloc)); } } JEMALLOC_ALWAYS_INLINE void * -iralloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero) +iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment, + bool zero) { - return (iralloct(ptr, size, extra, alignment, zero, true, true, NULL)); + return (iralloct(tsd, ptr, oldsize, size, alignment, zero, true, true, + NULL)); } JEMALLOC_ALWAYS_INLINE bool -ixalloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero) +ixalloc(void *ptr, size_t oldsize, size_t size, size_t extra, size_t alignment, + bool zero) { - size_t oldsize; assert(ptr != NULL); assert(size != 0); - oldsize = isalloc(ptr, config_prof); if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1)) != 0) { /* Existing object alignment is inadequate. */ return (true); } - if (size <= arena_maxclass) + if (likely(size <= arena_maxclass)) return (arena_ralloc_no_move(ptr, oldsize, size, extra, zero)); else - return (huge_ralloc_no_move(ptr, oldsize, size, extra)); + return (huge_ralloc_no_move(ptr, oldsize, size, extra, zero)); } - -malloc_tsd_externs(thread_allocated, thread_allocated_t) -malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, thread_allocated, thread_allocated_t, - THREAD_ALLOCATED_INITIALIZER, malloc_tsd_no_cleanup) #endif #include "jemalloc/internal/prof.h" diff --git a/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_decls.h b/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_decls.h new file mode 100644 index 000000000000..fb2effbf2a83 --- /dev/null +++ b/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_decls.h @@ -0,0 +1,60 @@ +#ifndef JEMALLOC_INTERNAL_DECLS_H +#define JEMALLOC_INTERNAL_DECLS_H + +#include +#ifdef _WIN32 +# include +# define ENOENT ERROR_PATH_NOT_FOUND +# define EINVAL ERROR_BAD_ARGUMENTS +# define EAGAIN ERROR_OUTOFMEMORY +# define EPERM ERROR_WRITE_FAULT +# define EFAULT ERROR_INVALID_ADDRESS +# define ENOMEM ERROR_NOT_ENOUGH_MEMORY +# undef ERANGE +# define ERANGE ERROR_INVALID_DATA +#else +# include +# include +# if !defined(__pnacl__) && !defined(__native_client__) +# include +# if !defined(SYS_write) && defined(__NR_write) +# define SYS_write __NR_write +# endif +# include +# endif +# include +# include +#endif +#include + +#include +#ifndef SIZE_T_MAX +# define SIZE_T_MAX SIZE_MAX +#endif +#include +#include +#include +#include +#include +#include +#ifndef offsetof +# define offsetof(type, member) ((size_t)&(((type *)NULL)->member)) +#endif +#include +#include +#include +#include +#ifdef _MSC_VER +# include +typedef intptr_t ssize_t; +# define PATH_MAX 1024 +# define STDERR_FILENO 2 +# define __func__ __FUNCTION__ +/* Disable warnings about deprecated system functions. */ +# pragma warning(disable: 4996) +#else +# include +#endif +#include + +#endif /* JEMALLOC_INTERNAL_H */ diff --git a/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_defs.h.in b/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_defs.h.in index 1a2587bc70af..c8d7dafbaa4e 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -22,6 +22,9 @@ */ #undef CPU_SPINWAIT +/* Defined if C11 atomics are available. */ +#undef JEMALLOC_C11ATOMICS + /* Defined if the equivalent of FreeBSD's atomic(9) functions are available. */ #undef JEMALLOC_ATOMIC9 @@ -35,7 +38,7 @@ * Defined if __sync_add_and_fetch(uint32_t *, uint32_t) and * __sync_sub_and_fetch(uint32_t *, uint32_t) are available, despite * __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 not being defined (which means the - * functions are defined in libgcc instead of being inlines) + * functions are defined in libgcc instead of being inlines). */ #undef JE_FORCE_SYNC_COMPARE_AND_SWAP_4 @@ -43,16 +46,36 @@ * Defined if __sync_add_and_fetch(uint64_t *, uint64_t) and * __sync_sub_and_fetch(uint64_t *, uint64_t) are available, despite * __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 not being defined (which means the - * functions are defined in libgcc instead of being inlines) + * functions are defined in libgcc instead of being inlines). */ #undef JE_FORCE_SYNC_COMPARE_AND_SWAP_8 +/* + * Defined if __builtin_clz() and __builtin_clzl() are available. + */ +#undef JEMALLOC_HAVE_BUILTIN_CLZ + +/* + * Defined if madvise(2) is available. + */ +#undef JEMALLOC_HAVE_MADVISE + /* * Defined if OSSpin*() functions are available, as provided by Darwin, and * documented in the spinlock(3) manual page. */ #undef JEMALLOC_OSSPIN +/* + * Defined if secure_getenv(3) is available. + */ +#undef JEMALLOC_HAVE_SECURE_GETENV + +/* + * Defined if issetugid(2) is available. + */ +#undef JEMALLOC_HAVE_ISSETUGID + /* * Defined if _malloc_thread_cleanup() exists. At least in the case of * FreeBSD, pthread_key_create() allocates, which if used during malloc @@ -76,9 +99,6 @@ */ #undef JEMALLOC_MUTEX_INIT_CB -/* Defined if sbrk() is supported. */ -#undef JEMALLOC_HAVE_SBRK - /* Non-empty if the tls_model attribute is supported. */ #undef JEMALLOC_TLS_MODEL @@ -137,8 +157,17 @@ /* Support lazy locking (avoid locking unless a second thread is launched). */ #undef JEMALLOC_LAZY_LOCK -/* One page is 2^STATIC_PAGE_SHIFT bytes. */ -#undef STATIC_PAGE_SHIFT +/* Minimum size class to support is 2^LG_TINY_MIN bytes. */ +#undef LG_TINY_MIN + +/* + * Minimum allocation alignment is 2^LG_QUANTUM bytes (ignoring tiny size + * classes). + */ +#undef LG_QUANTUM + +/* One page is 2^LG_PAGE bytes. */ +#undef LG_PAGE /* * If defined, use munmap() to unmap freed chunks, rather than storing them for @@ -147,13 +176,6 @@ */ #undef JEMALLOC_MUNMAP -/* - * If defined, use mremap(...MREMAP_FIXED...) for huge realloc(). This is - * disabled by default because it is Linux-specific and it will cause virtual - * memory map holes, much like munmap(2) does. - */ -#undef JEMALLOC_MREMAP - /* TLS is used to map arenas and magazine caches to threads. */ #undef JEMALLOC_TLS @@ -189,9 +211,7 @@ #undef JEMALLOC_PURGE_MADVISE_DONTNEED #undef JEMALLOC_PURGE_MADVISE_FREE -/* - * Define if operating system has alloca.h header. - */ +/* Define if operating system has alloca.h header. */ #undef JEMALLOC_HAS_ALLOCA_H /* C99 restrict keyword supported. */ @@ -209,4 +229,13 @@ /* sizeof(intmax_t) == 2^LG_SIZEOF_INTMAX_T. */ #undef LG_SIZEOF_INTMAX_T +/* glibc malloc hooks (__malloc_hook, __realloc_hook, __free_hook). */ +#undef JEMALLOC_GLIBC_MALLOC_HOOK + +/* glibc memalign hook. */ +#undef JEMALLOC_GLIBC_MEMALIGN_HOOK + +/* Adaptive mutex support in pthreads. */ +#undef JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP + #endif /* JEMALLOC_INTERNAL_DEFS_H_ */ diff --git a/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_macros.h b/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_macros.h index 4e2392302c76..a08ba772ead4 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_macros.h +++ b/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_macros.h @@ -39,9 +39,15 @@ #endif #define ZU(z) ((size_t)z) +#define ZI(z) ((ssize_t)z) #define QU(q) ((uint64_t)q) #define QI(q) ((int64_t)q) +#define KZU(z) ZU(z##ULL) +#define KZI(z) ZI(z##LL) +#define KQU(q) QU(q##ULL) +#define KQI(q) QI(q##LL) + #ifndef __DECONST # define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) #endif diff --git a/memory/jemalloc/src/include/jemalloc/internal/mutex.h b/memory/jemalloc/src/include/jemalloc/internal/mutex.h index de44e1435ad3..8a03d82504ec 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/mutex.h +++ b/memory/jemalloc/src/include/jemalloc/internal/mutex.h @@ -10,7 +10,7 @@ typedef struct malloc_mutex_s malloc_mutex_t; #elif (defined(JEMALLOC_MUTEX_INIT_CB)) # define MALLOC_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER, NULL} #else -# if (defined(PTHREAD_MUTEX_ADAPTIVE_NP) && \ +# if (defined(JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP) && \ defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP)) # define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_ADAPTIVE_NP # define MALLOC_MUTEX_INITIALIZER {PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP} diff --git a/memory/jemalloc/src/include/jemalloc/internal/private_symbols.txt b/memory/jemalloc/src/include/jemalloc/internal/private_symbols.txt index 93516d242b69..7e339152487c 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/private_symbols.txt +++ b/memory/jemalloc/src/include/jemalloc/internal/private_symbols.txt @@ -1,20 +1,33 @@ a0calloc a0free +a0get a0malloc +arena_get +arena_get_hard arena_alloc_junk_small arena_bin_index arena_bin_info +arena_bitselm_get arena_boot +arena_choose +arena_choose_hard +arena_chunk_alloc_huge +arena_chunk_dalloc_huge +arena_chunk_ralloc_huge_expand +arena_chunk_ralloc_huge_shrink +arena_chunk_ralloc_huge_similar +arena_cleanup arena_dalloc arena_dalloc_bin -arena_dalloc_bin_locked +arena_dalloc_bin_junked_locked arena_dalloc_junk_large arena_dalloc_junk_small arena_dalloc_large -arena_dalloc_large_locked +arena_dalloc_large_junked_locked arena_dalloc_small arena_dss_prec_get arena_dss_prec_set +arena_init arena_malloc arena_malloc_large arena_malloc_small @@ -36,8 +49,13 @@ arena_mapbits_unzeroed_set arena_mapbitsp_get arena_mapbitsp_read arena_mapbitsp_write -arena_mapp_get arena_maxclass +arena_maxrun +arena_migrate +arena_miscelm_get +arena_miscelm_to_pageind +arena_miscelm_to_rpages +arena_nbound arena_new arena_palloc arena_postfork_child @@ -46,9 +64,9 @@ arena_prefork arena_prof_accum arena_prof_accum_impl arena_prof_accum_locked -arena_prof_ctx_get -arena_prof_ctx_set arena_prof_promoted +arena_prof_tctx_get +arena_prof_tctx_set arena_ptr_small_binind_get arena_purge_all arena_quarantine_junk_small @@ -57,23 +75,13 @@ arena_ralloc_junk_large arena_ralloc_no_move arena_redzone_corruption arena_run_regind +arena_run_to_miscelm arena_salloc +arena_sdalloc arena_stats_merge arena_tcache_fill_small -arenas -arenas_booted -arenas_cleanup -arenas_extend -arenas_initialized -arenas_lock -arenas_tls -arenas_tsd -arenas_tsd_boot -arenas_tsd_cleanup_wrapper -arenas_tsd_get -arenas_tsd_get_wrapper -arenas_tsd_init_head -arenas_tsd_set +arenas_cache_bypass_cleanup +arenas_cache_cleanup atomic_add_u atomic_add_uint32 atomic_add_uint64 @@ -86,7 +94,7 @@ base_alloc base_boot base_calloc base_node_alloc -base_node_dealloc +base_node_dalloc base_postfork_child base_postfork_parent base_prefork @@ -101,14 +109,14 @@ bitmap_size bitmap_unset bt_init buferror -choose_arena -choose_arena_hard -chunk_alloc +chunk_alloc_arena +chunk_alloc_base +chunk_alloc_default chunk_alloc_dss chunk_alloc_mmap chunk_boot -chunk_dealloc -chunk_dealloc_mmap +chunk_dalloc_default +chunk_dalloc_mmap chunk_dss_boot chunk_dss_postfork_child chunk_dss_postfork_parent @@ -197,41 +205,45 @@ huge_allocated huge_boot huge_dalloc huge_dalloc_junk -huge_dss_prec_get huge_malloc -huge_mtx huge_ndalloc huge_nmalloc huge_palloc huge_postfork_child huge_postfork_parent huge_prefork -huge_prof_ctx_get -huge_prof_ctx_set +huge_prof_tctx_get +huge_prof_tctx_set huge_ralloc huge_ralloc_no_move huge_salloc -iallocm icalloc icalloct idalloc idalloct imalloc imalloct +in_valgrind +index2size +index2size_compute +index2size_lookup +index2size_tab ipalloc ipalloct iqalloc -iqalloct iralloc iralloct iralloct_realign isalloc +isdalloct isthreaded +isqalloc ivsalloc ixalloc jemalloc_postfork_child jemalloc_postfork_parent jemalloc_prefork +lg_floor malloc_cprintf malloc_mutex_init malloc_mutex_lock @@ -242,7 +254,8 @@ malloc_mutex_unlock malloc_printf malloc_snprintf malloc_strtoumax -malloc_tsd_boot +malloc_tsd_boot0 +malloc_tsd_boot1 malloc_tsd_cleanup_register malloc_tsd_dalloc malloc_tsd_malloc @@ -251,16 +264,18 @@ malloc_vcprintf malloc_vsnprintf malloc_write map_bias +map_misc_offset mb_write mutex_boot -narenas_auto -narenas_total +narenas_cache_cleanup narenas_total_get ncpus nhbins opt_abort opt_dss opt_junk +opt_junk_alloc +opt_junk_free opt_lg_chunk opt_lg_dirty_mult opt_lg_prof_interval @@ -279,61 +294,54 @@ opt_redzone opt_stats_print opt_tcache opt_utrace -opt_valgrind opt_xmalloc opt_zero p2rz pages_purge pow2_ceil +prof_active_get +prof_active_get_unlocked +prof_active_set +prof_alloc_prep +prof_alloc_rollback prof_backtrace prof_boot0 prof_boot1 prof_boot2 prof_bt_count -prof_ctx_get -prof_ctx_set +prof_dump_header prof_dump_open prof_free +prof_free_sampled_object prof_gdump prof_idump prof_interval prof_lookup prof_malloc +prof_malloc_sample_object prof_mdump prof_postfork_child prof_postfork_parent prof_prefork -prof_promote prof_realloc +prof_reset prof_sample_accum_update prof_sample_threshold_update -prof_tdata_booted +prof_tctx_get +prof_tctx_set prof_tdata_cleanup prof_tdata_get prof_tdata_init -prof_tdata_initialized -prof_tdata_tls -prof_tdata_tsd -prof_tdata_tsd_boot -prof_tdata_tsd_cleanup_wrapper -prof_tdata_tsd_get -prof_tdata_tsd_get_wrapper -prof_tdata_tsd_init_head -prof_tdata_tsd_set +prof_thread_active_get +prof_thread_active_init_get +prof_thread_active_init_set +prof_thread_active_set +prof_thread_name_get +prof_thread_name_set quarantine quarantine_alloc_hook -quarantine_boot -quarantine_booted +quarantine_alloc_hook_work quarantine_cleanup -quarantine_init -quarantine_tls -quarantine_tsd -quarantine_tsd_boot -quarantine_tsd_cleanup_wrapper -quarantine_tsd_get -quarantine_tsd_get_wrapper -quarantine_tsd_init_head -quarantine_tsd_set register_zone rtree_delete rtree_get @@ -344,9 +352,14 @@ rtree_postfork_parent rtree_prefork rtree_set s2u +s2u_compute +s2u_lookup sa2u set_errno -small_size2bin +size2index +size2index_compute +size2index_lookup +size2index_tab stats_cactive stats_cactive_add stats_cactive_get @@ -359,55 +372,62 @@ tcache_alloc_small tcache_alloc_small_hard tcache_arena_associate tcache_arena_dissociate +tcache_arena_reassociate tcache_bin_flush_large tcache_bin_flush_small tcache_bin_info -tcache_boot0 -tcache_boot1 -tcache_booted +tcache_boot +tcache_cleanup tcache_create tcache_dalloc_large tcache_dalloc_small -tcache_destroy -tcache_enabled_booted +tcache_enabled_cleanup tcache_enabled_get -tcache_enabled_initialized tcache_enabled_set -tcache_enabled_tls -tcache_enabled_tsd -tcache_enabled_tsd_boot -tcache_enabled_tsd_cleanup_wrapper -tcache_enabled_tsd_get -tcache_enabled_tsd_get_wrapper -tcache_enabled_tsd_init_head -tcache_enabled_tsd_set tcache_event tcache_event_hard tcache_flush tcache_get -tcache_initialized +tcache_get_hard tcache_maxclass tcache_salloc tcache_stats_merge -tcache_thread_cleanup -tcache_tls -tcache_tsd -tcache_tsd_boot -tcache_tsd_cleanup_wrapper -tcache_tsd_get -tcache_tsd_get_wrapper -tcache_tsd_init_head -tcache_tsd_set -thread_allocated_booted -thread_allocated_initialized -thread_allocated_tls -thread_allocated_tsd -thread_allocated_tsd_boot -thread_allocated_tsd_cleanup_wrapper -thread_allocated_tsd_get -thread_allocated_tsd_get_wrapper -thread_allocated_tsd_init_head -thread_allocated_tsd_set +thread_allocated_cleanup +thread_deallocated_cleanup +tsd_booted +tsd_arena_get +tsd_arena_set +tsd_boot +tsd_boot0 +tsd_boot1 +tsd_cleanup +tsd_cleanup_wrapper +tsd_fetch +tsd_get +tsd_wrapper_get +tsd_wrapper_set +tsd_initialized tsd_init_check_recursion tsd_init_finish +tsd_init_head +tsd_nominal +tsd_quarantine_get +tsd_quarantine_set +tsd_set +tsd_tcache_enabled_get +tsd_tcache_enabled_set +tsd_tcache_get +tsd_tcache_set +tsd_tls +tsd_tsd +tsd_prof_tdata_get +tsd_prof_tdata_set +tsd_thread_allocated_get +tsd_thread_allocated_set +tsd_thread_deallocated_get +tsd_thread_deallocated_set u2rz +valgrind_freelike_block +valgrind_make_mem_defined +valgrind_make_mem_noaccess +valgrind_make_mem_undefined diff --git a/memory/jemalloc/src/include/jemalloc/internal/prng.h b/memory/jemalloc/src/include/jemalloc/internal/prng.h index 7b2b06512ffc..c6b1797226e0 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/prng.h +++ b/memory/jemalloc/src/include/jemalloc/internal/prng.h @@ -15,7 +15,7 @@ * See Knuth's TAOCP 3rd Ed., Vol. 2, pg. 17 for details on these constraints. * * This choice of m has the disadvantage that the quality of the bits is - * proportional to bit position. For example. the lowest bit has a cycle of 2, + * proportional to bit position. For example, the lowest bit has a cycle of 2, * the next has a cycle of 4, etc. For this reason, we prefer to use the upper * bits. * diff --git a/memory/jemalloc/src/include/jemalloc/internal/prof.h b/memory/jemalloc/src/include/jemalloc/internal/prof.h index 6f162d21e840..e08188493474 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/prof.h +++ b/memory/jemalloc/src/include/jemalloc/internal/prof.h @@ -3,8 +3,8 @@ typedef struct prof_bt_s prof_bt_t; typedef struct prof_cnt_s prof_cnt_t; -typedef struct prof_thr_cnt_s prof_thr_cnt_t; -typedef struct prof_ctx_s prof_ctx_t; +typedef struct prof_tctx_s prof_tctx_t; +typedef struct prof_gctx_s prof_gctx_t; typedef struct prof_tdata_s prof_tdata_t; /* Option defaults. */ @@ -23,9 +23,6 @@ typedef struct prof_tdata_s prof_tdata_t; */ #define PROF_BT_MAX 128 -/* Maximum number of backtraces to store in each per thread LRU cache. */ -#define PROF_TCMAX 1024 - /* Initial hash table size. */ #define PROF_CKH_MINITEMS 64 @@ -36,11 +33,17 @@ typedef struct prof_tdata_s prof_tdata_t; #define PROF_PRINTF_BUFSIZE 128 /* - * Number of mutexes shared among all ctx's. No space is allocated for these + * Number of mutexes shared among all gctx's. No space is allocated for these * unless profiling is enabled, so it's okay to over-provision. */ #define PROF_NCTX_LOCKS 1024 +/* + * Number of mutexes shared among all tdata's. No space is allocated for these + * unless profiling is enabled, so it's okay to over-provision. + */ +#define PROF_NTDATA_LOCKS 256 + /* * prof_tdata pointers close to NULL are used to encode state information that * is used for cleaning up during thread shutdown. @@ -63,141 +66,163 @@ struct prof_bt_s { /* Data structure passed to libgcc _Unwind_Backtrace() callback functions. */ typedef struct { prof_bt_t *bt; - unsigned nignore; unsigned max; } prof_unwind_data_t; #endif struct prof_cnt_s { - /* - * Profiling counters. An allocation/deallocation pair can operate on - * different prof_thr_cnt_t objects that are linked into the same - * prof_ctx_t cnts_ql, so it is possible for the cur* counters to go - * negative. In principle it is possible for the *bytes counters to - * overflow/underflow, but a general solution would require something - * like 128-bit counters; this implementation doesn't bother to solve - * that problem. - */ - int64_t curobjs; - int64_t curbytes; + /* Profiling counters. */ + uint64_t curobjs; + uint64_t curbytes; uint64_t accumobjs; uint64_t accumbytes; }; -struct prof_thr_cnt_s { - /* Linkage into prof_ctx_t's cnts_ql. */ - ql_elm(prof_thr_cnt_t) cnts_link; +typedef enum { + prof_tctx_state_initializing, + prof_tctx_state_nominal, + prof_tctx_state_dumping, + prof_tctx_state_purgatory /* Dumper must finish destroying. */ +} prof_tctx_state_t; - /* Linkage into thread's LRU. */ - ql_elm(prof_thr_cnt_t) lru_link; +struct prof_tctx_s { + /* Thread data for thread that performed the allocation. */ + prof_tdata_t *tdata; /* - * Associated context. If a thread frees an object that it did not - * allocate, it is possible that the context is not cached in the - * thread's hash table, in which case it must be able to look up the - * context, insert a new prof_thr_cnt_t into the thread's hash table, - * and link it into the prof_ctx_t's cnts_ql. + * Copy of tdata->thr_uid, necessary because tdata may be defunct during + * teardown. */ - prof_ctx_t *ctx; + uint64_t thr_uid; - /* - * Threads use memory barriers to update the counters. Since there is - * only ever one writer, the only challenge is for the reader to get a - * consistent read of the counters. - * - * The writer uses this series of operations: - * - * 1) Increment epoch to an odd number. - * 2) Update counters. - * 3) Increment epoch to an even number. - * - * The reader must assure 1) that the epoch is even while it reads the - * counters, and 2) that the epoch doesn't change between the time it - * starts and finishes reading the counters. - */ - unsigned epoch; - - /* Profiling counters. */ + /* Profiling counters, protected by tdata->lock. */ prof_cnt_t cnts; + + /* Associated global context. */ + prof_gctx_t *gctx; + + /* Linkage into gctx's tctxs. */ + rb_node(prof_tctx_t) tctx_link; + + /* + * True during prof_alloc_prep()..prof_malloc_sample_object(), prevents + * sample vs destroy race. + */ + bool prepared; + + /* Current dump-related state, protected by gctx->lock. */ + prof_tctx_state_t state; + + /* + * Copy of cnts snapshotted during early dump phase, protected by + * dump_mtx. + */ + prof_cnt_t dump_cnts; }; +typedef rb_tree(prof_tctx_t) prof_tctx_tree_t; -struct prof_ctx_s { - /* Associated backtrace. */ - prof_bt_t *bt; - - /* Protects nlimbo, cnt_merged, and cnts_ql. */ +struct prof_gctx_s { + /* Protects nlimbo, cnt_summed, and tctxs. */ malloc_mutex_t *lock; /* - * Number of threads that currently cause this ctx to be in a state of + * Number of threads that currently cause this gctx to be in a state of * limbo due to one of: - * - Initializing per thread counters associated with this ctx. - * - Preparing to destroy this ctx. - * - Dumping a heap profile that includes this ctx. + * - Initializing this gctx. + * - Initializing per thread counters associated with this gctx. + * - Preparing to destroy this gctx. + * - Dumping a heap profile that includes this gctx. * nlimbo must be 1 (single destroyer) in order to safely destroy the - * ctx. + * gctx. */ unsigned nlimbo; + /* + * Tree of profile counters, one for each thread that has allocated in + * this context. + */ + prof_tctx_tree_t tctxs; + + /* Linkage for tree of contexts to be dumped. */ + rb_node(prof_gctx_t) dump_link; + /* Temporary storage for summation during dump. */ prof_cnt_t cnt_summed; - /* When threads exit, they merge their stats into cnt_merged. */ - prof_cnt_t cnt_merged; + /* Associated backtrace. */ + prof_bt_t bt; - /* - * List of profile counters, one for each thread that has allocated in - * this context. - */ - ql_head(prof_thr_cnt_t) cnts_ql; - - /* Linkage for list of contexts to be dumped. */ - ql_elm(prof_ctx_t) dump_link; + /* Backtrace vector, variable size, referred to by bt. */ + void *vec[1]; }; -typedef ql_head(prof_ctx_t) prof_ctx_list_t; +typedef rb_tree(prof_gctx_t) prof_gctx_tree_t; struct prof_tdata_s { + malloc_mutex_t *lock; + + /* Monotonically increasing unique thread identifier. */ + uint64_t thr_uid; + /* - * Hash of (prof_bt_t *)-->(prof_thr_cnt_t *). Each thread keeps a - * cache of backtraces, with associated thread-specific prof_thr_cnt_t - * objects. Other threads may read the prof_thr_cnt_t contents, but no - * others will ever write them. - * - * Upon thread exit, the thread must merge all the prof_thr_cnt_t - * counter data into the associated prof_ctx_t objects, and unlink/free - * the prof_thr_cnt_t objects. + * Monotonically increasing discriminator among tdata structures + * associated with the same thr_uid. */ - ckh_t bt2cnt; + uint64_t thr_discrim; - /* LRU for contents of bt2cnt. */ - ql_head(prof_thr_cnt_t) lru_ql; + /* Included in heap profile dumps if non-NULL. */ + char *thread_name; - /* Backtrace vector, used for calls to prof_backtrace(). */ - void **vec; + bool attached; + bool expired; + + rb_node(prof_tdata_t) tdata_link; + + /* + * Hash of (prof_bt_t *)-->(prof_tctx_t *). Each thread tracks + * backtraces for which it has non-zero allocation/deallocation counters + * associated with thread-specific prof_tctx_t objects. Other threads + * may write to prof_tctx_t contents when freeing associated objects. + */ + ckh_t bt2tctx; /* Sampling state. */ uint64_t prng_state; - uint64_t threshold; - uint64_t accum; + uint64_t bytes_until_sample; /* State used to avoid dumping while operating on prof internals. */ bool enq; bool enq_idump; bool enq_gdump; + + /* + * Set to true during an early dump phase for tdata's which are + * currently being dumped. New threads' tdata's have this initialized + * to false so that they aren't accidentally included in later dump + * phases. + */ + bool dumping; + + /* + * True if profiling is active for this tdata's thread + * (thread.prof.active mallctl). + */ + bool active; + + /* Temporary storage for summation during dump. */ + prof_cnt_t cnt_summed; + + /* Backtrace vector, used for calls to prof_backtrace(). */ + void *vec[PROF_BT_MAX]; }; +typedef rb_tree(prof_tdata_t) prof_tdata_tree_t; #endif /* JEMALLOC_H_STRUCTS */ /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS extern bool opt_prof; -/* - * Even if opt_prof is true, sampling can be temporarily disabled by setting - * opt_prof_active to false. No locking is used when updating opt_prof_active, - * so there are no guarantees regarding how long it will take for all threads - * to notice state changes. - */ extern bool opt_prof_active; +extern bool opt_prof_thread_active_init; extern size_t opt_lg_prof_sample; /* Mean bytes between samples. */ extern ssize_t opt_lg_prof_interval; /* lg(prof_interval). */ extern bool opt_prof_gdump; /* High-water memory dumping. */ @@ -211,6 +236,9 @@ extern char opt_prof_prefix[ #endif 1]; +/* Accessed via prof_active_[gs]et{_unlocked,}(). */ +extern bool prof_active; + /* * Profile dump interval, measured in bytes allocated. Each arena triggers a * profile dump when it reaches this threshold. The effect is that the @@ -221,191 +249,128 @@ extern char opt_prof_prefix[ extern uint64_t prof_interval; /* - * If true, promote small sampled objects to large objects, since small run - * headers do not have embedded profile context pointers. + * Initialized as opt_lg_prof_sample, and potentially modified during profiling + * resets. */ -extern bool prof_promote; +extern size_t lg_prof_sample; +void prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated); +void prof_malloc_sample_object(const void *ptr, size_t usize, + prof_tctx_t *tctx); +void prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx); void bt_init(prof_bt_t *bt, void **vec); -void prof_backtrace(prof_bt_t *bt, unsigned nignore); -prof_thr_cnt_t *prof_lookup(prof_bt_t *bt); +void prof_backtrace(prof_bt_t *bt); +prof_tctx_t *prof_lookup(tsd_t *tsd, prof_bt_t *bt); #ifdef JEMALLOC_JET +size_t prof_tdata_count(void); size_t prof_bt_count(void); +const prof_cnt_t *prof_cnt_all(void); typedef int (prof_dump_open_t)(bool, const char *); extern prof_dump_open_t *prof_dump_open; +typedef bool (prof_dump_header_t)(bool, const prof_cnt_t *); +extern prof_dump_header_t *prof_dump_header; #endif void prof_idump(void); bool prof_mdump(const char *filename); void prof_gdump(void); -prof_tdata_t *prof_tdata_init(void); -void prof_tdata_cleanup(void *arg); +prof_tdata_t *prof_tdata_init(tsd_t *tsd); +prof_tdata_t *prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata); +void prof_reset(tsd_t *tsd, size_t lg_sample); +void prof_tdata_cleanup(tsd_t *tsd); +const char *prof_thread_name_get(void); +bool prof_active_get(void); +bool prof_active_set(bool active); +int prof_thread_name_set(tsd_t *tsd, const char *thread_name); +bool prof_thread_active_get(void); +bool prof_thread_active_set(bool active); +bool prof_thread_active_init_get(void); +bool prof_thread_active_init_set(bool active_init); void prof_boot0(void); void prof_boot1(void); bool prof_boot2(void); void prof_prefork(void); void prof_postfork_parent(void); void prof_postfork_child(void); +void prof_sample_threshold_update(prof_tdata_t *tdata); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ #ifdef JEMALLOC_H_INLINES -#define PROF_ALLOC_PREP(nignore, size, ret) do { \ - prof_tdata_t *prof_tdata; \ - prof_bt_t bt; \ - \ - assert(size == s2u(size)); \ - \ - prof_tdata = prof_tdata_get(true); \ - if ((uintptr_t)prof_tdata <= (uintptr_t)PROF_TDATA_STATE_MAX) { \ - if (prof_tdata != NULL) \ - ret = (prof_thr_cnt_t *)(uintptr_t)1U; \ - else \ - ret = NULL; \ - break; \ - } \ - \ - if (opt_prof_active == false) { \ - /* Sampling is currently inactive, so avoid sampling. */\ - ret = (prof_thr_cnt_t *)(uintptr_t)1U; \ - } else if (opt_lg_prof_sample == 0) { \ - /* Don't bother with sampling logic, since sampling */\ - /* interval is 1. */\ - bt_init(&bt, prof_tdata->vec); \ - prof_backtrace(&bt, nignore); \ - ret = prof_lookup(&bt); \ - } else { \ - if (prof_tdata->threshold == 0) { \ - /* Initialize. Seed the prng differently for */\ - /* each thread. */\ - prof_tdata->prng_state = \ - (uint64_t)(uintptr_t)&size; \ - prof_sample_threshold_update(prof_tdata); \ - } \ - \ - /* Determine whether to capture a backtrace based on */\ - /* whether size is enough for prof_accum to reach */\ - /* prof_tdata->threshold. However, delay updating */\ - /* these variables until prof_{m,re}alloc(), because */\ - /* we don't know for sure that the allocation will */\ - /* succeed. */\ - /* */\ - /* Use subtraction rather than addition to avoid */\ - /* potential integer overflow. */\ - if (size >= prof_tdata->threshold - \ - prof_tdata->accum) { \ - bt_init(&bt, prof_tdata->vec); \ - prof_backtrace(&bt, nignore); \ - ret = prof_lookup(&bt); \ - } else \ - ret = (prof_thr_cnt_t *)(uintptr_t)1U; \ - } \ -} while (0) - #ifndef JEMALLOC_ENABLE_INLINE -malloc_tsd_protos(JEMALLOC_ATTR(unused), prof_tdata, prof_tdata_t *) - -prof_tdata_t *prof_tdata_get(bool create); -void prof_sample_threshold_update(prof_tdata_t *prof_tdata); -prof_ctx_t *prof_ctx_get(const void *ptr); -void prof_ctx_set(const void *ptr, size_t usize, prof_ctx_t *ctx); -bool prof_sample_accum_update(size_t size); -void prof_malloc(const void *ptr, size_t usize, prof_thr_cnt_t *cnt); -void prof_realloc(const void *ptr, size_t usize, prof_thr_cnt_t *cnt, - size_t old_usize, prof_ctx_t *old_ctx); -void prof_free(const void *ptr, size_t size); +bool prof_active_get_unlocked(void); +prof_tdata_t *prof_tdata_get(tsd_t *tsd, bool create); +bool prof_sample_accum_update(tsd_t *tsd, size_t usize, bool commit, + prof_tdata_t **tdata_out); +prof_tctx_t *prof_alloc_prep(tsd_t *tsd, size_t usize, bool update); +prof_tctx_t *prof_tctx_get(const void *ptr); +void prof_tctx_set(const void *ptr, prof_tctx_t *tctx); +void prof_malloc_sample_object(const void *ptr, size_t usize, + prof_tctx_t *tctx); +void prof_malloc(const void *ptr, size_t usize, prof_tctx_t *tctx); +void prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, + prof_tctx_t *tctx, bool updated, size_t old_usize, prof_tctx_t *old_tctx); +void prof_free(tsd_t *tsd, const void *ptr, size_t usize); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PROF_C_)) -/* Thread-specific backtrace cache, used to reduce bt2ctx contention. */ -malloc_tsd_externs(prof_tdata, prof_tdata_t *) -malloc_tsd_funcs(JEMALLOC_INLINE, prof_tdata, prof_tdata_t *, NULL, - prof_tdata_cleanup) - -JEMALLOC_INLINE prof_tdata_t * -prof_tdata_get(bool create) +JEMALLOC_ALWAYS_INLINE bool +prof_active_get_unlocked(void) { - prof_tdata_t *prof_tdata; + + /* + * Even if opt_prof is true, sampling can be temporarily disabled by + * setting prof_active to false. No locking is used when reading + * prof_active in the fast path, so there are no guarantees regarding + * how long it will take for all threads to notice state changes. + */ + return (prof_active); +} + +JEMALLOC_ALWAYS_INLINE prof_tdata_t * +prof_tdata_get(tsd_t *tsd, bool create) +{ + prof_tdata_t *tdata; cassert(config_prof); - prof_tdata = *prof_tdata_tsd_get(); - if (create && prof_tdata == NULL) - prof_tdata = prof_tdata_init(); + tdata = tsd_prof_tdata_get(tsd); + if (create) { + if (unlikely(tdata == NULL)) { + if (tsd_nominal(tsd)) { + tdata = prof_tdata_init(tsd); + tsd_prof_tdata_set(tsd, tdata); + } + } else if (unlikely(tdata->expired)) { + tdata = prof_tdata_reinit(tsd, tdata); + tsd_prof_tdata_set(tsd, tdata); + } + assert(tdata == NULL || tdata->attached); + } - return (prof_tdata); + return (tdata); } -JEMALLOC_INLINE void -prof_sample_threshold_update(prof_tdata_t *prof_tdata) +JEMALLOC_ALWAYS_INLINE prof_tctx_t * +prof_tctx_get(const void *ptr) { - /* - * The body of this function is compiled out unless heap profiling is - * enabled, so that it is possible to compile jemalloc with floating - * point support completely disabled. Avoiding floating point code is - * important on memory-constrained systems, but it also enables a - * workaround for versions of glibc that don't properly save/restore - * floating point registers during dynamic lazy symbol loading (which - * internally calls into whatever malloc implementation happens to be - * integrated into the application). Note that some compilers (e.g. - * gcc 4.8) may use floating point registers for fast memory moves, so - * jemalloc must be compiled with such optimizations disabled (e.g. - * -mno-sse) in order for the workaround to be complete. - */ -#ifdef JEMALLOC_PROF - uint64_t r; - double u; - - cassert(config_prof); - - /* - * Compute sample threshold as a geometrically distributed random - * variable with mean (2^opt_lg_prof_sample). - * - * __ __ - * | log(u) | 1 - * prof_tdata->threshold = | -------- |, where p = ------------------- - * | log(1-p) | opt_lg_prof_sample - * 2 - * - * For more information on the math, see: - * - * Non-Uniform Random Variate Generation - * Luc Devroye - * Springer-Verlag, New York, 1986 - * pp 500 - * (http://luc.devroye.org/rnbookindex.html) - */ - prng64(r, 53, prof_tdata->prng_state, - UINT64_C(6364136223846793005), UINT64_C(1442695040888963407)); - u = (double)r * (1.0/9007199254740992.0L); - prof_tdata->threshold = (uint64_t)(log(u) / - log(1.0 - (1.0 / (double)((uint64_t)1U << opt_lg_prof_sample)))) - + (uint64_t)1U; -#endif -} - -JEMALLOC_INLINE prof_ctx_t * -prof_ctx_get(const void *ptr) -{ - prof_ctx_t *ret; + prof_tctx_t *ret; arena_chunk_t *chunk; cassert(config_prof); assert(ptr != NULL); chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (chunk != ptr) { - /* Region. */ - ret = arena_prof_ctx_get(ptr); - } else - ret = huge_prof_ctx_get(ptr); + if (likely(chunk != ptr)) + ret = arena_prof_tctx_get(ptr); + else + ret = huge_prof_tctx_get(ptr); return (ret); } -JEMALLOC_INLINE void -prof_ctx_set(const void *ptr, size_t usize, prof_ctx_t *ctx) +JEMALLOC_ALWAYS_INLINE void +prof_tctx_set(const void *ptr, prof_tctx_t *tctx) { arena_chunk_t *chunk; @@ -413,199 +378,117 @@ prof_ctx_set(const void *ptr, size_t usize, prof_ctx_t *ctx) assert(ptr != NULL); chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (chunk != ptr) { - /* Region. */ - arena_prof_ctx_set(ptr, usize, ctx); - } else - huge_prof_ctx_set(ptr, ctx); + if (likely(chunk != ptr)) + arena_prof_tctx_set(ptr, tctx); + else + huge_prof_tctx_set(ptr, tctx); } -JEMALLOC_INLINE bool -prof_sample_accum_update(size_t size) +JEMALLOC_ALWAYS_INLINE bool +prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update, + prof_tdata_t **tdata_out) { - prof_tdata_t *prof_tdata; + prof_tdata_t *tdata; cassert(config_prof); - /* Sampling logic is unnecessary if the interval is 1. */ - assert(opt_lg_prof_sample != 0); - prof_tdata = prof_tdata_get(false); - if ((uintptr_t)prof_tdata <= (uintptr_t)PROF_TDATA_STATE_MAX) + tdata = prof_tdata_get(tsd, true); + if ((uintptr_t)tdata <= (uintptr_t)PROF_TDATA_STATE_MAX) + tdata = NULL; + + if (tdata_out != NULL) + *tdata_out = tdata; + + if (tdata == NULL) return (true); - /* Take care to avoid integer overflow. */ - if (size >= prof_tdata->threshold - prof_tdata->accum) { - prof_tdata->accum -= (prof_tdata->threshold - size); - /* Compute new sample threshold. */ - prof_sample_threshold_update(prof_tdata); - while (prof_tdata->accum >= prof_tdata->threshold) { - prof_tdata->accum -= prof_tdata->threshold; - prof_sample_threshold_update(prof_tdata); - } - return (false); + if (tdata->bytes_until_sample >= usize) { + if (update) + tdata->bytes_until_sample -= usize; + return (true); } else { - prof_tdata->accum += size; - return (true); + /* Compute new sample threshold. */ + if (update) + prof_sample_threshold_update(tdata); + return (!tdata->active); } } -JEMALLOC_INLINE void -prof_malloc(const void *ptr, size_t usize, prof_thr_cnt_t *cnt) +JEMALLOC_ALWAYS_INLINE prof_tctx_t * +prof_alloc_prep(tsd_t *tsd, size_t usize, bool update) +{ + prof_tctx_t *ret; + prof_tdata_t *tdata; + prof_bt_t bt; + + assert(usize == s2u(usize)); + + if (!prof_active_get_unlocked() || likely(prof_sample_accum_update(tsd, + usize, update, &tdata))) + ret = (prof_tctx_t *)(uintptr_t)1U; + else { + bt_init(&bt, tdata->vec); + prof_backtrace(&bt); + ret = prof_lookup(tsd, &bt); + } + + return (ret); +} + +JEMALLOC_ALWAYS_INLINE void +prof_malloc(const void *ptr, size_t usize, prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); assert(usize == isalloc(ptr, true)); - if (opt_lg_prof_sample != 0) { - if (prof_sample_accum_update(usize)) { - /* - * Don't sample. For malloc()-like allocation, it is - * always possible to tell in advance how large an - * object's usable size will be, so there should never - * be a difference between the usize passed to - * PROF_ALLOC_PREP() and prof_malloc(). - */ - assert((uintptr_t)cnt == (uintptr_t)1U); - } - } - - if ((uintptr_t)cnt > (uintptr_t)1U) { - prof_ctx_set(ptr, usize, cnt->ctx); - - cnt->epoch++; - /*********/ - mb_write(); - /*********/ - cnt->cnts.curobjs++; - cnt->cnts.curbytes += usize; - if (opt_prof_accum) { - cnt->cnts.accumobjs++; - cnt->cnts.accumbytes += usize; - } - /*********/ - mb_write(); - /*********/ - cnt->epoch++; - /*********/ - mb_write(); - /*********/ - } else - prof_ctx_set(ptr, usize, (prof_ctx_t *)(uintptr_t)1U); + if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) + prof_malloc_sample_object(ptr, usize, tctx); + else + prof_tctx_set(ptr, (prof_tctx_t *)(uintptr_t)1U); } -JEMALLOC_INLINE void -prof_realloc(const void *ptr, size_t usize, prof_thr_cnt_t *cnt, - size_t old_usize, prof_ctx_t *old_ctx) +JEMALLOC_ALWAYS_INLINE void +prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, prof_tctx_t *tctx, + bool updated, size_t old_usize, prof_tctx_t *old_tctx) { - prof_thr_cnt_t *told_cnt; cassert(config_prof); - assert(ptr != NULL || (uintptr_t)cnt <= (uintptr_t)1U); + assert(ptr != NULL || (uintptr_t)tctx <= (uintptr_t)1U); - if (ptr != NULL) { + if (!updated && ptr != NULL) { assert(usize == isalloc(ptr, true)); - if (opt_lg_prof_sample != 0) { - if (prof_sample_accum_update(usize)) { - /* - * Don't sample. The usize passed to - * PROF_ALLOC_PREP() was larger than what - * actually got allocated, so a backtrace was - * captured for this allocation, even though - * its actual usize was insufficient to cross - * the sample threshold. - */ - cnt = (prof_thr_cnt_t *)(uintptr_t)1U; - } - } - } - - if ((uintptr_t)old_ctx > (uintptr_t)1U) { - told_cnt = prof_lookup(old_ctx->bt); - if (told_cnt == NULL) { + if (prof_sample_accum_update(tsd, usize, true, NULL)) { /* - * It's too late to propagate OOM for this realloc(), - * so operate directly on old_cnt->ctx->cnt_merged. + * Don't sample. The usize passed to PROF_ALLOC_PREP() + * was larger than what actually got allocated, so a + * backtrace was captured for this allocation, even + * though its actual usize was insufficient to cross the + * sample threshold. */ - malloc_mutex_lock(old_ctx->lock); - old_ctx->cnt_merged.curobjs--; - old_ctx->cnt_merged.curbytes -= old_usize; - malloc_mutex_unlock(old_ctx->lock); - told_cnt = (prof_thr_cnt_t *)(uintptr_t)1U; + tctx = (prof_tctx_t *)(uintptr_t)1U; } - } else - told_cnt = (prof_thr_cnt_t *)(uintptr_t)1U; + } - if ((uintptr_t)told_cnt > (uintptr_t)1U) - told_cnt->epoch++; - if ((uintptr_t)cnt > (uintptr_t)1U) { - prof_ctx_set(ptr, usize, cnt->ctx); - cnt->epoch++; - } else if (ptr != NULL) - prof_ctx_set(ptr, usize, (prof_ctx_t *)(uintptr_t)1U); - /*********/ - mb_write(); - /*********/ - if ((uintptr_t)told_cnt > (uintptr_t)1U) { - told_cnt->cnts.curobjs--; - told_cnt->cnts.curbytes -= old_usize; - } - if ((uintptr_t)cnt > (uintptr_t)1U) { - cnt->cnts.curobjs++; - cnt->cnts.curbytes += usize; - if (opt_prof_accum) { - cnt->cnts.accumobjs++; - cnt->cnts.accumbytes += usize; - } - } - /*********/ - mb_write(); - /*********/ - if ((uintptr_t)told_cnt > (uintptr_t)1U) - told_cnt->epoch++; - if ((uintptr_t)cnt > (uintptr_t)1U) - cnt->epoch++; - /*********/ - mb_write(); /* Not strictly necessary. */ + if (unlikely((uintptr_t)old_tctx > (uintptr_t)1U)) + prof_free_sampled_object(tsd, old_usize, old_tctx); + if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) + prof_malloc_sample_object(ptr, usize, tctx); + else + prof_tctx_set(ptr, (prof_tctx_t *)(uintptr_t)1U); } -JEMALLOC_INLINE void -prof_free(const void *ptr, size_t size) +JEMALLOC_ALWAYS_INLINE void +prof_free(tsd_t *tsd, const void *ptr, size_t usize) { - prof_ctx_t *ctx = prof_ctx_get(ptr); + prof_tctx_t *tctx = prof_tctx_get(ptr); cassert(config_prof); + assert(usize == isalloc(ptr, true)); - if ((uintptr_t)ctx > (uintptr_t)1) { - prof_thr_cnt_t *tcnt; - assert(size == isalloc(ptr, true)); - tcnt = prof_lookup(ctx->bt); - - if (tcnt != NULL) { - tcnt->epoch++; - /*********/ - mb_write(); - /*********/ - tcnt->cnts.curobjs--; - tcnt->cnts.curbytes -= size; - /*********/ - mb_write(); - /*********/ - tcnt->epoch++; - /*********/ - mb_write(); - /*********/ - } else { - /* - * OOM during free() cannot be propagated, so operate - * directly on cnt->ctx->cnt_merged. - */ - malloc_mutex_lock(ctx->lock); - ctx->cnt_merged.curobjs--; - ctx->cnt_merged.curbytes -= size; - malloc_mutex_unlock(ctx->lock); - } - } + if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) + prof_free_sampled_object(tsd, usize, tctx); } #endif diff --git a/memory/jemalloc/src/include/jemalloc/internal/ql.h b/memory/jemalloc/src/include/jemalloc/internal/ql.h index f70c5f6f3919..1834bb8557ac 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/ql.h +++ b/memory/jemalloc/src/include/jemalloc/internal/ql.h @@ -1,6 +1,4 @@ -/* - * List definitions. - */ +/* List definitions. */ #define ql_head(a_type) \ struct { \ a_type *qlh_first; \ diff --git a/memory/jemalloc/src/include/jemalloc/internal/qr.h b/memory/jemalloc/src/include/jemalloc/internal/qr.h index 602944b9b4fa..0fbaec25e7c0 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/qr.h +++ b/memory/jemalloc/src/include/jemalloc/internal/qr.h @@ -40,8 +40,10 @@ struct { \ (a_qr_b)->a_field.qre_prev = t; \ } while (0) -/* qr_meld() and qr_split() are functionally equivalent, so there's no need to - * have two copies of the code. */ +/* + * qr_meld() and qr_split() are functionally equivalent, so there's no need to + * have two copies of the code. + */ #define qr_split(a_qr_a, a_qr_b, a_field) \ qr_meld((a_qr_a), (a_qr_b), a_field) diff --git a/memory/jemalloc/src/include/jemalloc/internal/quarantine.h b/memory/jemalloc/src/include/jemalloc/internal/quarantine.h index 16f677f73da0..ae607399f6d7 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/quarantine.h +++ b/memory/jemalloc/src/include/jemalloc/internal/quarantine.h @@ -29,36 +29,29 @@ struct quarantine_s { /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS -quarantine_t *quarantine_init(size_t lg_maxobjs); -void quarantine(void *ptr); -void quarantine_cleanup(void *arg); -bool quarantine_boot(void); +void quarantine_alloc_hook_work(tsd_t *tsd); +void quarantine(tsd_t *tsd, void *ptr); +void quarantine_cleanup(tsd_t *tsd); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE -malloc_tsd_protos(JEMALLOC_ATTR(unused), quarantine, quarantine_t *) - void quarantine_alloc_hook(void); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_QUARANTINE_C_)) -malloc_tsd_externs(quarantine, quarantine_t *) -malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, quarantine, quarantine_t *, NULL, - quarantine_cleanup) - JEMALLOC_ALWAYS_INLINE void quarantine_alloc_hook(void) { - quarantine_t *quarantine; + tsd_t *tsd; assert(config_fill && opt_quarantine); - quarantine = *quarantine_tsd_get(); - if (quarantine == NULL) - quarantine_init(LG_MAXOBJS_INIT); + tsd = tsd_fetch(); + if (tsd_quarantine_get(tsd) == NULL) + quarantine_alloc_hook_work(tsd); } #endif diff --git a/memory/jemalloc/src/include/jemalloc/internal/rb.h b/memory/jemalloc/src/include/jemalloc/internal/rb.h index 423802eb2dce..2ca8e5933b28 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/rb.h +++ b/memory/jemalloc/src/include/jemalloc/internal/rb.h @@ -158,6 +158,8 @@ struct { \ #define rb_proto(a_attr, a_prefix, a_rbt_type, a_type) \ a_attr void \ a_prefix##new(a_rbt_type *rbtree); \ +a_attr bool \ +a_prefix##empty(a_rbt_type *rbtree); \ a_attr a_type * \ a_prefix##first(a_rbt_type *rbtree); \ a_attr a_type * \ @@ -198,7 +200,7 @@ a_prefix##reverse_iter(a_rbt_type *rbtree, a_type *start, \ * int (a_cmp *)(a_type *a_node, a_type *a_other); * ^^^^^^ * or a_key - * Interpretation of comparision function return values: + * Interpretation of comparison function return values: * -1 : a_node < a_other * 0 : a_node == a_other * 1 : a_node > a_other @@ -224,6 +226,13 @@ a_prefix##reverse_iter(a_rbt_type *rbtree, a_type *start, \ * Args: * tree: Pointer to an uninitialized red-black tree object. * + * static bool + * ex_empty(ex_t *tree); + * Description: Determine whether tree is empty. + * Args: + * tree: Pointer to an initialized red-black tree object. + * Ret: True if tree is empty, false otherwise. + * * static ex_node_t * * ex_first(ex_t *tree); * static ex_node_t * @@ -309,6 +318,10 @@ a_attr void \ a_prefix##new(a_rbt_type *rbtree) { \ rb_new(a_type, a_field, rbtree); \ } \ +a_attr bool \ +a_prefix##empty(a_rbt_type *rbtree) { \ + return (rbtree->rbt_root == &rbtree->rbt_nil); \ +} \ a_attr a_type * \ a_prefix##first(a_rbt_type *rbtree) { \ a_type *ret; \ @@ -580,7 +593,7 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \ if (left != &rbtree->rbt_nil) { \ /* node has no successor, but it has a left child. */\ /* Splice node out, without losing the left child. */\ - assert(rbtn_red_get(a_type, a_field, node) == false); \ + assert(!rbtn_red_get(a_type, a_field, node)); \ assert(rbtn_red_get(a_type, a_field, left)); \ rbtn_black_set(a_type, a_field, left); \ if (pathp == path) { \ @@ -616,8 +629,7 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \ if (pathp->cmp < 0) { \ rbtn_left_set(a_type, a_field, pathp->node, \ pathp[1].node); \ - assert(rbtn_red_get(a_type, a_field, pathp[1].node) \ - == false); \ + assert(!rbtn_red_get(a_type, a_field, pathp[1].node)); \ if (rbtn_red_get(a_type, a_field, pathp->node)) { \ a_type *right = rbtn_right_get(a_type, a_field, \ pathp->node); \ @@ -681,7 +693,7 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \ rbtn_rotate_left(a_type, a_field, pathp->node, \ tnode); \ /* Balance restored, but rotation modified */\ - /* subree root, which may actually be the tree */\ + /* subtree root, which may actually be the tree */\ /* root. */\ if (pathp == path) { \ /* Set root. */ \ @@ -849,7 +861,7 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \ } \ /* Set root. */ \ rbtree->rbt_root = path->node; \ - assert(rbtn_red_get(a_type, a_field, rbtree->rbt_root) == false); \ + assert(!rbtn_red_get(a_type, a_field, rbtree->rbt_root)); \ } \ a_attr a_type * \ a_prefix##iter_recurse(a_rbt_type *rbtree, a_type *node, \ diff --git a/memory/jemalloc/src/include/jemalloc/internal/size_classes.sh b/memory/jemalloc/src/include/jemalloc/internal/size_classes.sh index 29c80c1fb8d1..38020dc6f27d 100755 --- a/memory/jemalloc/src/include/jemalloc/internal/size_classes.sh +++ b/memory/jemalloc/src/include/jemalloc/internal/size_classes.sh @@ -1,17 +1,26 @@ #!/bin/sh +# +# Usage: size_classes.sh # The following limits are chosen such that they cover all supported platforms. -# Range of quanta. -lg_qmin=3 -lg_qmax=4 +# Pointer sizes. +lg_zarr="2 3" + +# Quanta. +lg_qarr=$1 # The range of tiny size classes is [2^lg_tmin..2^(lg_q-1)]. -lg_tmin=3 +lg_tmin=$2 -# Range of page sizes. -lg_pmin=12 -lg_pmax=16 +# Maximum lookup size. +lg_kmax=12 + +# Page sizes. +lg_parr=`echo $3 | tr ',' ' '` + +# Size class group size (number of size classes for each size doubling). +lg_g=$4 pow2() { e=$1 @@ -22,68 +31,218 @@ pow2() { done } +lg() { + x=$1 + lg_result=0 + while [ ${x} -gt 1 ] ; do + lg_result=$((${lg_result} + 1)) + x=$((${x} / 2)) + done +} + +size_class() { + index=$1 + lg_grp=$2 + lg_delta=$3 + ndelta=$4 + lg_p=$5 + lg_kmax=$6 + + lg ${ndelta}; lg_ndelta=${lg_result}; pow2 ${lg_ndelta} + if [ ${pow2_result} -lt ${ndelta} ] ; then + rem="yes" + else + rem="no" + fi + + lg_size=${lg_grp} + if [ $((${lg_delta} + ${lg_ndelta})) -eq ${lg_grp} ] ; then + lg_size=$((${lg_grp} + 1)) + else + lg_size=${lg_grp} + rem="yes" + fi + + if [ ${lg_size} -lt $((${lg_p} + ${lg_g})) ] ; then + bin="yes" + else + bin="no" + fi + if [ ${lg_size} -lt ${lg_kmax} \ + -o ${lg_size} -eq ${lg_kmax} -a ${rem} = "no" ] ; then + lg_delta_lookup=${lg_delta} + else + lg_delta_lookup="no" + fi + printf ' SC(%3d, %6d, %8d, %6d, %3s, %2s) \\\n' ${index} ${lg_grp} ${lg_delta} ${ndelta} ${bin} ${lg_delta_lookup} + # Defined upon return: + # - lg_delta_lookup (${lg_delta} or "no") + # - bin ("yes" or "no") +} + +sep_line() { + echo " \\" +} + +size_classes() { + lg_z=$1 + lg_q=$2 + lg_t=$3 + lg_p=$4 + lg_g=$5 + + pow2 $((${lg_z} + 3)); ptr_bits=${pow2_result} + pow2 ${lg_g}; g=${pow2_result} + + echo "#define SIZE_CLASSES \\" + echo " /* index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup */ \\" + + ntbins=0 + nlbins=0 + lg_tiny_maxclass='"NA"' + nbins=0 + + # Tiny size classes. + ndelta=0 + index=0 + lg_grp=${lg_t} + lg_delta=${lg_grp} + while [ ${lg_grp} -lt ${lg_q} ] ; do + size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax} + if [ ${lg_delta_lookup} != "no" ] ; then + nlbins=$((${index} + 1)) + fi + if [ ${bin} != "no" ] ; then + nbins=$((${index} + 1)) + fi + ntbins=$((${ntbins} + 1)) + lg_tiny_maxclass=${lg_grp} # Final written value is correct. + index=$((${index} + 1)) + lg_delta=${lg_grp} + lg_grp=$((${lg_grp} + 1)) + done + + # First non-tiny group. + if [ ${ntbins} -gt 0 ] ; then + sep_line + # The first size class has an unusual encoding, because the size has to be + # split between grp and delta*ndelta. + lg_grp=$((${lg_grp} - 1)) + ndelta=1 + size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax} + index=$((${index} + 1)) + lg_grp=$((${lg_grp} + 1)) + lg_delta=$((${lg_delta} + 1)) + fi + while [ ${ndelta} -lt ${g} ] ; do + size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax} + index=$((${index} + 1)) + ndelta=$((${ndelta} + 1)) + done + + # All remaining groups. + lg_grp=$((${lg_grp} + ${lg_g})) + while [ ${lg_grp} -lt ${ptr_bits} ] ; do + sep_line + ndelta=1 + if [ ${lg_grp} -eq $((${ptr_bits} - 1)) ] ; then + ndelta_limit=$((${g} - 1)) + else + ndelta_limit=${g} + fi + while [ ${ndelta} -le ${ndelta_limit} ] ; do + size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax} + if [ ${lg_delta_lookup} != "no" ] ; then + nlbins=$((${index} + 1)) + # Final written value is correct: + lookup_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))" + fi + if [ ${bin} != "no" ] ; then + nbins=$((${index} + 1)) + # Final written value is correct: + small_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))" + if [ ${lg_g} -gt 0 ] ; then + lg_large_minclass=$((${lg_grp} + 1)) + else + lg_large_minclass=$((${lg_grp} + 2)) + fi + fi + index=$((${index} + 1)) + ndelta=$((${ndelta} + 1)) + done + lg_grp=$((${lg_grp} + 1)) + lg_delta=$((${lg_delta} + 1)) + done + echo + nsizes=${index} + + # Defined upon completion: + # - ntbins + # - nlbins + # - nbins + # - nsizes + # - lg_tiny_maxclass + # - lookup_maxclass + # - small_maxclass + # - lg_large_minclass +} + cat < 255) # error "Too many small size classes" diff --git a/memory/jemalloc/src/include/jemalloc/internal/stats.h b/memory/jemalloc/src/include/jemalloc/internal/stats.h index 27f68e3681cf..d8600ed438c2 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/stats.h +++ b/memory/jemalloc/src/include/jemalloc/internal/stats.h @@ -4,6 +4,7 @@ typedef struct tcache_bin_stats_s tcache_bin_stats_t; typedef struct malloc_bin_stats_s malloc_bin_stats_t; typedef struct malloc_large_stats_s malloc_large_stats_t; +typedef struct malloc_huge_stats_s malloc_huge_stats_t; typedef struct arena_stats_s arena_stats_t; typedef struct chunk_stats_s chunk_stats_t; @@ -20,12 +21,6 @@ struct tcache_bin_stats_s { }; struct malloc_bin_stats_s { - /* - * Current number of bytes allocated, including objects currently - * cached by tcache. - */ - size_t allocated; - /* * Total number of allocation/deallocation requests served directly by * the bin. Note that tcache may allocate an object, then recycle it @@ -42,6 +37,12 @@ struct malloc_bin_stats_s { */ uint64_t nrequests; + /* + * Current number of regions of this size class, including regions + * currently cached by tcache. + */ + size_t curregs; + /* Number of tcache fills from this bin. */ uint64_t nfills; @@ -78,10 +79,25 @@ struct malloc_large_stats_s { */ uint64_t nrequests; - /* Current number of runs of this size class. */ + /* + * Current number of runs of this size class, including runs currently + * cached by tcache. + */ size_t curruns; }; +struct malloc_huge_stats_s { + /* + * Total number of allocation/deallocation requests served directly by + * the arena. + */ + uint64_t nmalloc; + uint64_t ndalloc; + + /* Current number of (multi-)chunk allocations of this size class. */ + size_t curhchunks; +}; + struct arena_stats_s { /* Number of bytes currently mapped. */ size_t mapped; @@ -101,13 +117,15 @@ struct arena_stats_s { uint64_t ndalloc_large; uint64_t nrequests_large; - /* - * One element for each possible size class, including sizes that - * overlap with bin size classes. This is necessary because ipalloc() - * sometimes has to use such large objects in order to assure proper - * alignment. - */ + size_t allocated_huge; + uint64_t nmalloc_huge; + uint64_t ndalloc_huge; + + /* One element for each large size class. */ malloc_large_stats_t *lstats; + + /* One element for each huge size class. */ + malloc_huge_stats_t *hstats; }; struct chunk_stats_s { diff --git a/memory/jemalloc/src/include/jemalloc/internal/tcache.h b/memory/jemalloc/src/include/jemalloc/internal/tcache.h index c3d4b58d4dc5..6e97b3dd144c 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/tcache.h +++ b/memory/jemalloc/src/include/jemalloc/internal/tcache.h @@ -69,10 +69,10 @@ struct tcache_bin_s { struct tcache_s { ql_elm(tcache_t) link; /* Used for aggregating stats. */ - uint64_t prof_accumbytes;/* Cleared after arena_prof_accum() */ + uint64_t prof_accumbytes;/* Cleared after arena_prof_accum(). */ arena_t *arena; /* This thread's arena. */ unsigned ev_cnt; /* Event count since incremental GC. */ - unsigned next_gc_bin; /* Next bin to GC. */ + index_t next_gc_bin; /* Next bin to GC. */ tcache_bin_t tbins[1]; /* Dynamically sized. */ /* * The pointer stacks associated with tbins follow as a contiguous @@ -103,76 +103,63 @@ extern size_t tcache_maxclass; size_t tcache_salloc(const void *ptr); void tcache_event_hard(tcache_t *tcache); void *tcache_alloc_small_hard(tcache_t *tcache, tcache_bin_t *tbin, - size_t binind); -void tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem, + index_t binind); +void tcache_bin_flush_small(tcache_bin_t *tbin, index_t binind, unsigned rem, tcache_t *tcache); -void tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem, +void tcache_bin_flush_large(tcache_bin_t *tbin, index_t binind, unsigned rem, tcache_t *tcache); void tcache_arena_associate(tcache_t *tcache, arena_t *arena); +void tcache_arena_reassociate(tcache_t *tcache, arena_t *arena); void tcache_arena_dissociate(tcache_t *tcache); -tcache_t *tcache_create(arena_t *arena); -void tcache_destroy(tcache_t *tcache); -void tcache_thread_cleanup(void *arg); +tcache_t *tcache_get_hard(tsd_t *tsd); +tcache_t *tcache_create(tsd_t *tsd, arena_t *arena); +void tcache_cleanup(tsd_t *tsd); +void tcache_enabled_cleanup(tsd_t *tsd); void tcache_stats_merge(tcache_t *tcache, arena_t *arena); -bool tcache_boot0(void); -bool tcache_boot1(void); +bool tcache_boot(void); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE -malloc_tsd_protos(JEMALLOC_ATTR(unused), tcache, tcache_t *) -malloc_tsd_protos(JEMALLOC_ATTR(unused), tcache_enabled, tcache_enabled_t) - void tcache_event(tcache_t *tcache); void tcache_flush(void); bool tcache_enabled_get(void); -tcache_t *tcache_get(bool create); +tcache_t *tcache_get(tsd_t *tsd, bool create); void tcache_enabled_set(bool enabled); void *tcache_alloc_easy(tcache_bin_t *tbin); void *tcache_alloc_small(tcache_t *tcache, size_t size, bool zero); void *tcache_alloc_large(tcache_t *tcache, size_t size, bool zero); -void tcache_dalloc_small(tcache_t *tcache, void *ptr, size_t binind); +void tcache_dalloc_small(tcache_t *tcache, void *ptr, index_t binind); void tcache_dalloc_large(tcache_t *tcache, void *ptr, size_t size); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TCACHE_C_)) -/* Map of thread-specific caches. */ -malloc_tsd_externs(tcache, tcache_t *) -malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, tcache, tcache_t *, NULL, - tcache_thread_cleanup) -/* Per thread flag that allows thread caches to be disabled. */ -malloc_tsd_externs(tcache_enabled, tcache_enabled_t) -malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, tcache_enabled, tcache_enabled_t, - tcache_enabled_default, malloc_tsd_no_cleanup) - JEMALLOC_INLINE void tcache_flush(void) { - tcache_t *tcache; + tsd_t *tsd; cassert(config_tcache); - tcache = *tcache_tsd_get(); - if ((uintptr_t)tcache <= (uintptr_t)TCACHE_STATE_MAX) - return; - tcache_destroy(tcache); - tcache = NULL; - tcache_tsd_set(&tcache); + tsd = tsd_fetch(); + tcache_cleanup(tsd); } JEMALLOC_INLINE bool tcache_enabled_get(void) { + tsd_t *tsd; tcache_enabled_t tcache_enabled; cassert(config_tcache); - tcache_enabled = *tcache_enabled_tsd_get(); + tsd = tsd_fetch(); + tcache_enabled = tsd_tcache_enabled_get(tsd); if (tcache_enabled == tcache_enabled_default) { tcache_enabled = (tcache_enabled_t)opt_tcache; - tcache_enabled_tsd_set(&tcache_enabled); + tsd_tcache_enabled_set(tsd, tcache_enabled); } return ((bool)tcache_enabled); @@ -181,78 +168,34 @@ tcache_enabled_get(void) JEMALLOC_INLINE void tcache_enabled_set(bool enabled) { + tsd_t *tsd; tcache_enabled_t tcache_enabled; - tcache_t *tcache; cassert(config_tcache); + tsd = tsd_fetch(); + tcache_enabled = (tcache_enabled_t)enabled; - tcache_enabled_tsd_set(&tcache_enabled); - tcache = *tcache_tsd_get(); - if (enabled) { - if (tcache == TCACHE_STATE_DISABLED) { - tcache = NULL; - tcache_tsd_set(&tcache); - } - } else /* disabled */ { - if (tcache > TCACHE_STATE_MAX) { - tcache_destroy(tcache); - tcache = NULL; - } - if (tcache == NULL) { - tcache = TCACHE_STATE_DISABLED; - tcache_tsd_set(&tcache); - } - } + tsd_tcache_enabled_set(tsd, tcache_enabled); + + if (!enabled) + tcache_cleanup(tsd); } JEMALLOC_ALWAYS_INLINE tcache_t * -tcache_get(bool create) +tcache_get(tsd_t *tsd, bool create) { tcache_t *tcache; - if (config_tcache == false) - return (NULL); - if (config_lazy_lock && isthreaded == false) + if (!config_tcache) return (NULL); - tcache = *tcache_tsd_get(); - if ((uintptr_t)tcache <= (uintptr_t)TCACHE_STATE_MAX) { - if (tcache == TCACHE_STATE_DISABLED) - return (NULL); - if (tcache == NULL) { - if (create == false) { - /* - * Creating a tcache here would cause - * allocation as a side effect of free(). - * Ordinarily that would be okay since - * tcache_create() failure is a soft failure - * that doesn't propagate. However, if TLS - * data are freed via free() as in glibc, - * subtle corruption could result from setting - * a TLS variable after its backing memory is - * freed. - */ - return (NULL); - } - if (tcache_enabled_get() == false) { - tcache_enabled_set(false); /* Memoize. */ - return (NULL); - } - return (tcache_create(choose_arena(NULL))); - } - if (tcache == TCACHE_STATE_PURGATORY) { - /* - * Make a note that an allocator function was called - * after tcache_thread_cleanup() was called. - */ - tcache = TCACHE_STATE_REINCARNATED; - tcache_tsd_set(&tcache); - return (NULL); - } - if (tcache == TCACHE_STATE_REINCARNATED) - return (NULL); - not_reached(); + tcache = tsd_tcache_get(tsd); + if (!create) + return (tcache); + if (unlikely(tcache == NULL) && tsd_nominal(tsd)) { + tcache = tcache_get_hard(tsd); + tsd_tcache_set(tsd, tcache); } return (tcache); @@ -267,7 +210,7 @@ tcache_event(tcache_t *tcache) tcache->ev_cnt++; assert(tcache->ev_cnt <= TCACHE_GC_INCR); - if (tcache->ev_cnt == TCACHE_GC_INCR) + if (unlikely(tcache->ev_cnt == TCACHE_GC_INCR)) tcache_event_hard(tcache); } @@ -276,12 +219,12 @@ tcache_alloc_easy(tcache_bin_t *tbin) { void *ret; - if (tbin->ncached == 0) { + if (unlikely(tbin->ncached == 0)) { tbin->low_water = -1; return (NULL); } tbin->ncached--; - if ((int)tbin->ncached < tbin->low_water) + if (unlikely((int)tbin->ncached < tbin->low_water)) tbin->low_water = tbin->ncached; ret = tbin->avail[tbin->ncached]; return (ret); @@ -291,43 +234,42 @@ JEMALLOC_ALWAYS_INLINE void * tcache_alloc_small(tcache_t *tcache, size_t size, bool zero) { void *ret; - size_t binind; + index_t binind; + size_t usize; tcache_bin_t *tbin; - binind = SMALL_SIZE2BIN(size); + binind = size2index(size); assert(binind < NBINS); tbin = &tcache->tbins[binind]; - size = arena_bin_info[binind].reg_size; + usize = index2size(binind); ret = tcache_alloc_easy(tbin); - if (ret == NULL) { + if (unlikely(ret == NULL)) { ret = tcache_alloc_small_hard(tcache, tbin, binind); if (ret == NULL) return (NULL); } - assert(tcache_salloc(ret) == arena_bin_info[binind].reg_size); + assert(tcache_salloc(ret) == usize); - if (zero == false) { + if (likely(!zero)) { if (config_fill) { - if (opt_junk) { + if (unlikely(opt_junk_alloc)) { arena_alloc_junk_small(ret, &arena_bin_info[binind], false); - } else if (opt_zero) - memset(ret, 0, size); + } else if (unlikely(opt_zero)) + memset(ret, 0, usize); } - VALGRIND_MAKE_MEM_UNDEFINED(ret, size); } else { - if (config_fill && opt_junk) { + if (config_fill && unlikely(opt_junk_alloc)) { arena_alloc_junk_small(ret, &arena_bin_info[binind], true); } - VALGRIND_MAKE_MEM_UNDEFINED(ret, size); - memset(ret, 0, size); + memset(ret, 0, usize); } if (config_stats) tbin->tstats.nrequests++; if (config_prof) - tcache->prof_accumbytes += arena_bin_info[binind].reg_size; + tcache->prof_accumbytes += usize; tcache_event(tcache); return (ret); } @@ -336,25 +278,26 @@ JEMALLOC_ALWAYS_INLINE void * tcache_alloc_large(tcache_t *tcache, size_t size, bool zero) { void *ret; - size_t binind; + index_t binind; + size_t usize; tcache_bin_t *tbin; - size = PAGE_CEILING(size); - assert(size <= tcache_maxclass); - binind = NBINS + (size >> LG_PAGE) - 1; + binind = size2index(size); + usize = index2size(binind); + assert(usize <= tcache_maxclass); assert(binind < nhbins); tbin = &tcache->tbins[binind]; ret = tcache_alloc_easy(tbin); - if (ret == NULL) { + if (unlikely(ret == NULL)) { /* * Only allocate one large object at a time, because it's quite * expensive to create one and not use it. */ - ret = arena_malloc_large(tcache->arena, size, zero); + ret = arena_malloc_large(tcache->arena, usize, zero); if (ret == NULL) return (NULL); } else { - if (config_prof && prof_promote && size == PAGE) { + if (config_prof && usize == LARGE_MINCLASS) { arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ret); size_t pageind = (((uintptr_t)ret - (uintptr_t)chunk) >> @@ -362,23 +305,20 @@ tcache_alloc_large(tcache_t *tcache, size_t size, bool zero) arena_mapbits_large_binind_set(chunk, pageind, BININD_INVALID); } - if (zero == false) { + if (likely(!zero)) { if (config_fill) { - if (opt_junk) - memset(ret, 0xa5, size); - else if (opt_zero) - memset(ret, 0, size); + if (unlikely(opt_junk_alloc)) + memset(ret, 0xa5, usize); + else if (unlikely(opt_zero)) + memset(ret, 0, usize); } - VALGRIND_MAKE_MEM_UNDEFINED(ret, size); - } else { - VALGRIND_MAKE_MEM_UNDEFINED(ret, size); - memset(ret, 0, size); - } + } else + memset(ret, 0, usize); if (config_stats) tbin->tstats.nrequests++; if (config_prof) - tcache->prof_accumbytes += size; + tcache->prof_accumbytes += usize; } tcache_event(tcache); @@ -386,19 +326,19 @@ tcache_alloc_large(tcache_t *tcache, size_t size, bool zero) } JEMALLOC_ALWAYS_INLINE void -tcache_dalloc_small(tcache_t *tcache, void *ptr, size_t binind) +tcache_dalloc_small(tcache_t *tcache, void *ptr, index_t binind) { tcache_bin_t *tbin; tcache_bin_info_t *tbin_info; assert(tcache_salloc(ptr) <= SMALL_MAXCLASS); - if (config_fill && opt_junk) + if (config_fill && unlikely(opt_junk_free)) arena_dalloc_junk_small(ptr, &arena_bin_info[binind]); tbin = &tcache->tbins[binind]; tbin_info = &tcache_bin_info[binind]; - if (tbin->ncached == tbin_info->ncached_max) { + if (unlikely(tbin->ncached == tbin_info->ncached_max)) { tcache_bin_flush_small(tbin, binind, (tbin_info->ncached_max >> 1), tcache); } @@ -412,7 +352,7 @@ tcache_dalloc_small(tcache_t *tcache, void *ptr, size_t binind) JEMALLOC_ALWAYS_INLINE void tcache_dalloc_large(tcache_t *tcache, void *ptr, size_t size) { - size_t binind; + index_t binind; tcache_bin_t *tbin; tcache_bin_info_t *tbin_info; @@ -420,14 +360,14 @@ tcache_dalloc_large(tcache_t *tcache, void *ptr, size_t size) assert(tcache_salloc(ptr) > SMALL_MAXCLASS); assert(tcache_salloc(ptr) <= tcache_maxclass); - binind = NBINS + (size >> LG_PAGE) - 1; + binind = size2index(size); - if (config_fill && opt_junk) - memset(ptr, 0x5a, size); + if (config_fill && unlikely(opt_junk_free)) + arena_dalloc_junk_large(ptr, size); tbin = &tcache->tbins[binind]; tbin_info = &tcache_bin_info[binind]; - if (tbin->ncached == tbin_info->ncached_max) { + if (unlikely(tbin->ncached == tbin_info->ncached_max)) { tcache_bin_flush_large(tbin, binind, (tbin_info->ncached_max >> 1), tcache); } diff --git a/memory/jemalloc/src/include/jemalloc/internal/tsd.h b/memory/jemalloc/src/include/jemalloc/internal/tsd.h index 9fb4a23ec6bf..35dd86289f92 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/tsd.h +++ b/memory/jemalloc/src/include/jemalloc/internal/tsd.h @@ -2,7 +2,7 @@ #ifdef JEMALLOC_H_TYPES /* Maximum number of malloc_tsd users with cleanup functions. */ -#define MALLOC_TSD_CLEANUPS_MAX 8 +#define MALLOC_TSD_CLEANUPS_MAX 2 typedef bool (*malloc_tsd_cleanup_t)(void); @@ -12,9 +12,18 @@ typedef struct tsd_init_block_s tsd_init_block_t; typedef struct tsd_init_head_s tsd_init_head_t; #endif +typedef struct tsd_s tsd_t; + +typedef enum { + tsd_state_uninitialized, + tsd_state_nominal, + tsd_state_purgatory, + tsd_state_reincarnated +} tsd_state_t; + /* * TLS/TSD-agnostic macro-based implementation of thread-specific data. There - * are four macros that support (at least) three use cases: file-private, + * are five macros that support (at least) three use cases: file-private, * library-private, and library-private inlined. Following is an example * library-private tsd variable: * @@ -24,34 +33,36 @@ typedef struct tsd_init_head_s tsd_init_head_t; * int y; * } example_t; * #define EX_INITIALIZER JEMALLOC_CONCAT({0, 0}) - * malloc_tsd_protos(, example, example_t *) - * malloc_tsd_externs(example, example_t *) + * malloc_tsd_types(example_, example_t) + * malloc_tsd_protos(, example_, example_t) + * malloc_tsd_externs(example_, example_t) * In example.c: - * malloc_tsd_data(, example, example_t *, EX_INITIALIZER) - * malloc_tsd_funcs(, example, example_t *, EX_INITIALIZER, + * malloc_tsd_data(, example_, example_t, EX_INITIALIZER) + * malloc_tsd_funcs(, example_, example_t, EX_INITIALIZER, * example_tsd_cleanup) * * The result is a set of generated functions, e.g.: * * bool example_tsd_boot(void) {...} - * example_t **example_tsd_get() {...} - * void example_tsd_set(example_t **val) {...} + * example_t *example_tsd_get() {...} + * void example_tsd_set(example_t *val) {...} * * Note that all of the functions deal in terms of (a_type *) rather than * (a_type) so that it is possible to support non-pointer types (unlike * pthreads TSD). example_tsd_cleanup() is passed an (a_type *) pointer that is - * cast to (void *). This means that the cleanup function needs to cast *and* - * dereference the function argument, e.g.: + * cast to (void *). This means that the cleanup function needs to cast the + * function argument to (a_type *), then dereference the resulting pointer to + * access fields, e.g. * * void * example_tsd_cleanup(void *arg) * { - * example_t *example = *(example_t **)arg; + * example_t *example = (example_t *)arg; * + * example->x = 42; * [...] - * if ([want the cleanup function to be called again]) { - * example_tsd_set(&example); - * } + * if ([want the cleanup function to be called again]) + * example_tsd_set(example); * } * * If example_tsd_set() is called within example_tsd_cleanup(), it will be @@ -60,63 +71,96 @@ typedef struct tsd_init_head_s tsd_init_head_t; * non-NULL. */ +/* malloc_tsd_types(). */ +#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP +#define malloc_tsd_types(a_name, a_type) +#elif (defined(JEMALLOC_TLS)) +#define malloc_tsd_types(a_name, a_type) +#elif (defined(_WIN32)) +#define malloc_tsd_types(a_name, a_type) \ +typedef struct { \ + bool initialized; \ + a_type val; \ +} a_name##tsd_wrapper_t; +#else +#define malloc_tsd_types(a_name, a_type) \ +typedef struct { \ + bool initialized; \ + a_type val; \ +} a_name##tsd_wrapper_t; +#endif + /* malloc_tsd_protos(). */ #define malloc_tsd_protos(a_attr, a_name, a_type) \ a_attr bool \ -a_name##_tsd_boot(void); \ -a_attr a_type * \ -a_name##_tsd_get(void); \ +a_name##tsd_boot0(void); \ a_attr void \ -a_name##_tsd_set(a_type *val); +a_name##tsd_boot1(void); \ +a_attr bool \ +a_name##tsd_boot(void); \ +a_attr a_type * \ +a_name##tsd_get(void); \ +a_attr void \ +a_name##tsd_set(a_type *val); /* malloc_tsd_externs(). */ #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP #define malloc_tsd_externs(a_name, a_type) \ -extern __thread a_type a_name##_tls; \ -extern __thread bool a_name##_initialized; \ -extern bool a_name##_booted; +extern __thread a_type a_name##tsd_tls; \ +extern __thread bool a_name##tsd_initialized; \ +extern bool a_name##tsd_booted; #elif (defined(JEMALLOC_TLS)) #define malloc_tsd_externs(a_name, a_type) \ -extern __thread a_type a_name##_tls; \ -extern pthread_key_t a_name##_tsd; \ -extern bool a_name##_booted; +extern __thread a_type a_name##tsd_tls; \ +extern pthread_key_t a_name##tsd_tsd; \ +extern bool a_name##tsd_booted; #elif (defined(_WIN32)) #define malloc_tsd_externs(a_name, a_type) \ -extern DWORD a_name##_tsd; \ -extern bool a_name##_booted; +extern DWORD a_name##tsd_tsd; \ +extern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \ +extern bool a_name##tsd_booted; #else #define malloc_tsd_externs(a_name, a_type) \ -extern pthread_key_t a_name##_tsd; \ -extern tsd_init_head_t a_name##_tsd_init_head; \ -extern bool a_name##_booted; +extern pthread_key_t a_name##tsd_tsd; \ +extern tsd_init_head_t a_name##tsd_init_head; \ +extern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \ +extern bool a_name##tsd_booted; #endif /* malloc_tsd_data(). */ #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ a_attr __thread a_type JEMALLOC_TLS_MODEL \ - a_name##_tls = a_initializer; \ + a_name##tsd_tls = a_initializer; \ a_attr __thread bool JEMALLOC_TLS_MODEL \ - a_name##_initialized = false; \ -a_attr bool a_name##_booted = false; + a_name##tsd_initialized = false; \ +a_attr bool a_name##tsd_booted = false; #elif (defined(JEMALLOC_TLS)) #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ a_attr __thread a_type JEMALLOC_TLS_MODEL \ - a_name##_tls = a_initializer; \ -a_attr pthread_key_t a_name##_tsd; \ -a_attr bool a_name##_booted = false; + a_name##tsd_tls = a_initializer; \ +a_attr pthread_key_t a_name##tsd_tsd; \ +a_attr bool a_name##tsd_booted = false; #elif (defined(_WIN32)) #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ -a_attr DWORD a_name##_tsd; \ -a_attr bool a_name##_booted = false; +a_attr DWORD a_name##tsd_tsd; \ +a_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \ + false, \ + a_initializer \ +}; \ +a_attr bool a_name##tsd_booted = false; #else #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ -a_attr pthread_key_t a_name##_tsd; \ -a_attr tsd_init_head_t a_name##_tsd_init_head = { \ +a_attr pthread_key_t a_name##tsd_tsd; \ +a_attr tsd_init_head_t a_name##tsd_init_head = { \ ql_head_initializer(blocks), \ MALLOC_MUTEX_INITIALIZER \ }; \ -a_attr bool a_name##_booted = false; +a_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \ + false, \ + a_initializer \ +}; \ +a_attr bool a_name##tsd_booted = false; #endif /* malloc_tsd_funcs(). */ @@ -125,75 +169,100 @@ a_attr bool a_name##_booted = false; a_cleanup) \ /* Initialization/cleanup. */ \ a_attr bool \ -a_name##_tsd_cleanup_wrapper(void) \ +a_name##tsd_cleanup_wrapper(void) \ { \ \ - if (a_name##_initialized) { \ - a_name##_initialized = false; \ - a_cleanup(&a_name##_tls); \ + if (a_name##tsd_initialized) { \ + a_name##tsd_initialized = false; \ + a_cleanup(&a_name##tsd_tls); \ } \ - return (a_name##_initialized); \ + return (a_name##tsd_initialized); \ } \ a_attr bool \ -a_name##_tsd_boot(void) \ +a_name##tsd_boot0(void) \ { \ \ if (a_cleanup != malloc_tsd_no_cleanup) { \ malloc_tsd_cleanup_register( \ - &a_name##_tsd_cleanup_wrapper); \ + &a_name##tsd_cleanup_wrapper); \ } \ - a_name##_booted = true; \ + a_name##tsd_booted = true; \ return (false); \ } \ +a_attr void \ +a_name##tsd_boot1() \ +{ \ + \ + /* Do nothing. */ \ +} \ +a_attr bool \ +a_name##tsd_boot(void) \ +{ \ + \ + return (a_name##tsd_boot0()); \ +} \ /* Get/set. */ \ a_attr a_type * \ -a_name##_tsd_get(void) \ +a_name##tsd_get(void) \ { \ \ - assert(a_name##_booted); \ - return (&a_name##_tls); \ + assert(a_name##tsd_booted); \ + return (&a_name##tsd_tls); \ } \ a_attr void \ -a_name##_tsd_set(a_type *val) \ +a_name##tsd_set(a_type *val) \ { \ \ - assert(a_name##_booted); \ - a_name##_tls = (*val); \ + assert(a_name##tsd_booted); \ + a_name##tsd_tls = (*val); \ if (a_cleanup != malloc_tsd_no_cleanup) \ - a_name##_initialized = true; \ + a_name##tsd_initialized = true; \ } #elif (defined(JEMALLOC_TLS)) #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ a_cleanup) \ /* Initialization/cleanup. */ \ a_attr bool \ -a_name##_tsd_boot(void) \ +a_name##tsd_boot0(void) \ { \ \ if (a_cleanup != malloc_tsd_no_cleanup) { \ - if (pthread_key_create(&a_name##_tsd, a_cleanup) != 0) \ + if (pthread_key_create(&a_name##tsd_tsd, a_cleanup) != \ + 0) \ return (true); \ } \ - a_name##_booted = true; \ + a_name##tsd_booted = true; \ return (false); \ } \ +a_attr void \ +a_name##tsd_boot1() \ +{ \ + \ + /* Do nothing. */ \ +} \ +a_attr bool \ +a_name##tsd_boot(void) \ +{ \ + \ + return (a_name##tsd_boot0()); \ +} \ /* Get/set. */ \ a_attr a_type * \ -a_name##_tsd_get(void) \ +a_name##tsd_get(void) \ { \ \ - assert(a_name##_booted); \ - return (&a_name##_tls); \ + assert(a_name##tsd_booted); \ + return (&a_name##tsd_tls); \ } \ a_attr void \ -a_name##_tsd_set(a_type *val) \ +a_name##tsd_set(a_type *val) \ { \ \ - assert(a_name##_booted); \ - a_name##_tls = (*val); \ + assert(a_name##tsd_booted); \ + a_name##tsd_tls = (*val); \ if (a_cleanup != malloc_tsd_no_cleanup) { \ - if (pthread_setspecific(a_name##_tsd, \ - (void *)(&a_name##_tls))) { \ + if (pthread_setspecific(a_name##tsd_tsd, \ + (void *)(&a_name##tsd_tls))) { \ malloc_write(": Error" \ " setting TSD for "#a_name"\n"); \ if (opt_abort) \ @@ -204,27 +273,19 @@ a_name##_tsd_set(a_type *val) \ #elif (defined(_WIN32)) #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ a_cleanup) \ -/* Data structure. */ \ -typedef struct { \ - bool initialized; \ - a_type val; \ -} a_name##_tsd_wrapper_t; \ /* Initialization/cleanup. */ \ a_attr bool \ -a_name##_tsd_cleanup_wrapper(void) \ +a_name##tsd_cleanup_wrapper(void) \ { \ - a_name##_tsd_wrapper_t *wrapper; \ + a_name##tsd_wrapper_t *wrapper; \ \ - wrapper = (a_name##_tsd_wrapper_t *) TlsGetValue(a_name##_tsd); \ + wrapper = (a_name##tsd_wrapper_t *)TlsGetValue(a_name##tsd_tsd);\ if (wrapper == NULL) \ return (false); \ if (a_cleanup != malloc_tsd_no_cleanup && \ wrapper->initialized) { \ - a_type val = wrapper->val; \ - a_type tsd_static_data = a_initializer; \ wrapper->initialized = false; \ - wrapper->val = tsd_static_data; \ - a_cleanup(&val); \ + a_cleanup(&wrapper->val); \ if (wrapper->initialized) { \ /* Trigger another cleanup round. */ \ return (true); \ @@ -233,63 +294,93 @@ a_name##_tsd_cleanup_wrapper(void) \ malloc_tsd_dalloc(wrapper); \ return (false); \ } \ -a_attr bool \ -a_name##_tsd_boot(void) \ +a_attr void \ +a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \ { \ \ - a_name##_tsd = TlsAlloc(); \ - if (a_name##_tsd == TLS_OUT_OF_INDEXES) \ - return (true); \ - if (a_cleanup != malloc_tsd_no_cleanup) { \ - malloc_tsd_cleanup_register( \ - &a_name##_tsd_cleanup_wrapper); \ + if (!TlsSetValue(a_name##tsd_tsd, (void *)wrapper)) { \ + malloc_write(": Error setting" \ + " TSD for "#a_name"\n"); \ + abort(); \ } \ - a_name##_booted = true; \ - return (false); \ } \ -/* Get/set. */ \ -a_attr a_name##_tsd_wrapper_t * \ -a_name##_tsd_get_wrapper(void) \ +a_attr a_name##tsd_wrapper_t * \ +a_name##tsd_wrapper_get(void) \ { \ - a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *) \ - TlsGetValue(a_name##_tsd); \ + a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ + TlsGetValue(a_name##tsd_tsd); \ \ - if (wrapper == NULL) { \ - wrapper = (a_name##_tsd_wrapper_t *) \ - malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \ + if (unlikely(wrapper == NULL)) { \ + wrapper = (a_name##tsd_wrapper_t *) \ + malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ if (wrapper == NULL) { \ malloc_write(": Error allocating" \ " TSD for "#a_name"\n"); \ abort(); \ } else { \ - static a_type tsd_static_data = a_initializer; \ wrapper->initialized = false; \ - wrapper->val = tsd_static_data; \ - } \ - if (!TlsSetValue(a_name##_tsd, (void *)wrapper)) { \ - malloc_write(": Error setting" \ - " TSD for "#a_name"\n"); \ - abort(); \ + wrapper->val = a_initializer; \ } \ + a_name##tsd_wrapper_set(wrapper); \ } \ return (wrapper); \ } \ -a_attr a_type * \ -a_name##_tsd_get(void) \ +a_attr bool \ +a_name##tsd_boot0(void) \ { \ - a_name##_tsd_wrapper_t *wrapper; \ \ - assert(a_name##_booted); \ - wrapper = a_name##_tsd_get_wrapper(); \ + a_name##tsd_tsd = TlsAlloc(); \ + if (a_name##tsd_tsd == TLS_OUT_OF_INDEXES) \ + return (true); \ + if (a_cleanup != malloc_tsd_no_cleanup) { \ + malloc_tsd_cleanup_register( \ + &a_name##tsd_cleanup_wrapper); \ + } \ + a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \ + a_name##tsd_booted = true; \ + return (false); \ +} \ +a_attr void \ +a_name##tsd_boot1() \ +{ \ + a_name##tsd_wrapper_t *wrapper; \ + wrapper = (a_name##tsd_wrapper_t *) \ + malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ + if (wrapper == NULL) { \ + malloc_write(": Error allocating" \ + " TSD for "#a_name"\n"); \ + abort(); \ + } \ + memcpy(wrapper, &a_name##tsd_boot_wrapper, \ + sizeof(a_name##tsd_wrapper_t)); \ + a_name##tsd_wrapper_set(wrapper); \ +} \ +a_attr bool \ +a_name##tsd_boot(void) \ +{ \ + \ + if (a_name##tsd_boot0()) \ + return (true); \ + a_name##tsd_boot1(); \ + return (false); \ +} \ +/* Get/set. */ \ +a_attr a_type * \ +a_name##tsd_get(void) \ +{ \ + a_name##tsd_wrapper_t *wrapper; \ + \ + assert(a_name##tsd_booted); \ + wrapper = a_name##tsd_wrapper_get(); \ return (&wrapper->val); \ } \ a_attr void \ -a_name##_tsd_set(a_type *val) \ +a_name##tsd_set(a_type *val) \ { \ - a_name##_tsd_wrapper_t *wrapper; \ + a_name##tsd_wrapper_t *wrapper; \ \ - assert(a_name##_booted); \ - wrapper = a_name##_tsd_get_wrapper(); \ + assert(a_name##tsd_booted); \ + wrapper = a_name##tsd_wrapper_get(); \ wrapper->val = *(val); \ if (a_cleanup != malloc_tsd_no_cleanup) \ wrapper->initialized = true; \ @@ -297,16 +388,11 @@ a_name##_tsd_set(a_type *val) \ #else #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ a_cleanup) \ -/* Data structure. */ \ -typedef struct { \ - bool initialized; \ - a_type val; \ -} a_name##_tsd_wrapper_t; \ /* Initialization/cleanup. */ \ a_attr void \ -a_name##_tsd_cleanup_wrapper(void *arg) \ +a_name##tsd_cleanup_wrapper(void *arg) \ { \ - a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)arg;\ + a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *)arg; \ \ if (a_cleanup != malloc_tsd_no_cleanup && \ wrapper->initialized) { \ @@ -314,7 +400,7 @@ a_name##_tsd_cleanup_wrapper(void *arg) \ a_cleanup(&wrapper->val); \ if (wrapper->initialized) { \ /* Trigger another cleanup round. */ \ - if (pthread_setspecific(a_name##_tsd, \ + if (pthread_setspecific(a_name##tsd_tsd, \ (void *)wrapper)) { \ malloc_write(": Error" \ " setting TSD for "#a_name"\n"); \ @@ -326,67 +412,97 @@ a_name##_tsd_cleanup_wrapper(void *arg) \ } \ malloc_tsd_dalloc(wrapper); \ } \ -a_attr bool \ -a_name##_tsd_boot(void) \ +a_attr void \ +a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \ { \ \ - if (pthread_key_create(&a_name##_tsd, \ - a_name##_tsd_cleanup_wrapper) != 0) \ - return (true); \ - a_name##_booted = true; \ - return (false); \ + if (pthread_setspecific(a_name##tsd_tsd, \ + (void *)wrapper)) { \ + malloc_write(": Error setting" \ + " TSD for "#a_name"\n"); \ + abort(); \ + } \ } \ -/* Get/set. */ \ -a_attr a_name##_tsd_wrapper_t * \ -a_name##_tsd_get_wrapper(void) \ +a_attr a_name##tsd_wrapper_t * \ +a_name##tsd_wrapper_get(void) \ { \ - a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *) \ - pthread_getspecific(a_name##_tsd); \ + a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ + pthread_getspecific(a_name##tsd_tsd); \ \ - if (wrapper == NULL) { \ + if (unlikely(wrapper == NULL)) { \ tsd_init_block_t block; \ wrapper = tsd_init_check_recursion( \ - &a_name##_tsd_init_head, &block); \ + &a_name##tsd_init_head, &block); \ if (wrapper) \ return (wrapper); \ - wrapper = (a_name##_tsd_wrapper_t *) \ - malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \ + wrapper = (a_name##tsd_wrapper_t *) \ + malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ block.data = wrapper; \ if (wrapper == NULL) { \ malloc_write(": Error allocating" \ " TSD for "#a_name"\n"); \ abort(); \ } else { \ - static a_type tsd_static_data = a_initializer; \ wrapper->initialized = false; \ - wrapper->val = tsd_static_data; \ + wrapper->val = a_initializer; \ } \ - if (pthread_setspecific(a_name##_tsd, \ - (void *)wrapper)) { \ - malloc_write(": Error setting" \ - " TSD for "#a_name"\n"); \ - abort(); \ - } \ - tsd_init_finish(&a_name##_tsd_init_head, &block); \ + a_name##tsd_wrapper_set(wrapper); \ + tsd_init_finish(&a_name##tsd_init_head, &block); \ } \ return (wrapper); \ } \ -a_attr a_type * \ -a_name##_tsd_get(void) \ +a_attr bool \ +a_name##tsd_boot0(void) \ { \ - a_name##_tsd_wrapper_t *wrapper; \ \ - assert(a_name##_booted); \ - wrapper = a_name##_tsd_get_wrapper(); \ + if (pthread_key_create(&a_name##tsd_tsd, \ + a_name##tsd_cleanup_wrapper) != 0) \ + return (true); \ + a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \ + a_name##tsd_booted = true; \ + return (false); \ +} \ +a_attr void \ +a_name##tsd_boot1() \ +{ \ + a_name##tsd_wrapper_t *wrapper; \ + wrapper = (a_name##tsd_wrapper_t *) \ + malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ + if (wrapper == NULL) { \ + malloc_write(": Error allocating" \ + " TSD for "#a_name"\n"); \ + abort(); \ + } \ + memcpy(wrapper, &a_name##tsd_boot_wrapper, \ + sizeof(a_name##tsd_wrapper_t)); \ + a_name##tsd_wrapper_set(wrapper); \ +} \ +a_attr bool \ +a_name##tsd_boot(void) \ +{ \ + \ + if (a_name##tsd_boot0()) \ + return (true); \ + a_name##tsd_boot1(); \ + return (false); \ +} \ +/* Get/set. */ \ +a_attr a_type * \ +a_name##tsd_get(void) \ +{ \ + a_name##tsd_wrapper_t *wrapper; \ + \ + assert(a_name##tsd_booted); \ + wrapper = a_name##tsd_wrapper_get(); \ return (&wrapper->val); \ } \ a_attr void \ -a_name##_tsd_set(a_type *val) \ +a_name##tsd_set(a_type *val) \ { \ - a_name##_tsd_wrapper_t *wrapper; \ + a_name##tsd_wrapper_t *wrapper; \ \ - assert(a_name##_booted); \ - wrapper = a_name##_tsd_get_wrapper(); \ + assert(a_name##tsd_booted); \ + wrapper = a_name##tsd_wrapper_get(); \ wrapper->val = *(val); \ if (a_cleanup != malloc_tsd_no_cleanup) \ wrapper->initialized = true; \ @@ -410,25 +526,136 @@ struct tsd_init_head_s { }; #endif +#define MALLOC_TSD \ +/* O(name, type) */ \ + O(tcache, tcache_t *) \ + O(thread_allocated, uint64_t) \ + O(thread_deallocated, uint64_t) \ + O(prof_tdata, prof_tdata_t *) \ + O(arena, arena_t *) \ + O(arenas_cache, arena_t **) \ + O(narenas_cache, unsigned) \ + O(arenas_cache_bypass, bool) \ + O(tcache_enabled, tcache_enabled_t) \ + O(quarantine, quarantine_t *) \ + +#define TSD_INITIALIZER { \ + tsd_state_uninitialized, \ + NULL, \ + 0, \ + 0, \ + NULL, \ + NULL, \ + NULL, \ + 0, \ + false, \ + tcache_enabled_default, \ + NULL \ +} + +struct tsd_s { + tsd_state_t state; +#define O(n, t) \ + t n; +MALLOC_TSD +#undef O +}; + +static const tsd_t tsd_initializer = TSD_INITIALIZER; + +malloc_tsd_types(, tsd_t) + #endif /* JEMALLOC_H_STRUCTS */ /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS void *malloc_tsd_malloc(size_t size); void malloc_tsd_dalloc(void *wrapper); -void malloc_tsd_no_cleanup(void *); +void malloc_tsd_no_cleanup(void *arg); void malloc_tsd_cleanup_register(bool (*f)(void)); -void malloc_tsd_boot(void); +bool malloc_tsd_boot0(void); +void malloc_tsd_boot1(void); #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ !defined(_WIN32)) void *tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block); void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block); #endif +void tsd_cleanup(void *arg); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ #ifdef JEMALLOC_H_INLINES +#ifndef JEMALLOC_ENABLE_INLINE +malloc_tsd_protos(JEMALLOC_ATTR(unused), , tsd_t) + +tsd_t *tsd_fetch(void); +bool tsd_nominal(tsd_t *tsd); +#define O(n, t) \ +t *tsd_##n##p_get(tsd_t *tsd); \ +t tsd_##n##_get(tsd_t *tsd); \ +void tsd_##n##_set(tsd_t *tsd, t n); +MALLOC_TSD +#undef O +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TSD_C_)) +malloc_tsd_externs(, tsd_t) +malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup) + +JEMALLOC_ALWAYS_INLINE tsd_t * +tsd_fetch(void) +{ + tsd_t *tsd = tsd_get(); + + if (unlikely(tsd->state != tsd_state_nominal)) { + if (tsd->state == tsd_state_uninitialized) { + tsd->state = tsd_state_nominal; + /* Trigger cleanup handler registration. */ + tsd_set(tsd); + } else if (tsd->state == tsd_state_purgatory) { + tsd->state = tsd_state_reincarnated; + tsd_set(tsd); + } else + assert(tsd->state == tsd_state_reincarnated); + } + + return (tsd); +} + +JEMALLOC_INLINE bool +tsd_nominal(tsd_t *tsd) +{ + + return (tsd->state == tsd_state_nominal); +} + +#define O(n, t) \ +JEMALLOC_ALWAYS_INLINE t * \ +tsd_##n##p_get(tsd_t *tsd) \ +{ \ + \ + return (&tsd->n); \ +} \ + \ +JEMALLOC_ALWAYS_INLINE t \ +tsd_##n##_get(tsd_t *tsd) \ +{ \ + \ + return (*tsd_##n##p_get(tsd)); \ +} \ + \ +JEMALLOC_ALWAYS_INLINE void \ +tsd_##n##_set(tsd_t *tsd, t n) \ +{ \ + \ + assert(tsd->state == tsd_state_nominal); \ + tsd->n = n; \ +} +MALLOC_TSD +#undef O +#endif + #endif /* JEMALLOC_H_INLINES */ /******************************************************************************/ diff --git a/memory/jemalloc/src/include/jemalloc/internal/util.h b/memory/jemalloc/src/include/jemalloc/internal/util.h index a144e43e5fa2..b2b4ab740aa6 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/util.h +++ b/memory/jemalloc/src/include/jemalloc/internal/util.h @@ -27,13 +27,21 @@ # define JEMALLOC_CC_SILENCE_INIT(v) #endif +#ifdef __GNUC__ +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#else +#define likely(x) !!(x) +#define unlikely(x) !!(x) +#endif + /* * Define a custom assert() in order to reduce the chances of deadlock during * assertion failure. */ #ifndef assert #define assert(e) do { \ - if (config_debug && !(e)) { \ + if (unlikely(config_debug && !(e))) { \ malloc_printf( \ ": %s:%d: Failed assertion: \"%s\"\n", \ __FILE__, __LINE__, #e); \ @@ -65,14 +73,14 @@ #ifndef assert_not_implemented #define assert_not_implemented(e) do { \ - if (config_debug && !(e)) \ + if (unlikely(config_debug && !(e))) \ not_implemented(); \ } while (0) #endif /* Use to assert a particular configuration, e.g., cassert(config_debug). */ #define cassert(c) do { \ - if ((c) == false) \ + if (unlikely(!(c))) \ not_reached(); \ } while (0) @@ -112,13 +120,14 @@ void malloc_printf(const char *format, ...) int jemalloc_ffsl(long bitmap); int jemalloc_ffs(int bitmap); size_t pow2_ceil(size_t x); +size_t lg_floor(size_t x); void set_errno(int errnum); int get_errno(void); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_UTIL_C_)) -/* Sanity check: */ +/* Sanity check. */ #if !defined(JEMALLOC_INTERNAL_FFSL) || !defined(JEMALLOC_INTERNAL_FFS) # error Both JEMALLOC_INTERNAL_FFSL && JEMALLOC_INTERNAL_FFS should have been defined by configure #endif @@ -155,7 +164,74 @@ pow2_ceil(size_t x) return (x); } -/* Sets error code */ +#if (defined(__i386__) || defined(__amd64__) || defined(__x86_64__)) +JEMALLOC_INLINE size_t +lg_floor(size_t x) +{ + size_t ret; + + asm ("bsr %1, %0" + : "=r"(ret) // Outputs. + : "r"(x) // Inputs. + ); + return (ret); +} +#elif (defined(_MSC_VER)) +JEMALLOC_INLINE size_t +lg_floor(size_t x) +{ + unsigned long ret; + +#if (LG_SIZEOF_PTR == 3) + _BitScanReverse64(&ret, x); +#elif (LG_SIZEOF_PTR == 2) + _BitScanReverse(&ret, x); +#else +# error "Unsupported type sizes for lg_floor()" +#endif + return (ret); +} +#elif (defined(JEMALLOC_HAVE_BUILTIN_CLZ)) +JEMALLOC_INLINE size_t +lg_floor(size_t x) +{ + +#if (LG_SIZEOF_PTR == LG_SIZEOF_INT) + return (((8 << LG_SIZEOF_PTR) - 1) - __builtin_clz(x)); +#elif (LG_SIZEOF_PTR == LG_SIZEOF_LONG) + return (((8 << LG_SIZEOF_PTR) - 1) - __builtin_clzl(x)); +#else +# error "Unsupported type sizes for lg_floor()" +#endif +} +#else +JEMALLOC_INLINE size_t +lg_floor(size_t x) +{ + + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); +#if (LG_SIZEOF_PTR == 3 && LG_SIZEOF_PTR == LG_SIZEOF_LONG) + x |= (x >> 32); + if (x == KZU(0xffffffffffffffff)) + return (63); + x++; + return (jemalloc_ffsl(x) - 2); +#elif (LG_SIZEOF_PTR == 2) + if (x == KZU(0xffffffff)) + return (31); + x++; + return (jemalloc_ffs(x) - 2); +#else +# error "Unsupported type sizes for lg_floor()" +#endif +} +#endif + +/* Set error code. */ JEMALLOC_INLINE void set_errno(int errnum) { @@ -167,7 +243,7 @@ set_errno(int errnum) #endif } -/* Get last error code */ +/* Get last error code. */ JEMALLOC_INLINE int get_errno(void) { diff --git a/memory/jemalloc/src/include/jemalloc/internal/valgrind.h b/memory/jemalloc/src/include/jemalloc/internal/valgrind.h new file mode 100644 index 000000000000..a3380df9265d --- /dev/null +++ b/memory/jemalloc/src/include/jemalloc/internal/valgrind.h @@ -0,0 +1,112 @@ +/******************************************************************************/ +#ifdef JEMALLOC_H_TYPES + +#ifdef JEMALLOC_VALGRIND +#include + +/* + * The size that is reported to Valgrind must be consistent through a chain of + * malloc..realloc..realloc calls. Request size isn't recorded anywhere in + * jemalloc, so it is critical that all callers of these macros provide usize + * rather than request size. As a result, buffer overflow detection is + * technically weakened for the standard API, though it is generally accepted + * practice to consider any extra bytes reported by malloc_usable_size() as + * usable space. + */ +#define JEMALLOC_VALGRIND_MAKE_MEM_NOACCESS(ptr, usize) do { \ + if (unlikely(in_valgrind)) \ + valgrind_make_mem_noaccess(ptr, usize); \ +} while (0) +#define JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ptr, usize) do { \ + if (unlikely(in_valgrind)) \ + valgrind_make_mem_undefined(ptr, usize); \ +} while (0) +#define JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ptr, usize) do { \ + if (unlikely(in_valgrind)) \ + valgrind_make_mem_defined(ptr, usize); \ +} while (0) +/* + * The VALGRIND_MALLOCLIKE_BLOCK() and VALGRIND_RESIZEINPLACE_BLOCK() macro + * calls must be embedded in macros rather than in functions so that when + * Valgrind reports errors, there are no extra stack frames in the backtraces. + */ +#define JEMALLOC_VALGRIND_MALLOC(cond, ptr, usize, zero) do { \ + if (unlikely(in_valgrind && cond)) \ + VALGRIND_MALLOCLIKE_BLOCK(ptr, usize, p2rz(ptr), zero); \ +} while (0) +#define JEMALLOC_VALGRIND_REALLOC(maybe_moved, ptr, usize, \ + ptr_maybe_null, old_ptr, old_usize, old_rzsize, old_ptr_maybe_null, \ + zero) do { \ + if (unlikely(in_valgrind)) { \ + size_t rzsize = p2rz(ptr); \ + \ + if (!maybe_moved || ptr == old_ptr) { \ + VALGRIND_RESIZEINPLACE_BLOCK(ptr, old_usize, \ + usize, rzsize); \ + if (zero && old_usize < usize) { \ + valgrind_make_mem_defined( \ + (void *)((uintptr_t)ptr + \ + old_usize), usize - old_usize); \ + } \ + } else { \ + if (!old_ptr_maybe_null || old_ptr != NULL) { \ + valgrind_freelike_block(old_ptr, \ + old_rzsize); \ + } \ + if (!ptr_maybe_null || ptr != NULL) { \ + size_t copy_size = (old_usize < usize) \ + ? old_usize : usize; \ + size_t tail_size = usize - copy_size; \ + VALGRIND_MALLOCLIKE_BLOCK(ptr, usize, \ + rzsize, false); \ + if (copy_size > 0) { \ + valgrind_make_mem_defined(ptr, \ + copy_size); \ + } \ + if (zero && tail_size > 0) { \ + valgrind_make_mem_defined( \ + (void *)((uintptr_t)ptr + \ + copy_size), tail_size); \ + } \ + } \ + } \ + } \ +} while (0) +#define JEMALLOC_VALGRIND_FREE(ptr, rzsize) do { \ + if (unlikely(in_valgrind)) \ + valgrind_freelike_block(ptr, rzsize); \ +} while (0) +#else +#define RUNNING_ON_VALGRIND ((unsigned)0) +#define JEMALLOC_VALGRIND_MAKE_MEM_NOACCESS(ptr, usize) do {} while (0) +#define JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ptr, usize) do {} while (0) +#define JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ptr, usize) do {} while (0) +#define JEMALLOC_VALGRIND_MALLOC(cond, ptr, usize, zero) do {} while (0) +#define JEMALLOC_VALGRIND_REALLOC(maybe_moved, ptr, usize, \ + ptr_maybe_null, old_ptr, old_usize, old_rzsize, old_ptr_maybe_null, \ + zero) do {} while (0) +#define JEMALLOC_VALGRIND_FREE(ptr, rzsize) do {} while (0) +#endif + +#endif /* JEMALLOC_H_TYPES */ +/******************************************************************************/ +#ifdef JEMALLOC_H_STRUCTS + +#endif /* JEMALLOC_H_STRUCTS */ +/******************************************************************************/ +#ifdef JEMALLOC_H_EXTERNS + +#ifdef JEMALLOC_VALGRIND +void valgrind_make_mem_noaccess(void *ptr, size_t usize); +void valgrind_make_mem_undefined(void *ptr, size_t usize); +void valgrind_make_mem_defined(void *ptr, size_t usize); +void valgrind_freelike_block(void *ptr, size_t usize); +#endif + +#endif /* JEMALLOC_H_EXTERNS */ +/******************************************************************************/ +#ifdef JEMALLOC_H_INLINES + +#endif /* JEMALLOC_H_INLINES */ +/******************************************************************************/ + diff --git a/memory/jemalloc/src/include/jemalloc/jemalloc.sh b/memory/jemalloc/src/include/jemalloc/jemalloc.sh index e4738ebae99a..7e1c8be18f76 100755 --- a/memory/jemalloc/src/include/jemalloc/jemalloc.sh +++ b/memory/jemalloc/src/include/jemalloc/jemalloc.sh @@ -12,7 +12,7 @@ extern "C" { EOF for hdr in jemalloc_defs.h jemalloc_rename.h jemalloc_macros.h \ - jemalloc_protos.h jemalloc_mangle.h ; do + jemalloc_protos.h jemalloc_typedefs.h jemalloc_mangle.h ; do cat "${objroot}include/jemalloc/${hdr}" \ | grep -v 'Generated from .* by configure\.' \ | sed -e 's/^#define /#define /g' \ diff --git a/memory/jemalloc/src/include/jemalloc/jemalloc_defs.h.in b/memory/jemalloc/src/include/jemalloc/jemalloc_defs.h.in index eb38d7105ca5..ce6c6987c5b0 100644 --- a/memory/jemalloc/src/include/jemalloc/jemalloc_defs.h.in +++ b/memory/jemalloc/src/include/jemalloc/jemalloc_defs.h.in @@ -1,9 +1,6 @@ /* Defined if __attribute__((...)) syntax is supported. */ #undef JEMALLOC_HAVE_ATTR -/* Support the experimental API. */ -#undef JEMALLOC_EXPERIMENTAL - /* * Define overrides for non-standard allocator-related functions if they are * present on the system. diff --git a/memory/jemalloc/src/include/jemalloc/jemalloc_macros.h.in b/memory/jemalloc/src/include/jemalloc/jemalloc_macros.h.in index 13dbdd91209a..99f12611d6bf 100644 --- a/memory/jemalloc/src/include/jemalloc/jemalloc_macros.h.in +++ b/memory/jemalloc/src/include/jemalloc/jemalloc_macros.h.in @@ -1,3 +1,6 @@ +#include +#include +#include #include #include @@ -19,23 +22,6 @@ /* Bias arena index bits so that 0 encodes "MALLOCX_ARENA() unspecified". */ # define MALLOCX_ARENA(a) ((int)(((a)+1) << 8)) -#ifdef JEMALLOC_EXPERIMENTAL -# define ALLOCM_LG_ALIGN(la) (la) -# if LG_SIZEOF_PTR == 2 -# define ALLOCM_ALIGN(a) (ffs(a)-1) -# else -# define ALLOCM_ALIGN(a) \ - ((a < (size_t)INT_MAX) ? ffs(a)-1 : ffs(a>>32)+31) -# endif -# define ALLOCM_ZERO ((int)0x40) -# define ALLOCM_NO_MOVE ((int)0x80) -/* Bias arena index bits so that 0 encodes "ALLOCM_ARENA() unspecified". */ -# define ALLOCM_ARENA(a) ((int)(((a)+1) << 8)) -# define ALLOCM_SUCCESS 0 -# define ALLOCM_ERR_OOM 1 -# define ALLOCM_ERR_NOT_MOVED 2 -#endif - #ifdef JEMALLOC_HAVE_ATTR # define JEMALLOC_ATTR(s) __attribute__((s)) # define JEMALLOC_EXPORT JEMALLOC_ATTR(visibility("default")) diff --git a/memory/jemalloc/src/include/jemalloc/jemalloc_protos.h.in b/memory/jemalloc/src/include/jemalloc/jemalloc_protos.h.in index 25446de3d96e..f81adc14a7e7 100644 --- a/memory/jemalloc/src/include/jemalloc/jemalloc_protos.h.in +++ b/memory/jemalloc/src/include/jemalloc/jemalloc_protos.h.in @@ -17,13 +17,17 @@ JEMALLOC_EXPORT void *@je_@aligned_alloc(size_t alignment, size_t size) JEMALLOC_EXPORT void *@je_@realloc(void *ptr, size_t size); JEMALLOC_EXPORT void @je_@free(void *ptr); -JEMALLOC_EXPORT void *@je_@mallocx(size_t size, int flags); +JEMALLOC_EXPORT void *@je_@mallocx(size_t size, int flags) + JEMALLOC_ATTR(malloc); JEMALLOC_EXPORT void *@je_@rallocx(void *ptr, size_t size, int flags); JEMALLOC_EXPORT size_t @je_@xallocx(void *ptr, size_t size, size_t extra, int flags); -JEMALLOC_EXPORT size_t @je_@sallocx(const void *ptr, int flags); +JEMALLOC_EXPORT size_t @je_@sallocx(const void *ptr, int flags) + JEMALLOC_ATTR(pure); JEMALLOC_EXPORT void @je_@dallocx(void *ptr, int flags); -JEMALLOC_EXPORT size_t @je_@nallocx(size_t size, int flags); +JEMALLOC_EXPORT void @je_@sdallocx(void *ptr, size_t size, int flags); +JEMALLOC_EXPORT size_t @je_@nallocx(size_t size, int flags) + JEMALLOC_ATTR(pure); JEMALLOC_EXPORT int @je_@mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen); @@ -44,15 +48,3 @@ JEMALLOC_EXPORT void * @je_@memalign(size_t alignment, size_t size) #ifdef JEMALLOC_OVERRIDE_VALLOC JEMALLOC_EXPORT void * @je_@valloc(size_t size) JEMALLOC_ATTR(malloc); #endif - -#ifdef JEMALLOC_EXPERIMENTAL -JEMALLOC_EXPORT int @je_@allocm(void **ptr, size_t *rsize, size_t size, - int flags) JEMALLOC_ATTR(nonnull(1)); -JEMALLOC_EXPORT int @je_@rallocm(void **ptr, size_t *rsize, size_t size, - size_t extra, int flags) JEMALLOC_ATTR(nonnull(1)); -JEMALLOC_EXPORT int @je_@sallocm(const void *ptr, size_t *rsize, int flags) - JEMALLOC_ATTR(nonnull(1)); -JEMALLOC_EXPORT int @je_@dallocm(void *ptr, int flags) - JEMALLOC_ATTR(nonnull(1)); -JEMALLOC_EXPORT int @je_@nallocm(size_t *rsize, size_t size, int flags); -#endif diff --git a/memory/jemalloc/src/include/jemalloc/jemalloc_typedefs.h.in b/memory/jemalloc/src/include/jemalloc/jemalloc_typedefs.h.in new file mode 100644 index 000000000000..8092f1b155e6 --- /dev/null +++ b/memory/jemalloc/src/include/jemalloc/jemalloc_typedefs.h.in @@ -0,0 +1,2 @@ +typedef void *(chunk_alloc_t)(void *, size_t, size_t, bool *, unsigned); +typedef bool (chunk_dalloc_t)(void *, size_t, unsigned); diff --git a/memory/jemalloc/src/include/msvc_compat/C99/stdbool.h b/memory/jemalloc/src/include/msvc_compat/C99/stdbool.h index dee22288d4d5..d92160ebc752 100644 --- a/memory/jemalloc/src/include/msvc_compat/C99/stdbool.h +++ b/memory/jemalloc/src/include/msvc_compat/C99/stdbool.h @@ -5,6 +5,8 @@ /* MSVC doesn't define _Bool or bool in C, but does have BOOL */ /* Note this doesn't pass autoconf's test because (bool) 0.5 != true */ +/* Clang-cl uses MSVC headers, so needs msvc_compat, but has _Bool as + * a built-in type. */ #ifndef __clang__ typedef BOOL _Bool; #endif diff --git a/memory/jemalloc/src/jemalloc.pc.in b/memory/jemalloc/src/jemalloc.pc.in new file mode 100644 index 000000000000..af3f945d42f7 --- /dev/null +++ b/memory/jemalloc/src/jemalloc.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: jemalloc +Description: A general purpose malloc(3) implementation that emphasizes fragmentation avoidance and scalable concurrency support. +URL: http://www.canonware.com/jemalloc +Version: @jemalloc_version@ +Cflags: -I${includedir} +Libs: -L${libdir} -ljemalloc diff --git a/memory/jemalloc/src/src/arena.c b/memory/jemalloc/src/src/arena.c index 75b4f1f937ce..bf789950234d 100644 --- a/memory/jemalloc/src/src/arena.c +++ b/memory/jemalloc/src/src/arena.c @@ -7,35 +7,12 @@ ssize_t opt_lg_dirty_mult = LG_DIRTY_MULT_DEFAULT; arena_bin_info_t arena_bin_info[NBINS]; -JEMALLOC_ALIGNED(CACHELINE) -const uint8_t small_size2bin[] = { -#define S2B_8(i) i, -#define S2B_16(i) S2B_8(i) S2B_8(i) -#define S2B_32(i) S2B_16(i) S2B_16(i) -#define S2B_64(i) S2B_32(i) S2B_32(i) -#define S2B_128(i) S2B_64(i) S2B_64(i) -#define S2B_256(i) S2B_128(i) S2B_128(i) -#define S2B_512(i) S2B_256(i) S2B_256(i) -#define S2B_1024(i) S2B_512(i) S2B_512(i) -#define S2B_2048(i) S2B_1024(i) S2B_1024(i) -#define S2B_4096(i) S2B_2048(i) S2B_2048(i) -#define S2B_8192(i) S2B_4096(i) S2B_4096(i) -#define SIZE_CLASS(bin, delta, size) \ - S2B_##delta(bin) - SIZE_CLASSES -#undef S2B_8 -#undef S2B_16 -#undef S2B_32 -#undef S2B_64 -#undef S2B_128 -#undef S2B_256 -#undef S2B_512 -#undef S2B_1024 -#undef S2B_2048 -#undef S2B_4096 -#undef S2B_8192 -#undef SIZE_CLASS -}; +size_t map_bias; +size_t map_misc_offset; +size_t arena_maxrun; /* Max run size for arenas. */ +size_t arena_maxclass; /* Max size class for arenas. */ +unsigned nlclasses; /* Number of large size classes. */ +unsigned nhclasses; /* Number of huge size classes. */ /******************************************************************************/ /* @@ -53,296 +30,180 @@ static void arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk, /******************************************************************************/ -static inline int -arena_run_comp(arena_chunk_map_t *a, arena_chunk_map_t *b) +JEMALLOC_INLINE_C size_t +arena_miscelm_to_bits(arena_chunk_map_misc_t *miscelm) { - uintptr_t a_mapelm = (uintptr_t)a; - uintptr_t b_mapelm = (uintptr_t)b; + arena_chunk_t *chunk = CHUNK_ADDR2BASE(miscelm); + size_t pageind = arena_miscelm_to_pageind(miscelm); + + return (arena_mapbits_get(chunk, pageind)); +} + +JEMALLOC_INLINE_C int +arena_run_comp(arena_chunk_map_misc_t *a, arena_chunk_map_misc_t *b) +{ + uintptr_t a_miscelm = (uintptr_t)a; + uintptr_t b_miscelm = (uintptr_t)b; assert(a != NULL); assert(b != NULL); - return ((a_mapelm > b_mapelm) - (a_mapelm < b_mapelm)); + return ((a_miscelm > b_miscelm) - (a_miscelm < b_miscelm)); } /* Generate red-black tree functions. */ -rb_gen(static UNUSED, arena_run_tree_, arena_run_tree_t, arena_chunk_map_t, - u.rb_link, arena_run_comp) +rb_gen(static UNUSED, arena_run_tree_, arena_run_tree_t, arena_chunk_map_misc_t, + rb_link, arena_run_comp) -static inline int -arena_avail_comp(arena_chunk_map_t *a, arena_chunk_map_t *b) +JEMALLOC_INLINE_C int +arena_avail_comp(arena_chunk_map_misc_t *a, arena_chunk_map_misc_t *b) { int ret; - size_t a_size = a->bits & ~PAGE_MASK; - size_t b_size = b->bits & ~PAGE_MASK; + size_t a_size; + size_t b_size = arena_miscelm_to_bits(b) & ~PAGE_MASK; + uintptr_t a_miscelm = (uintptr_t)a; + uintptr_t b_miscelm = (uintptr_t)b; + + if (a_miscelm & CHUNK_MAP_KEY) + a_size = a_miscelm & ~PAGE_MASK; + else + a_size = arena_miscelm_to_bits(a) & ~PAGE_MASK; ret = (a_size > b_size) - (a_size < b_size); if (ret == 0) { - uintptr_t a_mapelm, b_mapelm; - - if ((a->bits & CHUNK_MAP_KEY) != CHUNK_MAP_KEY) - a_mapelm = (uintptr_t)a; + if (!(a_miscelm & CHUNK_MAP_KEY)) + ret = (a_miscelm > b_miscelm) - (a_miscelm < b_miscelm); else { /* - * Treat keys as though they are lower than anything - * else. + * Treat keys as if they are lower than anything else. */ - a_mapelm = 0; + ret = -1; } - b_mapelm = (uintptr_t)b; - - ret = (a_mapelm > b_mapelm) - (a_mapelm < b_mapelm); } return (ret); } /* Generate red-black tree functions. */ -rb_gen(static UNUSED, arena_avail_tree_, arena_avail_tree_t, arena_chunk_map_t, - u.rb_link, arena_avail_comp) - -static inline int -arena_chunk_dirty_comp(arena_chunk_t *a, arena_chunk_t *b) -{ - - assert(a != NULL); - assert(b != NULL); - - /* - * Short-circuit for self comparison. The following comparison code - * would come to the same result, but at the cost of executing the slow - * path. - */ - if (a == b) - return (0); - - /* - * Order such that chunks with higher fragmentation are "less than" - * those with lower fragmentation -- purging order is from "least" to - * "greatest". Fragmentation is measured as: - * - * mean current avail run size - * -------------------------------- - * mean defragmented avail run size - * - * navail - * ----------- - * nruns_avail nruns_avail-nruns_adjac - * = ========================= = ----------------------- - * navail nruns_avail - * ----------------------- - * nruns_avail-nruns_adjac - * - * The following code multiplies away the denominator prior to - * comparison, in order to avoid division. - * - */ - { - size_t a_val = (a->nruns_avail - a->nruns_adjac) * - b->nruns_avail; - size_t b_val = (b->nruns_avail - b->nruns_adjac) * - a->nruns_avail; - - if (a_val < b_val) - return (1); - if (a_val > b_val) - return (-1); - } - /* - * Break ties by chunk address. For fragmented chunks, report lower - * addresses as "lower", so that fragmentation reduction happens first - * at lower addresses. However, use the opposite ordering for - * unfragmented chunks, in order to increase the chances of - * re-allocating dirty runs. - */ - { - uintptr_t a_chunk = (uintptr_t)a; - uintptr_t b_chunk = (uintptr_t)b; - int ret = ((a_chunk > b_chunk) - (a_chunk < b_chunk)); - if (a->nruns_adjac == 0) { - assert(b->nruns_adjac == 0); - ret = -ret; - } - return (ret); - } -} - -/* Generate red-black tree functions. */ -rb_gen(static UNUSED, arena_chunk_dirty_, arena_chunk_tree_t, arena_chunk_t, - dirty_link, arena_chunk_dirty_comp) - -static inline bool -arena_avail_adjac_pred(arena_chunk_t *chunk, size_t pageind) -{ - bool ret; - - if (pageind-1 < map_bias) - ret = false; - else { - ret = (arena_mapbits_allocated_get(chunk, pageind-1) == 0); - assert(ret == false || arena_mapbits_dirty_get(chunk, - pageind-1) != arena_mapbits_dirty_get(chunk, pageind)); - } - return (ret); -} - -static inline bool -arena_avail_adjac_succ(arena_chunk_t *chunk, size_t pageind, size_t npages) -{ - bool ret; - - if (pageind+npages == chunk_npages) - ret = false; - else { - assert(pageind+npages < chunk_npages); - ret = (arena_mapbits_allocated_get(chunk, pageind+npages) == 0); - assert(ret == false || arena_mapbits_dirty_get(chunk, pageind) - != arena_mapbits_dirty_get(chunk, pageind+npages)); - } - return (ret); -} - -static inline bool -arena_avail_adjac(arena_chunk_t *chunk, size_t pageind, size_t npages) -{ - - return (arena_avail_adjac_pred(chunk, pageind) || - arena_avail_adjac_succ(chunk, pageind, npages)); -} +rb_gen(static UNUSED, arena_avail_tree_, arena_avail_tree_t, + arena_chunk_map_misc_t, rb_link, arena_avail_comp) static void arena_avail_insert(arena_t *arena, arena_chunk_t *chunk, size_t pageind, - size_t npages, bool maybe_adjac_pred, bool maybe_adjac_succ) + size_t npages) { assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> LG_PAGE)); - - /* - * chunks_dirty is keyed by nruns_{avail,adjac}, so the chunk must be - * removed and reinserted even if the run to be inserted is clean. - */ - if (chunk->ndirty != 0) - arena_chunk_dirty_remove(&arena->chunks_dirty, chunk); - - if (maybe_adjac_pred && arena_avail_adjac_pred(chunk, pageind)) - chunk->nruns_adjac++; - if (maybe_adjac_succ && arena_avail_adjac_succ(chunk, pageind, npages)) - chunk->nruns_adjac++; - chunk->nruns_avail++; - assert(chunk->nruns_avail > chunk->nruns_adjac); - - if (arena_mapbits_dirty_get(chunk, pageind) != 0) { - arena->ndirty += npages; - chunk->ndirty += npages; - } - if (chunk->ndirty != 0) - arena_chunk_dirty_insert(&arena->chunks_dirty, chunk); - - arena_avail_tree_insert(&arena->runs_avail, arena_mapp_get(chunk, + arena_avail_tree_insert(&arena->runs_avail, arena_miscelm_get(chunk, pageind)); } static void arena_avail_remove(arena_t *arena, arena_chunk_t *chunk, size_t pageind, - size_t npages, bool maybe_adjac_pred, bool maybe_adjac_succ) + size_t npages) { assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> LG_PAGE)); - - /* - * chunks_dirty is keyed by nruns_{avail,adjac}, so the chunk must be - * removed and reinserted even if the run to be removed is clean. - */ - if (chunk->ndirty != 0) - arena_chunk_dirty_remove(&arena->chunks_dirty, chunk); - - if (maybe_adjac_pred && arena_avail_adjac_pred(chunk, pageind)) - chunk->nruns_adjac--; - if (maybe_adjac_succ && arena_avail_adjac_succ(chunk, pageind, npages)) - chunk->nruns_adjac--; - chunk->nruns_avail--; - assert(chunk->nruns_avail > chunk->nruns_adjac || (chunk->nruns_avail - == 0 && chunk->nruns_adjac == 0)); - - if (arena_mapbits_dirty_get(chunk, pageind) != 0) { - arena->ndirty -= npages; - chunk->ndirty -= npages; - } - if (chunk->ndirty != 0) - arena_chunk_dirty_insert(&arena->chunks_dirty, chunk); - - arena_avail_tree_remove(&arena->runs_avail, arena_mapp_get(chunk, + arena_avail_tree_remove(&arena->runs_avail, arena_miscelm_get(chunk, pageind)); } -static inline void * +static void +arena_dirty_insert(arena_t *arena, arena_chunk_t *chunk, size_t pageind, + size_t npages) +{ + arena_chunk_map_misc_t *miscelm = arena_miscelm_get(chunk, pageind); + assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> + LG_PAGE)); + assert(arena_mapbits_dirty_get(chunk, pageind) == CHUNK_MAP_DIRTY); + assert(arena_mapbits_dirty_get(chunk, pageind+npages-1) == + CHUNK_MAP_DIRTY); + ql_elm_new(miscelm, dr_link); + ql_tail_insert(&arena->runs_dirty, miscelm, dr_link); + arena->ndirty += npages; +} + +static void +arena_dirty_remove(arena_t *arena, arena_chunk_t *chunk, size_t pageind, + size_t npages) +{ + arena_chunk_map_misc_t *miscelm = arena_miscelm_get(chunk, pageind); + assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> + LG_PAGE)); + assert(arena_mapbits_dirty_get(chunk, pageind) == CHUNK_MAP_DIRTY); + assert(arena_mapbits_dirty_get(chunk, pageind+npages-1) == + CHUNK_MAP_DIRTY); + ql_remove(&arena->runs_dirty, miscelm, dr_link); + arena->ndirty -= npages; +} + +JEMALLOC_INLINE_C void * arena_run_reg_alloc(arena_run_t *run, arena_bin_info_t *bin_info) { void *ret; unsigned regind; - bitmap_t *bitmap = (bitmap_t *)((uintptr_t)run + - (uintptr_t)bin_info->bitmap_offset); + arena_chunk_map_misc_t *miscelm; + void *rpages; assert(run->nfree > 0); - assert(bitmap_full(bitmap, &bin_info->bitmap_info) == false); + assert(!bitmap_full(run->bitmap, &bin_info->bitmap_info)); - regind = bitmap_sfu(bitmap, &bin_info->bitmap_info); - ret = (void *)((uintptr_t)run + (uintptr_t)bin_info->reg0_offset + + regind = bitmap_sfu(run->bitmap, &bin_info->bitmap_info); + miscelm = arena_run_to_miscelm(run); + rpages = arena_miscelm_to_rpages(miscelm); + ret = (void *)((uintptr_t)rpages + (uintptr_t)bin_info->reg0_offset + (uintptr_t)(bin_info->reg_interval * regind)); run->nfree--; - if (regind == run->nextind) - run->nextind++; - assert(regind < run->nextind); return (ret); } -static inline void +JEMALLOC_INLINE_C void arena_run_reg_dalloc(arena_run_t *run, void *ptr) { arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; size_t mapbits = arena_mapbits_get(chunk, pageind); - size_t binind = arena_ptr_small_binind_get(ptr, mapbits); + index_t binind = arena_ptr_small_binind_get(ptr, mapbits); arena_bin_info_t *bin_info = &arena_bin_info[binind]; unsigned regind = arena_run_regind(run, bin_info, ptr); - bitmap_t *bitmap = (bitmap_t *)((uintptr_t)run + - (uintptr_t)bin_info->bitmap_offset); assert(run->nfree < bin_info->nregs); /* Freeing an interior pointer can cause assertion failure. */ - assert(((uintptr_t)ptr - ((uintptr_t)run + + assert(((uintptr_t)ptr - + ((uintptr_t)arena_miscelm_to_rpages(arena_run_to_miscelm(run)) + (uintptr_t)bin_info->reg0_offset)) % (uintptr_t)bin_info->reg_interval == 0); - assert((uintptr_t)ptr >= (uintptr_t)run + + assert((uintptr_t)ptr >= + (uintptr_t)arena_miscelm_to_rpages(arena_run_to_miscelm(run)) + (uintptr_t)bin_info->reg0_offset); /* Freeing an unallocated pointer can cause assertion failure. */ - assert(bitmap_get(bitmap, &bin_info->bitmap_info, regind)); + assert(bitmap_get(run->bitmap, &bin_info->bitmap_info, regind)); - bitmap_unset(bitmap, &bin_info->bitmap_info, regind); + bitmap_unset(run->bitmap, &bin_info->bitmap_info, regind); run->nfree++; } -static inline void +JEMALLOC_INLINE_C void arena_run_zero(arena_chunk_t *chunk, size_t run_ind, size_t npages) { - VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + (run_ind << - LG_PAGE)), (npages << LG_PAGE)); + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + + (run_ind << LG_PAGE)), (npages << LG_PAGE)); memset((void *)((uintptr_t)chunk + (run_ind << LG_PAGE)), 0, (npages << LG_PAGE)); } -static inline void +JEMALLOC_INLINE_C void arena_run_page_mark_zeroed(arena_chunk_t *chunk, size_t run_ind) { - VALGRIND_MAKE_MEM_DEFINED((void *)((uintptr_t)chunk + (run_ind << - LG_PAGE)), PAGE); + JEMALLOC_VALGRIND_MAKE_MEM_DEFINED((void *)((uintptr_t)chunk + (run_ind + << LG_PAGE)), PAGE); } -static inline void +JEMALLOC_INLINE_C void arena_run_page_validate_zeroed(arena_chunk_t *chunk, size_t run_ind) { size_t i; @@ -358,9 +219,9 @@ arena_cactive_update(arena_t *arena, size_t add_pages, size_t sub_pages) { if (config_stats) { - ssize_t cactive_diff = CHUNK_CEILING((arena->nactive + - add_pages) << LG_PAGE) - CHUNK_CEILING((arena->nactive - - sub_pages) << LG_PAGE); + ssize_t cactive_diff = CHUNK_CEILING((arena->nactive + add_pages + - sub_pages) << LG_PAGE) - CHUNK_CEILING(arena->nactive << + LG_PAGE); if (cactive_diff != 0) stats_cactive_add(cactive_diff); } @@ -379,7 +240,9 @@ arena_run_split_remove(arena_t *arena, arena_chunk_t *chunk, size_t run_ind, assert(need_pages <= total_pages); rem_pages = total_pages - need_pages; - arena_avail_remove(arena, chunk, run_ind, total_pages, true, true); + arena_avail_remove(arena, chunk, run_ind, total_pages); + if (flag_dirty != 0) + arena_dirty_remove(arena, chunk, run_ind, total_pages); arena_cactive_update(arena, need_pages, 0); arena->nactive += need_pages; @@ -392,6 +255,8 @@ arena_run_split_remove(arena_t *arena, arena_chunk_t *chunk, size_t run_ind, arena_mapbits_unallocated_set(chunk, run_ind+total_pages-1, (rem_pages << LG_PAGE), flag_dirty); + arena_dirty_insert(arena, chunk, run_ind+need_pages, + rem_pages); } else { arena_mapbits_unallocated_set(chunk, run_ind+need_pages, (rem_pages << LG_PAGE), @@ -402,8 +267,7 @@ arena_run_split_remove(arena_t *arena, arena_chunk_t *chunk, size_t run_ind, arena_mapbits_unzeroed_get(chunk, run_ind+total_pages-1)); } - arena_avail_insert(arena, chunk, run_ind+need_pages, rem_pages, - false, true); + arena_avail_insert(arena, chunk, run_ind+need_pages, rem_pages); } } @@ -412,10 +276,12 @@ arena_run_split_large_helper(arena_t *arena, arena_run_t *run, size_t size, bool remove, bool zero) { arena_chunk_t *chunk; + arena_chunk_map_misc_t *miscelm; size_t flag_dirty, run_ind, need_pages, i; chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); - run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE); + miscelm = arena_run_to_miscelm(run); + run_ind = arena_miscelm_to_pageind(miscelm); flag_dirty = arena_mapbits_dirty_get(chunk, run_ind); need_pages = (size >> LG_PAGE); assert(need_pages > 0); @@ -448,7 +314,7 @@ arena_run_split_large_helper(arena_t *arena, arena_run_t *run, size_t size, arena_run_zero(chunk, run_ind, need_pages); } } else { - VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + (run_ind << LG_PAGE)), (need_pages << LG_PAGE)); } @@ -476,47 +342,30 @@ arena_run_init_large(arena_t *arena, arena_run_t *run, size_t size, bool zero) static void arena_run_split_small(arena_t *arena, arena_run_t *run, size_t size, - size_t binind) + index_t binind) { arena_chunk_t *chunk; + arena_chunk_map_misc_t *miscelm; size_t flag_dirty, run_ind, need_pages, i; assert(binind != BININD_INVALID); chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); - run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE); + miscelm = arena_run_to_miscelm(run); + run_ind = arena_miscelm_to_pageind(miscelm); flag_dirty = arena_mapbits_dirty_get(chunk, run_ind); need_pages = (size >> LG_PAGE); assert(need_pages > 0); arena_run_split_remove(arena, chunk, run_ind, flag_dirty, need_pages); - /* - * Propagate the dirty and unzeroed flags to the allocated small run, - * so that arena_dalloc_bin_run() has the ability to conditionally trim - * clean pages. - */ - arena_mapbits_small_set(chunk, run_ind, 0, binind, flag_dirty); - /* - * The first page will always be dirtied during small run - * initialization, so a validation failure here would not actually - * cause an observable failure. - */ - if (config_debug && flag_dirty == 0 && arena_mapbits_unzeroed_get(chunk, - run_ind) == 0) - arena_run_page_validate_zeroed(chunk, run_ind); - for (i = 1; i < need_pages - 1; i++) { + for (i = 0; i < need_pages; i++) { arena_mapbits_small_set(chunk, run_ind+i, i, binind, 0); if (config_debug && flag_dirty == 0 && arena_mapbits_unzeroed_get(chunk, run_ind+i) == 0) arena_run_page_validate_zeroed(chunk, run_ind+i); } - arena_mapbits_small_set(chunk, run_ind+need_pages-1, need_pages-1, - binind, flag_dirty); - if (config_debug && flag_dirty == 0 && arena_mapbits_unzeroed_get(chunk, - run_ind+need_pages-1) == 0) - arena_run_page_validate_zeroed(chunk, run_ind+need_pages-1); - VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + (run_ind << LG_PAGE)), (need_pages << LG_PAGE)); } @@ -533,15 +382,35 @@ arena_chunk_init_spare(arena_t *arena) assert(arena_mapbits_allocated_get(chunk, map_bias) == 0); assert(arena_mapbits_allocated_get(chunk, chunk_npages-1) == 0); assert(arena_mapbits_unallocated_size_get(chunk, map_bias) == - arena_maxclass); + arena_maxrun); assert(arena_mapbits_unallocated_size_get(chunk, chunk_npages-1) == - arena_maxclass); + arena_maxrun); assert(arena_mapbits_dirty_get(chunk, map_bias) == arena_mapbits_dirty_get(chunk, chunk_npages-1)); return (chunk); } +static arena_chunk_t * +arena_chunk_alloc_internal(arena_t *arena, size_t size, size_t alignment, + bool *zero) +{ + arena_chunk_t *chunk; + chunk_alloc_t *chunk_alloc; + chunk_dalloc_t *chunk_dalloc; + + chunk_alloc = arena->chunk_alloc; + chunk_dalloc = arena->chunk_dalloc; + malloc_mutex_unlock(&arena->lock); + chunk = (arena_chunk_t *)chunk_alloc_arena(chunk_alloc, chunk_dalloc, + arena->ind, NULL, size, alignment, zero); + malloc_mutex_lock(&arena->lock); + if (config_stats && chunk != NULL) + arena->stats.mapped += chunksize; + + return (chunk); +} + static arena_chunk_t * arena_chunk_init_hard(arena_t *arena) { @@ -552,48 +421,35 @@ arena_chunk_init_hard(arena_t *arena) assert(arena->spare == NULL); zero = false; - malloc_mutex_unlock(&arena->lock); - chunk = (arena_chunk_t *)chunk_alloc(chunksize, chunksize, false, - &zero, arena->dss_prec); - malloc_mutex_lock(&arena->lock); + chunk = arena_chunk_alloc_internal(arena, chunksize, chunksize, &zero); if (chunk == NULL) return (NULL); - if (config_stats) - arena->stats.mapped += chunksize; chunk->arena = arena; - /* - * Claim that no pages are in use, since the header is merely overhead. - */ - chunk->ndirty = 0; - - chunk->nruns_avail = 0; - chunk->nruns_adjac = 0; - /* * Initialize the map to contain one maximal free untouched run. Mark * the pages as zeroed iff chunk_alloc() returned a zeroed chunk. */ unzeroed = zero ? 0 : CHUNK_MAP_UNZEROED; - arena_mapbits_unallocated_set(chunk, map_bias, arena_maxclass, - unzeroed); + arena_mapbits_unallocated_set(chunk, map_bias, arena_maxrun, unzeroed); /* * There is no need to initialize the internal page map entries unless * the chunk is not zeroed. */ - if (zero == false) { - VALGRIND_MAKE_MEM_UNDEFINED((void *)arena_mapp_get(chunk, - map_bias+1), (size_t)((uintptr_t) arena_mapp_get(chunk, - chunk_npages-1) - (uintptr_t)arena_mapp_get(chunk, + if (!zero) { + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED( + (void *)arena_bitselm_get(chunk, map_bias+1), + (size_t)((uintptr_t) arena_bitselm_get(chunk, + chunk_npages-1) - (uintptr_t)arena_bitselm_get(chunk, map_bias+1))); for (i = map_bias+1; i < chunk_npages-1; i++) arena_mapbits_unzeroed_set(chunk, i, unzeroed); } else { - VALGRIND_MAKE_MEM_DEFINED((void *)arena_mapp_get(chunk, - map_bias+1), (size_t)((uintptr_t) arena_mapp_get(chunk, - chunk_npages-1) - (uintptr_t)arena_mapp_get(chunk, - map_bias+1))); + JEMALLOC_VALGRIND_MAKE_MEM_DEFINED((void + *)arena_bitselm_get(chunk, map_bias+1), (size_t)((uintptr_t) + arena_bitselm_get(chunk, chunk_npages-1) - + (uintptr_t)arena_bitselm_get(chunk, map_bias+1))); if (config_debug) { for (i = map_bias+1; i < chunk_npages-1; i++) { assert(arena_mapbits_unzeroed_get(chunk, i) == @@ -601,7 +457,7 @@ arena_chunk_init_hard(arena_t *arena) } } } - arena_mapbits_unallocated_set(chunk, chunk_npages-1, arena_maxclass, + arena_mapbits_unallocated_set(chunk, chunk_npages-1, arena_maxrun, unzeroed); return (chunk); @@ -621,21 +477,21 @@ arena_chunk_alloc(arena_t *arena) } /* Insert the run into the runs_avail tree. */ - arena_avail_insert(arena, chunk, map_bias, chunk_npages-map_bias, - false, false); + arena_avail_insert(arena, chunk, map_bias, chunk_npages-map_bias); return (chunk); } static void -arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk) +arena_chunk_dalloc(arena_t *arena, arena_chunk_t *chunk) { + assert(arena_mapbits_allocated_get(chunk, map_bias) == 0); assert(arena_mapbits_allocated_get(chunk, chunk_npages-1) == 0); assert(arena_mapbits_unallocated_size_get(chunk, map_bias) == - arena_maxclass); + arena_maxrun); assert(arena_mapbits_unallocated_size_get(chunk, chunk_npages-1) == - arena_maxclass); + arena_maxrun); assert(arena_mapbits_dirty_get(chunk, map_bias) == arena_mapbits_dirty_get(chunk, chunk_npages-1)); @@ -643,15 +499,20 @@ arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk) * Remove run from the runs_avail tree, so that the arena does not use * it. */ - arena_avail_remove(arena, chunk, map_bias, chunk_npages-map_bias, - false, false); + arena_avail_remove(arena, chunk, map_bias, chunk_npages-map_bias); if (arena->spare != NULL) { arena_chunk_t *spare = arena->spare; + chunk_dalloc_t *chunk_dalloc; arena->spare = chunk; + if (arena_mapbits_dirty_get(spare, map_bias) != 0) { + arena_dirty_remove(arena, spare, map_bias, + chunk_npages-map_bias); + } + chunk_dalloc = arena->chunk_dalloc; malloc_mutex_unlock(&arena->lock); - chunk_dealloc((void *)spare, chunksize, true); + chunk_dalloc((void *)spare, chunksize, arena->ind); malloc_mutex_lock(&arena->lock); if (config_stats) arena->stats.mapped -= chunksize; @@ -659,23 +520,234 @@ arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk) arena->spare = chunk; } +static void +arena_huge_malloc_stats_update(arena_t *arena, size_t usize) +{ + index_t index = size2index(usize) - nlclasses - NBINS; + + cassert(config_stats); + + arena->stats.nmalloc_huge++; + arena->stats.allocated_huge += usize; + arena->stats.hstats[index].nmalloc++; + arena->stats.hstats[index].curhchunks++; +} + +static void +arena_huge_malloc_stats_update_undo(arena_t *arena, size_t usize) +{ + index_t index = size2index(usize) - nlclasses - NBINS; + + cassert(config_stats); + + arena->stats.nmalloc_huge--; + arena->stats.allocated_huge -= usize; + arena->stats.hstats[index].nmalloc--; + arena->stats.hstats[index].curhchunks--; +} + +static void +arena_huge_dalloc_stats_update(arena_t *arena, size_t usize) +{ + index_t index = size2index(usize) - nlclasses - NBINS; + + cassert(config_stats); + + arena->stats.ndalloc_huge++; + arena->stats.allocated_huge -= usize; + arena->stats.hstats[index].ndalloc++; + arena->stats.hstats[index].curhchunks--; +} + +static void +arena_huge_dalloc_stats_update_undo(arena_t *arena, size_t usize) +{ + index_t index = size2index(usize) - nlclasses - NBINS; + + cassert(config_stats); + + arena->stats.ndalloc_huge--; + arena->stats.allocated_huge += usize; + arena->stats.hstats[index].ndalloc--; + arena->stats.hstats[index].curhchunks++; +} + +static void +arena_huge_ralloc_stats_update(arena_t *arena, size_t oldsize, size_t usize) +{ + + arena_huge_dalloc_stats_update(arena, oldsize); + arena_huge_malloc_stats_update(arena, usize); +} + +static void +arena_huge_ralloc_stats_update_undo(arena_t *arena, size_t oldsize, + size_t usize) +{ + + arena_huge_dalloc_stats_update_undo(arena, oldsize); + arena_huge_malloc_stats_update_undo(arena, usize); +} + +void * +arena_chunk_alloc_huge(arena_t *arena, size_t usize, size_t alignment, + bool *zero) +{ + void *ret; + chunk_alloc_t *chunk_alloc; + chunk_dalloc_t *chunk_dalloc; + size_t csize = CHUNK_CEILING(usize); + + malloc_mutex_lock(&arena->lock); + chunk_alloc = arena->chunk_alloc; + chunk_dalloc = arena->chunk_dalloc; + if (config_stats) { + /* Optimistically update stats prior to unlocking. */ + arena_huge_malloc_stats_update(arena, usize); + arena->stats.mapped += usize; + } + arena->nactive += (usize >> LG_PAGE); + malloc_mutex_unlock(&arena->lock); + + ret = chunk_alloc_arena(chunk_alloc, chunk_dalloc, arena->ind, NULL, + csize, alignment, zero); + if (ret == NULL) { + /* Revert optimistic stats updates. */ + malloc_mutex_lock(&arena->lock); + if (config_stats) { + arena_huge_malloc_stats_update_undo(arena, usize); + arena->stats.mapped -= usize; + } + arena->nactive -= (usize >> LG_PAGE); + malloc_mutex_unlock(&arena->lock); + return (NULL); + } + + if (config_stats) + stats_cactive_add(usize); + + return (ret); +} + +void +arena_chunk_dalloc_huge(arena_t *arena, void *chunk, size_t usize) +{ + chunk_dalloc_t *chunk_dalloc; + + malloc_mutex_lock(&arena->lock); + chunk_dalloc = arena->chunk_dalloc; + if (config_stats) { + arena_huge_dalloc_stats_update(arena, usize); + arena->stats.mapped -= usize; + stats_cactive_sub(usize); + } + arena->nactive -= (usize >> LG_PAGE); + malloc_mutex_unlock(&arena->lock); + chunk_dalloc(chunk, CHUNK_CEILING(usize), arena->ind); +} + +void +arena_chunk_ralloc_huge_similar(arena_t *arena, void *chunk, size_t oldsize, + size_t usize) +{ + + assert(CHUNK_CEILING(oldsize) == CHUNK_CEILING(usize)); + assert(oldsize != usize); + + malloc_mutex_lock(&arena->lock); + if (config_stats) + arena_huge_ralloc_stats_update(arena, oldsize, usize); + if (oldsize < usize) { + size_t udiff = usize - oldsize; + arena->nactive += udiff >> LG_PAGE; + if (config_stats) + stats_cactive_add(udiff); + } else { + size_t udiff = oldsize - usize; + arena->nactive -= udiff >> LG_PAGE; + if (config_stats) + stats_cactive_sub(udiff); + } + malloc_mutex_unlock(&arena->lock); +} + +void +arena_chunk_ralloc_huge_shrink(arena_t *arena, void *chunk, size_t oldsize, + size_t usize) +{ + chunk_dalloc_t *chunk_dalloc; + size_t udiff = oldsize - usize; + size_t cdiff = CHUNK_CEILING(oldsize) - CHUNK_CEILING(usize); + + malloc_mutex_lock(&arena->lock); + chunk_dalloc = arena->chunk_dalloc; + if (config_stats) { + arena_huge_ralloc_stats_update(arena, oldsize, usize); + if (cdiff != 0) { + arena->stats.mapped -= cdiff; + stats_cactive_sub(udiff); + } + } + arena->nactive -= udiff >> LG_PAGE; + malloc_mutex_unlock(&arena->lock); + if (cdiff != 0) { + chunk_dalloc((void *)((uintptr_t)chunk + CHUNK_CEILING(usize)), + cdiff, arena->ind); + } +} + +bool +arena_chunk_ralloc_huge_expand(arena_t *arena, void *chunk, size_t oldsize, + size_t usize, bool *zero) +{ + chunk_alloc_t *chunk_alloc; + chunk_dalloc_t *chunk_dalloc; + size_t udiff = usize - oldsize; + size_t cdiff = CHUNK_CEILING(usize) - CHUNK_CEILING(oldsize); + + malloc_mutex_lock(&arena->lock); + chunk_alloc = arena->chunk_alloc; + chunk_dalloc = arena->chunk_dalloc; + if (config_stats) { + /* Optimistically update stats prior to unlocking. */ + arena_huge_ralloc_stats_update(arena, oldsize, usize); + arena->stats.mapped += cdiff; + } + arena->nactive += (udiff >> LG_PAGE); + malloc_mutex_unlock(&arena->lock); + + if (chunk_alloc_arena(chunk_alloc, chunk_dalloc, arena->ind, + (void *)((uintptr_t)chunk + CHUNK_CEILING(oldsize)), cdiff, + chunksize, zero) == NULL) { + /* Revert optimistic stats updates. */ + malloc_mutex_lock(&arena->lock); + if (config_stats) { + arena_huge_ralloc_stats_update_undo(arena, + oldsize, usize); + arena->stats.mapped -= cdiff; + } + arena->nactive -= (udiff >> LG_PAGE); + malloc_mutex_unlock(&arena->lock); + return (true); + } + + if (config_stats) + stats_cactive_add(udiff); + + return (false); +} + static arena_run_t * arena_run_alloc_large_helper(arena_t *arena, size_t size, bool zero) { - arena_run_t *run; - arena_chunk_map_t *mapelm, key; + arena_chunk_map_misc_t *miscelm; + arena_chunk_map_misc_t *key; - key.bits = size | CHUNK_MAP_KEY; - mapelm = arena_avail_tree_nsearch(&arena->runs_avail, &key); - if (mapelm != NULL) { - arena_chunk_t *run_chunk = CHUNK_ADDR2BASE(mapelm); - size_t pageind = (((uintptr_t)mapelm - - (uintptr_t)run_chunk->map) / sizeof(arena_chunk_map_t)) - + map_bias; - - run = (arena_run_t *)((uintptr_t)run_chunk + (pageind << - LG_PAGE)); - arena_run_split_large(arena, run, size, zero); + key = (arena_chunk_map_misc_t *)(size | CHUNK_MAP_KEY); + miscelm = arena_avail_tree_nsearch(&arena->runs_avail, key); + if (miscelm != NULL) { + arena_run_t *run = &miscelm->run; + arena_run_split_large(arena, &miscelm->run, size, zero); return (run); } @@ -688,7 +760,7 @@ arena_run_alloc_large(arena_t *arena, size_t size, bool zero) arena_chunk_t *chunk; arena_run_t *run; - assert(size <= arena_maxclass); + assert(size <= arena_maxrun); assert((size & PAGE_MASK) == 0); /* Search the arena's chunks for the lowest best fit. */ @@ -701,7 +773,7 @@ arena_run_alloc_large(arena_t *arena, size_t size, bool zero) */ chunk = arena_chunk_alloc(arena); if (chunk != NULL) { - run = (arena_run_t *)((uintptr_t)chunk + (map_bias << LG_PAGE)); + run = &arena_miscelm_get(chunk, map_bias)->run; arena_run_split_large(arena, run, size, zero); return (run); } @@ -715,21 +787,16 @@ arena_run_alloc_large(arena_t *arena, size_t size, bool zero) } static arena_run_t * -arena_run_alloc_small_helper(arena_t *arena, size_t size, size_t binind) +arena_run_alloc_small_helper(arena_t *arena, size_t size, index_t binind) { arena_run_t *run; - arena_chunk_map_t *mapelm, key; + arena_chunk_map_misc_t *miscelm; + arena_chunk_map_misc_t *key; - key.bits = size | CHUNK_MAP_KEY; - mapelm = arena_avail_tree_nsearch(&arena->runs_avail, &key); - if (mapelm != NULL) { - arena_chunk_t *run_chunk = CHUNK_ADDR2BASE(mapelm); - size_t pageind = (((uintptr_t)mapelm - - (uintptr_t)run_chunk->map) / sizeof(arena_chunk_map_t)) - + map_bias; - - run = (arena_run_t *)((uintptr_t)run_chunk + (pageind << - LG_PAGE)); + key = (arena_chunk_map_misc_t *)(size | CHUNK_MAP_KEY); + miscelm = arena_avail_tree_nsearch(&arena->runs_avail, key); + if (miscelm != NULL) { + run = &miscelm->run; arena_run_split_small(arena, run, size, binind); return (run); } @@ -738,12 +805,12 @@ arena_run_alloc_small_helper(arena_t *arena, size_t size, size_t binind) } static arena_run_t * -arena_run_alloc_small(arena_t *arena, size_t size, size_t binind) +arena_run_alloc_small(arena_t *arena, size_t size, index_t binind) { arena_chunk_t *chunk; arena_run_t *run; - assert(size <= arena_maxclass); + assert(size <= arena_maxrun); assert((size & PAGE_MASK) == 0); assert(binind != BININD_INVALID); @@ -757,7 +824,7 @@ arena_run_alloc_small(arena_t *arena, size_t size, size_t binind) */ chunk = arena_chunk_alloc(arena); if (chunk != NULL) { - run = (arena_run_t *)((uintptr_t)chunk + (map_bias << LG_PAGE)); + run = &arena_miscelm_get(chunk, map_bias)->run; arena_run_split_small(arena, run, size, binind); return (run); } @@ -770,141 +837,137 @@ arena_run_alloc_small(arena_t *arena, size_t size, size_t binind) return (arena_run_alloc_small_helper(arena, size, binind)); } -static inline void +JEMALLOC_INLINE_C void arena_maybe_purge(arena_t *arena) { - size_t npurgeable, threshold; + size_t threshold; /* Don't purge if the option is disabled. */ if (opt_lg_dirty_mult < 0) return; - /* Don't purge if all dirty pages are already being purged. */ - if (arena->ndirty <= arena->npurgatory) - return; - npurgeable = arena->ndirty - arena->npurgatory; threshold = (arena->nactive >> opt_lg_dirty_mult); /* * Don't purge unless the number of purgeable pages exceeds the * threshold. */ - if (npurgeable <= threshold) + if (arena->ndirty <= threshold) return; arena_purge(arena, false); } -static arena_chunk_t * -chunks_dirty_iter_cb(arena_chunk_tree_t *tree, arena_chunk_t *chunk, void *arg) +static size_t +arena_dirty_count(arena_t *arena) { - size_t *ndirty = (size_t *)arg; + size_t ndirty = 0; + arena_chunk_map_misc_t *miscelm; + arena_chunk_t *chunk; + size_t pageind, npages; - assert(chunk->ndirty != 0); - *ndirty += chunk->ndirty; - return (NULL); + ql_foreach(miscelm, &arena->runs_dirty, dr_link) { + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(miscelm); + pageind = arena_miscelm_to_pageind(miscelm); + assert(arena_mapbits_allocated_get(chunk, pageind) == 0); + assert(arena_mapbits_large_get(chunk, pageind) == 0); + assert(arena_mapbits_dirty_get(chunk, pageind) != 0); + npages = arena_mapbits_unallocated_size_get(chunk, pageind) >> + LG_PAGE; + ndirty += npages; + } + + return (ndirty); } static size_t -arena_compute_npurgatory(arena_t *arena, bool all) +arena_compute_npurge(arena_t *arena, bool all) { - size_t npurgatory, npurgeable; + size_t npurge; /* * Compute the minimum number of pages that this thread should try to * purge. */ - npurgeable = arena->ndirty - arena->npurgatory; - - if (all == false) { + if (!all) { size_t threshold = (arena->nactive >> opt_lg_dirty_mult); - npurgatory = npurgeable - threshold; + npurge = arena->ndirty - threshold; } else - npurgatory = npurgeable; + npurge = arena->ndirty; - return (npurgatory); -} - -static void -arena_chunk_stash_dirty(arena_t *arena, arena_chunk_t *chunk, bool all, - arena_chunk_mapelms_t *mapelms) -{ - size_t pageind, npages; - - /* - * Temporarily allocate free dirty runs within chunk. If all is false, - * only operate on dirty runs that are fragments; otherwise operate on - * all dirty runs. - */ - for (pageind = map_bias; pageind < chunk_npages; pageind += npages) { - arena_chunk_map_t *mapelm = arena_mapp_get(chunk, pageind); - if (arena_mapbits_allocated_get(chunk, pageind) == 0) { - size_t run_size = - arena_mapbits_unallocated_size_get(chunk, pageind); - - npages = run_size >> LG_PAGE; - assert(pageind + npages <= chunk_npages); - assert(arena_mapbits_dirty_get(chunk, pageind) == - arena_mapbits_dirty_get(chunk, pageind+npages-1)); - - if (arena_mapbits_dirty_get(chunk, pageind) != 0 && - (all || arena_avail_adjac(chunk, pageind, - npages))) { - arena_run_t *run = (arena_run_t *)((uintptr_t) - chunk + (uintptr_t)(pageind << LG_PAGE)); - - arena_run_split_large(arena, run, run_size, - false); - /* Append to list for later processing. */ - ql_elm_new(mapelm, u.ql_link); - ql_tail_insert(mapelms, mapelm, u.ql_link); - } - } else { - /* Skip run. */ - if (arena_mapbits_large_get(chunk, pageind) != 0) { - npages = arena_mapbits_large_size_get(chunk, - pageind) >> LG_PAGE; - } else { - size_t binind; - arena_bin_info_t *bin_info; - arena_run_t *run = (arena_run_t *)((uintptr_t) - chunk + (uintptr_t)(pageind << LG_PAGE)); - - assert(arena_mapbits_small_runind_get(chunk, - pageind) == 0); - binind = arena_bin_index(arena, run->bin); - bin_info = &arena_bin_info[binind]; - npages = bin_info->run_size >> LG_PAGE; - } - } - } - assert(pageind == chunk_npages); - assert(chunk->ndirty == 0 || all == false); - assert(chunk->nruns_adjac == 0); + return (npurge); } static size_t -arena_chunk_purge_stashed(arena_t *arena, arena_chunk_t *chunk, - arena_chunk_mapelms_t *mapelms) +arena_stash_dirty(arena_t *arena, bool all, size_t npurge, + arena_chunk_miscelms_t *miscelms) { - size_t npurged, pageind, npages, nmadvise; - arena_chunk_map_t *mapelm; + arena_chunk_map_misc_t *miscelm; + size_t nstashed = 0; + + /* Add at least npurge pages to purge_list. */ + for (miscelm = ql_first(&arena->runs_dirty); miscelm != NULL; + miscelm = ql_first(&arena->runs_dirty)) { + arena_chunk_t *chunk = + (arena_chunk_t *)CHUNK_ADDR2BASE(miscelm); + size_t pageind = arena_miscelm_to_pageind(miscelm); + size_t run_size = arena_mapbits_unallocated_size_get(chunk, + pageind); + size_t npages = run_size >> LG_PAGE; + arena_run_t *run = &miscelm->run; + + assert(pageind + npages <= chunk_npages); + assert(arena_mapbits_dirty_get(chunk, pageind) == + arena_mapbits_dirty_get(chunk, pageind+npages-1)); + + /* + * If purging the spare chunk's run, make it available prior to + * allocation. + */ + if (chunk == arena->spare) + arena_chunk_alloc(arena); + + /* Temporarily allocate the free dirty run. */ + arena_run_split_large(arena, run, run_size, false); + /* Append to purge_list for later processing. */ + ql_elm_new(miscelm, dr_link); + ql_tail_insert(miscelms, miscelm, dr_link); + + nstashed += npages; + + if (!all && nstashed >= npurge) + break; + } + + return (nstashed); +} + +static size_t +arena_purge_stashed(arena_t *arena, arena_chunk_miscelms_t *miscelms) +{ + size_t npurged, nmadvise; + arena_chunk_map_misc_t *miscelm; - malloc_mutex_unlock(&arena->lock); if (config_stats) nmadvise = 0; npurged = 0; - ql_foreach(mapelm, mapelms, u.ql_link) { - bool unzeroed; - size_t flag_unzeroed, i; - pageind = (((uintptr_t)mapelm - (uintptr_t)chunk->map) / - sizeof(arena_chunk_map_t)) + map_bias; - npages = arena_mapbits_large_size_get(chunk, pageind) >> - LG_PAGE; + malloc_mutex_unlock(&arena->lock); + + ql_foreach(miscelm, miscelms, dr_link) { + arena_chunk_t *chunk; + size_t pageind, run_size, npages, flag_unzeroed, i; + bool unzeroed; + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(miscelm); + pageind = arena_miscelm_to_pageind(miscelm); + run_size = arena_mapbits_large_size_get(chunk, pageind); + npages = run_size >> LG_PAGE; + assert(pageind + npages <= chunk_npages); unzeroed = pages_purge((void *)((uintptr_t)chunk + (pageind << - LG_PAGE)), (npages << LG_PAGE)); + LG_PAGE)), run_size); flag_unzeroed = unzeroed ? CHUNK_MAP_UNZEROED : 0; + /* * Set the unzeroed flag for all pages, now that pages_purge() * has returned whether the pages were zeroed as a side effect @@ -919,164 +982,62 @@ arena_chunk_purge_stashed(arena_t *arena, arena_chunk_t *chunk, arena_mapbits_unzeroed_set(chunk, pageind+i, flag_unzeroed); } + npurged += npages; if (config_stats) nmadvise++; } + malloc_mutex_lock(&arena->lock); - if (config_stats) + + if (config_stats) { arena->stats.nmadvise += nmadvise; + arena->stats.purged += npurged; + } return (npurged); } static void -arena_chunk_unstash_purged(arena_t *arena, arena_chunk_t *chunk, - arena_chunk_mapelms_t *mapelms) +arena_unstash_purged(arena_t *arena, arena_chunk_miscelms_t *miscelms) { - arena_chunk_map_t *mapelm; - size_t pageind; + arena_chunk_map_misc_t *miscelm; /* Deallocate runs. */ - for (mapelm = ql_first(mapelms); mapelm != NULL; - mapelm = ql_first(mapelms)) { - arena_run_t *run; - - pageind = (((uintptr_t)mapelm - (uintptr_t)chunk->map) / - sizeof(arena_chunk_map_t)) + map_bias; - run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)(pageind << - LG_PAGE)); - ql_remove(mapelms, mapelm, u.ql_link); + for (miscelm = ql_first(miscelms); miscelm != NULL; + miscelm = ql_first(miscelms)) { + arena_run_t *run = &miscelm->run; + ql_remove(miscelms, miscelm, dr_link); arena_run_dalloc(arena, run, false, true); } } -static inline size_t -arena_chunk_purge(arena_t *arena, arena_chunk_t *chunk, bool all) -{ - size_t npurged; - arena_chunk_mapelms_t mapelms; - - ql_new(&mapelms); - - /* - * If chunk is the spare, temporarily re-allocate it, 1) so that its - * run is reinserted into runs_avail, and 2) so that it cannot be - * completely discarded by another thread while arena->lock is dropped - * by this thread. Note that the arena_run_dalloc() call will - * implicitly deallocate the chunk, so no explicit action is required - * in this function to deallocate the chunk. - * - * Note that once a chunk contains dirty pages, it cannot again contain - * a single run unless 1) it is a dirty run, or 2) this function purges - * dirty pages and causes the transition to a single clean run. Thus - * (chunk == arena->spare) is possible, but it is not possible for - * this function to be called on the spare unless it contains a dirty - * run. - */ - if (chunk == arena->spare) { - assert(arena_mapbits_dirty_get(chunk, map_bias) != 0); - assert(arena_mapbits_dirty_get(chunk, chunk_npages-1) != 0); - - arena_chunk_alloc(arena); - } - - if (config_stats) - arena->stats.purged += chunk->ndirty; - - /* - * Operate on all dirty runs if there is no clean/dirty run - * fragmentation. - */ - if (chunk->nruns_adjac == 0) - all = true; - - arena_chunk_stash_dirty(arena, chunk, all, &mapelms); - npurged = arena_chunk_purge_stashed(arena, chunk, &mapelms); - arena_chunk_unstash_purged(arena, chunk, &mapelms); - - return (npurged); -} - -static void +void arena_purge(arena_t *arena, bool all) { - arena_chunk_t *chunk; - size_t npurgatory; - if (config_debug) { - size_t ndirty = 0; + size_t npurge, npurgeable, npurged; + arena_chunk_miscelms_t purge_list; - arena_chunk_dirty_iter(&arena->chunks_dirty, NULL, - chunks_dirty_iter_cb, (void *)&ndirty); + /* + * Calls to arena_dirty_count() are disabled even for debug builds + * because overhead grows nonlinearly as memory usage increases. + */ + if (false && config_debug) { + size_t ndirty = arena_dirty_count(arena); assert(ndirty == arena->ndirty); } - assert(arena->ndirty > arena->npurgatory || all); - assert((arena->nactive >> opt_lg_dirty_mult) < (arena->ndirty - - arena->npurgatory) || all); + assert((arena->nactive >> opt_lg_dirty_mult) < arena->ndirty || all); if (config_stats) arena->stats.npurge++; - /* - * Add the minimum number of pages this thread should try to purge to - * arena->npurgatory. This will keep multiple threads from racing to - * reduce ndirty below the threshold. - */ - npurgatory = arena_compute_npurgatory(arena, all); - arena->npurgatory += npurgatory; - - while (npurgatory > 0) { - size_t npurgeable, npurged, nunpurged; - - /* Get next chunk with dirty pages. */ - chunk = arena_chunk_dirty_first(&arena->chunks_dirty); - if (chunk == NULL) { - /* - * This thread was unable to purge as many pages as - * originally intended, due to races with other threads - * that either did some of the purging work, or re-used - * dirty pages. - */ - arena->npurgatory -= npurgatory; - return; - } - npurgeable = chunk->ndirty; - assert(npurgeable != 0); - - if (npurgeable > npurgatory && chunk->nruns_adjac == 0) { - /* - * This thread will purge all the dirty pages in chunk, - * so set npurgatory to reflect this thread's intent to - * purge the pages. This tends to reduce the chances - * of the following scenario: - * - * 1) This thread sets arena->npurgatory such that - * (arena->ndirty - arena->npurgatory) is at the - * threshold. - * 2) This thread drops arena->lock. - * 3) Another thread causes one or more pages to be - * dirtied, and immediately determines that it must - * purge dirty pages. - * - * If this scenario *does* play out, that's okay, - * because all of the purging work being done really - * needs to happen. - */ - arena->npurgatory += npurgeable - npurgatory; - npurgatory = npurgeable; - } - - /* - * Keep track of how many pages are purgeable, versus how many - * actually get purged, and adjust counters accordingly. - */ - arena->npurgatory -= npurgeable; - npurgatory -= npurgeable; - npurged = arena_chunk_purge(arena, chunk, all); - nunpurged = npurgeable - npurged; - arena->npurgatory += nunpurged; - npurgatory += nunpurged; - } + npurge = arena_compute_npurge(arena, all); + ql_new(&purge_list); + npurgeable = arena_stash_dirty(arena, all, npurge, &purge_list); + assert(npurgeable >= npurge); + npurged = arena_purge_stashed(arena, &purge_list); + assert(npurged == npurgeable); + arena_unstash_purged(arena, &purge_list); } void @@ -1112,8 +1073,13 @@ arena_run_coalesce(arena_t *arena, arena_chunk_t *chunk, size_t *p_size, run_ind+run_pages+nrun_pages-1) == nrun_size); assert(arena_mapbits_dirty_get(chunk, run_ind+run_pages+nrun_pages-1) == flag_dirty); - arena_avail_remove(arena, chunk, run_ind+run_pages, nrun_pages, - false, true); + arena_avail_remove(arena, chunk, run_ind+run_pages, nrun_pages); + + /* If the successor is dirty, remove it from runs_dirty. */ + if (flag_dirty != 0) { + arena_dirty_remove(arena, chunk, run_ind+run_pages, + nrun_pages); + } size += nrun_size; run_pages += nrun_pages; @@ -1140,8 +1106,11 @@ arena_run_coalesce(arena_t *arena, arena_chunk_t *chunk, size_t *p_size, assert(arena_mapbits_unallocated_size_get(chunk, run_ind) == prun_size); assert(arena_mapbits_dirty_get(chunk, run_ind) == flag_dirty); - arena_avail_remove(arena, chunk, run_ind, prun_pages, true, - false); + arena_avail_remove(arena, chunk, run_ind, prun_pages); + + /* If the predecessor is dirty, remove it from runs_dirty. */ + if (flag_dirty != 0) + arena_dirty_remove(arena, chunk, run_ind, prun_pages); size += prun_size; run_pages += prun_pages; @@ -1160,10 +1129,12 @@ static void arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty, bool cleaned) { arena_chunk_t *chunk; + arena_chunk_map_misc_t *miscelm; size_t size, run_ind, run_pages, flag_dirty; chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); - run_ind = (size_t)(((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE); + miscelm = arena_run_to_miscelm(run); + run_ind = arena_miscelm_to_pageind(miscelm); assert(run_ind >= map_bias); assert(run_ind < chunk_npages); if (arena_mapbits_large_get(chunk, run_ind) != 0) { @@ -1172,8 +1143,7 @@ arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty, bool cleaned) arena_mapbits_large_size_get(chunk, run_ind+(size>>LG_PAGE)-1) == 0); } else { - size_t binind = arena_bin_index(arena, run->bin); - arena_bin_info_t *bin_info = &arena_bin_info[binind]; + arena_bin_info_t *bin_info = &arena_bin_info[run->binind]; size = bin_info->run_size; } run_pages = (size >> LG_PAGE); @@ -1187,7 +1157,7 @@ arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty, bool cleaned) */ assert(arena_mapbits_dirty_get(chunk, run_ind) == arena_mapbits_dirty_get(chunk, run_ind+run_pages-1)); - if (cleaned == false && arena_mapbits_dirty_get(chunk, run_ind) != 0) + if (!cleaned && arena_mapbits_dirty_get(chunk, run_ind) != 0) dirty = true; flag_dirty = dirty ? CHUNK_MAP_DIRTY : 0; @@ -1204,21 +1174,23 @@ arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty, bool cleaned) arena_mapbits_unzeroed_get(chunk, run_ind+run_pages-1)); } - arena_run_coalesce(arena, chunk, &size, &run_ind, &run_pages, - flag_dirty); + arena_run_coalesce(arena, chunk, &size, &run_ind, &run_pages, flag_dirty); /* Insert into runs_avail, now that coalescing is complete. */ assert(arena_mapbits_unallocated_size_get(chunk, run_ind) == arena_mapbits_unallocated_size_get(chunk, run_ind+run_pages-1)); assert(arena_mapbits_dirty_get(chunk, run_ind) == arena_mapbits_dirty_get(chunk, run_ind+run_pages-1)); - arena_avail_insert(arena, chunk, run_ind, run_pages, true, true); + arena_avail_insert(arena, chunk, run_ind, run_pages); + + if (dirty) + arena_dirty_insert(arena, chunk, run_ind, run_pages); /* Deallocate chunk if it is now completely unused. */ - if (size == arena_maxclass) { + if (size == arena_maxrun) { assert(run_ind == map_bias); - assert(run_pages == (arena_maxclass >> LG_PAGE)); - arena_chunk_dealloc(arena, chunk); + assert(run_pages == (arena_maxrun >> LG_PAGE)); + arena_chunk_dalloc(arena, chunk); } /* @@ -1236,7 +1208,8 @@ static void arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, size_t oldsize, size_t newsize) { - size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE; + arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run); + size_t pageind = arena_miscelm_to_pageind(miscelm); size_t head_npages = (oldsize - newsize) >> LG_PAGE; size_t flag_dirty = arena_mapbits_dirty_get(chunk, pageind); @@ -1268,9 +1241,12 @@ static void arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, size_t oldsize, size_t newsize, bool dirty) { - size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE; + arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run); + size_t pageind = arena_miscelm_to_pageind(miscelm); size_t head_npages = newsize >> LG_PAGE; size_t flag_dirty = arena_mapbits_dirty_get(chunk, pageind); + arena_chunk_map_misc_t *tail_miscelm; + arena_run_t *tail_run; assert(oldsize > newsize); @@ -1293,27 +1269,17 @@ arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, arena_mapbits_large_set(chunk, pageind+head_npages, oldsize-newsize, flag_dirty); - arena_run_dalloc(arena, (arena_run_t *)((uintptr_t)run + newsize), - dirty, false); + tail_miscelm = arena_miscelm_get(chunk, pageind + head_npages); + tail_run = &tail_miscelm->run; + arena_run_dalloc(arena, tail_run, dirty, false); } static arena_run_t * arena_bin_runs_first(arena_bin_t *bin) { - arena_chunk_map_t *mapelm = arena_run_tree_first(&bin->runs); - if (mapelm != NULL) { - arena_chunk_t *chunk; - size_t pageind; - arena_run_t *run; - - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(mapelm); - pageind = ((((uintptr_t)mapelm - (uintptr_t)chunk->map) / - sizeof(arena_chunk_map_t))) + map_bias; - run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind - - arena_mapbits_small_runind_get(chunk, pageind)) << - LG_PAGE)); - return (run); - } + arena_chunk_map_misc_t *miscelm = arena_run_tree_first(&bin->runs); + if (miscelm != NULL) + return (&miscelm->run); return (NULL); } @@ -1321,25 +1287,21 @@ arena_bin_runs_first(arena_bin_t *bin) static void arena_bin_runs_insert(arena_bin_t *bin, arena_run_t *run) { - arena_chunk_t *chunk = CHUNK_ADDR2BASE(run); - size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE; - arena_chunk_map_t *mapelm = arena_mapp_get(chunk, pageind); + arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run); - assert(arena_run_tree_search(&bin->runs, mapelm) == NULL); + assert(arena_run_tree_search(&bin->runs, miscelm) == NULL); - arena_run_tree_insert(&bin->runs, mapelm); + arena_run_tree_insert(&bin->runs, miscelm); } static void arena_bin_runs_remove(arena_bin_t *bin, arena_run_t *run) { - arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); - size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE; - arena_chunk_map_t *mapelm = arena_mapp_get(chunk, pageind); + arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run); - assert(arena_run_tree_search(&bin->runs, mapelm) != NULL); + assert(arena_run_tree_search(&bin->runs, miscelm) != NULL); - arena_run_tree_remove(&bin->runs, mapelm); + arena_run_tree_remove(&bin->runs, miscelm); } static arena_run_t * @@ -1358,7 +1320,7 @@ static arena_run_t * arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin) { arena_run_t *run; - size_t binind; + index_t binind; arena_bin_info_t *bin_info; /* Look for a usable run. */ @@ -1376,14 +1338,10 @@ arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin) malloc_mutex_lock(&arena->lock); run = arena_run_alloc_small(arena, bin_info->run_size, binind); if (run != NULL) { - bitmap_t *bitmap = (bitmap_t *)((uintptr_t)run + - (uintptr_t)bin_info->bitmap_offset); - /* Initialize run internals. */ - run->bin = bin; - run->nextind = 0; + run->binind = binind; run->nfree = bin_info->nregs; - bitmap_init(bitmap, &bin_info->bitmap_info); + bitmap_init(run->bitmap, &bin_info->bitmap_info); } malloc_mutex_unlock(&arena->lock); /********************************/ @@ -1413,7 +1371,7 @@ static void * arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin) { void *ret; - size_t binind; + index_t binind; arena_bin_info_t *bin_info; arena_run_t *run; @@ -1459,7 +1417,7 @@ arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin) } void -arena_tcache_fill_small(arena_t *arena, tcache_bin_t *tbin, size_t binind, +arena_tcache_fill_small(arena_t *arena, tcache_bin_t *tbin, index_t binind, uint64_t prof_accumbytes) { unsigned i, nfill; @@ -1479,9 +1437,20 @@ arena_tcache_fill_small(arena_t *arena, tcache_bin_t *tbin, size_t binind, ptr = arena_run_reg_alloc(run, &arena_bin_info[binind]); else ptr = arena_bin_malloc_hard(arena, bin); - if (ptr == NULL) + if (ptr == NULL) { + /* + * OOM. tbin->avail isn't yet filled down to its first + * element, so the successful allocations (if any) must + * be moved to the base of tbin->avail before bailing + * out. + */ + if (i > 0) { + memmove(tbin->avail, &tbin->avail[nfill - i], + i * sizeof(void *)); + } break; - if (config_fill && opt_junk) { + } + if (config_fill && unlikely(opt_junk_alloc)) { arena_alloc_junk_small(ptr, &arena_bin_info[binind], true); } @@ -1489,9 +1458,9 @@ arena_tcache_fill_small(arena_t *arena, tcache_bin_t *tbin, size_t binind, tbin->avail[nfill - 1 - i] = ptr; } if (config_stats) { - bin->stats.allocated += i * arena_bin_info[binind].reg_size; bin->stats.nmalloc += i; bin->stats.nrequests += tbin->tstats.nrequests; + bin->stats.curregs += i; bin->stats.nfills++; tbin->tstats.nrequests = 0; } @@ -1543,24 +1512,27 @@ arena_redzones_validate(void *ptr, arena_bin_info_t *bin_info, bool reset) size_t i; bool error = false; - for (i = 1; i <= redzone_size; i++) { - uint8_t *byte = (uint8_t *)((uintptr_t)ptr - i); - if (*byte != 0xa5) { - error = true; - arena_redzone_corruption(ptr, size, false, i, *byte); - if (reset) - *byte = 0xa5; - } - } - for (i = 0; i < redzone_size; i++) { - uint8_t *byte = (uint8_t *)((uintptr_t)ptr + size + i); - if (*byte != 0xa5) { - error = true; - arena_redzone_corruption(ptr, size, true, i, *byte); - if (reset) - *byte = 0xa5; + if (opt_junk_alloc) { + for (i = 1; i <= redzone_size; i++) { + uint8_t *byte = (uint8_t *)((uintptr_t)ptr - i); + if (*byte != 0xa5) { + error = true; + arena_redzone_corruption(ptr, size, false, i, *byte); + if (reset) + *byte = 0xa5; + } + } + for (i = 0; i < redzone_size; i++) { + uint8_t *byte = (uint8_t *)((uintptr_t)ptr + size + i); + if (*byte != 0xa5) { + error = true; + arena_redzone_corruption(ptr, size, true, i, *byte); + if (reset) + *byte = 0xa5; + } } } + if (opt_abort && error) abort(); } @@ -1588,14 +1560,14 @@ arena_dalloc_junk_small_t *arena_dalloc_junk_small = void arena_quarantine_junk_small(void *ptr, size_t usize) { - size_t binind; + index_t binind; arena_bin_info_t *bin_info; cassert(config_fill); - assert(opt_junk); + assert(opt_junk_free); assert(opt_quarantine); assert(usize <= SMALL_MAXCLASS); - binind = SMALL_SIZE2BIN(usize); + binind = size2index(usize); bin_info = &arena_bin_info[binind]; arena_redzones_validate(ptr, bin_info, true); } @@ -1606,12 +1578,12 @@ arena_malloc_small(arena_t *arena, size_t size, bool zero) void *ret; arena_bin_t *bin; arena_run_t *run; - size_t binind; + index_t binind; - binind = SMALL_SIZE2BIN(size); + binind = size2index(size); assert(binind < NBINS); bin = &arena->bins[binind]; - size = arena_bin_info[binind].reg_size; + size = index2size(binind); malloc_mutex_lock(&bin->lock); if ((run = bin->runcur) != NULL && run->nfree > 0) @@ -1625,29 +1597,29 @@ arena_malloc_small(arena_t *arena, size_t size, bool zero) } if (config_stats) { - bin->stats.allocated += size; bin->stats.nmalloc++; bin->stats.nrequests++; + bin->stats.curregs++; } malloc_mutex_unlock(&bin->lock); - if (config_prof && isthreaded == false && arena_prof_accum(arena, size)) + if (config_prof && !isthreaded && arena_prof_accum(arena, size)) prof_idump(); - if (zero == false) { + if (!zero) { if (config_fill) { - if (opt_junk) { + if (unlikely(opt_junk_alloc)) { arena_alloc_junk_small(ret, &arena_bin_info[binind], false); - } else if (opt_zero) + } else if (unlikely(opt_zero)) memset(ret, 0, size); } - VALGRIND_MAKE_MEM_UNDEFINED(ret, size); + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, size); } else { - if (config_fill && opt_junk) { + if (config_fill && unlikely(opt_junk_alloc)) { arena_alloc_junk_small(ret, &arena_bin_info[binind], true); } - VALGRIND_MAKE_MEM_UNDEFINED(ret, size); + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, size); memset(ret, 0, size); } @@ -1658,36 +1630,43 @@ void * arena_malloc_large(arena_t *arena, size_t size, bool zero) { void *ret; + size_t usize; + arena_run_t *run; + arena_chunk_map_misc_t *miscelm; UNUSED bool idump; /* Large allocation. */ - size = PAGE_CEILING(size); + usize = s2u(size); malloc_mutex_lock(&arena->lock); - ret = (void *)arena_run_alloc_large(arena, size, zero); - if (ret == NULL) { + run = arena_run_alloc_large(arena, usize, zero); + if (run == NULL) { malloc_mutex_unlock(&arena->lock); return (NULL); } + miscelm = arena_run_to_miscelm(run); + ret = arena_miscelm_to_rpages(miscelm); if (config_stats) { + index_t index = size2index(usize) - NBINS; + arena->stats.nmalloc_large++; arena->stats.nrequests_large++; - arena->stats.allocated_large += size; - arena->stats.lstats[(size >> LG_PAGE) - 1].nmalloc++; - arena->stats.lstats[(size >> LG_PAGE) - 1].nrequests++; - arena->stats.lstats[(size >> LG_PAGE) - 1].curruns++; + arena->stats.allocated_large += usize; + arena->stats.lstats[index].nmalloc++; + arena->stats.lstats[index].nrequests++; + arena->stats.lstats[index].curruns++; } if (config_prof) - idump = arena_prof_accum_locked(arena, size); + idump = arena_prof_accum_locked(arena, usize); malloc_mutex_unlock(&arena->lock); if (config_prof && idump) prof_idump(); - if (zero == false) { + if (!zero) { if (config_fill) { - if (opt_junk) - memset(ret, 0xa5, size); - else if (opt_zero) - memset(ret, 0, size); + if (unlikely(opt_junk_alloc)) + memset(ret, 0xa5, usize); + else if (unlikely(opt_zero)) + memset(ret, 0, usize); } } @@ -1702,6 +1681,8 @@ arena_palloc(arena_t *arena, size_t size, size_t alignment, bool zero) size_t alloc_size, leadsize, trailsize; arena_run_t *run; arena_chunk_t *chunk; + arena_chunk_map_misc_t *miscelm; + void *rpages; assert((size & PAGE_MASK) == 0); @@ -1715,36 +1696,48 @@ arena_palloc(arena_t *arena, size_t size, size_t alignment, bool zero) return (NULL); } chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); + miscelm = arena_run_to_miscelm(run); + rpages = arena_miscelm_to_rpages(miscelm); - leadsize = ALIGNMENT_CEILING((uintptr_t)run, alignment) - - (uintptr_t)run; + leadsize = ALIGNMENT_CEILING((uintptr_t)rpages, alignment) - + (uintptr_t)rpages; assert(alloc_size >= leadsize + size); trailsize = alloc_size - leadsize - size; - ret = (void *)((uintptr_t)run + leadsize); if (leadsize != 0) { - arena_run_trim_head(arena, chunk, run, alloc_size, alloc_size - - leadsize); + arena_chunk_map_misc_t *head_miscelm = miscelm; + arena_run_t *head_run = run; + + miscelm = arena_miscelm_get(chunk, + arena_miscelm_to_pageind(head_miscelm) + (leadsize >> + LG_PAGE)); + run = &miscelm->run; + + arena_run_trim_head(arena, chunk, head_run, alloc_size, + alloc_size - leadsize); } if (trailsize != 0) { - arena_run_trim_tail(arena, chunk, ret, size + trailsize, size, + arena_run_trim_tail(arena, chunk, run, size + trailsize, size, false); } - arena_run_init_large(arena, (arena_run_t *)ret, size, zero); + arena_run_init_large(arena, run, size, zero); + ret = arena_miscelm_to_rpages(miscelm); if (config_stats) { + index_t index = size2index(size) - NBINS; + arena->stats.nmalloc_large++; arena->stats.nrequests_large++; arena->stats.allocated_large += size; - arena->stats.lstats[(size >> LG_PAGE) - 1].nmalloc++; - arena->stats.lstats[(size >> LG_PAGE) - 1].nrequests++; - arena->stats.lstats[(size >> LG_PAGE) - 1].curruns++; + arena->stats.lstats[index].nmalloc++; + arena->stats.lstats[index].nrequests++; + arena->stats.lstats[index].curruns++; } malloc_mutex_unlock(&arena->lock); - if (config_fill && zero == false) { - if (opt_junk) + if (config_fill && !zero) { + if (unlikely(opt_junk_alloc)) memset(ret, 0xa5, size); - else if (opt_zero) + else if (unlikely(opt_zero)) memset(ret, 0, size); } return (ret); @@ -1754,22 +1747,23 @@ void arena_prof_promoted(const void *ptr, size_t size) { arena_chunk_t *chunk; - size_t pageind, binind; + size_t pageind; + index_t binind; cassert(config_prof); assert(ptr != NULL); assert(CHUNK_ADDR2BASE(ptr) != ptr); - assert(isalloc(ptr, false) == PAGE); - assert(isalloc(ptr, true) == PAGE); + assert(isalloc(ptr, false) == LARGE_MINCLASS); + assert(isalloc(ptr, true) == LARGE_MINCLASS); assert(size <= SMALL_MAXCLASS); chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - binind = SMALL_SIZE2BIN(size); + binind = size2index(size); assert(binind < NBINS); arena_mapbits_large_binind_set(chunk, pageind, binind); - assert(isalloc(ptr, false) == PAGE); + assert(isalloc(ptr, false) == LARGE_MINCLASS); assert(isalloc(ptr, true) == size); } @@ -1782,7 +1776,7 @@ arena_dissociate_bin_run(arena_chunk_t *chunk, arena_run_t *run, if (run == bin->runcur) bin->runcur = NULL; else { - size_t binind = arena_bin_index(chunk->arena, bin); + index_t binind = arena_bin_index(chunk->arena, bin); arena_bin_info_t *bin_info = &arena_bin_info[binind]; if (bin_info->nregs != 1) { @@ -1800,45 +1794,14 @@ static void arena_dalloc_bin_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, arena_bin_t *bin) { - size_t binind; - arena_bin_info_t *bin_info; - size_t npages, run_ind, past; assert(run != bin->runcur); - assert(arena_run_tree_search(&bin->runs, - arena_mapp_get(chunk, ((uintptr_t)run-(uintptr_t)chunk)>>LG_PAGE)) - == NULL); - - binind = arena_bin_index(chunk->arena, run->bin); - bin_info = &arena_bin_info[binind]; + assert(arena_run_tree_search(&bin->runs, arena_run_to_miscelm(run)) == + NULL); malloc_mutex_unlock(&bin->lock); /******************************/ - npages = bin_info->run_size >> LG_PAGE; - run_ind = (size_t)(((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE); - past = (size_t)(PAGE_CEILING((uintptr_t)run + - (uintptr_t)bin_info->reg0_offset + (uintptr_t)(run->nextind * - bin_info->reg_interval - bin_info->redzone_size) - - (uintptr_t)chunk) >> LG_PAGE); malloc_mutex_lock(&arena->lock); - - /* - * If the run was originally clean, and some pages were never touched, - * trim the clean pages before deallocating the dirty portion of the - * run. - */ - assert(arena_mapbits_dirty_get(chunk, run_ind) == - arena_mapbits_dirty_get(chunk, run_ind+npages-1)); - if (arena_mapbits_dirty_get(chunk, run_ind) == 0 && past - run_ind < - npages) { - /* Trim clean pages. Convert to large run beforehand. */ - assert(npages > 0); - arena_mapbits_large_set(chunk, run_ind, bin_info->run_size, 0); - arena_mapbits_large_set(chunk, run_ind+npages-1, 0, 0); - arena_run_trim_tail(arena, chunk, run, (npages << LG_PAGE), - ((past - run_ind) << LG_PAGE), false); - /* npages = past - run_ind; */ - } arena_run_dalloc(arena, run, true, false); malloc_mutex_unlock(&arena->lock); /****************************/ @@ -1868,26 +1831,24 @@ arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, arena_bin_runs_insert(bin, run); } -void -arena_dalloc_bin_locked(arena_t *arena, arena_chunk_t *chunk, void *ptr, - arena_chunk_map_t *mapelm) +static void +arena_dalloc_bin_locked_impl(arena_t *arena, arena_chunk_t *chunk, void *ptr, + arena_chunk_map_bits_t *bitselm, bool junked) { - size_t pageind; + size_t pageind, rpages_ind; arena_run_t *run; arena_bin_t *bin; arena_bin_info_t *bin_info; - size_t size, binind; + index_t binind; pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind - - arena_mapbits_small_runind_get(chunk, pageind)) << LG_PAGE)); - bin = run->bin; - binind = arena_ptr_small_binind_get(ptr, mapelm->bits); + rpages_ind = pageind - arena_mapbits_small_runind_get(chunk, pageind); + run = &arena_miscelm_get(chunk, rpages_ind)->run; + binind = run->binind; + bin = &arena->bins[binind]; bin_info = &arena_bin_info[binind]; - if (config_fill || config_stats) - size = bin_info->reg_size; - if (config_fill && opt_junk) + if (!junked && config_fill && unlikely(opt_junk_free)) arena_dalloc_junk_small(ptr, bin_info); arena_run_reg_dalloc(run, ptr); @@ -1898,23 +1859,32 @@ arena_dalloc_bin_locked(arena_t *arena, arena_chunk_t *chunk, void *ptr, arena_bin_lower_run(arena, chunk, run, bin); if (config_stats) { - bin->stats.allocated -= size; bin->stats.ndalloc++; + bin->stats.curregs--; } } +void +arena_dalloc_bin_junked_locked(arena_t *arena, arena_chunk_t *chunk, void *ptr, + arena_chunk_map_bits_t *bitselm) +{ + + arena_dalloc_bin_locked_impl(arena, chunk, ptr, bitselm, true); +} + void arena_dalloc_bin(arena_t *arena, arena_chunk_t *chunk, void *ptr, - size_t pageind, arena_chunk_map_t *mapelm) + size_t pageind, arena_chunk_map_bits_t *bitselm) { arena_run_t *run; arena_bin_t *bin; + size_t rpages_ind; - run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind - - arena_mapbits_small_runind_get(chunk, pageind)) << LG_PAGE)); - bin = run->bin; + rpages_ind = pageind - arena_mapbits_small_runind_get(chunk, pageind); + run = &arena_miscelm_get(chunk, rpages_ind)->run; + bin = &arena->bins[run->binind]; malloc_mutex_lock(&bin->lock); - arena_dalloc_bin_locked(arena, chunk, ptr, mapelm); + arena_dalloc_bin_locked_impl(arena, chunk, ptr, bitselm, false); malloc_mutex_unlock(&bin->lock); } @@ -1922,26 +1892,26 @@ void arena_dalloc_small(arena_t *arena, arena_chunk_t *chunk, void *ptr, size_t pageind) { - arena_chunk_map_t *mapelm; + arena_chunk_map_bits_t *bitselm; if (config_debug) { /* arena_ptr_small_binind_get() does extra sanity checking. */ assert(arena_ptr_small_binind_get(ptr, arena_mapbits_get(chunk, pageind)) != BININD_INVALID); } - mapelm = arena_mapp_get(chunk, pageind); - arena_dalloc_bin(arena, chunk, ptr, pageind, mapelm); + bitselm = arena_bitselm_get(chunk, pageind); + arena_dalloc_bin(arena, chunk, ptr, pageind, bitselm); } #ifdef JEMALLOC_JET #undef arena_dalloc_junk_large #define arena_dalloc_junk_large JEMALLOC_N(arena_dalloc_junk_large_impl) #endif -static void +void arena_dalloc_junk_large(void *ptr, size_t usize) { - if (config_fill && opt_junk) + if (config_fill && unlikely(opt_junk_free)) memset(ptr, 0x5a, usize); } #ifdef JEMALLOC_JET @@ -1952,23 +1922,37 @@ arena_dalloc_junk_large_t *arena_dalloc_junk_large = #endif void -arena_dalloc_large_locked(arena_t *arena, arena_chunk_t *chunk, void *ptr) +arena_dalloc_large_locked_impl(arena_t *arena, arena_chunk_t *chunk, + void *ptr, bool junked) { + size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; + arena_chunk_map_misc_t *miscelm = arena_miscelm_get(chunk, pageind); + arena_run_t *run = &miscelm->run; if (config_fill || config_stats) { - size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; size_t usize = arena_mapbits_large_size_get(chunk, pageind); - arena_dalloc_junk_large(ptr, usize); + if (!junked) + arena_dalloc_junk_large(ptr, usize); if (config_stats) { + index_t index = size2index(usize) - NBINS; + arena->stats.ndalloc_large++; arena->stats.allocated_large -= usize; - arena->stats.lstats[(usize >> LG_PAGE) - 1].ndalloc++; - arena->stats.lstats[(usize >> LG_PAGE) - 1].curruns--; + arena->stats.lstats[index].ndalloc++; + arena->stats.lstats[index].curruns--; } } - arena_run_dalloc(arena, (arena_run_t *)ptr, true, false); + arena_run_dalloc(arena, run, true, false); +} + +void +arena_dalloc_large_junked_locked(arena_t *arena, arena_chunk_t *chunk, + void *ptr) +{ + + arena_dalloc_large_locked_impl(arena, chunk, ptr, true); } void @@ -1976,7 +1960,7 @@ arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr) { malloc_mutex_lock(&arena->lock); - arena_dalloc_large_locked(arena, chunk, ptr); + arena_dalloc_large_locked_impl(arena, chunk, ptr, false); malloc_mutex_unlock(&arena->lock); } @@ -1984,6 +1968,9 @@ static void arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr, size_t oldsize, size_t size) { + size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; + arena_chunk_map_misc_t *miscelm = arena_miscelm_get(chunk, pageind); + arena_run_t *run = &miscelm->run; assert(size < oldsize); @@ -1992,20 +1979,22 @@ arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr, * allocations. */ malloc_mutex_lock(&arena->lock); - arena_run_trim_tail(arena, chunk, (arena_run_t *)ptr, oldsize, size, - true); + arena_run_trim_tail(arena, chunk, run, oldsize, size, true); if (config_stats) { + index_t oldindex = size2index(oldsize) - NBINS; + index_t index = size2index(size) - NBINS; + arena->stats.ndalloc_large++; arena->stats.allocated_large -= oldsize; - arena->stats.lstats[(oldsize >> LG_PAGE) - 1].ndalloc++; - arena->stats.lstats[(oldsize >> LG_PAGE) - 1].curruns--; + arena->stats.lstats[oldindex].ndalloc++; + arena->stats.lstats[oldindex].curruns--; arena->stats.nmalloc_large++; arena->stats.nrequests_large++; arena->stats.allocated_large += size; - arena->stats.lstats[(size >> LG_PAGE) - 1].nmalloc++; - arena->stats.lstats[(size >> LG_PAGE) - 1].nrequests++; - arena->stats.lstats[(size >> LG_PAGE) - 1].curruns++; + arena->stats.lstats[index].nmalloc++; + arena->stats.lstats[index].nrequests++; + arena->stats.lstats[index].curruns++; } malloc_mutex_unlock(&arena->lock); } @@ -2017,26 +2006,33 @@ arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr, size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; size_t npages = oldsize >> LG_PAGE; size_t followsize; + size_t usize_min = s2u(size); assert(oldsize == arena_mapbits_large_size_get(chunk, pageind)); /* Try to extend the run. */ - assert(size + extra > oldsize); + assert(usize_min > oldsize); malloc_mutex_lock(&arena->lock); if (pageind + npages < chunk_npages && arena_mapbits_allocated_get(chunk, pageind+npages) == 0 && (followsize = arena_mapbits_unallocated_size_get(chunk, - pageind+npages)) >= size - oldsize) { + pageind+npages)) >= usize_min - oldsize) { /* * The next run is available and sufficiently large. Split the * following run, then merge the first part with the existing * allocation. */ - size_t flag_dirty; - size_t splitsize = (oldsize + followsize <= size + extra) - ? followsize : size + extra - oldsize; - arena_run_split_large(arena, (arena_run_t *)((uintptr_t)chunk + - ((pageind+npages) << LG_PAGE)), splitsize, zero); + size_t flag_dirty, splitsize, usize; + + usize = s2u(size + extra); + while (oldsize + followsize < usize) + usize = index2size(size2index(usize)-1); + assert(usize >= usize_min); + splitsize = usize - oldsize; + + arena_run_t *run = &arena_miscelm_get(chunk, + pageind+npages)->run; + arena_run_split_large(arena, run, splitsize, zero); size = oldsize + splitsize; npages = size >> LG_PAGE; @@ -2055,17 +2051,20 @@ arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr, arena_mapbits_large_set(chunk, pageind+npages-1, 0, flag_dirty); if (config_stats) { + index_t oldindex = size2index(oldsize) - NBINS; + index_t index = size2index(size) - NBINS; + arena->stats.ndalloc_large++; arena->stats.allocated_large -= oldsize; - arena->stats.lstats[(oldsize >> LG_PAGE) - 1].ndalloc++; - arena->stats.lstats[(oldsize >> LG_PAGE) - 1].curruns--; + arena->stats.lstats[oldindex].ndalloc++; + arena->stats.lstats[oldindex].curruns--; arena->stats.nmalloc_large++; arena->stats.nrequests_large++; arena->stats.allocated_large += size; - arena->stats.lstats[(size >> LG_PAGE) - 1].nmalloc++; - arena->stats.lstats[(size >> LG_PAGE) - 1].nrequests++; - arena->stats.lstats[(size >> LG_PAGE) - 1].curruns++; + arena->stats.lstats[index].nmalloc++; + arena->stats.lstats[index].nrequests++; + arena->stats.lstats[index].curruns++; } malloc_mutex_unlock(&arena->lock); return (false); @@ -2083,7 +2082,7 @@ static void arena_ralloc_junk_large(void *ptr, size_t old_usize, size_t usize) { - if (config_fill && opt_junk) { + if (config_fill && unlikely(opt_junk_free)) { memset((void *)((uintptr_t)ptr + usize), 0x5a, old_usize - usize); } @@ -2103,10 +2102,14 @@ static bool arena_ralloc_large(void *ptr, size_t oldsize, size_t size, size_t extra, bool zero) { - size_t psize; + size_t usize; - psize = PAGE_CEILING(size + extra); - if (psize == oldsize) { + /* Make sure extra can't cause size_t overflow. */ + if (unlikely(extra >= arena_maxclass)) + return (true); + + usize = s2u(size + extra); + if (usize == oldsize) { /* Same size class. */ return (false); } else { @@ -2116,22 +2119,21 @@ arena_ralloc_large(void *ptr, size_t oldsize, size_t size, size_t extra, chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); arena = chunk->arena; - if (psize < oldsize) { + if (usize < oldsize) { /* Fill before shrinking in order avoid a race. */ - arena_ralloc_junk_large(ptr, oldsize, psize); + arena_ralloc_junk_large(ptr, oldsize, usize); arena_ralloc_large_shrink(arena, chunk, ptr, oldsize, - psize); + usize); return (false); } else { bool ret = arena_ralloc_large_grow(arena, chunk, ptr, - oldsize, PAGE_CEILING(size), - psize - PAGE_CEILING(size), zero); - if (config_fill && ret == false && zero == false) { - if (opt_junk) { + oldsize, size, extra, zero); + if (config_fill && !ret && !zero) { + if (unlikely(opt_junk_alloc)) { memset((void *)((uintptr_t)ptr + oldsize), 0xa5, isalloc(ptr, config_prof) - oldsize); - } else if (opt_zero) { + } else if (unlikely(opt_zero)) { memset((void *)((uintptr_t)ptr + oldsize), 0, isalloc(ptr, config_prof) - oldsize); @@ -2150,20 +2152,19 @@ arena_ralloc_no_move(void *ptr, size_t oldsize, size_t size, size_t extra, /* * Avoid moving the allocation if the size class can be left the same. */ - if (oldsize <= arena_maxclass) { + if (likely(oldsize <= arena_maxclass)) { if (oldsize <= SMALL_MAXCLASS) { - assert(arena_bin_info[SMALL_SIZE2BIN(oldsize)].reg_size + assert(arena_bin_info[size2index(oldsize)].reg_size == oldsize); - if ((size + extra <= SMALL_MAXCLASS && - SMALL_SIZE2BIN(size + extra) == - SMALL_SIZE2BIN(oldsize)) || (size <= oldsize && - size + extra >= oldsize)) + if ((size + extra <= SMALL_MAXCLASS && size2index(size + + extra) == size2index(oldsize)) || (size <= oldsize + && size + extra >= oldsize)) return (false); } else { assert(size <= arena_maxclass); if (size + extra > SMALL_MAXCLASS) { - if (arena_ralloc_large(ptr, oldsize, size, - extra, zero) == false) + if (!arena_ralloc_large(ptr, oldsize, size, + extra, zero)) return (false); } } @@ -2174,7 +2175,7 @@ arena_ralloc_no_move(void *ptr, size_t oldsize, size_t size, size_t extra, } void * -arena_ralloc(arena_t *arena, void *ptr, size_t oldsize, size_t size, +arena_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero, bool try_tcache_alloc, bool try_tcache_dalloc) { @@ -2182,7 +2183,7 @@ arena_ralloc(arena_t *arena, void *ptr, size_t oldsize, size_t size, size_t copysize; /* Try to avoid moving the allocation. */ - if (arena_ralloc_no_move(ptr, oldsize, size, extra, zero) == false) + if (!arena_ralloc_no_move(ptr, oldsize, size, extra, zero)) return (ptr); /* @@ -2194,9 +2195,12 @@ arena_ralloc(arena_t *arena, void *ptr, size_t oldsize, size_t size, size_t usize = sa2u(size + extra, alignment); if (usize == 0) return (NULL); - ret = ipalloct(usize, alignment, zero, try_tcache_alloc, arena); - } else - ret = arena_malloc(arena, size + extra, zero, try_tcache_alloc); + ret = ipalloct(tsd, usize, alignment, zero, try_tcache_alloc, + arena); + } else { + ret = arena_malloc(tsd, arena, size + extra, zero, + try_tcache_alloc); + } if (ret == NULL) { if (extra == 0) @@ -2206,10 +2210,12 @@ arena_ralloc(arena_t *arena, void *ptr, size_t oldsize, size_t size, size_t usize = sa2u(size, alignment); if (usize == 0) return (NULL); - ret = ipalloct(usize, alignment, zero, try_tcache_alloc, - arena); - } else - ret = arena_malloc(arena, size, zero, try_tcache_alloc); + ret = ipalloct(tsd, usize, alignment, zero, + try_tcache_alloc, arena); + } else { + ret = arena_malloc(tsd, arena, size, zero, + try_tcache_alloc); + } if (ret == NULL) return (NULL); @@ -2222,9 +2228,9 @@ arena_ralloc(arena_t *arena, void *ptr, size_t oldsize, size_t size, * expectation that the extra bytes will be reliably preserved. */ copysize = (size < oldsize) ? size : oldsize; - VALGRIND_MAKE_MEM_UNDEFINED(ret, copysize); + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, copysize); memcpy(ret, ptr, copysize); - iqalloct(ptr, try_tcache_dalloc); + isqalloc(tsd, ptr, oldsize, try_tcache_dalloc); return (ret); } @@ -2239,19 +2245,22 @@ arena_dss_prec_get(arena_t *arena) return (ret); } -void +bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec) { + if (!have_dss) + return (dss_prec != dss_prec_disabled); malloc_mutex_lock(&arena->lock); arena->dss_prec = dss_prec; malloc_mutex_unlock(&arena->lock); + return (false); } void arena_stats_merge(arena_t *arena, const char **dss, size_t *nactive, size_t *ndirty, arena_stats_t *astats, malloc_bin_stats_t *bstats, - malloc_large_stats_t *lstats) + malloc_large_stats_t *lstats, malloc_huge_stats_t *hstats) { unsigned i; @@ -2268,6 +2277,9 @@ arena_stats_merge(arena_t *arena, const char **dss, size_t *nactive, astats->nmalloc_large += arena->stats.nmalloc_large; astats->ndalloc_large += arena->stats.ndalloc_large; astats->nrequests_large += arena->stats.nrequests_large; + astats->allocated_huge += arena->stats.allocated_huge; + astats->nmalloc_huge += arena->stats.nmalloc_huge; + astats->ndalloc_huge += arena->stats.ndalloc_huge; for (i = 0; i < nlclasses; i++) { lstats[i].nmalloc += arena->stats.lstats[i].nmalloc; @@ -2275,16 +2287,22 @@ arena_stats_merge(arena_t *arena, const char **dss, size_t *nactive, lstats[i].nrequests += arena->stats.lstats[i].nrequests; lstats[i].curruns += arena->stats.lstats[i].curruns; } + + for (i = 0; i < nhclasses; i++) { + hstats[i].nmalloc += arena->stats.hstats[i].nmalloc; + hstats[i].ndalloc += arena->stats.hstats[i].ndalloc; + hstats[i].curhchunks += arena->stats.hstats[i].curhchunks; + } malloc_mutex_unlock(&arena->lock); for (i = 0; i < NBINS; i++) { arena_bin_t *bin = &arena->bins[i]; malloc_mutex_lock(&bin->lock); - bstats[i].allocated += bin->stats.allocated; bstats[i].nmalloc += bin->stats.nmalloc; bstats[i].ndalloc += bin->stats.ndalloc; bstats[i].nrequests += bin->stats.nrequests; + bstats[i].curregs += bin->stats.curregs; if (config_tcache) { bstats[i].nfills += bin->stats.nfills; bstats[i].nflushes += bin->stats.nflushes; @@ -2296,27 +2314,45 @@ arena_stats_merge(arena_t *arena, const char **dss, size_t *nactive, } } -bool -arena_new(arena_t *arena, unsigned ind) +arena_t * +arena_new(unsigned ind) { + arena_t *arena; unsigned i; arena_bin_t *bin; + /* + * Allocate arena, arena->lstats, and arena->hstats contiguously, mainly + * because there is no way to clean up if base_alloc() OOMs. + */ + if (config_stats) { + arena = (arena_t *)base_alloc(CACHELINE_CEILING(sizeof(arena_t)) + + QUANTUM_CEILING(nlclasses * sizeof(malloc_large_stats_t) + + nhclasses) * sizeof(malloc_huge_stats_t)); + } else + arena = (arena_t *)base_alloc(sizeof(arena_t)); + if (arena == NULL) + return (NULL); + arena->ind = ind; arena->nthreads = 0; + arena->chunk_alloc = chunk_alloc_default; + arena->chunk_dalloc = chunk_dalloc_default; if (malloc_mutex_init(&arena->lock)) - return (true); + return (NULL); if (config_stats) { memset(&arena->stats, 0, sizeof(arena_stats_t)); - arena->stats.lstats = - (malloc_large_stats_t *)base_alloc(nlclasses * - sizeof(malloc_large_stats_t)); - if (arena->stats.lstats == NULL) - return (true); + arena->stats.lstats = (malloc_large_stats_t *)((uintptr_t)arena + + CACHELINE_CEILING(sizeof(arena_t))); memset(arena->stats.lstats, 0, nlclasses * sizeof(malloc_large_stats_t)); + arena->stats.hstats = (malloc_huge_stats_t *)((uintptr_t)arena + + CACHELINE_CEILING(sizeof(arena_t)) + + QUANTUM_CEILING(nlclasses * sizeof(malloc_large_stats_t))); + memset(arena->stats.hstats, 0, nhclasses * + sizeof(malloc_huge_stats_t)); if (config_tcache) ql_new(&arena->tcache_ql); } @@ -2326,54 +2362,43 @@ arena_new(arena_t *arena, unsigned ind) arena->dss_prec = chunk_dss_prec_get(); - /* Initialize chunks. */ - arena_chunk_dirty_new(&arena->chunks_dirty); arena->spare = NULL; arena->nactive = 0; arena->ndirty = 0; - arena->npurgatory = 0; arena_avail_tree_new(&arena->runs_avail); + ql_new(&arena->runs_dirty); /* Initialize bins. */ for (i = 0; i < NBINS; i++) { bin = &arena->bins[i]; if (malloc_mutex_init(&bin->lock)) - return (true); + return (NULL); bin->runcur = NULL; arena_run_tree_new(&bin->runs); if (config_stats) memset(&bin->stats, 0, sizeof(malloc_bin_stats_t)); } - return (false); + return (arena); } /* * Calculate bin_info->run_size such that it meets the following constraints: * - * *) bin_info->run_size >= min_run_size - * *) bin_info->run_size <= arena_maxclass - * *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed). + * *) bin_info->run_size <= arena_maxrun * *) bin_info->nregs <= RUN_MAXREGS * - * bin_info->nregs, bin_info->bitmap_offset, and bin_info->reg0_offset are also - * calculated here, since these settings are all interdependent. + * bin_info->nregs and bin_info->reg0_offset are also calculated here, since + * these settings are all interdependent. */ -static size_t -bin_info_run_size_calc(arena_bin_info_t *bin_info, size_t min_run_size) +static void +bin_info_run_size_calc(arena_bin_info_t *bin_info) { size_t pad_size; - size_t try_run_size, good_run_size; - uint32_t try_nregs, good_nregs; - uint32_t try_hdr_size, good_hdr_size; - uint32_t try_bitmap_offset, good_bitmap_offset; - uint32_t try_ctx0_offset, good_ctx0_offset; - uint32_t try_redzone0_offset, good_redzone0_offset; - - assert(min_run_size >= PAGE); - assert(min_run_size <= arena_maxclass); + size_t try_run_size, perfect_run_size, actual_run_size; + uint32_t try_nregs, perfect_nregs, actual_nregs; /* * Determine redzone size based on minimum alignment and minimum @@ -2382,8 +2407,9 @@ bin_info_run_size_calc(arena_bin_info_t *bin_info, size_t min_run_size) * minimum alignment; without the padding, each redzone would have to * be twice as large in order to maintain alignment. */ - if (config_fill && opt_redzone) { - size_t align_min = ZU(1) << (jemalloc_ffs(bin_info->reg_size) - 1); + if (config_fill && unlikely(opt_redzone)) { + size_t align_min = ZU(1) << (jemalloc_ffs(bin_info->reg_size) - + 1); if (align_min <= REDZONE_MINSIZE) { bin_info->redzone_size = REDZONE_MINSIZE; pad_size = 0; @@ -2399,119 +2425,74 @@ bin_info_run_size_calc(arena_bin_info_t *bin_info, size_t min_run_size) (bin_info->redzone_size << 1); /* - * Calculate known-valid settings before entering the run_size - * expansion loop, so that the first part of the loop always copies - * valid settings. - * - * The do..while loop iteratively reduces the number of regions until - * the run header and the regions no longer overlap. A closed formula - * would be quite messy, since there is an interdependency between the - * header's mask length and the number of regions. + * Compute run size under ideal conditions (no redzones, no limit on run + * size). */ - try_run_size = min_run_size; - try_nregs = ((try_run_size - sizeof(arena_run_t)) / - bin_info->reg_interval) - + 1; /* Counter-act try_nregs-- in loop. */ - if (try_nregs > RUN_MAXREGS) { - try_nregs = RUN_MAXREGS - + 1; /* Counter-act try_nregs-- in loop. */ - } + try_run_size = PAGE; + try_nregs = try_run_size / bin_info->reg_size; do { - try_nregs--; - try_hdr_size = sizeof(arena_run_t); - /* Pad to a long boundary. */ - try_hdr_size = LONG_CEILING(try_hdr_size); - try_bitmap_offset = try_hdr_size; - /* Add space for bitmap. */ - try_hdr_size += bitmap_size(try_nregs); - if (config_prof && opt_prof && prof_promote == false) { - /* Pad to a quantum boundary. */ - try_hdr_size = QUANTUM_CEILING(try_hdr_size); - try_ctx0_offset = try_hdr_size; - /* Add space for one (prof_ctx_t *) per region. */ - try_hdr_size += try_nregs * sizeof(prof_ctx_t *); - } else - try_ctx0_offset = 0; - try_redzone0_offset = try_run_size - (try_nregs * - bin_info->reg_interval) - pad_size; - } while (try_hdr_size > try_redzone0_offset); + perfect_run_size = try_run_size; + perfect_nregs = try_nregs; - /* run_size expansion loop. */ - do { - /* - * Copy valid settings before trying more aggressive settings. - */ - good_run_size = try_run_size; - good_nregs = try_nregs; - good_hdr_size = try_hdr_size; - good_bitmap_offset = try_bitmap_offset; - good_ctx0_offset = try_ctx0_offset; - good_redzone0_offset = try_redzone0_offset; - - /* Try more aggressive settings. */ try_run_size += PAGE; - try_nregs = ((try_run_size - sizeof(arena_run_t) - pad_size) / - bin_info->reg_interval) - + 1; /* Counter-act try_nregs-- in loop. */ - if (try_nregs > RUN_MAXREGS) { - try_nregs = RUN_MAXREGS - + 1; /* Counter-act try_nregs-- in loop. */ - } - do { - try_nregs--; - try_hdr_size = sizeof(arena_run_t); - /* Pad to a long boundary. */ - try_hdr_size = LONG_CEILING(try_hdr_size); - try_bitmap_offset = try_hdr_size; - /* Add space for bitmap. */ - try_hdr_size += bitmap_size(try_nregs); - if (config_prof && opt_prof && prof_promote == false) { - /* Pad to a quantum boundary. */ - try_hdr_size = QUANTUM_CEILING(try_hdr_size); - try_ctx0_offset = try_hdr_size; - /* - * Add space for one (prof_ctx_t *) per region. - */ - try_hdr_size += try_nregs * - sizeof(prof_ctx_t *); - } - try_redzone0_offset = try_run_size - (try_nregs * - bin_info->reg_interval) - pad_size; - } while (try_hdr_size > try_redzone0_offset); - } while (try_run_size <= arena_maxclass - && RUN_MAX_OVRHD * (bin_info->reg_interval << 3) > - RUN_MAX_OVRHD_RELAX - && (try_redzone0_offset << RUN_BFP) > RUN_MAX_OVRHD * try_run_size - && try_nregs < RUN_MAXREGS); + try_nregs = try_run_size / bin_info->reg_size; + } while (perfect_run_size != perfect_nregs * bin_info->reg_size); + assert(perfect_nregs <= RUN_MAXREGS); - assert(good_hdr_size <= good_redzone0_offset); + actual_run_size = perfect_run_size; + actual_nregs = (actual_run_size - pad_size) / bin_info->reg_interval; + + /* + * Redzones can require enough padding that not even a single region can + * fit within the number of pages that would normally be dedicated to a + * run for this size class. Increase the run size until at least one + * region fits. + */ + while (actual_nregs == 0) { + assert(config_fill && unlikely(opt_redzone)); + + actual_run_size += PAGE; + actual_nregs = (actual_run_size - pad_size) / + bin_info->reg_interval; + } + + /* + * Make sure that the run will fit within an arena chunk. + */ + while (actual_run_size > arena_maxrun) { + actual_run_size -= PAGE; + actual_nregs = (actual_run_size - pad_size) / + bin_info->reg_interval; + } + assert(actual_nregs > 0); /* Copy final settings. */ - bin_info->run_size = good_run_size; - bin_info->nregs = good_nregs; - bin_info->bitmap_offset = good_bitmap_offset; - bin_info->ctx0_offset = good_ctx0_offset; - bin_info->reg0_offset = good_redzone0_offset + bin_info->redzone_size; + bin_info->run_size = actual_run_size; + bin_info->nregs = actual_nregs; + bin_info->reg0_offset = actual_run_size - (actual_nregs * + bin_info->reg_interval) - pad_size + bin_info->redzone_size; assert(bin_info->reg0_offset - bin_info->redzone_size + (bin_info->nregs * bin_info->reg_interval) + pad_size == bin_info->run_size); - - return (good_run_size); } static void bin_info_init(void) { arena_bin_info_t *bin_info; - size_t prev_run_size = PAGE; -#define SIZE_CLASS(bin, delta, size) \ - bin_info = &arena_bin_info[bin]; \ +#define BIN_INFO_INIT_bin_yes(index, size) \ + bin_info = &arena_bin_info[index]; \ bin_info->reg_size = size; \ - prev_run_size = bin_info_run_size_calc(bin_info, prev_run_size);\ + bin_info_run_size_calc(bin_info); \ bitmap_info_init(&bin_info->bitmap_info, bin_info->nregs); +#define BIN_INFO_INIT_bin_no(index, size) +#define SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \ + BIN_INFO_INIT_bin_##bin(index, (ZU(1)<> LG_PAGE) + ((header_size & PAGE_MASK) - != 0); + header_size = offsetof(arena_chunk_t, map_bits) + + ((sizeof(arena_chunk_map_bits_t) + + sizeof(arena_chunk_map_misc_t)) * (chunk_npages-map_bias)); + map_bias = (header_size + PAGE_MASK) >> LG_PAGE; } assert(map_bias > 0); - arena_maxclass = chunksize - (map_bias << LG_PAGE); + map_misc_offset = offsetof(arena_chunk_t, map_bits) + + sizeof(arena_chunk_map_bits_t) * (chunk_npages-map_bias); + + arena_maxrun = chunksize - (map_bias << LG_PAGE); + assert(arena_maxrun > 0); + arena_maxclass = index2size(size2index(chunksize)-1); + if (arena_maxclass > arena_maxrun) { + /* + * For small chunk sizes it's possible for there to be fewer + * non-header pages available than are necessary to serve the + * size classes just below chunksize. + */ + arena_maxclass = arena_maxrun; + } + assert(arena_maxclass > 0); + nlclasses = size2index(arena_maxclass) - size2index(SMALL_MAXCLASS); + nhclasses = NSIZES - nlclasses - NBINS; bin_info_init(); } diff --git a/memory/jemalloc/src/src/base.c b/memory/jemalloc/src/src/base.c index 4e62e8fa9189..409c7bb78c1e 100644 --- a/memory/jemalloc/src/src/base.c +++ b/memory/jemalloc/src/src/base.c @@ -16,24 +16,16 @@ static void *base_next_addr; static void *base_past_addr; /* Addr immediately past base_pages. */ static extent_node_t *base_nodes; -/******************************************************************************/ -/* Function prototypes for non-inline static functions. */ - -static bool base_pages_alloc(size_t minsize); - /******************************************************************************/ static bool base_pages_alloc(size_t minsize) { size_t csize; - bool zero; assert(minsize != 0); csize = CHUNK_CEILING(minsize); - zero = false; - base_pages = chunk_alloc(csize, chunksize, true, &zero, - chunk_dss_prec_get()); + base_pages = chunk_alloc_base(csize); if (base_pages == NULL) return (true); base_next_addr = base_pages; @@ -63,7 +55,7 @@ base_alloc(size_t size) ret = base_next_addr; base_next_addr = (void *)((uintptr_t)base_next_addr + csize); malloc_mutex_unlock(&base_mtx); - VALGRIND_MAKE_MEM_UNDEFINED(ret, csize); + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, csize); return (ret); } @@ -89,7 +81,8 @@ base_node_alloc(void) ret = base_nodes; base_nodes = *(extent_node_t **)ret; malloc_mutex_unlock(&base_mtx); - VALGRIND_MAKE_MEM_UNDEFINED(ret, sizeof(extent_node_t)); + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, + sizeof(extent_node_t)); } else { malloc_mutex_unlock(&base_mtx); ret = (extent_node_t *)base_alloc(sizeof(extent_node_t)); @@ -99,10 +92,10 @@ base_node_alloc(void) } void -base_node_dealloc(extent_node_t *node) +base_node_dalloc(extent_node_t *node) { - VALGRIND_MAKE_MEM_UNDEFINED(node, sizeof(extent_node_t)); + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(node, sizeof(extent_node_t)); malloc_mutex_lock(&base_mtx); *(extent_node_t **)node = base_nodes; base_nodes = node; diff --git a/memory/jemalloc/src/src/bitmap.c b/memory/jemalloc/src/src/bitmap.c index e2bd907d558d..c733372b4cb2 100644 --- a/memory/jemalloc/src/src/bitmap.c +++ b/memory/jemalloc/src/src/bitmap.c @@ -2,19 +2,6 @@ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ -/* Function prototypes for non-inline static functions. */ - -static size_t bits2groups(size_t nbits); - -/******************************************************************************/ - -static size_t -bits2groups(size_t nbits) -{ - - return ((nbits >> LG_BITMAP_GROUP_NBITS) + - !!(nbits & BITMAP_GROUP_NBITS_MASK)); -} void bitmap_info_init(bitmap_info_t *binfo, size_t nbits) @@ -31,15 +18,16 @@ bitmap_info_init(bitmap_info_t *binfo, size_t nbits) * that requires only one group. */ binfo->levels[0].group_offset = 0; - group_count = bits2groups(nbits); + group_count = BITMAP_BITS2GROUPS(nbits); for (i = 1; group_count > 1; i++) { assert(i < BITMAP_MAX_LEVELS); binfo->levels[i].group_offset = binfo->levels[i-1].group_offset + group_count; - group_count = bits2groups(group_count); + group_count = BITMAP_BITS2GROUPS(group_count); } binfo->levels[i].group_offset = binfo->levels[i-1].group_offset + group_count; + assert(binfo->levels[i].group_offset <= BITMAP_GROUPS_MAX); binfo->nlevels = i; binfo->nbits = nbits; } diff --git a/memory/jemalloc/src/src/chunk.c b/memory/jemalloc/src/src/chunk.c index 90ab116ae5fa..7926452729f2 100644 --- a/memory/jemalloc/src/src/chunk.c +++ b/memory/jemalloc/src/src/chunk.c @@ -27,23 +27,20 @@ rtree_t *chunks_rtree; size_t chunksize; size_t chunksize_mask; /* (chunksize - 1). */ size_t chunk_npages; -size_t map_bias; -size_t arena_maxclass; /* Max size class for arenas. */ /******************************************************************************/ -/* Function prototypes for non-inline static functions. */ +/* + * Function prototypes for static functions that are referenced prior to + * definition. + */ -static void *chunk_recycle(extent_tree_t *chunks_szad, - extent_tree_t *chunks_ad, size_t size, size_t alignment, bool base, - bool *zero); -static void chunk_record(extent_tree_t *chunks_szad, - extent_tree_t *chunks_ad, void *chunk, size_t size); +static void chunk_dalloc_core(void *chunk, size_t size); /******************************************************************************/ static void * -chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size, - size_t alignment, bool base, bool *zero) +chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, + void *new_addr, size_t size, size_t alignment, bool base, bool *zero) { void *ret; extent_node_t *node; @@ -65,11 +62,11 @@ chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size, /* Beware size_t wrap-around. */ if (alloc_size < size) return (NULL); - key.addr = NULL; + key.addr = new_addr; key.size = alloc_size; malloc_mutex_lock(&chunks_mtx); node = extent_tree_szad_nsearch(chunks_szad, &key); - if (node == NULL) { + if (node == NULL || (new_addr && node->addr != new_addr)) { malloc_mutex_unlock(&chunks_mtx); return (NULL); } @@ -104,7 +101,7 @@ chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size, malloc_mutex_unlock(&chunks_mtx); node = base_node_alloc(); if (node == NULL) { - chunk_dealloc(ret, size, true); + chunk_dalloc_core(ret, size); return (NULL); } malloc_mutex_lock(&chunks_mtx); @@ -119,15 +116,15 @@ chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size, malloc_mutex_unlock(&chunks_mtx); if (node != NULL) - base_node_dealloc(node); + base_node_dalloc(node); if (*zero) { - if (zeroed == false) + if (!zeroed) memset(ret, 0, size); else if (config_debug) { size_t i; size_t *p = (size_t *)(uintptr_t)ret; - VALGRIND_MAKE_MEM_DEFINED(ret, size); + JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ret, size); for (i = 0; i < size / sizeof(size_t); i++) assert(p[i] == 0); } @@ -136,14 +133,14 @@ chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size, } /* - * If the caller specifies (*zero == false), it is still possible to receive - * zeroed memory, in which case *zero is toggled to true. arena_chunk_alloc() - * takes advantage of this to avoid demanding zeroed chunks, but taking - * advantage of them if they are returned. + * If the caller specifies (!*zero), it is still possible to receive zeroed + * memory, in which case *zero is toggled to true. arena_chunk_alloc() takes + * advantage of this to avoid demanding zeroed chunks, but taking advantage of + * them if they are returned. */ -void * -chunk_alloc(size_t size, size_t alignment, bool base, bool *zero, - dss_prec_t dss_prec) +static void * +chunk_alloc_core(void *new_addr, size_t size, size_t alignment, bool base, + bool *zero, dss_prec_t dss_prec) { void *ret; @@ -153,62 +150,121 @@ chunk_alloc(size_t size, size_t alignment, bool base, bool *zero, assert((alignment & chunksize_mask) == 0); /* "primary" dss. */ - if (config_dss && dss_prec == dss_prec_primary) { - if ((ret = chunk_recycle(&chunks_szad_dss, &chunks_ad_dss, size, - alignment, base, zero)) != NULL) - goto label_return; - if ((ret = chunk_alloc_dss(size, alignment, zero)) != NULL) - goto label_return; + if (have_dss && dss_prec == dss_prec_primary) { + if ((ret = chunk_recycle(&chunks_szad_dss, &chunks_ad_dss, + new_addr, size, alignment, base, zero)) != NULL) + return (ret); + if ((ret = chunk_alloc_dss(new_addr, size, alignment, zero)) + != NULL) + return (ret); } /* mmap. */ - if ((ret = chunk_recycle(&chunks_szad_mmap, &chunks_ad_mmap, size, - alignment, base, zero)) != NULL) - goto label_return; - if ((ret = chunk_alloc_mmap(size, alignment, zero)) != NULL) - goto label_return; + if ((ret = chunk_recycle(&chunks_szad_mmap, &chunks_ad_mmap, new_addr, + size, alignment, base, zero)) != NULL) + return (ret); + /* Requesting an address not implemented for chunk_alloc_mmap(). */ + if (new_addr == NULL && + (ret = chunk_alloc_mmap(size, alignment, zero)) != NULL) + return (ret); /* "secondary" dss. */ - if (config_dss && dss_prec == dss_prec_secondary) { - if ((ret = chunk_recycle(&chunks_szad_dss, &chunks_ad_dss, size, - alignment, base, zero)) != NULL) - goto label_return; - if ((ret = chunk_alloc_dss(size, alignment, zero)) != NULL) - goto label_return; + if (have_dss && dss_prec == dss_prec_secondary) { + if ((ret = chunk_recycle(&chunks_szad_dss, &chunks_ad_dss, + new_addr, size, alignment, base, zero)) != NULL) + return (ret); + if ((ret = chunk_alloc_dss(new_addr, size, alignment, zero)) + != NULL) + return (ret); } /* All strategies for allocation failed. */ - ret = NULL; -label_return: - if (ret != NULL) { - if (config_ivsalloc && base == false) { - if (rtree_set(chunks_rtree, (uintptr_t)ret, 1)) { - chunk_dealloc(ret, size, true); - return (NULL); - } - } - if (config_stats || config_prof) { - bool gdump; - malloc_mutex_lock(&chunks_mtx); - if (config_stats) - stats_chunks.nchunks += (size / chunksize); - stats_chunks.curchunks += (size / chunksize); - if (stats_chunks.curchunks > stats_chunks.highchunks) { - stats_chunks.highchunks = - stats_chunks.curchunks; - if (config_prof) - gdump = true; - } else if (config_prof) - gdump = false; - malloc_mutex_unlock(&chunks_mtx); - if (config_prof && opt_prof && opt_prof_gdump && gdump) - prof_gdump(); - } - if (config_valgrind) - VALGRIND_MAKE_MEM_UNDEFINED(ret, size); + return (NULL); +} + +static bool +chunk_register(void *chunk, size_t size, bool base) +{ + + assert(chunk != NULL); + assert(CHUNK_ADDR2BASE(chunk) == chunk); + + if (config_ivsalloc && !base) { + if (rtree_set(chunks_rtree, (uintptr_t)chunk, 1)) + return (true); + } + if (config_stats || config_prof) { + bool gdump; + malloc_mutex_lock(&chunks_mtx); + if (config_stats) + stats_chunks.nchunks += (size / chunksize); + stats_chunks.curchunks += (size / chunksize); + if (stats_chunks.curchunks > stats_chunks.highchunks) { + stats_chunks.highchunks = + stats_chunks.curchunks; + if (config_prof) + gdump = true; + } else if (config_prof) + gdump = false; + malloc_mutex_unlock(&chunks_mtx); + if (config_prof && opt_prof && opt_prof_gdump && gdump) + prof_gdump(); + } + if (config_valgrind) + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(chunk, size); + return (false); +} + +void * +chunk_alloc_base(size_t size) +{ + void *ret; + bool zero; + + zero = false; + ret = chunk_alloc_core(NULL, size, chunksize, true, &zero, + chunk_dss_prec_get()); + if (ret == NULL) + return (NULL); + if (chunk_register(ret, size, true)) { + chunk_dalloc_core(ret, size); + return (NULL); } - assert(CHUNK_ADDR2BASE(ret) == ret); return (ret); } +void * +chunk_alloc_arena(chunk_alloc_t *chunk_alloc, chunk_dalloc_t *chunk_dalloc, + unsigned arena_ind, void *new_addr, size_t size, size_t alignment, + bool *zero) +{ + void *ret; + + ret = chunk_alloc(new_addr, size, alignment, zero, arena_ind); + if (ret != NULL && chunk_register(ret, size, false)) { + chunk_dalloc(ret, size, arena_ind); + ret = NULL; + } + + return (ret); +} + +/* Default arena chunk allocation routine in the absence of user override. */ +void * +chunk_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, + unsigned arena_ind) +{ + arena_t *arena; + + arena = arena_get(tsd_fetch(), arena_ind, false, true); + /* + * The arena we're allocating on behalf of must have been initialized + * already. + */ + assert(arena != NULL); + + return (chunk_alloc_core(new_addr, size, alignment, false, zero, + arena->dss_prec)); +} + static void chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk, size_t size) @@ -217,7 +273,7 @@ chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk, extent_node_t *xnode, *node, *prev, *xprev, key; unzeroed = pages_purge(chunk, size); - VALGRIND_MAKE_MEM_NOACCESS(chunk, size); + JEMALLOC_VALGRIND_MAKE_MEM_NOACCESS(chunk, size); /* * Allocate a node before acquiring chunks_mtx even though it might not @@ -242,7 +298,7 @@ chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk, extent_tree_szad_remove(chunks_szad, node); node->addr = chunk; node->size += size; - node->zeroed = (node->zeroed && (unzeroed == false)); + node->zeroed = (node->zeroed && !unzeroed); extent_tree_szad_insert(chunks_szad, node); } else { /* Coalescing forward failed, so insert a new node. */ @@ -259,7 +315,7 @@ chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk, xnode = NULL; /* Prevent deallocation below. */ node->addr = chunk; node->size = size; - node->zeroed = (unzeroed == false); + node->zeroed = !unzeroed; extent_tree_ad_insert(chunks_ad, node); extent_tree_szad_insert(chunks_szad, node); } @@ -292,9 +348,9 @@ label_return: * avoid potential deadlock. */ if (xnode != NULL) - base_node_dealloc(xnode); + base_node_dalloc(xnode); if (xprev != NULL) - base_node_dealloc(xprev); + base_node_dalloc(xprev); } void @@ -305,14 +361,14 @@ chunk_unmap(void *chunk, size_t size) assert(size != 0); assert((size & chunksize_mask) == 0); - if (config_dss && chunk_in_dss(chunk)) + if (have_dss && chunk_in_dss(chunk)) chunk_record(&chunks_szad_dss, &chunks_ad_dss, chunk, size); - else if (chunk_dealloc_mmap(chunk, size)) + else if (chunk_dalloc_mmap(chunk, size)) chunk_record(&chunks_szad_mmap, &chunks_ad_mmap, chunk, size); } -void -chunk_dealloc(void *chunk, size_t size, bool unmap) +static void +chunk_dalloc_core(void *chunk, size_t size) { assert(chunk != NULL); @@ -329,8 +385,16 @@ chunk_dealloc(void *chunk, size_t size, bool unmap) malloc_mutex_unlock(&chunks_mtx); } - if (unmap) - chunk_unmap(chunk, size); + chunk_unmap(chunk, size); +} + +/* Default arena chunk deallocation routine in the absence of user override. */ +bool +chunk_dalloc_default(void *chunk, size_t size, unsigned arena_ind) +{ + + chunk_dalloc_core(chunk, size); + return (false); } bool @@ -343,12 +407,11 @@ chunk_boot(void) chunksize_mask = chunksize - 1; chunk_npages = (chunksize >> LG_PAGE); - if (config_stats || config_prof) { - if (malloc_mutex_init(&chunks_mtx)) - return (true); + if (malloc_mutex_init(&chunks_mtx)) + return (true); + if (config_stats || config_prof) memset(&stats_chunks, 0, sizeof(chunk_stats_t)); - } - if (config_dss && chunk_dss_boot()) + if (have_dss && chunk_dss_boot()) return (true); extent_tree_szad_new(&chunks_szad_mmap); extent_tree_ad_new(&chunks_ad_mmap); diff --git a/memory/jemalloc/src/src/chunk_dss.c b/memory/jemalloc/src/src/chunk_dss.c index 510bb8bee859..edba3b23a8f3 100644 --- a/memory/jemalloc/src/src/chunk_dss.c +++ b/memory/jemalloc/src/src/chunk_dss.c @@ -32,7 +32,7 @@ static void * chunk_dss_sbrk(intptr_t increment) { -#ifdef JEMALLOC_HAVE_SBRK +#ifdef JEMALLOC_DSS return (sbrk(increment)); #else not_implemented(); @@ -45,7 +45,7 @@ chunk_dss_prec_get(void) { dss_prec_t ret; - if (config_dss == false) + if (!have_dss) return (dss_prec_disabled); malloc_mutex_lock(&dss_mtx); ret = dss_prec_default; @@ -57,8 +57,8 @@ bool chunk_dss_prec_set(dss_prec_t dss_prec) { - if (config_dss == false) - return (true); + if (!have_dss) + return (dss_prec != dss_prec_disabled); malloc_mutex_lock(&dss_mtx); dss_prec_default = dss_prec; malloc_mutex_unlock(&dss_mtx); @@ -66,11 +66,11 @@ chunk_dss_prec_set(dss_prec_t dss_prec) } void * -chunk_alloc_dss(size_t size, size_t alignment, bool *zero) +chunk_alloc_dss(void *new_addr, size_t size, size_t alignment, bool *zero) { void *ret; - cassert(config_dss); + cassert(have_dss); assert(size > 0 && (size & chunksize_mask) == 0); assert(alignment > 0 && (alignment & chunksize_mask) == 0); @@ -93,8 +93,17 @@ chunk_alloc_dss(size_t size, size_t alignment, bool *zero) * malloc. */ do { + /* Avoid an unnecessary system call. */ + if (new_addr != NULL && dss_max != new_addr) + break; + /* Get the current end of the DSS. */ dss_max = chunk_dss_sbrk(0); + + /* Make sure the earlier condition still holds. */ + if (new_addr != NULL && dss_max != new_addr) + break; + /* * Calculate how much padding is necessary to * chunk-align the end of the DSS. @@ -126,7 +135,8 @@ chunk_alloc_dss(size_t size, size_t alignment, bool *zero) if (cpad_size != 0) chunk_unmap(cpad, cpad_size); if (*zero) { - VALGRIND_MAKE_MEM_UNDEFINED(ret, size); + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED( + ret, size); memset(ret, 0, size); } return (ret); @@ -143,7 +153,7 @@ chunk_in_dss(void *chunk) { bool ret; - cassert(config_dss); + cassert(have_dss); malloc_mutex_lock(&dss_mtx); if ((uintptr_t)chunk >= (uintptr_t)dss_base @@ -160,7 +170,7 @@ bool chunk_dss_boot(void) { - cassert(config_dss); + cassert(have_dss); if (malloc_mutex_init(&dss_mtx)) return (true); @@ -175,7 +185,7 @@ void chunk_dss_prefork(void) { - if (config_dss) + if (have_dss) malloc_mutex_prefork(&dss_mtx); } @@ -183,7 +193,7 @@ void chunk_dss_postfork_parent(void) { - if (config_dss) + if (have_dss) malloc_mutex_postfork_parent(&dss_mtx); } @@ -191,7 +201,7 @@ void chunk_dss_postfork_child(void) { - if (config_dss) + if (have_dss) malloc_mutex_postfork_child(&dss_mtx); } diff --git a/memory/jemalloc/src/src/chunk_mmap.c b/memory/jemalloc/src/src/chunk_mmap.c index 2056d793f053..7e02c10223ea 100644 --- a/memory/jemalloc/src/src/chunk_mmap.c +++ b/memory/jemalloc/src/src/chunk_mmap.c @@ -121,7 +121,7 @@ pages_purge(void *addr, size_t length) #ifdef _WIN32 VirtualAlloc(addr, length, MEM_RESET, PAGE_READWRITE); unzeroed = true; -#else +#elif defined(JEMALLOC_HAVE_MADVISE) # ifdef JEMALLOC_PURGE_MADVISE_DONTNEED # define JEMALLOC_MADV_PURGE MADV_DONTNEED # define JEMALLOC_MADV_ZEROS true @@ -129,12 +129,15 @@ pages_purge(void *addr, size_t length) # define JEMALLOC_MADV_PURGE MADV_FREE # define JEMALLOC_MADV_ZEROS false # else -# error "No method defined for purging unused dirty pages." +# error "No madvise(2) flag defined for purging unused dirty pages." # endif int err = madvise(addr, length, JEMALLOC_MADV_PURGE); - unzeroed = (JEMALLOC_MADV_ZEROS == false || err != 0); + unzeroed = (!JEMALLOC_MADV_ZEROS || err != 0); # undef JEMALLOC_MADV_PURGE # undef JEMALLOC_MADV_ZEROS +#else + /* Last resort no-op. */ + unzeroed = true; #endif return (unzeroed); } @@ -200,11 +203,11 @@ chunk_alloc_mmap(size_t size, size_t alignment, bool *zero) } bool -chunk_dealloc_mmap(void *chunk, size_t size) +chunk_dalloc_mmap(void *chunk, size_t size) { if (config_munmap) pages_unmap(chunk, size); - return (config_munmap == false); + return (!config_munmap); } diff --git a/memory/jemalloc/src/src/ckh.c b/memory/jemalloc/src/src/ckh.c index 04c52966193a..db2ae3920be2 100644 --- a/memory/jemalloc/src/src/ckh.c +++ b/memory/jemalloc/src/src/ckh.c @@ -40,8 +40,8 @@ /******************************************************************************/ /* Function prototypes for non-inline static functions. */ -static bool ckh_grow(ckh_t *ckh); -static void ckh_shrink(ckh_t *ckh); +static bool ckh_grow(tsd_t *tsd, ckh_t *ckh); +static void ckh_shrink(tsd_t *tsd, ckh_t *ckh); /******************************************************************************/ @@ -185,7 +185,7 @@ ckh_evict_reloc_insert(ckh_t *ckh, size_t argbucket, void const **argkey, } bucket = tbucket; - if (ckh_try_bucket_insert(ckh, bucket, key, data) == false) + if (!ckh_try_bucket_insert(ckh, bucket, key, data)) return (false); } } @@ -201,12 +201,12 @@ ckh_try_insert(ckh_t *ckh, void const**argkey, void const**argdata) /* Try to insert in primary bucket. */ bucket = hashes[0] & ((ZU(1) << ckh->lg_curbuckets) - 1); - if (ckh_try_bucket_insert(ckh, bucket, key, data) == false) + if (!ckh_try_bucket_insert(ckh, bucket, key, data)) return (false); /* Try to insert in secondary bucket. */ bucket = hashes[1] & ((ZU(1) << ckh->lg_curbuckets) - 1); - if (ckh_try_bucket_insert(ckh, bucket, key, data) == false) + if (!ckh_try_bucket_insert(ckh, bucket, key, data)) return (false); /* @@ -243,7 +243,7 @@ ckh_rebuild(ckh_t *ckh, ckhc_t *aTab) } static bool -ckh_grow(ckh_t *ckh) +ckh_grow(tsd_t *tsd, ckh_t *ckh) { bool ret; ckhc_t *tab, *ttab; @@ -270,7 +270,7 @@ ckh_grow(ckh_t *ckh) ret = true; goto label_return; } - tab = (ckhc_t *)ipalloc(usize, CACHELINE, true); + tab = (ckhc_t *)ipalloc(tsd, usize, CACHELINE, true); if (tab == NULL) { ret = true; goto label_return; @@ -281,13 +281,13 @@ ckh_grow(ckh_t *ckh) tab = ttab; ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; - if (ckh_rebuild(ckh, tab) == false) { - idalloc(tab); + if (!ckh_rebuild(ckh, tab)) { + idalloc(tsd, tab); break; } /* Rebuilding failed, so back out partially rebuilt table. */ - idalloc(ckh->tab); + idalloc(tsd, ckh->tab); ckh->tab = tab; ckh->lg_curbuckets = lg_prevbuckets; } @@ -298,7 +298,7 @@ label_return: } static void -ckh_shrink(ckh_t *ckh) +ckh_shrink(tsd_t *tsd, ckh_t *ckh) { ckhc_t *tab, *ttab; size_t lg_curcells, usize; @@ -313,7 +313,7 @@ ckh_shrink(ckh_t *ckh) usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); if (usize == 0) return; - tab = (ckhc_t *)ipalloc(usize, CACHELINE, true); + tab = (ckhc_t *)ipalloc(tsd, usize, CACHELINE, true); if (tab == NULL) { /* * An OOM error isn't worth propagating, since it doesn't @@ -327,8 +327,8 @@ ckh_shrink(ckh_t *ckh) tab = ttab; ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; - if (ckh_rebuild(ckh, tab) == false) { - idalloc(tab); + if (!ckh_rebuild(ckh, tab)) { + idalloc(tsd, tab); #ifdef CKH_COUNT ckh->nshrinks++; #endif @@ -336,7 +336,7 @@ ckh_shrink(ckh_t *ckh) } /* Rebuilding failed, so back out partially rebuilt table. */ - idalloc(ckh->tab); + idalloc(tsd, ckh->tab); ckh->tab = tab; ckh->lg_curbuckets = lg_prevbuckets; #ifdef CKH_COUNT @@ -345,7 +345,8 @@ ckh_shrink(ckh_t *ckh) } bool -ckh_new(ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp) +ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, + ckh_keycomp_t *keycomp) { bool ret; size_t mincells, usize; @@ -366,10 +367,10 @@ ckh_new(ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp) ckh->count = 0; /* - * Find the minimum power of 2 that is large enough to fit aBaseCount + * Find the minimum power of 2 that is large enough to fit minitems * entries. We are using (2+,2) cuckoo hashing, which has an expected * maximum load factor of at least ~0.86, so 0.75 is a conservative load - * factor that will typically allow 2^aLgMinItems to fit without ever + * factor that will typically allow mincells items to fit without ever * growing the table. */ assert(LG_CKH_BUCKET_CELLS > 0); @@ -388,7 +389,7 @@ ckh_new(ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp) ret = true; goto label_return; } - ckh->tab = (ckhc_t *)ipalloc(usize, CACHELINE, true); + ckh->tab = (ckhc_t *)ipalloc(tsd, usize, CACHELINE, true); if (ckh->tab == NULL) { ret = true; goto label_return; @@ -400,7 +401,7 @@ label_return: } void -ckh_delete(ckh_t *ckh) +ckh_delete(tsd_t *tsd, ckh_t *ckh) { assert(ckh != NULL); @@ -417,7 +418,7 @@ ckh_delete(ckh_t *ckh) (unsigned long long)ckh->nrelocs); #endif - idalloc(ckh->tab); + idalloc(tsd, ckh->tab); if (config_debug) memset(ckh, 0x5a, sizeof(ckh_t)); } @@ -452,7 +453,7 @@ ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data) } bool -ckh_insert(ckh_t *ckh, const void *key, const void *data) +ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data) { bool ret; @@ -464,7 +465,7 @@ ckh_insert(ckh_t *ckh, const void *key, const void *data) #endif while (ckh_try_insert(ckh, &key, &data)) { - if (ckh_grow(ckh)) { + if (ckh_grow(tsd, ckh)) { ret = true; goto label_return; } @@ -476,7 +477,8 @@ label_return: } bool -ckh_remove(ckh_t *ckh, const void *searchkey, void **key, void **data) +ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key, + void **data) { size_t cell; @@ -497,7 +499,7 @@ ckh_remove(ckh_t *ckh, const void *searchkey, void **key, void **data) + LG_CKH_BUCKET_CELLS - 2)) && ckh->lg_curbuckets > ckh->lg_minbuckets) { /* Ignore error due to OOM. */ - ckh_shrink(ckh); + ckh_shrink(tsd, ckh); } return (false); diff --git a/memory/jemalloc/src/src/ctl.c b/memory/jemalloc/src/src/ctl.c index cc2c5aef570f..90bad7ee0531 100644 --- a/memory/jemalloc/src/src/ctl.c +++ b/memory/jemalloc/src/src/ctl.c @@ -7,7 +7,6 @@ /* * ctl_mtx protects the following: * - ctl_stats.* - * - opt_prof_active */ static malloc_mutex_t ctl_mtx; static bool ctl_initialized; @@ -17,14 +16,14 @@ static ctl_stats_t ctl_stats; /******************************************************************************/ /* Helpers for named and indexed nodes. */ -static inline const ctl_named_node_t * +JEMALLOC_INLINE_C const ctl_named_node_t * ctl_named_node(const ctl_node_t *node) { return ((node->named) ? (const ctl_named_node_t *)node : NULL); } -static inline const ctl_named_node_t * +JEMALLOC_INLINE_C const ctl_named_node_t * ctl_named_children(const ctl_named_node_t *node, int index) { const ctl_named_node_t *children = ctl_named_node(node->children); @@ -32,12 +31,11 @@ ctl_named_children(const ctl_named_node_t *node, int index) return (children ? &children[index] : NULL); } -static inline const ctl_indexed_node_t * +JEMALLOC_INLINE_C const ctl_indexed_node_t * ctl_indexed_node(const ctl_node_t *node) { - return ((node->named == false) ? (const ctl_indexed_node_t *)node : - NULL); + return (!node->named ? (const ctl_indexed_node_t *)node : NULL); } /******************************************************************************/ @@ -68,16 +66,16 @@ CTL_PROTO(version) CTL_PROTO(epoch) CTL_PROTO(thread_tcache_enabled) CTL_PROTO(thread_tcache_flush) +CTL_PROTO(thread_prof_name) +CTL_PROTO(thread_prof_active) CTL_PROTO(thread_arena) CTL_PROTO(thread_allocated) CTL_PROTO(thread_allocatedp) CTL_PROTO(thread_deallocated) CTL_PROTO(thread_deallocatedp) CTL_PROTO(config_debug) -CTL_PROTO(config_dss) CTL_PROTO(config_fill) CTL_PROTO(config_lazy_lock) -CTL_PROTO(config_mremap) CTL_PROTO(config_munmap) CTL_PROTO(config_prof) CTL_PROTO(config_prof_libgcc) @@ -99,13 +97,13 @@ CTL_PROTO(opt_zero) CTL_PROTO(opt_quarantine) CTL_PROTO(opt_redzone) CTL_PROTO(opt_utrace) -CTL_PROTO(opt_valgrind) CTL_PROTO(opt_xmalloc) CTL_PROTO(opt_tcache) CTL_PROTO(opt_lg_tcache_max) CTL_PROTO(opt_prof) CTL_PROTO(opt_prof_prefix) CTL_PROTO(opt_prof_active) +CTL_PROTO(opt_prof_thread_active_init) CTL_PROTO(opt_lg_prof_sample) CTL_PROTO(opt_lg_prof_interval) CTL_PROTO(opt_prof_gdump) @@ -115,6 +113,8 @@ CTL_PROTO(opt_prof_accum) CTL_PROTO(arena_i_purge) static void arena_purge(unsigned arena_ind); CTL_PROTO(arena_i_dss) +CTL_PROTO(arena_i_chunk_alloc) +CTL_PROTO(arena_i_chunk_dalloc) INDEX_PROTO(arena_i) CTL_PROTO(arenas_bin_i_size) CTL_PROTO(arenas_bin_i_nregs) @@ -122,6 +122,8 @@ CTL_PROTO(arenas_bin_i_run_size) INDEX_PROTO(arenas_bin_i) CTL_PROTO(arenas_lrun_i_size) INDEX_PROTO(arenas_lrun_i) +CTL_PROTO(arenas_hchunk_i_size) +INDEX_PROTO(arenas_hchunk_i) CTL_PROTO(arenas_narenas) CTL_PROTO(arenas_initialized) CTL_PROTO(arenas_quantum) @@ -130,17 +132,17 @@ CTL_PROTO(arenas_tcache_max) CTL_PROTO(arenas_nbins) CTL_PROTO(arenas_nhbins) CTL_PROTO(arenas_nlruns) -CTL_PROTO(arenas_purge) +CTL_PROTO(arenas_nhchunks) CTL_PROTO(arenas_extend) +CTL_PROTO(prof_thread_active_init) CTL_PROTO(prof_active) CTL_PROTO(prof_dump) +CTL_PROTO(prof_reset) CTL_PROTO(prof_interval) +CTL_PROTO(lg_prof_sample) CTL_PROTO(stats_chunks_current) CTL_PROTO(stats_chunks_total) CTL_PROTO(stats_chunks_high) -CTL_PROTO(stats_huge_allocated) -CTL_PROTO(stats_huge_nmalloc) -CTL_PROTO(stats_huge_ndalloc) CTL_PROTO(stats_arenas_i_small_allocated) CTL_PROTO(stats_arenas_i_small_nmalloc) CTL_PROTO(stats_arenas_i_small_ndalloc) @@ -149,10 +151,14 @@ CTL_PROTO(stats_arenas_i_large_allocated) CTL_PROTO(stats_arenas_i_large_nmalloc) CTL_PROTO(stats_arenas_i_large_ndalloc) CTL_PROTO(stats_arenas_i_large_nrequests) -CTL_PROTO(stats_arenas_i_bins_j_allocated) +CTL_PROTO(stats_arenas_i_huge_allocated) +CTL_PROTO(stats_arenas_i_huge_nmalloc) +CTL_PROTO(stats_arenas_i_huge_ndalloc) +CTL_PROTO(stats_arenas_i_huge_nrequests) CTL_PROTO(stats_arenas_i_bins_j_nmalloc) CTL_PROTO(stats_arenas_i_bins_j_ndalloc) CTL_PROTO(stats_arenas_i_bins_j_nrequests) +CTL_PROTO(stats_arenas_i_bins_j_curregs) CTL_PROTO(stats_arenas_i_bins_j_nfills) CTL_PROTO(stats_arenas_i_bins_j_nflushes) CTL_PROTO(stats_arenas_i_bins_j_nruns) @@ -164,6 +170,11 @@ CTL_PROTO(stats_arenas_i_lruns_j_ndalloc) CTL_PROTO(stats_arenas_i_lruns_j_nrequests) CTL_PROTO(stats_arenas_i_lruns_j_curruns) INDEX_PROTO(stats_arenas_i_lruns_j) +CTL_PROTO(stats_arenas_i_hchunks_j_nmalloc) +CTL_PROTO(stats_arenas_i_hchunks_j_ndalloc) +CTL_PROTO(stats_arenas_i_hchunks_j_nrequests) +CTL_PROTO(stats_arenas_i_hchunks_j_curhchunks) +INDEX_PROTO(stats_arenas_i_hchunks_j) CTL_PROTO(stats_arenas_i_nthreads) CTL_PROTO(stats_arenas_i_dss) CTL_PROTO(stats_arenas_i_pactive) @@ -197,71 +208,81 @@ CTL_PROTO(stats_mapped) */ #define INDEX(i) {false}, i##_index -static const ctl_named_node_t tcache_node[] = { +static const ctl_named_node_t thread_tcache_node[] = { {NAME("enabled"), CTL(thread_tcache_enabled)}, {NAME("flush"), CTL(thread_tcache_flush)} }; +static const ctl_named_node_t thread_prof_node[] = { + {NAME("name"), CTL(thread_prof_name)}, + {NAME("active"), CTL(thread_prof_active)} +}; + static const ctl_named_node_t thread_node[] = { {NAME("arena"), CTL(thread_arena)}, {NAME("allocated"), CTL(thread_allocated)}, {NAME("allocatedp"), CTL(thread_allocatedp)}, {NAME("deallocated"), CTL(thread_deallocated)}, {NAME("deallocatedp"), CTL(thread_deallocatedp)}, - {NAME("tcache"), CHILD(named, tcache)} + {NAME("tcache"), CHILD(named, thread_tcache)}, + {NAME("prof"), CHILD(named, thread_prof)} }; static const ctl_named_node_t config_node[] = { - {NAME("debug"), CTL(config_debug)}, - {NAME("dss"), CTL(config_dss)}, - {NAME("fill"), CTL(config_fill)}, - {NAME("lazy_lock"), CTL(config_lazy_lock)}, - {NAME("mremap"), CTL(config_mremap)}, - {NAME("munmap"), CTL(config_munmap)}, - {NAME("prof"), CTL(config_prof)}, - {NAME("prof_libgcc"), CTL(config_prof_libgcc)}, - {NAME("prof_libunwind"), CTL(config_prof_libunwind)}, - {NAME("stats"), CTL(config_stats)}, - {NAME("tcache"), CTL(config_tcache)}, - {NAME("tls"), CTL(config_tls)}, - {NAME("utrace"), CTL(config_utrace)}, - {NAME("valgrind"), CTL(config_valgrind)}, - {NAME("xmalloc"), CTL(config_xmalloc)} + {NAME("debug"), CTL(config_debug)}, + {NAME("fill"), CTL(config_fill)}, + {NAME("lazy_lock"), CTL(config_lazy_lock)}, + {NAME("munmap"), CTL(config_munmap)}, + {NAME("prof"), CTL(config_prof)}, + {NAME("prof_libgcc"), CTL(config_prof_libgcc)}, + {NAME("prof_libunwind"), CTL(config_prof_libunwind)}, + {NAME("stats"), CTL(config_stats)}, + {NAME("tcache"), CTL(config_tcache)}, + {NAME("tls"), CTL(config_tls)}, + {NAME("utrace"), CTL(config_utrace)}, + {NAME("valgrind"), CTL(config_valgrind)}, + {NAME("xmalloc"), CTL(config_xmalloc)} }; static const ctl_named_node_t opt_node[] = { - {NAME("abort"), CTL(opt_abort)}, - {NAME("dss"), CTL(opt_dss)}, - {NAME("lg_chunk"), CTL(opt_lg_chunk)}, - {NAME("narenas"), CTL(opt_narenas)}, - {NAME("lg_dirty_mult"), CTL(opt_lg_dirty_mult)}, - {NAME("stats_print"), CTL(opt_stats_print)}, - {NAME("junk"), CTL(opt_junk)}, - {NAME("zero"), CTL(opt_zero)}, - {NAME("quarantine"), CTL(opt_quarantine)}, - {NAME("redzone"), CTL(opt_redzone)}, - {NAME("utrace"), CTL(opt_utrace)}, - {NAME("valgrind"), CTL(opt_valgrind)}, - {NAME("xmalloc"), CTL(opt_xmalloc)}, - {NAME("tcache"), CTL(opt_tcache)}, - {NAME("lg_tcache_max"), CTL(opt_lg_tcache_max)}, - {NAME("prof"), CTL(opt_prof)}, - {NAME("prof_prefix"), CTL(opt_prof_prefix)}, - {NAME("prof_active"), CTL(opt_prof_active)}, - {NAME("lg_prof_sample"), CTL(opt_lg_prof_sample)}, - {NAME("lg_prof_interval"), CTL(opt_lg_prof_interval)}, - {NAME("prof_gdump"), CTL(opt_prof_gdump)}, - {NAME("prof_final"), CTL(opt_prof_final)}, - {NAME("prof_leak"), CTL(opt_prof_leak)}, - {NAME("prof_accum"), CTL(opt_prof_accum)} + {NAME("abort"), CTL(opt_abort)}, + {NAME("dss"), CTL(opt_dss)}, + {NAME("lg_chunk"), CTL(opt_lg_chunk)}, + {NAME("narenas"), CTL(opt_narenas)}, + {NAME("lg_dirty_mult"), CTL(opt_lg_dirty_mult)}, + {NAME("stats_print"), CTL(opt_stats_print)}, + {NAME("junk"), CTL(opt_junk)}, + {NAME("zero"), CTL(opt_zero)}, + {NAME("quarantine"), CTL(opt_quarantine)}, + {NAME("redzone"), CTL(opt_redzone)}, + {NAME("utrace"), CTL(opt_utrace)}, + {NAME("xmalloc"), CTL(opt_xmalloc)}, + {NAME("tcache"), CTL(opt_tcache)}, + {NAME("lg_tcache_max"), CTL(opt_lg_tcache_max)}, + {NAME("prof"), CTL(opt_prof)}, + {NAME("prof_prefix"), CTL(opt_prof_prefix)}, + {NAME("prof_active"), CTL(opt_prof_active)}, + {NAME("prof_thread_active_init"), CTL(opt_prof_thread_active_init)}, + {NAME("lg_prof_sample"), CTL(opt_lg_prof_sample)}, + {NAME("lg_prof_interval"), CTL(opt_lg_prof_interval)}, + {NAME("prof_gdump"), CTL(opt_prof_gdump)}, + {NAME("prof_final"), CTL(opt_prof_final)}, + {NAME("prof_leak"), CTL(opt_prof_leak)}, + {NAME("prof_accum"), CTL(opt_prof_accum)} +}; + +static const ctl_named_node_t chunk_node[] = { + {NAME("alloc"), CTL(arena_i_chunk_alloc)}, + {NAME("dalloc"), CTL(arena_i_chunk_dalloc)} }; static const ctl_named_node_t arena_i_node[] = { - {NAME("purge"), CTL(arena_i_purge)}, - {NAME("dss"), CTL(arena_i_dss)} + {NAME("purge"), CTL(arena_i_purge)}, + {NAME("dss"), CTL(arena_i_dss)}, + {NAME("chunk"), CHILD(named, chunk)}, }; static const ctl_named_node_t super_arena_i_node[] = { - {NAME(""), CHILD(named, arena_i)} + {NAME(""), CHILD(named, arena_i)} }; static const ctl_indexed_node_t arena_node[] = { @@ -269,12 +290,12 @@ static const ctl_indexed_node_t arena_node[] = { }; static const ctl_named_node_t arenas_bin_i_node[] = { - {NAME("size"), CTL(arenas_bin_i_size)}, - {NAME("nregs"), CTL(arenas_bin_i_nregs)}, - {NAME("run_size"), CTL(arenas_bin_i_run_size)} + {NAME("size"), CTL(arenas_bin_i_size)}, + {NAME("nregs"), CTL(arenas_bin_i_nregs)}, + {NAME("run_size"), CTL(arenas_bin_i_run_size)} }; static const ctl_named_node_t super_arenas_bin_i_node[] = { - {NAME(""), CHILD(named, arenas_bin_i)} + {NAME(""), CHILD(named, arenas_bin_i)} }; static const ctl_indexed_node_t arenas_bin_node[] = { @@ -282,76 +303,92 @@ static const ctl_indexed_node_t arenas_bin_node[] = { }; static const ctl_named_node_t arenas_lrun_i_node[] = { - {NAME("size"), CTL(arenas_lrun_i_size)} + {NAME("size"), CTL(arenas_lrun_i_size)} }; static const ctl_named_node_t super_arenas_lrun_i_node[] = { - {NAME(""), CHILD(named, arenas_lrun_i)} + {NAME(""), CHILD(named, arenas_lrun_i)} }; static const ctl_indexed_node_t arenas_lrun_node[] = { {INDEX(arenas_lrun_i)} }; +static const ctl_named_node_t arenas_hchunk_i_node[] = { + {NAME("size"), CTL(arenas_hchunk_i_size)} +}; +static const ctl_named_node_t super_arenas_hchunk_i_node[] = { + {NAME(""), CHILD(named, arenas_hchunk_i)} +}; + +static const ctl_indexed_node_t arenas_hchunk_node[] = { + {INDEX(arenas_hchunk_i)} +}; + static const ctl_named_node_t arenas_node[] = { - {NAME("narenas"), CTL(arenas_narenas)}, - {NAME("initialized"), CTL(arenas_initialized)}, - {NAME("quantum"), CTL(arenas_quantum)}, - {NAME("page"), CTL(arenas_page)}, - {NAME("tcache_max"), CTL(arenas_tcache_max)}, - {NAME("nbins"), CTL(arenas_nbins)}, - {NAME("nhbins"), CTL(arenas_nhbins)}, - {NAME("bin"), CHILD(indexed, arenas_bin)}, - {NAME("nlruns"), CTL(arenas_nlruns)}, - {NAME("lrun"), CHILD(indexed, arenas_lrun)}, - {NAME("purge"), CTL(arenas_purge)}, - {NAME("extend"), CTL(arenas_extend)} + {NAME("narenas"), CTL(arenas_narenas)}, + {NAME("initialized"), CTL(arenas_initialized)}, + {NAME("quantum"), CTL(arenas_quantum)}, + {NAME("page"), CTL(arenas_page)}, + {NAME("tcache_max"), CTL(arenas_tcache_max)}, + {NAME("nbins"), CTL(arenas_nbins)}, + {NAME("nhbins"), CTL(arenas_nhbins)}, + {NAME("bin"), CHILD(indexed, arenas_bin)}, + {NAME("nlruns"), CTL(arenas_nlruns)}, + {NAME("lrun"), CHILD(indexed, arenas_lrun)}, + {NAME("nhchunks"), CTL(arenas_nhchunks)}, + {NAME("hchunk"), CHILD(indexed, arenas_hchunk)}, + {NAME("extend"), CTL(arenas_extend)} }; static const ctl_named_node_t prof_node[] = { + {NAME("thread_active_init"), CTL(prof_thread_active_init)}, {NAME("active"), CTL(prof_active)}, {NAME("dump"), CTL(prof_dump)}, - {NAME("interval"), CTL(prof_interval)} + {NAME("reset"), CTL(prof_reset)}, + {NAME("interval"), CTL(prof_interval)}, + {NAME("lg_sample"), CTL(lg_prof_sample)} }; static const ctl_named_node_t stats_chunks_node[] = { - {NAME("current"), CTL(stats_chunks_current)}, - {NAME("total"), CTL(stats_chunks_total)}, - {NAME("high"), CTL(stats_chunks_high)} -}; - -static const ctl_named_node_t stats_huge_node[] = { - {NAME("allocated"), CTL(stats_huge_allocated)}, - {NAME("nmalloc"), CTL(stats_huge_nmalloc)}, - {NAME("ndalloc"), CTL(stats_huge_ndalloc)} + {NAME("current"), CTL(stats_chunks_current)}, + {NAME("total"), CTL(stats_chunks_total)}, + {NAME("high"), CTL(stats_chunks_high)} }; static const ctl_named_node_t stats_arenas_i_small_node[] = { - {NAME("allocated"), CTL(stats_arenas_i_small_allocated)}, - {NAME("nmalloc"), CTL(stats_arenas_i_small_nmalloc)}, - {NAME("ndalloc"), CTL(stats_arenas_i_small_ndalloc)}, - {NAME("nrequests"), CTL(stats_arenas_i_small_nrequests)} + {NAME("allocated"), CTL(stats_arenas_i_small_allocated)}, + {NAME("nmalloc"), CTL(stats_arenas_i_small_nmalloc)}, + {NAME("ndalloc"), CTL(stats_arenas_i_small_ndalloc)}, + {NAME("nrequests"), CTL(stats_arenas_i_small_nrequests)} }; static const ctl_named_node_t stats_arenas_i_large_node[] = { - {NAME("allocated"), CTL(stats_arenas_i_large_allocated)}, - {NAME("nmalloc"), CTL(stats_arenas_i_large_nmalloc)}, - {NAME("ndalloc"), CTL(stats_arenas_i_large_ndalloc)}, - {NAME("nrequests"), CTL(stats_arenas_i_large_nrequests)} + {NAME("allocated"), CTL(stats_arenas_i_large_allocated)}, + {NAME("nmalloc"), CTL(stats_arenas_i_large_nmalloc)}, + {NAME("ndalloc"), CTL(stats_arenas_i_large_ndalloc)}, + {NAME("nrequests"), CTL(stats_arenas_i_large_nrequests)} +}; + +static const ctl_named_node_t stats_arenas_i_huge_node[] = { + {NAME("allocated"), CTL(stats_arenas_i_huge_allocated)}, + {NAME("nmalloc"), CTL(stats_arenas_i_huge_nmalloc)}, + {NAME("ndalloc"), CTL(stats_arenas_i_huge_ndalloc)}, + {NAME("nrequests"), CTL(stats_arenas_i_huge_nrequests)} }; static const ctl_named_node_t stats_arenas_i_bins_j_node[] = { - {NAME("allocated"), CTL(stats_arenas_i_bins_j_allocated)}, - {NAME("nmalloc"), CTL(stats_arenas_i_bins_j_nmalloc)}, - {NAME("ndalloc"), CTL(stats_arenas_i_bins_j_ndalloc)}, - {NAME("nrequests"), CTL(stats_arenas_i_bins_j_nrequests)}, - {NAME("nfills"), CTL(stats_arenas_i_bins_j_nfills)}, - {NAME("nflushes"), CTL(stats_arenas_i_bins_j_nflushes)}, - {NAME("nruns"), CTL(stats_arenas_i_bins_j_nruns)}, - {NAME("nreruns"), CTL(stats_arenas_i_bins_j_nreruns)}, - {NAME("curruns"), CTL(stats_arenas_i_bins_j_curruns)} + {NAME("nmalloc"), CTL(stats_arenas_i_bins_j_nmalloc)}, + {NAME("ndalloc"), CTL(stats_arenas_i_bins_j_ndalloc)}, + {NAME("nrequests"), CTL(stats_arenas_i_bins_j_nrequests)}, + {NAME("curregs"), CTL(stats_arenas_i_bins_j_curregs)}, + {NAME("nfills"), CTL(stats_arenas_i_bins_j_nfills)}, + {NAME("nflushes"), CTL(stats_arenas_i_bins_j_nflushes)}, + {NAME("nruns"), CTL(stats_arenas_i_bins_j_nruns)}, + {NAME("nreruns"), CTL(stats_arenas_i_bins_j_nreruns)}, + {NAME("curruns"), CTL(stats_arenas_i_bins_j_curruns)} }; static const ctl_named_node_t super_stats_arenas_i_bins_j_node[] = { - {NAME(""), CHILD(named, stats_arenas_i_bins_j)} + {NAME(""), CHILD(named, stats_arenas_i_bins_j)} }; static const ctl_indexed_node_t stats_arenas_i_bins_node[] = { @@ -359,35 +396,51 @@ static const ctl_indexed_node_t stats_arenas_i_bins_node[] = { }; static const ctl_named_node_t stats_arenas_i_lruns_j_node[] = { - {NAME("nmalloc"), CTL(stats_arenas_i_lruns_j_nmalloc)}, - {NAME("ndalloc"), CTL(stats_arenas_i_lruns_j_ndalloc)}, - {NAME("nrequests"), CTL(stats_arenas_i_lruns_j_nrequests)}, - {NAME("curruns"), CTL(stats_arenas_i_lruns_j_curruns)} + {NAME("nmalloc"), CTL(stats_arenas_i_lruns_j_nmalloc)}, + {NAME("ndalloc"), CTL(stats_arenas_i_lruns_j_ndalloc)}, + {NAME("nrequests"), CTL(stats_arenas_i_lruns_j_nrequests)}, + {NAME("curruns"), CTL(stats_arenas_i_lruns_j_curruns)} }; static const ctl_named_node_t super_stats_arenas_i_lruns_j_node[] = { - {NAME(""), CHILD(named, stats_arenas_i_lruns_j)} + {NAME(""), CHILD(named, stats_arenas_i_lruns_j)} }; static const ctl_indexed_node_t stats_arenas_i_lruns_node[] = { {INDEX(stats_arenas_i_lruns_j)} }; +static const ctl_named_node_t stats_arenas_i_hchunks_j_node[] = { + {NAME("nmalloc"), CTL(stats_arenas_i_hchunks_j_nmalloc)}, + {NAME("ndalloc"), CTL(stats_arenas_i_hchunks_j_ndalloc)}, + {NAME("nrequests"), CTL(stats_arenas_i_hchunks_j_nrequests)}, + {NAME("curhchunks"), CTL(stats_arenas_i_hchunks_j_curhchunks)} +}; +static const ctl_named_node_t super_stats_arenas_i_hchunks_j_node[] = { + {NAME(""), CHILD(named, stats_arenas_i_hchunks_j)} +}; + +static const ctl_indexed_node_t stats_arenas_i_hchunks_node[] = { + {INDEX(stats_arenas_i_hchunks_j)} +}; + static const ctl_named_node_t stats_arenas_i_node[] = { - {NAME("nthreads"), CTL(stats_arenas_i_nthreads)}, - {NAME("dss"), CTL(stats_arenas_i_dss)}, - {NAME("pactive"), CTL(stats_arenas_i_pactive)}, - {NAME("pdirty"), CTL(stats_arenas_i_pdirty)}, - {NAME("mapped"), CTL(stats_arenas_i_mapped)}, - {NAME("npurge"), CTL(stats_arenas_i_npurge)}, - {NAME("nmadvise"), CTL(stats_arenas_i_nmadvise)}, - {NAME("purged"), CTL(stats_arenas_i_purged)}, - {NAME("small"), CHILD(named, stats_arenas_i_small)}, - {NAME("large"), CHILD(named, stats_arenas_i_large)}, - {NAME("bins"), CHILD(indexed, stats_arenas_i_bins)}, - {NAME("lruns"), CHILD(indexed, stats_arenas_i_lruns)} + {NAME("nthreads"), CTL(stats_arenas_i_nthreads)}, + {NAME("dss"), CTL(stats_arenas_i_dss)}, + {NAME("pactive"), CTL(stats_arenas_i_pactive)}, + {NAME("pdirty"), CTL(stats_arenas_i_pdirty)}, + {NAME("mapped"), CTL(stats_arenas_i_mapped)}, + {NAME("npurge"), CTL(stats_arenas_i_npurge)}, + {NAME("nmadvise"), CTL(stats_arenas_i_nmadvise)}, + {NAME("purged"), CTL(stats_arenas_i_purged)}, + {NAME("small"), CHILD(named, stats_arenas_i_small)}, + {NAME("large"), CHILD(named, stats_arenas_i_large)}, + {NAME("huge"), CHILD(named, stats_arenas_i_huge)}, + {NAME("bins"), CHILD(indexed, stats_arenas_i_bins)}, + {NAME("lruns"), CHILD(indexed, stats_arenas_i_lruns)}, + {NAME("hchunks"), CHILD(indexed, stats_arenas_i_hchunks)} }; static const ctl_named_node_t super_stats_arenas_i_node[] = { - {NAME(""), CHILD(named, stats_arenas_i)} + {NAME(""), CHILD(named, stats_arenas_i)} }; static const ctl_indexed_node_t stats_arenas_node[] = { @@ -395,13 +448,12 @@ static const ctl_indexed_node_t stats_arenas_node[] = { }; static const ctl_named_node_t stats_node[] = { - {NAME("cactive"), CTL(stats_cactive)}, - {NAME("allocated"), CTL(stats_allocated)}, - {NAME("active"), CTL(stats_active)}, - {NAME("mapped"), CTL(stats_mapped)}, - {NAME("chunks"), CHILD(named, stats_chunks)}, - {NAME("huge"), CHILD(named, stats_huge)}, - {NAME("arenas"), CHILD(indexed, stats_arenas)} + {NAME("cactive"), CTL(stats_cactive)}, + {NAME("allocated"), CTL(stats_allocated)}, + {NAME("active"), CTL(stats_active)}, + {NAME("mapped"), CTL(stats_mapped)}, + {NAME("chunks"), CHILD(named, stats_chunks)}, + {NAME("arenas"), CHILD(indexed, stats_arenas)} }; static const ctl_named_node_t root_node[] = { @@ -431,12 +483,19 @@ ctl_arena_init(ctl_arena_stats_t *astats) { if (astats->lstats == NULL) { - astats->lstats = (malloc_large_stats_t *)base_alloc(nlclasses * + astats->lstats = (malloc_large_stats_t *)a0malloc(nlclasses * sizeof(malloc_large_stats_t)); if (astats->lstats == NULL) return (true); } + if (astats->hstats == NULL) { + astats->hstats = (malloc_huge_stats_t *)a0malloc(nhclasses * + sizeof(malloc_huge_stats_t)); + if (astats->hstats == NULL) + return (true); + } + return (false); } @@ -456,6 +515,8 @@ ctl_arena_clear(ctl_arena_stats_t *astats) memset(astats->bstats, 0, NBINS * sizeof(malloc_bin_stats_t)); memset(astats->lstats, 0, nlclasses * sizeof(malloc_large_stats_t)); + memset(astats->hstats, 0, nhclasses * + sizeof(malloc_huge_stats_t)); } } @@ -465,10 +526,12 @@ ctl_arena_stats_amerge(ctl_arena_stats_t *cstats, arena_t *arena) unsigned i; arena_stats_merge(arena, &cstats->dss, &cstats->pactive, - &cstats->pdirty, &cstats->astats, cstats->bstats, cstats->lstats); + &cstats->pdirty, &cstats->astats, cstats->bstats, cstats->lstats, + cstats->hstats); for (i = 0; i < NBINS; i++) { - cstats->allocated_small += cstats->bstats[i].allocated; + cstats->allocated_small += cstats->bstats[i].curregs * + index2size(i); cstats->nmalloc_small += cstats->bstats[i].nmalloc; cstats->ndalloc_small += cstats->bstats[i].ndalloc; cstats->nrequests_small += cstats->bstats[i].nrequests; @@ -498,18 +561,15 @@ ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats) sstats->astats.ndalloc_large += astats->astats.ndalloc_large; sstats->astats.nrequests_large += astats->astats.nrequests_large; - for (i = 0; i < nlclasses; i++) { - sstats->lstats[i].nmalloc += astats->lstats[i].nmalloc; - sstats->lstats[i].ndalloc += astats->lstats[i].ndalloc; - sstats->lstats[i].nrequests += astats->lstats[i].nrequests; - sstats->lstats[i].curruns += astats->lstats[i].curruns; - } + sstats->astats.allocated_huge += astats->astats.allocated_huge; + sstats->astats.nmalloc_huge += astats->astats.nmalloc_huge; + sstats->astats.ndalloc_huge += astats->astats.ndalloc_huge; for (i = 0; i < NBINS; i++) { - sstats->bstats[i].allocated += astats->bstats[i].allocated; sstats->bstats[i].nmalloc += astats->bstats[i].nmalloc; sstats->bstats[i].ndalloc += astats->bstats[i].ndalloc; sstats->bstats[i].nrequests += astats->bstats[i].nrequests; + sstats->bstats[i].curregs += astats->bstats[i].curregs; if (config_tcache) { sstats->bstats[i].nfills += astats->bstats[i].nfills; sstats->bstats[i].nflushes += @@ -519,6 +579,19 @@ ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats) sstats->bstats[i].reruns += astats->bstats[i].reruns; sstats->bstats[i].curruns += astats->bstats[i].curruns; } + + for (i = 0; i < nlclasses; i++) { + sstats->lstats[i].nmalloc += astats->lstats[i].nmalloc; + sstats->lstats[i].ndalloc += astats->lstats[i].ndalloc; + sstats->lstats[i].nrequests += astats->lstats[i].nrequests; + sstats->lstats[i].curruns += astats->lstats[i].curruns; + } + + for (i = 0; i < nhclasses; i++) { + sstats->hstats[i].nmalloc += astats->hstats[i].nmalloc; + sstats->hstats[i].ndalloc += astats->hstats[i].ndalloc; + sstats->hstats[i].curhchunks += astats->hstats[i].curhchunks; + } } static void @@ -547,27 +620,23 @@ static bool ctl_grow(void) { ctl_arena_stats_t *astats; - arena_t **tarenas; - /* Allocate extended arena stats and arenas arrays. */ - astats = (ctl_arena_stats_t *)imalloc((ctl_stats.narenas + 2) * + /* Initialize new arena. */ + if (arena_init(ctl_stats.narenas) == NULL) + return (true); + + /* Allocate extended arena stats. */ + astats = (ctl_arena_stats_t *)a0malloc((ctl_stats.narenas + 2) * sizeof(ctl_arena_stats_t)); if (astats == NULL) return (true); - tarenas = (arena_t **)imalloc((ctl_stats.narenas + 1) * - sizeof(arena_t *)); - if (tarenas == NULL) { - idalloc(astats); - return (true); - } /* Initialize the new astats element. */ memcpy(astats, ctl_stats.arenas, (ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t)); memset(&astats[ctl_stats.narenas + 1], 0, sizeof(ctl_arena_stats_t)); if (ctl_arena_init(&astats[ctl_stats.narenas + 1])) { - idalloc(tarenas); - idalloc(astats); + a0free(astats); return (true); } /* Swap merged stats to their new location. */ @@ -580,32 +649,7 @@ ctl_grow(void) memcpy(&astats[ctl_stats.narenas + 1], &tstats, sizeof(ctl_arena_stats_t)); } - /* Initialize the new arenas element. */ - tarenas[ctl_stats.narenas] = NULL; - { - arena_t **arenas_old = arenas; - /* - * Swap extended arenas array into place. Although ctl_mtx - * protects this function from other threads extending the - * array, it does not protect from other threads mutating it - * (i.e. initializing arenas and setting array elements to - * point to them). Therefore, array copying must happen under - * the protection of arenas_lock. - */ - malloc_mutex_lock(&arenas_lock); - arenas = tarenas; - memcpy(arenas, arenas_old, ctl_stats.narenas * - sizeof(arena_t *)); - narenas_total++; - arenas_extend(narenas_total - 1); - malloc_mutex_unlock(&arenas_lock); - /* - * Deallocate arenas_old only if it came from imalloc() (not - * base_alloc()). - */ - if (ctl_stats.narenas != narenas_auto) - idalloc(arenas_old); - } + a0free(ctl_stats.arenas); ctl_stats.arenas = astats; ctl_stats.narenas++; @@ -615,6 +659,7 @@ ctl_grow(void) static void ctl_refresh(void) { + tsd_t *tsd; unsigned i; VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas); @@ -624,12 +669,6 @@ ctl_refresh(void) ctl_stats.chunks.total = stats_chunks.nchunks; ctl_stats.chunks.high = stats_chunks.highchunks; malloc_mutex_unlock(&chunks_mtx); - - malloc_mutex_lock(&huge_mtx); - ctl_stats.huge.allocated = huge_allocated; - ctl_stats.huge.nmalloc = huge_nmalloc; - ctl_stats.huge.ndalloc = huge_ndalloc; - malloc_mutex_unlock(&huge_mtx); } /* @@ -639,15 +678,17 @@ ctl_refresh(void) ctl_stats.arenas[ctl_stats.narenas].nthreads = 0; ctl_arena_clear(&ctl_stats.arenas[ctl_stats.narenas]); - malloc_mutex_lock(&arenas_lock); - memcpy(tarenas, arenas, sizeof(arena_t *) * ctl_stats.narenas); + tsd = tsd_fetch(); + for (i = 0; i < ctl_stats.narenas; i++) + tarenas[i] = arena_get(tsd, i, false, (i == 0)); + for (i = 0; i < ctl_stats.narenas; i++) { - if (arenas[i] != NULL) - ctl_stats.arenas[i].nthreads = arenas[i]->nthreads; + if (tarenas[i] != NULL) + ctl_stats.arenas[i].nthreads = arena_nbound(i); else ctl_stats.arenas[i].nthreads = 0; } - malloc_mutex_unlock(&arenas_lock); + for (i = 0; i < ctl_stats.narenas; i++) { bool initialized = (tarenas[i] != NULL); @@ -660,10 +701,9 @@ ctl_refresh(void) ctl_stats.allocated = ctl_stats.arenas[ctl_stats.narenas].allocated_small + ctl_stats.arenas[ctl_stats.narenas].astats.allocated_large - + ctl_stats.huge.allocated; + + ctl_stats.arenas[ctl_stats.narenas].astats.allocated_huge; ctl_stats.active = - (ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE) - + ctl_stats.huge.allocated; + (ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE); ctl_stats.mapped = (ctl_stats.chunks.current << opt_lg_chunk); } @@ -676,14 +716,13 @@ ctl_init(void) bool ret; malloc_mutex_lock(&ctl_mtx); - if (ctl_initialized == false) { + if (!ctl_initialized) { /* * Allocate space for one extra arena stats element, which * contains summed stats across all arenas. */ - assert(narenas_auto == narenas_total_get()); - ctl_stats.narenas = narenas_auto; - ctl_stats.arenas = (ctl_arena_stats_t *)base_alloc( + ctl_stats.narenas = narenas_total_get(); + ctl_stats.arenas = (ctl_arena_stats_t *)a0malloc( (ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t)); if (ctl_stats.arenas == NULL) { ret = true; @@ -701,6 +740,15 @@ ctl_init(void) unsigned i; for (i = 0; i <= ctl_stats.narenas; i++) { if (ctl_arena_init(&ctl_stats.arenas[i])) { + unsigned j; + for (j = 0; j < i; j++) { + a0free( + ctl_stats.arenas[j].lstats); + a0free( + ctl_stats.arenas[j].hstats); + } + a0free(ctl_stats.arenas); + ctl_stats.arenas = NULL; ret = true; goto label_return; } @@ -826,7 +874,7 @@ ctl_byname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t mib[CTL_MAX_DEPTH]; const ctl_named_node_t *node; - if (ctl_initialized == false && ctl_init()) { + if (!ctl_initialized && ctl_init()) { ret = EAGAIN; goto label_return; } @@ -853,7 +901,7 @@ ctl_nametomib(const char *name, size_t *mibp, size_t *miblenp) { int ret; - if (ctl_initialized == false && ctl_init()) { + if (!ctl_initialized && ctl_init()) { ret = EAGAIN; goto label_return; } @@ -871,7 +919,7 @@ ctl_bymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, const ctl_named_node_t *node; size_t i; - if (ctl_initialized == false && ctl_init()) { + if (!ctl_initialized && ctl_init()) { ret = EAGAIN; goto label_return; } @@ -963,6 +1011,14 @@ ctl_postfork_child(void) } \ } while (0) +#define READ_XOR_WRITE() do { \ + if ((oldp != NULL && oldlenp != NULL) && (newp != NULL || \ + newlen != 0)) { \ + ret = EPERM; \ + goto label_return; \ + } \ +} while (0) + #define READ(v, t) do { \ if (oldp != NULL && oldlenp != NULL) { \ if (*oldlenp != sizeof(t)) { \ @@ -998,7 +1054,7 @@ n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ int ret; \ t oldval; \ \ - if ((c) == false) \ + if (!(c)) \ return (ENOENT); \ if (l) \ malloc_mutex_lock(&ctl_mtx); \ @@ -1021,7 +1077,7 @@ n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ int ret; \ t oldval; \ \ - if ((c) == false) \ + if (!(c)) \ return (ENOENT); \ malloc_mutex_lock(&ctl_mtx); \ READONLY(); \ @@ -1065,7 +1121,7 @@ n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ int ret; \ t oldval; \ \ - if ((c) == false) \ + if (!(c)) \ return (ENOENT); \ READONLY(); \ oldval = (v); \ @@ -1093,6 +1149,27 @@ label_return: \ return (ret); \ } +#define CTL_TSD_RO_NL_CGEN(c, n, m, t) \ +static int \ +n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ + void *newp, size_t newlen) \ +{ \ + int ret; \ + t oldval; \ + tsd_t *tsd; \ + \ + if (!(c)) \ + return (ENOENT); \ + READONLY(); \ + tsd = tsd_fetch(); \ + oldval = (m(tsd)); \ + READ(oldval, t); \ + \ + ret = 0; \ +label_return: \ + return (ret); \ +} + #define CTL_RO_BOOL_CONFIG_GEN(n) \ static int \ n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ @@ -1136,10 +1213,8 @@ label_return: /******************************************************************************/ CTL_RO_BOOL_CONFIG_GEN(config_debug) -CTL_RO_BOOL_CONFIG_GEN(config_dss) CTL_RO_BOOL_CONFIG_GEN(config_fill) CTL_RO_BOOL_CONFIG_GEN(config_lazy_lock) -CTL_RO_BOOL_CONFIG_GEN(config_mremap) CTL_RO_BOOL_CONFIG_GEN(config_munmap) CTL_RO_BOOL_CONFIG_GEN(config_prof) CTL_RO_BOOL_CONFIG_GEN(config_prof_libgcc) @@ -1159,18 +1234,19 @@ CTL_RO_NL_GEN(opt_lg_chunk, opt_lg_chunk, size_t) CTL_RO_NL_GEN(opt_narenas, opt_narenas, size_t) CTL_RO_NL_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t) CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool) -CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, bool) +CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *) CTL_RO_NL_CGEN(config_fill, opt_quarantine, opt_quarantine, size_t) CTL_RO_NL_CGEN(config_fill, opt_redzone, opt_redzone, bool) CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool) CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool) -CTL_RO_NL_CGEN(config_valgrind, opt_valgrind, opt_valgrind, bool) CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool) CTL_RO_NL_CGEN(config_tcache, opt_tcache, opt_tcache, bool) CTL_RO_NL_CGEN(config_tcache, opt_lg_tcache_max, opt_lg_tcache_max, ssize_t) CTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool) CTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *) -CTL_RO_CGEN(config_prof, opt_prof_active, opt_prof_active, bool) /* Mutable. */ +CTL_RO_NL_CGEN(config_prof, opt_prof_active, opt_prof_active, bool) +CTL_RO_NL_CGEN(config_prof, opt_prof_thread_active_init, + opt_prof_thread_active_init, bool) CTL_RO_NL_CGEN(config_prof, opt_lg_prof_sample, opt_lg_prof_sample, size_t) CTL_RO_NL_CGEN(config_prof, opt_prof_accum, opt_prof_accum, bool) CTL_RO_NL_CGEN(config_prof, opt_lg_prof_interval, opt_lg_prof_interval, ssize_t) @@ -1185,15 +1261,20 @@ thread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; + tsd_t *tsd; + arena_t *arena; unsigned newind, oldind; + tsd = tsd_fetch(); + arena = arena_choose(tsd, NULL); + if (arena == NULL) + return (EAGAIN); + malloc_mutex_lock(&ctl_mtx); - newind = oldind = choose_arena(NULL)->ind; + newind = oldind = arena->ind; WRITE(newind, unsigned); READ(oldind, unsigned); if (newind != oldind) { - arena_t *arena; - if (newind >= ctl_stats.narenas) { /* New arena index is out of range. */ ret = EFAULT; @@ -1201,28 +1282,18 @@ thread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, } /* Initialize arena if necessary. */ - malloc_mutex_lock(&arenas_lock); - if ((arena = arenas[newind]) == NULL && (arena = - arenas_extend(newind)) == NULL) { - malloc_mutex_unlock(&arenas_lock); + arena = arena_get(tsd, newind, true, true); + if (arena == NULL) { ret = EAGAIN; goto label_return; } - assert(arena == arenas[newind]); - arenas[oldind]->nthreads--; - arenas[newind]->nthreads++; - malloc_mutex_unlock(&arenas_lock); - - /* Set new arena association. */ + /* Set new arena/tcache associations. */ + arena_migrate(tsd, oldind, newind); if (config_tcache) { - tcache_t *tcache; - if ((uintptr_t)(tcache = *tcache_tsd_get()) > - (uintptr_t)TCACHE_STATE_MAX) { - tcache_arena_dissociate(tcache); - tcache_arena_associate(tcache, arena); - } + tcache_t *tcache = tsd_tcache_get(tsd); + if (tcache != NULL) + tcache_arena_reassociate(tcache, arena); } - arenas_tsd_set(&arena); } ret = 0; @@ -1231,14 +1302,14 @@ label_return: return (ret); } -CTL_RO_NL_CGEN(config_stats, thread_allocated, - thread_allocated_tsd_get()->allocated, uint64_t) -CTL_RO_NL_CGEN(config_stats, thread_allocatedp, - &thread_allocated_tsd_get()->allocated, uint64_t *) -CTL_RO_NL_CGEN(config_stats, thread_deallocated, - thread_allocated_tsd_get()->deallocated, uint64_t) -CTL_RO_NL_CGEN(config_stats, thread_deallocatedp, - &thread_allocated_tsd_get()->deallocated, uint64_t *) +CTL_TSD_RO_NL_CGEN(config_stats, thread_allocated, tsd_thread_allocated_get, + uint64_t) +CTL_TSD_RO_NL_CGEN(config_stats, thread_allocatedp, tsd_thread_allocatedp_get, + uint64_t *) +CTL_TSD_RO_NL_CGEN(config_stats, thread_deallocated, tsd_thread_deallocated_get, + uint64_t) +CTL_TSD_RO_NL_CGEN(config_stats, thread_deallocatedp, + tsd_thread_deallocatedp_get, uint64_t *) static int thread_tcache_enabled_ctl(const size_t *mib, size_t miblen, void *oldp, @@ -1247,7 +1318,7 @@ thread_tcache_enabled_ctl(const size_t *mib, size_t miblen, void *oldp, int ret; bool oldval; - if (config_tcache == false) + if (!config_tcache) return (ENOENT); oldval = tcache_enabled_get(); @@ -1271,7 +1342,7 @@ thread_tcache_flush_ctl(const size_t *mib, size_t miblen, void *oldp, { int ret; - if (config_tcache == false) + if (!config_tcache) return (ENOENT); READONLY(); @@ -1284,17 +1355,81 @@ label_return: return (ret); } +static int +thread_prof_name_ctl(const size_t *mib, size_t miblen, void *oldp, + size_t *oldlenp, void *newp, size_t newlen) +{ + int ret; + + if (!config_prof) + return (ENOENT); + + READ_XOR_WRITE(); + + if (newp != NULL) { + tsd_t *tsd; + + if (newlen != sizeof(const char *)) { + ret = EINVAL; + goto label_return; + } + + tsd = tsd_fetch(); + + if ((ret = prof_thread_name_set(tsd, *(const char **)newp)) != + 0) + goto label_return; + } else { + const char *oldname = prof_thread_name_get(); + READ(oldname, const char *); + } + + ret = 0; +label_return: + return (ret); +} + +static int +thread_prof_active_ctl(const size_t *mib, size_t miblen, void *oldp, + size_t *oldlenp, void *newp, size_t newlen) +{ + int ret; + bool oldval; + + if (!config_prof) + return (ENOENT); + + oldval = prof_thread_active_get(); + if (newp != NULL) { + if (newlen != sizeof(bool)) { + ret = EINVAL; + goto label_return; + } + if (prof_thread_active_set(*(bool *)newp)) { + ret = EAGAIN; + goto label_return; + } + } + READ(oldval, bool); + + ret = 0; +label_return: + return (ret); +} + /******************************************************************************/ /* ctl_mutex must be held during execution of this function. */ static void arena_purge(unsigned arena_ind) { + tsd_t *tsd; + unsigned i; VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas); - malloc_mutex_lock(&arenas_lock); - memcpy(tarenas, arenas, sizeof(arena_t *) * ctl_stats.narenas); - malloc_mutex_unlock(&arenas_lock); + tsd = tsd_fetch(); + for (i = 0; i < ctl_stats.narenas; i++) + tarenas[i] = arena_get(tsd, i, false, (i == 0)); if (arena_ind == ctl_stats.narenas) { unsigned i; @@ -1330,46 +1465,51 @@ static int arena_i_dss_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { - int ret, i; - bool match, err; - const char *dss; + int ret; + const char *dss = NULL; unsigned arena_ind = mib[1]; dss_prec_t dss_prec_old = dss_prec_limit; dss_prec_t dss_prec = dss_prec_limit; malloc_mutex_lock(&ctl_mtx); WRITE(dss, const char *); - match = false; - for (i = 0; i < dss_prec_limit; i++) { - if (strcmp(dss_prec_names[i], dss) == 0) { - dss_prec = i; - match = true; - break; + if (dss != NULL) { + int i; + bool match = false; + + for (i = 0; i < dss_prec_limit; i++) { + if (strcmp(dss_prec_names[i], dss) == 0) { + dss_prec = i; + match = true; + break; + } + } + + if (!match) { + ret = EINVAL; + goto label_return; } - } - if (match == false) { - ret = EINVAL; - goto label_return; } if (arena_ind < ctl_stats.narenas) { - arena_t *arena = arenas[arena_ind]; - if (arena != NULL) { - dss_prec_old = arena_dss_prec_get(arena); - arena_dss_prec_set(arena, dss_prec); - err = false; - } else - err = true; + arena_t *arena = arena_get(tsd_fetch(), arena_ind, false, true); + if (arena == NULL || (dss_prec != dss_prec_limit && + arena_dss_prec_set(arena, dss_prec))) { + ret = EFAULT; + goto label_return; + } + dss_prec_old = arena_dss_prec_get(arena); } else { + if (dss_prec != dss_prec_limit && + chunk_dss_prec_set(dss_prec)) { + ret = EFAULT; + goto label_return; + } dss_prec_old = chunk_dss_prec_get(); - err = chunk_dss_prec_set(dss_prec); } + dss = dss_prec_names[dss_prec_old]; READ(dss, const char *); - if (err) { - ret = EFAULT; - goto label_return; - } ret = 0; label_return: @@ -1377,6 +1517,59 @@ label_return: return (ret); } +static int +arena_i_chunk_alloc_ctl(const size_t *mib, size_t miblen, void *oldp, + size_t *oldlenp, void *newp, size_t newlen) +{ + int ret; + unsigned arena_ind = mib[1]; + arena_t *arena; + + malloc_mutex_lock(&ctl_mtx); + if (arena_ind < narenas_total_get() && (arena = arena_get(tsd_fetch(), + arena_ind, false, true)) != NULL) { + malloc_mutex_lock(&arena->lock); + READ(arena->chunk_alloc, chunk_alloc_t *); + WRITE(arena->chunk_alloc, chunk_alloc_t *); + } else { + ret = EFAULT; + goto label_outer_return; + } + ret = 0; +label_return: + malloc_mutex_unlock(&arena->lock); +label_outer_return: + malloc_mutex_unlock(&ctl_mtx); + return (ret); +} + +static int +arena_i_chunk_dalloc_ctl(const size_t *mib, size_t miblen, void *oldp, + size_t *oldlenp, void *newp, size_t newlen) +{ + + int ret; + unsigned arena_ind = mib[1]; + arena_t *arena; + + malloc_mutex_lock(&ctl_mtx); + if (arena_ind < narenas_total_get() && (arena = arena_get(tsd_fetch(), + arena_ind, false, true)) != NULL) { + malloc_mutex_lock(&arena->lock); + READ(arena->chunk_dalloc, chunk_dalloc_t *); + WRITE(arena->chunk_dalloc, chunk_dalloc_t *); + } else { + ret = EFAULT; + goto label_outer_return; + } + ret = 0; +label_return: + malloc_mutex_unlock(&arena->lock); +label_outer_return: + malloc_mutex_unlock(&ctl_mtx); + return (ret); +} + static const ctl_named_node_t * arena_i_index(const size_t *mib, size_t miblen, size_t i) { @@ -1461,8 +1654,8 @@ arenas_bin_i_index(const size_t *mib, size_t miblen, size_t i) return (super_arenas_bin_i_node); } -CTL_RO_NL_GEN(arenas_nlruns, nlclasses, size_t) -CTL_RO_NL_GEN(arenas_lrun_i_size, ((mib[2]+1) << LG_PAGE), size_t) +CTL_RO_NL_GEN(arenas_nlruns, nlclasses, unsigned) +CTL_RO_NL_GEN(arenas_lrun_i_size, index2size(NBINS+mib[2]), size_t) static const ctl_named_node_t * arenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i) { @@ -1472,29 +1665,15 @@ arenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i) return (super_arenas_lrun_i_node); } -static int -arenas_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen) +CTL_RO_NL_GEN(arenas_nhchunks, nhclasses, unsigned) +CTL_RO_NL_GEN(arenas_hchunk_i_size, index2size(NBINS+nlclasses+mib[2]), size_t) +static const ctl_named_node_t * +arenas_hchunk_i_index(const size_t *mib, size_t miblen, size_t i) { - int ret; - unsigned arena_ind; - malloc_mutex_lock(&ctl_mtx); - WRITEONLY(); - arena_ind = UINT_MAX; - WRITE(arena_ind, unsigned); - if (newp != NULL && arena_ind >= ctl_stats.narenas) - ret = EFAULT; - else { - if (arena_ind == UINT_MAX) - arena_ind = ctl_stats.narenas; - arena_purge(arena_ind); - ret = 0; - } - -label_return: - malloc_mutex_unlock(&ctl_mtx); - return (ret); + if (i > nhclasses) + return (NULL); + return (super_arenas_hchunk_i_node); } static int @@ -1521,6 +1700,31 @@ label_return: /******************************************************************************/ +static int +prof_thread_active_init_ctl(const size_t *mib, size_t miblen, void *oldp, + size_t *oldlenp, void *newp, size_t newlen) +{ + int ret; + bool oldval; + + if (!config_prof) + return (ENOENT); + + if (newp != NULL) { + if (newlen != sizeof(bool)) { + ret = EINVAL; + goto label_return; + } + oldval = prof_thread_active_init_set(*(bool *)newp); + } else + oldval = prof_thread_active_init_get(); + READ(oldval, bool); + + ret = 0; +label_return: + return (ret); +} + static int prof_active_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) @@ -1528,25 +1732,21 @@ prof_active_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, int ret; bool oldval; - if (config_prof == false) + if (!config_prof) return (ENOENT); - malloc_mutex_lock(&ctl_mtx); /* Protect opt_prof_active. */ - oldval = opt_prof_active; if (newp != NULL) { - /* - * The memory barriers will tend to make opt_prof_active - * propagate faster on systems with weak memory ordering. - */ - mb_write(); - WRITE(opt_prof_active, bool); - mb_write(); - } + if (newlen != sizeof(bool)) { + ret = EINVAL; + goto label_return; + } + oldval = prof_active_set(*(bool *)newp); + } else + oldval = prof_active_get(); READ(oldval, bool); ret = 0; label_return: - malloc_mutex_unlock(&ctl_mtx); return (ret); } @@ -1557,7 +1757,7 @@ prof_dump_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, int ret; const char *filename = NULL; - if (config_prof == false) + if (!config_prof) return (ENOENT); WRITEONLY(); @@ -1573,7 +1773,33 @@ label_return: return (ret); } +static int +prof_reset_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, + void *newp, size_t newlen) +{ + int ret; + size_t lg_sample = lg_prof_sample; + tsd_t *tsd; + + if (!config_prof) + return (ENOENT); + + WRITEONLY(); + WRITE(lg_sample, size_t); + if (lg_sample >= (sizeof(uint64_t) << 3)) + lg_sample = (sizeof(uint64_t) << 3) - 1; + + tsd = tsd_fetch(); + + prof_reset(tsd, lg_sample); + + ret = 0; +label_return: + return (ret); +} + CTL_RO_NL_CGEN(config_prof, prof_interval, prof_interval, uint64_t) +CTL_RO_NL_CGEN(config_prof, lg_prof_sample, lg_prof_sample, size_t) /******************************************************************************/ @@ -1586,9 +1812,6 @@ CTL_RO_CGEN(config_stats, stats_chunks_current, ctl_stats.chunks.current, size_t) CTL_RO_CGEN(config_stats, stats_chunks_total, ctl_stats.chunks.total, uint64_t) CTL_RO_CGEN(config_stats, stats_chunks_high, ctl_stats.chunks.high, size_t) -CTL_RO_CGEN(config_stats, stats_huge_allocated, huge_allocated, size_t) -CTL_RO_CGEN(config_stats, stats_huge_nmalloc, huge_nmalloc, uint64_t) -CTL_RO_CGEN(config_stats, stats_huge_ndalloc, huge_ndalloc, uint64_t) CTL_RO_GEN(stats_arenas_i_dss, ctl_stats.arenas[mib[2]].dss, const char *) CTL_RO_GEN(stats_arenas_i_nthreads, ctl_stats.arenas[mib[2]].nthreads, unsigned) @@ -1619,15 +1842,23 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc, ctl_stats.arenas[mib[2]].astats.ndalloc_large, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests, ctl_stats.arenas[mib[2]].astats.nrequests_large, uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_huge_allocated, + ctl_stats.arenas[mib[2]].astats.allocated_huge, size_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_huge_nmalloc, + ctl_stats.arenas[mib[2]].astats.nmalloc_huge, uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_huge_ndalloc, + ctl_stats.arenas[mib[2]].astats.ndalloc_huge, uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_huge_nrequests, + ctl_stats.arenas[mib[2]].astats.nmalloc_huge, uint64_t) /* Intentional. */ -CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_allocated, - ctl_stats.arenas[mib[2]].bstats[mib[4]].allocated, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc, ctl_stats.arenas[mib[2]].bstats[mib[4]].nmalloc, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc, ctl_stats.arenas[mib[2]].bstats[mib[4]].ndalloc, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests, ctl_stats.arenas[mib[2]].bstats[mib[4]].nrequests, uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curregs, + ctl_stats.arenas[mib[2]].bstats[mib[4]].curregs, size_t) CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nfills, ctl_stats.arenas[mib[2]].bstats[mib[4]].nfills, uint64_t) CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nflushes, @@ -1666,13 +1897,32 @@ stats_arenas_i_lruns_j_index(const size_t *mib, size_t miblen, size_t j) return (super_stats_arenas_i_lruns_j_node); } +CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_nmalloc, + ctl_stats.arenas[mib[2]].hstats[mib[4]].nmalloc, uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_ndalloc, + ctl_stats.arenas[mib[2]].hstats[mib[4]].ndalloc, uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_nrequests, + ctl_stats.arenas[mib[2]].hstats[mib[4]].nmalloc, /* Intentional. */ + uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_curhchunks, + ctl_stats.arenas[mib[2]].hstats[mib[4]].curhchunks, size_t) + +static const ctl_named_node_t * +stats_arenas_i_hchunks_j_index(const size_t *mib, size_t miblen, size_t j) +{ + + if (j > nhclasses) + return (NULL); + return (super_stats_arenas_i_hchunks_j_node); +} + static const ctl_named_node_t * stats_arenas_i_index(const size_t *mib, size_t miblen, size_t i) { const ctl_named_node_t * ret; malloc_mutex_lock(&ctl_mtx); - if (i > ctl_stats.narenas || ctl_stats.arenas[i].initialized == false) { + if (i > ctl_stats.narenas || !ctl_stats.arenas[i].initialized) { ret = NULL; goto label_return; } diff --git a/memory/jemalloc/src/src/extent.c b/memory/jemalloc/src/src/extent.c index 8c09b486ed81..ca852016763d 100644 --- a/memory/jemalloc/src/src/extent.c +++ b/memory/jemalloc/src/src/extent.c @@ -3,7 +3,7 @@ /******************************************************************************/ -static inline int +JEMALLOC_INLINE_C int extent_szad_comp(extent_node_t *a, extent_node_t *b) { int ret; @@ -25,7 +25,7 @@ extent_szad_comp(extent_node_t *a, extent_node_t *b) rb_gen(, extent_tree_szad_, extent_tree_t, extent_node_t, link_szad, extent_szad_comp) -static inline int +JEMALLOC_INLINE_C int extent_ad_comp(extent_node_t *a, extent_node_t *b) { uintptr_t a_addr = (uintptr_t)a->addr; diff --git a/memory/jemalloc/src/src/huge.c b/memory/jemalloc/src/src/huge.c index d72f21357021..416cb172bc9d 100644 --- a/memory/jemalloc/src/src/huge.c +++ b/memory/jemalloc/src/src/huge.c @@ -4,11 +4,8 @@ /******************************************************************************/ /* Data. */ -uint64_t huge_nmalloc; -uint64_t huge_ndalloc; -size_t huge_allocated; - -malloc_mutex_t huge_mtx; +/* Protects chunk-related data structures. */ +static malloc_mutex_t huge_mtx; /******************************************************************************/ @@ -16,30 +13,32 @@ malloc_mutex_t huge_mtx; static extent_tree_t huge; void * -huge_malloc(size_t size, bool zero, dss_prec_t dss_prec) +huge_malloc(tsd_t *tsd, arena_t *arena, size_t size, bool zero, bool try_tcache) { + size_t usize; - return (huge_palloc(size, chunksize, zero, dss_prec)); + usize = s2u(size); + if (usize == 0) { + /* size_t overflow. */ + return (NULL); + } + + return (huge_palloc(tsd, arena, usize, chunksize, zero, try_tcache)); } void * -huge_palloc(size_t size, size_t alignment, bool zero, dss_prec_t dss_prec) +huge_palloc(tsd_t *tsd, arena_t *arena, size_t usize, size_t alignment, + bool zero, bool try_tcache) { void *ret; - size_t csize; extent_node_t *node; bool is_zeroed; /* Allocate one or more contiguous chunks for this request. */ - csize = CHUNK_CEILING(size); - if (csize == 0) { - /* size is large enough to cause size_t wrap-around. */ - return (NULL); - } - /* Allocate an extent node with which to track the chunk. */ - node = base_node_alloc(); + node = ipalloct(tsd, CACHELINE_CEILING(sizeof(extent_node_t)), + CACHELINE, false, try_tcache, NULL); if (node == NULL) return (NULL); @@ -48,148 +47,32 @@ huge_palloc(size_t size, size_t alignment, bool zero, dss_prec_t dss_prec) * it is possible to make correct junk/zero fill decisions below. */ is_zeroed = zero; - ret = chunk_alloc(csize, alignment, false, &is_zeroed, dss_prec); - if (ret == NULL) { - base_node_dealloc(node); + arena = arena_choose(tsd, arena); + if (unlikely(arena == NULL) || (ret = arena_chunk_alloc_huge(arena, + usize, alignment, &is_zeroed)) == NULL) { + idalloct(tsd, node, try_tcache); return (NULL); } /* Insert node into huge. */ node->addr = ret; - node->size = csize; + node->size = usize; + node->zeroed = is_zeroed; + node->arena = arena; malloc_mutex_lock(&huge_mtx); extent_tree_ad_insert(&huge, node); - if (config_stats) { - stats_cactive_add(csize); - huge_nmalloc++; - huge_allocated += csize; - } malloc_mutex_unlock(&huge_mtx); - if (config_fill && zero == false) { - if (opt_junk) - memset(ret, 0xa5, csize); - else if (opt_zero && is_zeroed == false) - memset(ret, 0, csize); - } + if (zero || (config_fill && unlikely(opt_zero))) { + if (!is_zeroed) + memset(ret, 0, usize); + } else if (config_fill && unlikely(opt_junk_alloc)) + memset(ret, 0xa5, usize); return (ret); } -bool -huge_ralloc_no_move(void *ptr, size_t oldsize, size_t size, size_t extra) -{ - - /* - * Avoid moving the allocation if the size class can be left the same. - */ - if (oldsize > arena_maxclass - && CHUNK_CEILING(oldsize) >= CHUNK_CEILING(size) - && CHUNK_CEILING(oldsize) <= CHUNK_CEILING(size+extra)) { - assert(CHUNK_CEILING(oldsize) == oldsize); - return (false); - } - - /* Reallocation would require a move. */ - return (true); -} - -void * -huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra, - size_t alignment, bool zero, bool try_tcache_dalloc, dss_prec_t dss_prec) -{ - void *ret; - size_t copysize; - - /* Try to avoid moving the allocation. */ - if (huge_ralloc_no_move(ptr, oldsize, size, extra) == false) - return (ptr); - - /* - * size and oldsize are different enough that we need to use a - * different size class. In that case, fall back to allocating new - * space and copying. - */ - if (alignment > chunksize) - ret = huge_palloc(size + extra, alignment, zero, dss_prec); - else - ret = huge_malloc(size + extra, zero, dss_prec); - - if (ret == NULL) { - if (extra == 0) - return (NULL); - /* Try again, this time without extra. */ - if (alignment > chunksize) - ret = huge_palloc(size, alignment, zero, dss_prec); - else - ret = huge_malloc(size, zero, dss_prec); - - if (ret == NULL) - return (NULL); - } - - /* - * Copy at most size bytes (not size+extra), since the caller has no - * expectation that the extra bytes will be reliably preserved. - */ - copysize = (size < oldsize) ? size : oldsize; - -#ifdef JEMALLOC_MREMAP - /* - * Use mremap(2) if this is a huge-->huge reallocation, and neither the - * source nor the destination are in dss. - */ - if (oldsize >= chunksize && (config_dss == false || (chunk_in_dss(ptr) - == false && chunk_in_dss(ret) == false))) { - size_t newsize = huge_salloc(ret); - - /* - * Remove ptr from the tree of huge allocations before - * performing the remap operation, in order to avoid the - * possibility of another thread acquiring that mapping before - * this one removes it from the tree. - */ - huge_dalloc(ptr, false); - if (mremap(ptr, oldsize, newsize, MREMAP_MAYMOVE|MREMAP_FIXED, - ret) == MAP_FAILED) { - /* - * Assuming no chunk management bugs in the allocator, - * the only documented way an error can occur here is - * if the application changed the map type for a - * portion of the old allocation. This is firmly in - * undefined behavior territory, so write a diagnostic - * message, and optionally abort. - */ - char buf[BUFERROR_BUF]; - - buferror(get_errno(), buf, sizeof(buf)); - malloc_printf(": Error in mremap(): %s\n", - buf); - if (opt_abort) - abort(); - memcpy(ret, ptr, copysize); - chunk_dealloc_mmap(ptr, oldsize); - } else if (config_fill && zero == false && opt_junk && oldsize - < newsize) { - /* - * mremap(2) clobbers the original mapping, so - * junk/zero filling is not preserved. There is no - * need to zero fill here, since any trailing - * uninititialized memory is demand-zeroed by the - * kernel, but junk filling must be redone. - */ - memset(ret + oldsize, 0xa5, newsize - oldsize); - } - } else -#endif - { - memcpy(ret, ptr, copysize); - iqalloct(ptr, try_tcache_dalloc); - } - return (ret); -} - #ifdef JEMALLOC_JET #undef huge_dalloc_junk #define huge_dalloc_junk JEMALLOC_N(huge_dalloc_junk_impl) @@ -198,12 +81,12 @@ static void huge_dalloc_junk(void *ptr, size_t usize) { - if (config_fill && config_dss && opt_junk) { + if (config_fill && have_dss && unlikely(opt_junk_free)) { /* * Only bother junk filling if the chunk isn't about to be * unmapped. */ - if (config_munmap == false || (config_dss && chunk_in_dss(ptr))) + if (!config_munmap || (have_dss && chunk_in_dss(ptr))) memset(ptr, 0x5a, usize); } } @@ -213,34 +96,266 @@ huge_dalloc_junk(void *ptr, size_t usize) huge_dalloc_junk_t *huge_dalloc_junk = JEMALLOC_N(huge_dalloc_junk_impl); #endif +static void +huge_ralloc_no_move_similar(void *ptr, size_t oldsize, size_t usize, + size_t size, size_t extra, bool zero) +{ + size_t usize_next; + bool zeroed; + extent_node_t *node, key; + arena_t *arena; + + /* Increase usize to incorporate extra. */ + while (usize < s2u(size+extra) && (usize_next = s2u(usize+1)) < oldsize) + usize = usize_next; + + if (oldsize == usize) + return; + + /* Fill if necessary (shrinking). */ + if (oldsize > usize) { + size_t sdiff = CHUNK_CEILING(usize) - usize; + zeroed = (sdiff != 0) ? !pages_purge((void *)((uintptr_t)ptr + + usize), sdiff) : true; + if (config_fill && unlikely(opt_junk_free)) { + memset((void *)((uintptr_t)ptr + usize), 0x5a, oldsize - + usize); + zeroed = false; + } + } else + zeroed = true; + + malloc_mutex_lock(&huge_mtx); + key.addr = ptr; + node = extent_tree_ad_search(&huge, &key); + assert(node != NULL); + assert(node->addr == ptr); + arena = node->arena; + /* Update the size of the huge allocation. */ + assert(node->size != usize); + node->size = usize; + /* Clear node->zeroed if zeroing failed above. */ + node->zeroed = (node->zeroed && zeroed); + malloc_mutex_unlock(&huge_mtx); + + arena_chunk_ralloc_huge_similar(arena, ptr, oldsize, usize); + + /* Fill if necessary (growing). */ + if (oldsize < usize) { + if (zero || (config_fill && unlikely(opt_zero))) { + if (!zeroed) { + memset((void *)((uintptr_t)ptr + oldsize), 0, + usize - oldsize); + } + } else if (config_fill && unlikely(opt_junk_alloc)) { + memset((void *)((uintptr_t)ptr + oldsize), 0xa5, usize - + oldsize); + } + } +} + +static void +huge_ralloc_no_move_shrink(void *ptr, size_t oldsize, size_t usize) +{ + size_t sdiff; + bool zeroed; + extent_node_t *node, key; + arena_t *arena; + + sdiff = CHUNK_CEILING(usize) - usize; + zeroed = (sdiff != 0) ? !pages_purge((void *)((uintptr_t)ptr + usize), + sdiff) : true; + if (config_fill && unlikely(opt_junk_free)) { + huge_dalloc_junk((void *)((uintptr_t)ptr + usize), oldsize - + usize); + zeroed = false; + } + + malloc_mutex_lock(&huge_mtx); + key.addr = ptr; + node = extent_tree_ad_search(&huge, &key); + assert(node != NULL); + assert(node->addr == ptr); + arena = node->arena; + /* Update the size of the huge allocation. */ + node->size = usize; + /* Clear node->zeroed if zeroing failed above. */ + node->zeroed = (node->zeroed && zeroed); + malloc_mutex_unlock(&huge_mtx); + + /* Zap the excess chunks. */ + arena_chunk_ralloc_huge_shrink(arena, ptr, oldsize, usize); +} + +static bool +huge_ralloc_no_move_expand(void *ptr, size_t oldsize, size_t size, bool zero) { + size_t usize; + extent_node_t *node, key; + arena_t *arena; + bool is_zeroed_subchunk, is_zeroed_chunk; + + usize = s2u(size); + if (usize == 0) { + /* size_t overflow. */ + return (true); + } + + malloc_mutex_lock(&huge_mtx); + key.addr = ptr; + node = extent_tree_ad_search(&huge, &key); + assert(node != NULL); + assert(node->addr == ptr); + arena = node->arena; + is_zeroed_subchunk = node->zeroed; + malloc_mutex_unlock(&huge_mtx); + + /* + * Copy zero into is_zeroed_chunk and pass the copy to chunk_alloc(), so + * that it is possible to make correct junk/zero fill decisions below. + */ + is_zeroed_chunk = zero; + + if (arena_chunk_ralloc_huge_expand(arena, ptr, oldsize, usize, + &is_zeroed_chunk)) + return (true); + + malloc_mutex_lock(&huge_mtx); + /* Update the size of the huge allocation. */ + node->size = usize; + malloc_mutex_unlock(&huge_mtx); + + if (zero || (config_fill && unlikely(opt_zero))) { + if (!is_zeroed_subchunk) { + memset((void *)((uintptr_t)ptr + oldsize), 0, + CHUNK_CEILING(oldsize) - oldsize); + } + if (!is_zeroed_chunk) { + memset((void *)((uintptr_t)ptr + + CHUNK_CEILING(oldsize)), 0, usize - + CHUNK_CEILING(oldsize)); + } + } else if (config_fill && unlikely(opt_junk_alloc)) { + memset((void *)((uintptr_t)ptr + oldsize), 0xa5, usize - + oldsize); + } + + return (false); +} + +bool +huge_ralloc_no_move(void *ptr, size_t oldsize, size_t size, size_t extra, + bool zero) +{ + size_t usize; + + /* Both allocations must be huge to avoid a move. */ + if (oldsize < chunksize) + return (true); + + assert(s2u(oldsize) == oldsize); + usize = s2u(size); + if (usize == 0) { + /* size_t overflow. */ + return (true); + } + + /* + * Avoid moving the allocation if the existing chunk size accommodates + * the new size. + */ + if (CHUNK_CEILING(oldsize) >= CHUNK_CEILING(usize) + && CHUNK_CEILING(oldsize) <= CHUNK_CEILING(size+extra)) { + huge_ralloc_no_move_similar(ptr, oldsize, usize, size, extra, + zero); + return (false); + } + + /* Shrink the allocation in-place. */ + if (CHUNK_CEILING(oldsize) >= CHUNK_CEILING(usize)) { + huge_ralloc_no_move_shrink(ptr, oldsize, usize); + return (false); + } + + /* Attempt to expand the allocation in-place. */ + if (huge_ralloc_no_move_expand(ptr, oldsize, size + extra, + zero)) { + if (extra == 0) + return (true); + + /* Try again, this time without extra. */ + return (huge_ralloc_no_move_expand(ptr, oldsize, size, zero)); + } + return (false); +} + +void * +huge_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, size_t size, + size_t extra, size_t alignment, bool zero, bool try_tcache_alloc, + bool try_tcache_dalloc) +{ + void *ret; + size_t copysize; + + /* Try to avoid moving the allocation. */ + if (!huge_ralloc_no_move(ptr, oldsize, size, extra, zero)) + return (ptr); + + /* + * size and oldsize are different enough that we need to use a + * different size class. In that case, fall back to allocating new + * space and copying. + */ + if (alignment > chunksize) { + ret = huge_palloc(tsd, arena, size + extra, alignment, zero, + try_tcache_alloc); + } else { + ret = huge_malloc(tsd, arena, size + extra, zero, + try_tcache_alloc); + } + + if (ret == NULL) { + if (extra == 0) + return (NULL); + /* Try again, this time without extra. */ + if (alignment > chunksize) { + ret = huge_palloc(tsd, arena, size, alignment, zero, + try_tcache_alloc); + } else { + ret = huge_malloc(tsd, arena, size, zero, + try_tcache_alloc); + } + + if (ret == NULL) + return (NULL); + } + + /* + * Copy at most size bytes (not size+extra), since the caller has no + * expectation that the extra bytes will be reliably preserved. + */ + copysize = (size < oldsize) ? size : oldsize; + memcpy(ret, ptr, copysize); + isqalloc(tsd, ptr, oldsize, try_tcache_dalloc); + return (ret); +} + void -huge_dalloc(void *ptr, bool unmap) +huge_dalloc(tsd_t *tsd, void *ptr, bool try_tcache) { extent_node_t *node, key; malloc_mutex_lock(&huge_mtx); - /* Extract from tree of huge allocations. */ key.addr = ptr; node = extent_tree_ad_search(&huge, &key); assert(node != NULL); assert(node->addr == ptr); extent_tree_ad_remove(&huge, node); - - if (config_stats) { - stats_cactive_sub(node->size); - huge_ndalloc++; - huge_allocated -= node->size; - } - malloc_mutex_unlock(&huge_mtx); - if (unmap) - huge_dalloc_junk(node->addr, node->size); - - chunk_dealloc(node->addr, node->size, unmap); - - base_node_dealloc(node); + huge_dalloc_junk(node->addr, node->size); + arena_chunk_dalloc_huge(node->arena, node->addr, node->size); + idalloct(tsd, node, try_tcache); } size_t @@ -263,17 +378,10 @@ huge_salloc(const void *ptr) return (ret); } -dss_prec_t -huge_dss_prec_get(arena_t *arena) +prof_tctx_t * +huge_prof_tctx_get(const void *ptr) { - - return (arena_dss_prec_get(choose_arena(arena))); -} - -prof_ctx_t * -huge_prof_ctx_get(const void *ptr) -{ - prof_ctx_t *ret; + prof_tctx_t *ret; extent_node_t *node, key; malloc_mutex_lock(&huge_mtx); @@ -283,7 +391,7 @@ huge_prof_ctx_get(const void *ptr) node = extent_tree_ad_search(&huge, &key); assert(node != NULL); - ret = node->prof_ctx; + ret = node->prof_tctx; malloc_mutex_unlock(&huge_mtx); @@ -291,7 +399,7 @@ huge_prof_ctx_get(const void *ptr) } void -huge_prof_ctx_set(const void *ptr, prof_ctx_t *ctx) +huge_prof_tctx_set(const void *ptr, prof_tctx_t *tctx) { extent_node_t *node, key; @@ -302,7 +410,7 @@ huge_prof_ctx_set(const void *ptr, prof_ctx_t *ctx) node = extent_tree_ad_search(&huge, &key); assert(node != NULL); - node->prof_ctx = ctx; + node->prof_tctx = tctx; malloc_mutex_unlock(&huge_mtx); } @@ -316,12 +424,6 @@ huge_boot(void) return (true); extent_tree_ad_new(&huge); - if (config_stats) { - huge_nmalloc = 0; - huge_ndalloc = 0; - huge_allocated = 0; - } - return (false); } diff --git a/memory/jemalloc/src/src/jemalloc.c b/memory/jemalloc/src/src/jemalloc.c index 204778bc89d8..e63dab3e2cf9 100644 --- a/memory/jemalloc/src/src/jemalloc.c +++ b/memory/jemalloc/src/src/jemalloc.c @@ -4,12 +4,8 @@ /******************************************************************************/ /* Data. */ -malloc_tsd_data(, arenas, arena_t *, NULL) -malloc_tsd_data(, thread_allocated, thread_allocated_t, - THREAD_ALLOCATED_INITIALIZER) - /* Runtime configuration options. */ -const char *je_malloc_conf; +const char *je_malloc_conf JEMALLOC_ATTR(weak); bool opt_abort = #ifdef JEMALLOC_DEBUG true @@ -17,31 +13,148 @@ bool opt_abort = false #endif ; -bool opt_junk = +const char *opt_junk = +#if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL)) + "true" +#else + "false" +#endif + ; +bool opt_junk_alloc = #if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL)) true #else false #endif ; +bool opt_junk_free = +#if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL)) + true +#else + false +#endif + ; + size_t opt_quarantine = ZU(0); bool opt_redzone = false; bool opt_utrace = false; -bool opt_valgrind = false; bool opt_xmalloc = false; bool opt_zero = false; size_t opt_narenas = 0; +/* Initialized to true if the process is running inside Valgrind. */ +bool in_valgrind; + unsigned ncpus; -malloc_mutex_t arenas_lock; -arena_t **arenas; -unsigned narenas_total; -unsigned narenas_auto; +/* Protects arenas initialization (arenas, narenas_total). */ +static malloc_mutex_t arenas_lock; +/* + * Arenas that are used to service external requests. Not all elements of the + * arenas array are necessarily used; arenas are created lazily as needed. + * + * arenas[0..narenas_auto) are used for automatic multiplexing of threads and + * arenas. arenas[narenas_auto..narenas_total) are only used if the application + * takes some action to create them and allocate from them. + */ +static arena_t **arenas; +static unsigned narenas_total; +static arena_t *a0; /* arenas[0]; read-only after initialization. */ +static unsigned narenas_auto; /* Read-only after initialization. */ /* Set to true once the allocator has been initialized. */ static bool malloc_initialized = false; +JEMALLOC_ALIGNED(CACHELINE) +const size_t index2size_tab[NSIZES] = { +#define SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \ + ((ZU(1)<: Error initializing arena\n"); - if (opt_abort) - abort(); - - return (arenas[0]); + if (config_fill && unlikely(opt_quarantine)) + quarantine_alloc_hook(); } -/* Slow path, called only by choose_arena(). */ +JEMALLOC_ALWAYS_INLINE_C bool +malloc_init(void) +{ + + if (unlikely(!malloc_initialized) && malloc_init_hard()) + return (true); + malloc_thread_init(); + + return (false); +} + +/* + * The a0*() functions are used instead of i[mcd]alloc() in bootstrap-sensitive + * situations that cannot tolerate TLS variable access. These functions are + * also exposed for use in static binaries on FreeBSD, hence the old-style + * malloc() API. + */ + arena_t * -choose_arena_hard(void) +a0get(void) +{ + + assert(a0 != NULL); + return (a0); +} + +static void * +a0alloc(size_t size, bool zero) +{ + void *ret; + + if (unlikely(malloc_init())) + return (NULL); + + if (size == 0) + size = 1; + + if (likely(size <= arena_maxclass)) + ret = arena_malloc(NULL, a0get(), size, zero, false); + else + ret = huge_malloc(NULL, a0get(), size, zero, false); + + return (ret); +} + +void * +a0malloc(size_t size) +{ + + return (a0alloc(size, false)); +} + +void * +a0calloc(size_t num, size_t size) +{ + + return (a0alloc(num * size, true)); +} + +void +a0free(void *ptr) +{ + arena_chunk_t *chunk; + + if (ptr == NULL) + return; + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + if (likely(chunk != ptr)) + arena_dalloc(NULL, chunk, ptr, false); + else + huge_dalloc(NULL, ptr, false); +} + +/* Create a new arena and insert it into the arenas array at index ind. */ +static arena_t * +arena_init_locked(unsigned ind) +{ + arena_t *arena; + + /* Expand arenas if necessary. */ + assert(ind <= narenas_total); + if (ind == narenas_total) { + unsigned narenas_new = narenas_total + 1; + arena_t **arenas_new = + (arena_t **)a0malloc(CACHELINE_CEILING(narenas_new * + sizeof(arena_t *))); + if (arenas_new == NULL) + return (NULL); + memcpy(arenas_new, arenas, narenas_total * sizeof(arena_t *)); + arenas_new[ind] = NULL; + /* + * Deallocate only if arenas came from a0malloc() (not + * base_alloc()). + */ + if (narenas_total != narenas_auto) + a0free(arenas); + arenas = arenas_new; + narenas_total = narenas_new; + } + + /* + * Another thread may have already initialized arenas[ind] if it's an + * auto arena. + */ + arena = arenas[ind]; + if (arena != NULL) { + assert(ind < narenas_auto); + return (arena); + } + + /* Actually initialize the arena. */ + arena = arenas[ind] = arena_new(ind); + return (arena); +} + +arena_t * +arena_init(unsigned ind) +{ + arena_t *arena; + + malloc_mutex_lock(&arenas_lock); + arena = arena_init_locked(ind); + malloc_mutex_unlock(&arenas_lock); + return (arena); +} + +unsigned +narenas_total_get(void) +{ + unsigned narenas; + + malloc_mutex_lock(&arenas_lock); + narenas = narenas_total; + malloc_mutex_unlock(&arenas_lock); + + return (narenas); +} + +static void +arena_bind_locked(tsd_t *tsd, unsigned ind) +{ + arena_t *arena; + + arena = arenas[ind]; + arena->nthreads++; + + if (tsd_nominal(tsd)) + tsd_arena_set(tsd, arena); +} + +static void +arena_bind(tsd_t *tsd, unsigned ind) +{ + + malloc_mutex_lock(&arenas_lock); + arena_bind_locked(tsd, ind); + malloc_mutex_unlock(&arenas_lock); +} + +void +arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind) +{ + arena_t *oldarena, *newarena; + + malloc_mutex_lock(&arenas_lock); + oldarena = arenas[oldind]; + newarena = arenas[newind]; + oldarena->nthreads--; + newarena->nthreads++; + malloc_mutex_unlock(&arenas_lock); + tsd_arena_set(tsd, newarena); +} + +unsigned +arena_nbound(unsigned ind) +{ + unsigned nthreads; + + malloc_mutex_lock(&arenas_lock); + nthreads = arenas[ind]->nthreads; + malloc_mutex_unlock(&arenas_lock); + return (nthreads); +} + +static void +arena_unbind(tsd_t *tsd, unsigned ind) +{ + arena_t *arena; + + malloc_mutex_lock(&arenas_lock); + arena = arenas[ind]; + arena->nthreads--; + malloc_mutex_unlock(&arenas_lock); + tsd_arena_set(tsd, NULL); +} + +arena_t * +arena_get_hard(tsd_t *tsd, unsigned ind, bool init_if_missing) +{ + arena_t *arena; + arena_t **arenas_cache = tsd_arenas_cache_get(tsd); + unsigned narenas_cache = tsd_narenas_cache_get(tsd); + unsigned narenas_actual = narenas_total_get(); + + /* Deallocate old cache if it's too small. */ + if (arenas_cache != NULL && narenas_cache < narenas_actual) { + a0free(arenas_cache); + arenas_cache = NULL; + narenas_cache = 0; + tsd_arenas_cache_set(tsd, arenas_cache); + tsd_narenas_cache_set(tsd, narenas_cache); + } + + /* Allocate cache if it's missing. */ + if (arenas_cache == NULL) { + bool *arenas_cache_bypassp = tsd_arenas_cache_bypassp_get(tsd); + assert(ind < narenas_actual || !init_if_missing); + narenas_cache = (ind < narenas_actual) ? narenas_actual : ind+1; + + if (!*arenas_cache_bypassp) { + *arenas_cache_bypassp = true; + arenas_cache = (arena_t **)a0malloc(sizeof(arena_t *) * + narenas_cache); + *arenas_cache_bypassp = false; + } else + arenas_cache = NULL; + if (arenas_cache == NULL) { + /* + * This function must always tell the truth, even if + * it's slow, so don't let OOM or recursive allocation + * avoidance (note arenas_cache_bypass check) get in the + * way. + */ + if (ind >= narenas_actual) + return (NULL); + malloc_mutex_lock(&arenas_lock); + arena = arenas[ind]; + malloc_mutex_unlock(&arenas_lock); + return (arena); + } + tsd_arenas_cache_set(tsd, arenas_cache); + tsd_narenas_cache_set(tsd, narenas_cache); + } + + /* + * Copy to cache. It's possible that the actual number of arenas has + * increased since narenas_total_get() was called above, but that causes + * no correctness issues unless two threads concurrently execute the + * arenas.extend mallctl, which we trust mallctl synchronization to + * prevent. + */ + malloc_mutex_lock(&arenas_lock); + memcpy(arenas_cache, arenas, sizeof(arena_t *) * narenas_actual); + malloc_mutex_unlock(&arenas_lock); + if (narenas_cache > narenas_actual) { + memset(&arenas_cache[narenas_actual], 0, sizeof(arena_t *) * + (narenas_cache - narenas_actual)); + } + + /* Read the refreshed cache, and init the arena if necessary. */ + arena = arenas_cache[ind]; + if (init_if_missing && arena == NULL) + arena = arenas_cache[ind] = arena_init(ind); + return (arena); +} + +/* Slow path, called only by arena_choose(). */ +arena_t * +arena_choose_hard(tsd_t *tsd) { arena_t *ret; @@ -150,7 +521,7 @@ choose_arena_hard(void) choose = 0; first_null = narenas_auto; malloc_mutex_lock(&arenas_lock); - assert(arenas[0] != NULL); + assert(a0get() != NULL); for (i = 1; i < narenas_auto; i++) { if (arenas[i] != NULL) { /* @@ -183,22 +554,71 @@ choose_arena_hard(void) ret = arenas[choose]; } else { /* Initialize a new arena. */ - ret = arenas_extend(first_null); + choose = first_null; + ret = arena_init_locked(choose); + if (ret == NULL) { + malloc_mutex_unlock(&arenas_lock); + return (NULL); + } } - ret->nthreads++; + arena_bind_locked(tsd, choose); malloc_mutex_unlock(&arenas_lock); } else { - ret = arenas[0]; - malloc_mutex_lock(&arenas_lock); - ret->nthreads++; - malloc_mutex_unlock(&arenas_lock); + ret = a0get(); + arena_bind(tsd, 0); } - arenas_tsd_set(&ret); - return (ret); } +void +thread_allocated_cleanup(tsd_t *tsd) +{ + + /* Do nothing. */ +} + +void +thread_deallocated_cleanup(tsd_t *tsd) +{ + + /* Do nothing. */ +} + +void +arena_cleanup(tsd_t *tsd) +{ + arena_t *arena; + + arena = tsd_arena_get(tsd); + if (arena != NULL) + arena_unbind(tsd, arena->ind); +} + +void +arenas_cache_cleanup(tsd_t *tsd) +{ + arena_t **arenas_cache; + + arenas_cache = tsd_arenas_cache_get(tsd); + if (arenas != NULL) + a0free(arenas_cache); +} + +void +narenas_cache_cleanup(tsd_t *tsd) +{ + + /* Do nothing. */ +} + +void +arenas_cache_bypass_cleanup(tsd_t *tsd) +{ + + /* Do nothing. */ +} + static void stats_print_atexit(void) { @@ -243,6 +663,27 @@ stats_print_atexit(void) * Begin initialization functions. */ +#ifndef JEMALLOC_HAVE_SECURE_GETENV +# ifdef JEMALLOC_HAVE_ISSETUGID +static char * +secure_getenv(const char *name) +{ + + if (issetugid() == 0) + return (getenv(name)); + else + return (NULL); +} +# else +static char * +secure_getenv(const char *name) +{ + + return (getenv(name)); +} +# endif +#endif + static unsigned malloc_ncpus(void) { @@ -258,44 +699,6 @@ malloc_ncpus(void) return ((result == -1) ? 1 : (unsigned)result); } -void -arenas_cleanup(void *arg) -{ - arena_t *arena = *(arena_t **)arg; - - malloc_mutex_lock(&arenas_lock); - arena->nthreads--; - malloc_mutex_unlock(&arenas_lock); -} - -JEMALLOC_ALWAYS_INLINE_C void -malloc_thread_init(void) -{ - - /* - * TSD initialization can't be safely done as a side effect of - * deallocation, because it is possible for a thread to do nothing but - * deallocate its TLS data via free(), in which case writing to TLS - * would cause write-after-free memory corruption. The quarantine - * facility *only* gets used as a side effect of deallocation, so make - * a best effort attempt at initializing its TSD by hooking all - * allocation events. - */ - if (config_fill && opt_quarantine) - quarantine_alloc_hook(); -} - -JEMALLOC_ALWAYS_INLINE_C bool -malloc_init(void) -{ - - if (malloc_initialized == false && malloc_init_hard()) - return (true); - malloc_thread_init(); - - return (false); -} - static bool malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p, char const **v_p, size_t *vlen_p) @@ -305,7 +708,7 @@ malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p, *k_p = opts; - for (accept = false; accept == false;) { + for (accept = false; !accept;) { switch (*opts) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': @@ -340,7 +743,7 @@ malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p, } } - for (accept = false; accept == false;) { + for (accept = false; !accept;) { switch (*opts) { case ',': opts++; @@ -394,14 +797,16 @@ malloc_conf_init(void) * valgrind option remains in jemalloc 3.x for compatibility reasons. */ if (config_valgrind) { - opt_valgrind = (RUNNING_ON_VALGRIND != 0) ? true : false; - if (config_fill && opt_valgrind) { - opt_junk = false; - assert(opt_zero == false); + in_valgrind = (RUNNING_ON_VALGRIND != 0) ? true : false; + if (config_fill && unlikely(in_valgrind)) { + opt_junk = "false"; + opt_junk_alloc = false; + opt_junk_free = false; + assert(!opt_zero); opt_quarantine = JEMALLOC_VALGRIND_QUARANTINE_DEFAULT; opt_redzone = true; } - if (config_tcache && opt_valgrind) + if (config_tcache && unlikely(in_valgrind)) opt_tcache = false; } @@ -441,7 +846,7 @@ malloc_conf_init(void) if (linklen == -1) { /* No configuration specified. */ linklen = 0; - /* restore errno */ + /* Restore errno. */ set_errno(saved_errno); } #endif @@ -457,7 +862,7 @@ malloc_conf_init(void) #endif ; - if ((opts = getenv(envname)) != NULL) { + if ((opts = secure_getenv(envname)) != NULL) { /* * Do nothing; opts is already initialized to * the value of the MALLOC_CONF environment @@ -475,27 +880,28 @@ malloc_conf_init(void) opts = buf; } - while (*opts != '\0' && malloc_conf_next(&opts, &k, &klen, &v, - &vlen) == false) { -#define CONF_HANDLE_BOOL(o, n) \ - if (sizeof(n)-1 == klen && strncmp(n, k, \ - klen) == 0) { \ - if (strncmp("true", v, vlen) == 0 && \ - vlen == sizeof("true")-1) \ + while (*opts != '\0' && !malloc_conf_next(&opts, &k, &klen, &v, + &vlen)) { +#define CONF_MATCH(n) \ + (sizeof(n)-1 == klen && strncmp(n, k, klen) == 0) +#define CONF_MATCH_VALUE(n) \ + (sizeof(n)-1 == vlen && strncmp(n, v, vlen) == 0) +#define CONF_HANDLE_BOOL(o, n, cont) \ + if (CONF_MATCH(n)) { \ + if (CONF_MATCH_VALUE("true")) \ o = true; \ - else if (strncmp("false", v, vlen) == \ - 0 && vlen == sizeof("false")-1) \ + else if (CONF_MATCH_VALUE("false")) \ o = false; \ else { \ malloc_conf_error( \ "Invalid conf value", \ k, klen, v, vlen); \ } \ - continue; \ + if (cont) \ + continue; \ } #define CONF_HANDLE_SIZE_T(o, n, min, max, clip) \ - if (sizeof(n)-1 == klen && strncmp(n, k, \ - klen) == 0) { \ + if (CONF_MATCH(n)) { \ uintmax_t um; \ char *end; \ \ @@ -507,15 +913,15 @@ malloc_conf_init(void) "Invalid conf value", \ k, klen, v, vlen); \ } else if (clip) { \ - if (min != 0 && um < min) \ - o = min; \ - else if (um > max) \ - o = max; \ + if ((min) != 0 && um < (min)) \ + o = (min); \ + else if (um > (max)) \ + o = (max); \ else \ o = um; \ } else { \ - if ((min != 0 && um < min) || \ - um > max) { \ + if (((min) != 0 && um < (min)) \ + || um > (max)) { \ malloc_conf_error( \ "Out-of-range " \ "conf value", \ @@ -526,8 +932,7 @@ malloc_conf_init(void) continue; \ } #define CONF_HANDLE_SSIZE_T(o, n, min, max) \ - if (sizeof(n)-1 == klen && strncmp(n, k, \ - klen) == 0) { \ + if (CONF_MATCH(n)) { \ long l; \ char *end; \ \ @@ -538,8 +943,8 @@ malloc_conf_init(void) malloc_conf_error( \ "Invalid conf value", \ k, klen, v, vlen); \ - } else if (l < (ssize_t)min || l > \ - (ssize_t)max) { \ + } else if (l < (ssize_t)(min) || l > \ + (ssize_t)(max)) { \ malloc_conf_error( \ "Out-of-range conf value", \ k, klen, v, vlen); \ @@ -548,8 +953,7 @@ malloc_conf_init(void) continue; \ } #define CONF_HANDLE_CHAR_P(o, n, d) \ - if (sizeof(n)-1 == klen && strncmp(n, k, \ - klen) == 0) { \ + if (CONF_MATCH(n)) { \ size_t cpylen = (vlen <= \ sizeof(o)-1) ? vlen : \ sizeof(o)-1; \ @@ -558,17 +962,18 @@ malloc_conf_init(void) continue; \ } - CONF_HANDLE_BOOL(opt_abort, "abort") + CONF_HANDLE_BOOL(opt_abort, "abort", true) /* - * Chunks always require at least one header page, plus - * one data page in the absence of redzones, or three - * pages in the presence of redzones. In order to - * simplify options processing, fix the limit based on - * config_fill. + * Chunks always require at least one header page, + * as many as 2^(LG_SIZE_CLASS_GROUP+1) data pages, and + * possibly an additional page in the presence of + * redzones. In order to simplify options processing, + * use a conservative bound that accommodates all these + * constraints. */ CONF_HANDLE_SIZE_T(opt_lg_chunk, "lg_chunk", LG_PAGE + - (config_fill ? 2 : 1), (sizeof(size_t) << 3) - 1, - true) + LG_SIZE_CLASS_GROUP + (config_fill ? 2 : 1), + (sizeof(size_t) << 3) - 1, true) if (strncmp("dss", k, klen) == 0) { int i; bool match = false; @@ -587,7 +992,7 @@ malloc_conf_init(void) } } } - if (match == false) { + if (!match) { malloc_conf_error("Invalid conf value", k, klen, v, vlen); } @@ -597,47 +1002,87 @@ malloc_conf_init(void) SIZE_T_MAX, false) CONF_HANDLE_SSIZE_T(opt_lg_dirty_mult, "lg_dirty_mult", -1, (sizeof(size_t) << 3) - 1) - CONF_HANDLE_BOOL(opt_stats_print, "stats_print") + CONF_HANDLE_BOOL(opt_stats_print, "stats_print", true) if (config_fill) { - CONF_HANDLE_BOOL(opt_junk, "junk") + if (CONF_MATCH("junk")) { + if (CONF_MATCH_VALUE("true")) { + opt_junk = "true"; + opt_junk_alloc = opt_junk_free = + true; + } else if (CONF_MATCH_VALUE("false")) { + opt_junk = "false"; + opt_junk_alloc = opt_junk_free = + false; + } else if (CONF_MATCH_VALUE("alloc")) { + opt_junk = "alloc"; + opt_junk_alloc = true; + opt_junk_free = false; + } else if (CONF_MATCH_VALUE("free")) { + opt_junk = "free"; + opt_junk_alloc = false; + opt_junk_free = true; + } else { + malloc_conf_error( + "Invalid conf value", k, + klen, v, vlen); + } + continue; + } CONF_HANDLE_SIZE_T(opt_quarantine, "quarantine", 0, SIZE_T_MAX, false) - CONF_HANDLE_BOOL(opt_redzone, "redzone") - CONF_HANDLE_BOOL(opt_zero, "zero") + CONF_HANDLE_BOOL(opt_redzone, "redzone", true) + CONF_HANDLE_BOOL(opt_zero, "zero", true) } if (config_utrace) { - CONF_HANDLE_BOOL(opt_utrace, "utrace") - } - if (config_valgrind) { - CONF_HANDLE_BOOL(opt_valgrind, "valgrind") + CONF_HANDLE_BOOL(opt_utrace, "utrace", true) } if (config_xmalloc) { - CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc") + CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc", true) } if (config_tcache) { - CONF_HANDLE_BOOL(opt_tcache, "tcache") + CONF_HANDLE_BOOL(opt_tcache, "tcache", + !config_valgrind || !in_valgrind) + if (CONF_MATCH("tcache")) { + assert(config_valgrind && in_valgrind); + if (opt_tcache) { + opt_tcache = false; + malloc_conf_error( + "tcache cannot be enabled " + "while running inside Valgrind", + k, klen, v, vlen); + } + continue; + } CONF_HANDLE_SSIZE_T(opt_lg_tcache_max, "lg_tcache_max", -1, (sizeof(size_t) << 3) - 1) } if (config_prof) { - CONF_HANDLE_BOOL(opt_prof, "prof") + CONF_HANDLE_BOOL(opt_prof, "prof", true) CONF_HANDLE_CHAR_P(opt_prof_prefix, "prof_prefix", "jeprof") - CONF_HANDLE_BOOL(opt_prof_active, "prof_active") - CONF_HANDLE_SSIZE_T(opt_lg_prof_sample, + CONF_HANDLE_BOOL(opt_prof_active, "prof_active", + true) + CONF_HANDLE_BOOL(opt_prof_thread_active_init, + "prof_thread_active_init", true) + CONF_HANDLE_SIZE_T(opt_lg_prof_sample, "lg_prof_sample", 0, - (sizeof(uint64_t) << 3) - 1) - CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum") + (sizeof(uint64_t) << 3) - 1, true) + CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum", + true) CONF_HANDLE_SSIZE_T(opt_lg_prof_interval, "lg_prof_interval", -1, (sizeof(uint64_t) << 3) - 1) - CONF_HANDLE_BOOL(opt_prof_gdump, "prof_gdump") - CONF_HANDLE_BOOL(opt_prof_final, "prof_final") - CONF_HANDLE_BOOL(opt_prof_leak, "prof_leak") + CONF_HANDLE_BOOL(opt_prof_gdump, "prof_gdump", + true) + CONF_HANDLE_BOOL(opt_prof_final, "prof_final", + true) + CONF_HANDLE_BOOL(opt_prof_leak, "prof_leak", + true) } malloc_conf_error("Invalid conf pair", k, klen, v, vlen); +#undef CONF_MATCH #undef CONF_HANDLE_BOOL #undef CONF_HANDLE_SIZE_T #undef CONF_HANDLE_SSIZE_T @@ -662,20 +1107,24 @@ malloc_init_hard(void) return (false); } #ifdef JEMALLOC_THREADED_INIT - if (malloc_initializer != NO_INITIALIZER && IS_INITIALIZER == false) { + if (malloc_initializer != NO_INITIALIZER && !IS_INITIALIZER) { /* Busy-wait until the initializing thread completes. */ do { malloc_mutex_unlock(&init_lock); CPU_SPINWAIT; malloc_mutex_lock(&init_lock); - } while (malloc_initialized == false); + } while (!malloc_initialized); malloc_mutex_unlock(&init_lock); return (false); } #endif malloc_initializer = INITIALIZER; - malloc_tsd_boot(); + if (malloc_tsd_boot0()) { + malloc_mutex_unlock(&init_lock); + return (true); + } + if (config_prof) prof_boot0(); @@ -710,7 +1159,7 @@ malloc_init_hard(void) arena_boot(); - if (config_tcache && tcache_boot0()) { + if (config_tcache && tcache_boot()) { malloc_mutex_unlock(&init_lock); return (true); } @@ -735,31 +1184,10 @@ malloc_init_hard(void) /* * Initialize one arena here. The rest are lazily created in - * choose_arena_hard(). + * arena_choose_hard(). */ - arenas_extend(0); - if (arenas[0] == NULL) { - malloc_mutex_unlock(&init_lock); - return (true); - } - - /* Initialize allocation counters before any allocations can occur. */ - if (config_stats && thread_allocated_tsd_boot()) { - malloc_mutex_unlock(&init_lock); - return (true); - } - - if (arenas_tsd_boot()) { - malloc_mutex_unlock(&init_lock); - return (true); - } - - if (config_tcache && tcache_boot1()) { - malloc_mutex_unlock(&init_lock); - return (true); - } - - if (config_fill && quarantine_boot()) { + a0 = arena_init(0); + if (a0 == NULL) { malloc_mutex_unlock(&init_lock); return (true); } @@ -776,7 +1204,7 @@ malloc_init_hard(void) ncpus = malloc_ncpus(); #if (!defined(JEMALLOC_MUTEX_INIT_CB) && !defined(JEMALLOC_ZONE) \ - && !defined(_WIN32)) + && !defined(_WIN32) && !defined(__native_client__)) /* LinuxThreads's pthread_atfork() allocates. */ if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent, jemalloc_postfork_child) != 0) { @@ -834,6 +1262,7 @@ malloc_init_hard(void) malloc_initialized = true; malloc_mutex_unlock(&init_lock); + malloc_tsd_boot1(); return (false); } @@ -847,98 +1276,83 @@ malloc_init_hard(void) */ static void * -imalloc_prof_sample(size_t usize, prof_thr_cnt_t *cnt) +imalloc_prof_sample(tsd_t *tsd, size_t usize, prof_tctx_t *tctx) { void *p; - if (cnt == NULL) + if (tctx == NULL) return (NULL); - if (prof_promote && usize <= SMALL_MAXCLASS) { - p = imalloc(SMALL_MAXCLASS+1); + if (usize <= SMALL_MAXCLASS) { + p = imalloc(tsd, LARGE_MINCLASS); if (p == NULL) return (NULL); arena_prof_promoted(p, usize); } else - p = imalloc(usize); + p = imalloc(tsd, usize); return (p); } JEMALLOC_ALWAYS_INLINE_C void * -imalloc_prof(size_t usize, prof_thr_cnt_t *cnt) +imalloc_prof(tsd_t *tsd, size_t usize) { void *p; + prof_tctx_t *tctx; - if ((uintptr_t)cnt != (uintptr_t)1U) - p = imalloc_prof_sample(usize, cnt); + tctx = prof_alloc_prep(tsd, usize, true); + if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) + p = imalloc_prof_sample(tsd, usize, tctx); else - p = imalloc(usize); - if (p == NULL) + p = imalloc(tsd, usize); + if (unlikely(p == NULL)) { + prof_alloc_rollback(tsd, tctx, true); return (NULL); - prof_malloc(p, usize, cnt); + } + prof_malloc(p, usize, tctx); return (p); } -/* - * MALLOC_BODY() is a macro rather than a function because its contents are in - * the fast path, but inlining would cause reliability issues when determining - * how many frames to discard from heap profiling backtraces. - */ -#define MALLOC_BODY(ret, size, usize) do { \ - if (malloc_init()) \ - ret = NULL; \ - else { \ - if (config_prof && opt_prof) { \ - prof_thr_cnt_t *cnt; \ - \ - usize = s2u(size); \ - /* \ - * Call PROF_ALLOC_PREP() here rather than in \ - * imalloc_prof() so that imalloc_prof() can be \ - * inlined without introducing uncertainty \ - * about the number of backtrace frames to \ - * ignore. imalloc_prof() is in the fast path \ - * when heap profiling is enabled, so inlining \ - * is critical to performance. (For \ - * consistency all callers of PROF_ALLOC_PREP() \ - * are structured similarly, even though e.g. \ - * realloc() isn't called enough for inlining \ - * to be critical.) \ - */ \ - PROF_ALLOC_PREP(1, usize, cnt); \ - ret = imalloc_prof(usize, cnt); \ - } else { \ - if (config_stats || (config_valgrind && \ - opt_valgrind)) \ - usize = s2u(size); \ - ret = imalloc(size); \ - } \ - } \ -} while (0) +JEMALLOC_ALWAYS_INLINE_C void * +imalloc_body(size_t size, tsd_t **tsd, size_t *usize) +{ + + if (unlikely(malloc_init())) + return (NULL); + *tsd = tsd_fetch(); + + if (config_prof && opt_prof) { + *usize = s2u(size); + return (imalloc_prof(*tsd, *usize)); + } + + if (config_stats || (config_valgrind && unlikely(in_valgrind))) + *usize = s2u(size); + return (imalloc(*tsd, size)); +} void * je_malloc(size_t size) { void *ret; + tsd_t *tsd; size_t usize JEMALLOC_CC_SILENCE_INIT(0); if (size == 0) size = 1; - MALLOC_BODY(ret, size, usize); - - if (ret == NULL) { - if (config_xmalloc && opt_xmalloc) { + ret = imalloc_body(size, &tsd, &usize); + if (unlikely(ret == NULL)) { + if (config_xmalloc && unlikely(opt_xmalloc)) { malloc_write(": Error in malloc(): " "out of memory\n"); abort(); } set_errno(ENOMEM); } - if (config_stats && ret != NULL) { + if (config_stats && likely(ret != NULL)) { assert(usize == isalloc(ret, config_prof)); - thread_allocated_tsd_get()->allocated += usize; + *tsd_thread_allocatedp_get(tsd) += usize; } UTRACE(0, size, ret); JEMALLOC_VALGRIND_MALLOC(ret != NULL, ret, usize, false); @@ -946,69 +1360,68 @@ je_malloc(size_t size) } static void * -imemalign_prof_sample(size_t alignment, size_t usize, prof_thr_cnt_t *cnt) +imemalign_prof_sample(tsd_t *tsd, size_t alignment, size_t usize, + prof_tctx_t *tctx) { void *p; - if (cnt == NULL) + if (tctx == NULL) return (NULL); - if (prof_promote && usize <= SMALL_MAXCLASS) { - assert(sa2u(SMALL_MAXCLASS+1, alignment) != 0); - p = ipalloc(sa2u(SMALL_MAXCLASS+1, alignment), alignment, - false); + if (usize <= SMALL_MAXCLASS) { + assert(sa2u(LARGE_MINCLASS, alignment) == LARGE_MINCLASS); + p = imalloc(tsd, LARGE_MINCLASS); if (p == NULL) return (NULL); arena_prof_promoted(p, usize); } else - p = ipalloc(usize, alignment, false); + p = ipalloc(tsd, usize, alignment, false); return (p); } JEMALLOC_ALWAYS_INLINE_C void * -imemalign_prof(size_t alignment, size_t usize, prof_thr_cnt_t *cnt) +imemalign_prof(tsd_t *tsd, size_t alignment, size_t usize) { void *p; + prof_tctx_t *tctx; - if ((uintptr_t)cnt != (uintptr_t)1U) - p = imemalign_prof_sample(alignment, usize, cnt); + tctx = prof_alloc_prep(tsd, usize, true); + if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) + p = imemalign_prof_sample(tsd, alignment, usize, tctx); else - p = ipalloc(usize, alignment, false); - if (p == NULL) + p = ipalloc(tsd, usize, alignment, false); + if (unlikely(p == NULL)) { + prof_alloc_rollback(tsd, tctx, true); return (NULL); - prof_malloc(p, usize, cnt); + } + prof_malloc(p, usize, tctx); return (p); } JEMALLOC_ATTR(nonnull(1)) -#ifdef JEMALLOC_PROF -/* - * Avoid any uncertainty as to how many backtrace frames to ignore in - * PROF_ALLOC_PREP(). - */ -JEMALLOC_NOINLINE -#endif static int imemalign(void **memptr, size_t alignment, size_t size, size_t min_alignment) { int ret; + tsd_t *tsd; size_t usize; void *result; assert(min_alignment != 0); - if (malloc_init()) { + if (unlikely(malloc_init())) { result = NULL; goto label_oom; } else { + tsd = tsd_fetch(); if (size == 0) size = 1; /* Make sure that alignment is a large enough power of 2. */ - if (((alignment - 1) & alignment) != 0 - || (alignment < min_alignment)) { - if (config_xmalloc && opt_xmalloc) { + if (unlikely(((alignment - 1) & alignment) != 0 + || (alignment < min_alignment))) { + if (config_xmalloc && unlikely(opt_xmalloc)) { malloc_write(": Error allocating " "aligned memory: invalid alignment\n"); abort(); @@ -1019,34 +1432,31 @@ imemalign(void **memptr, size_t alignment, size_t size, size_t min_alignment) } usize = sa2u(size, alignment); - if (usize == 0) { + if (unlikely(usize == 0)) { result = NULL; goto label_oom; } - if (config_prof && opt_prof) { - prof_thr_cnt_t *cnt; - - PROF_ALLOC_PREP(2, usize, cnt); - result = imemalign_prof(alignment, usize, cnt); - } else - result = ipalloc(usize, alignment, false); - if (result == NULL) + if (config_prof && opt_prof) + result = imemalign_prof(tsd, alignment, usize); + else + result = ipalloc(tsd, usize, alignment, false); + if (unlikely(result == NULL)) goto label_oom; } *memptr = result; ret = 0; label_return: - if (config_stats && result != NULL) { + if (config_stats && likely(result != NULL)) { assert(usize == isalloc(result, config_prof)); - thread_allocated_tsd_get()->allocated += usize; + *tsd_thread_allocatedp_get(tsd) += usize; } UTRACE(0, size, result); return (ret); label_oom: assert(result == NULL); - if (config_xmalloc && opt_xmalloc) { + if (config_xmalloc && unlikely(opt_xmalloc)) { malloc_write(": Error allocating aligned memory: " "out of memory\n"); abort(); @@ -1070,7 +1480,7 @@ je_aligned_alloc(size_t alignment, size_t size) void *ret; int err; - if ((err = imemalign(&ret, alignment, size, 1)) != 0) { + if (unlikely((err = imemalign(&ret, alignment, size, 1)) != 0)) { ret = NULL; set_errno(err); } @@ -1080,35 +1490,39 @@ je_aligned_alloc(size_t alignment, size_t size) } static void * -icalloc_prof_sample(size_t usize, prof_thr_cnt_t *cnt) +icalloc_prof_sample(tsd_t *tsd, size_t usize, prof_tctx_t *tctx) { void *p; - if (cnt == NULL) + if (tctx == NULL) return (NULL); - if (prof_promote && usize <= SMALL_MAXCLASS) { - p = icalloc(SMALL_MAXCLASS+1); + if (usize <= SMALL_MAXCLASS) { + p = icalloc(tsd, LARGE_MINCLASS); if (p == NULL) return (NULL); arena_prof_promoted(p, usize); } else - p = icalloc(usize); + p = icalloc(tsd, usize); return (p); } JEMALLOC_ALWAYS_INLINE_C void * -icalloc_prof(size_t usize, prof_thr_cnt_t *cnt) +icalloc_prof(tsd_t *tsd, size_t usize) { void *p; + prof_tctx_t *tctx; - if ((uintptr_t)cnt != (uintptr_t)1U) - p = icalloc_prof_sample(usize, cnt); + tctx = prof_alloc_prep(tsd, usize, true); + if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) + p = icalloc_prof_sample(tsd, usize, tctx); else - p = icalloc(usize); - if (p == NULL) + p = icalloc(tsd, usize); + if (unlikely(p == NULL)) { + prof_alloc_rollback(tsd, tctx, true); return (NULL); - prof_malloc(p, usize, cnt); + } + prof_malloc(p, usize, tctx); return (p); } @@ -1117,17 +1531,19 @@ void * je_calloc(size_t num, size_t size) { void *ret; + tsd_t *tsd; size_t num_size; size_t usize JEMALLOC_CC_SILENCE_INIT(0); - if (malloc_init()) { + if (unlikely(malloc_init())) { num_size = 0; ret = NULL; goto label_return; } + tsd = tsd_fetch(); num_size = num * size; - if (num_size == 0) { + if (unlikely(num_size == 0)) { if (num == 0 || size == 0) num_size = 1; else { @@ -1139,37 +1555,34 @@ je_calloc(size_t num, size_t size) * overflow during multiplication if neither operand uses any of the * most significant half of the bits in a size_t. */ - } else if (((num | size) & (SIZE_T_MAX << (sizeof(size_t) << 2))) - && (num_size / size != num)) { + } else if (unlikely(((num | size) & (SIZE_T_MAX << (sizeof(size_t) << + 2))) && (num_size / size != num))) { /* size_t overflow. */ ret = NULL; goto label_return; } if (config_prof && opt_prof) { - prof_thr_cnt_t *cnt; - usize = s2u(num_size); - PROF_ALLOC_PREP(1, usize, cnt); - ret = icalloc_prof(usize, cnt); + ret = icalloc_prof(tsd, usize); } else { - if (config_stats || (config_valgrind && opt_valgrind)) + if (config_stats || (config_valgrind && unlikely(in_valgrind))) usize = s2u(num_size); - ret = icalloc(num_size); + ret = icalloc(tsd, num_size); } label_return: - if (ret == NULL) { - if (config_xmalloc && opt_xmalloc) { + if (unlikely(ret == NULL)) { + if (config_xmalloc && unlikely(opt_xmalloc)) { malloc_write(": Error in calloc(): out of " "memory\n"); abort(); } set_errno(ENOMEM); } - if (config_stats && ret != NULL) { + if (config_stats && likely(ret != NULL)) { assert(usize == isalloc(ret, config_prof)); - thread_allocated_tsd_get()->allocated += usize; + *tsd_thread_allocatedp_get(tsd) += usize; } UTRACE(0, num_size, ret); JEMALLOC_VALGRIND_MALLOC(ret != NULL, ret, usize, true); @@ -1177,43 +1590,45 @@ label_return: } static void * -irealloc_prof_sample(void *oldptr, size_t usize, prof_thr_cnt_t *cnt) +irealloc_prof_sample(tsd_t *tsd, void *oldptr, size_t old_usize, size_t usize, + prof_tctx_t *tctx) { void *p; - if (cnt == NULL) + if (tctx == NULL) return (NULL); - if (prof_promote && usize <= SMALL_MAXCLASS) { - p = iralloc(oldptr, SMALL_MAXCLASS+1, 0, 0, false); + if (usize <= SMALL_MAXCLASS) { + p = iralloc(tsd, oldptr, old_usize, LARGE_MINCLASS, 0, false); if (p == NULL) return (NULL); arena_prof_promoted(p, usize); } else - p = iralloc(oldptr, usize, 0, 0, false); + p = iralloc(tsd, oldptr, old_usize, usize, 0, false); return (p); } JEMALLOC_ALWAYS_INLINE_C void * -irealloc_prof(void *oldptr, size_t old_usize, size_t usize, prof_thr_cnt_t *cnt) +irealloc_prof(tsd_t *tsd, void *oldptr, size_t old_usize, size_t usize) { void *p; - prof_ctx_t *old_ctx; + prof_tctx_t *old_tctx, *tctx; - old_ctx = prof_ctx_get(oldptr); - if ((uintptr_t)cnt != (uintptr_t)1U) - p = irealloc_prof_sample(oldptr, usize, cnt); + old_tctx = prof_tctx_get(oldptr); + tctx = prof_alloc_prep(tsd, usize, true); + if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) + p = irealloc_prof_sample(tsd, oldptr, old_usize, usize, tctx); else - p = iralloc(oldptr, usize, 0, 0, false); + p = iralloc(tsd, oldptr, old_usize, usize, 0, false); if (p == NULL) return (NULL); - prof_realloc(p, usize, cnt, old_usize, old_ctx); + prof_realloc(tsd, p, usize, tctx, true, old_usize, old_tctx); return (p); } JEMALLOC_INLINE_C void -ifree(void *ptr) +ifree(tsd_t *tsd, void *ptr, bool try_tcache) { size_t usize; UNUSED size_t rzsize JEMALLOC_CC_SILENCE_INIT(0); @@ -1223,14 +1638,32 @@ ifree(void *ptr) if (config_prof && opt_prof) { usize = isalloc(ptr, config_prof); - prof_free(ptr, usize); + prof_free(tsd, ptr, usize); } else if (config_stats || config_valgrind) usize = isalloc(ptr, config_prof); if (config_stats) - thread_allocated_tsd_get()->deallocated += usize; - if (config_valgrind && opt_valgrind) + *tsd_thread_deallocatedp_get(tsd) += usize; + if (config_valgrind && unlikely(in_valgrind)) rzsize = p2rz(ptr); - iqalloc(ptr); + iqalloc(tsd, ptr, try_tcache); + JEMALLOC_VALGRIND_FREE(ptr, rzsize); +} + +JEMALLOC_INLINE_C void +isfree(tsd_t *tsd, void *ptr, size_t usize, bool try_tcache) +{ + UNUSED size_t rzsize JEMALLOC_CC_SILENCE_INIT(0); + + assert(ptr != NULL); + assert(malloc_initialized || IS_INITIALIZER); + + if (config_prof && opt_prof) + prof_free(tsd, ptr, usize); + if (config_stats) + *tsd_thread_deallocatedp_get(tsd) += usize; + if (config_valgrind && unlikely(in_valgrind)) + rzsize = p2rz(ptr); + isqalloc(tsd, ptr, usize, try_tcache); JEMALLOC_VALGRIND_FREE(ptr, rzsize); } @@ -1238,64 +1671,61 @@ void * je_realloc(void *ptr, size_t size) { void *ret; + tsd_t *tsd JEMALLOC_CC_SILENCE_INIT(NULL); size_t usize JEMALLOC_CC_SILENCE_INIT(0); size_t old_usize = 0; UNUSED size_t old_rzsize JEMALLOC_CC_SILENCE_INIT(0); - if (size == 0) { + if (unlikely(size == 0)) { if (ptr != NULL) { /* realloc(ptr, 0) is equivalent to free(ptr). */ UTRACE(ptr, 0, 0); - ifree(ptr); + tsd = tsd_fetch(); + ifree(tsd, ptr, true); return (NULL); } size = 1; } - if (ptr != NULL) { + if (likely(ptr != NULL)) { assert(malloc_initialized || IS_INITIALIZER); malloc_thread_init(); + tsd = tsd_fetch(); - if ((config_prof && opt_prof) || config_stats || - (config_valgrind && opt_valgrind)) - old_usize = isalloc(ptr, config_prof); - if (config_valgrind && opt_valgrind) + old_usize = isalloc(ptr, config_prof); + if (config_valgrind && unlikely(in_valgrind)) old_rzsize = config_prof ? p2rz(ptr) : u2rz(old_usize); if (config_prof && opt_prof) { - prof_thr_cnt_t *cnt; - usize = s2u(size); - PROF_ALLOC_PREP(1, usize, cnt); - ret = irealloc_prof(ptr, old_usize, usize, cnt); + ret = irealloc_prof(tsd, ptr, old_usize, usize); } else { - if (config_stats || (config_valgrind && opt_valgrind)) + if (config_stats || (config_valgrind && + unlikely(in_valgrind))) usize = s2u(size); - ret = iralloc(ptr, size, 0, 0, false); + ret = iralloc(tsd, ptr, old_usize, size, 0, false); } } else { /* realloc(NULL, size) is equivalent to malloc(size). */ - MALLOC_BODY(ret, size, usize); + ret = imalloc_body(size, &tsd, &usize); } - if (ret == NULL) { - if (config_xmalloc && opt_xmalloc) { + if (unlikely(ret == NULL)) { + if (config_xmalloc && unlikely(opt_xmalloc)) { malloc_write(": Error in realloc(): " "out of memory\n"); abort(); } set_errno(ENOMEM); } - if (config_stats && ret != NULL) { - thread_allocated_t *ta; + if (config_stats && likely(ret != NULL)) { assert(usize == isalloc(ret, config_prof)); - ta = thread_allocated_tsd_get(); - ta->allocated += usize; - ta->deallocated += old_usize; + *tsd_thread_allocatedp_get(tsd) += usize; + *tsd_thread_deallocatedp_get(tsd) += old_usize; } UTRACE(ptr, size, ret); - JEMALLOC_VALGRIND_REALLOC(ret, usize, ptr, old_usize, old_rzsize, - false); + JEMALLOC_VALGRIND_REALLOC(true, ret, usize, true, ptr, old_usize, + old_rzsize, true, false); return (ret); } @@ -1304,8 +1734,8 @@ je_free(void *ptr) { UTRACE(ptr, 0, 0); - if (ptr != NULL) - ifree(ptr); + if (likely(ptr != NULL)) + ifree(tsd_fetch(), ptr, true); } /* @@ -1346,7 +1776,7 @@ je_valloc(size_t size) #define is_malloc_(a) malloc_is_ ## a #define is_malloc(a) is_malloc_(a) -#if ((is_malloc(je_malloc) == 1) && defined(__GLIBC__) && !defined(__UCLIBC__)) +#if ((is_malloc(je_malloc) == 1) && defined(JEMALLOC_GLIBC_MALLOC_HOOK)) /* * glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible * to inconsistently reference libc's malloc(3)-compatible functions @@ -1356,11 +1786,13 @@ je_valloc(size_t size) * passed an extra argument for the caller return address, which will be * ignored. */ -JEMALLOC_EXPORT void (* __free_hook)(void *ptr) = je_free; -JEMALLOC_EXPORT void *(* __malloc_hook)(size_t size) = je_malloc; -JEMALLOC_EXPORT void *(* __realloc_hook)(void *ptr, size_t size) = je_realloc; -JEMALLOC_EXPORT void *(* __memalign_hook)(size_t alignment, size_t size) = +JEMALLOC_EXPORT void (*__free_hook)(void *ptr) = je_free; +JEMALLOC_EXPORT void *(*__malloc_hook)(size_t size) = je_malloc; +JEMALLOC_EXPORT void *(*__realloc_hook)(void *ptr, size_t size) = je_realloc; +# ifdef JEMALLOC_GLIBC_MEMALIGN_HOOK +JEMALLOC_EXPORT void *(*__memalign_hook)(size_t alignment, size_t size) = je_memalign; +# endif #endif /* @@ -1371,111 +1803,177 @@ JEMALLOC_EXPORT void *(* __memalign_hook)(size_t alignment, size_t size) = * Begin non-standard functions. */ -JEMALLOC_ALWAYS_INLINE_C void * -imallocx(size_t usize, size_t alignment, bool zero, bool try_tcache, - arena_t *arena) +JEMALLOC_ALWAYS_INLINE_C bool +imallocx_flags_decode_hard(tsd_t *tsd, size_t size, int flags, size_t *usize, + size_t *alignment, bool *zero, bool *try_tcache, arena_t **arena) { - assert(usize == ((alignment == 0) ? s2u(usize) : sa2u(usize, - alignment))); + if ((flags & MALLOCX_LG_ALIGN_MASK) == 0) { + *alignment = 0; + *usize = s2u(size); + } else { + *alignment = MALLOCX_ALIGN_GET_SPECIFIED(flags); + *usize = sa2u(size, *alignment); + } + *zero = MALLOCX_ZERO_GET(flags); + if ((flags & MALLOCX_ARENA_MASK) != 0) { + unsigned arena_ind = MALLOCX_ARENA_GET(flags); + *try_tcache = false; + *arena = arena_get(tsd, arena_ind, true, true); + if (unlikely(*arena == NULL)) + return (true); + } else { + *try_tcache = true; + *arena = NULL; + } + return (false); +} - if (alignment != 0) - return (ipalloct(usize, alignment, zero, try_tcache, arena)); - else if (zero) - return (icalloct(usize, try_tcache, arena)); - else - return (imalloct(usize, try_tcache, arena)); +JEMALLOC_ALWAYS_INLINE_C bool +imallocx_flags_decode(tsd_t *tsd, size_t size, int flags, size_t *usize, + size_t *alignment, bool *zero, bool *try_tcache, arena_t **arena) +{ + + if (likely(flags == 0)) { + *usize = s2u(size); + assert(usize != 0); + *alignment = 0; + *zero = false; + *try_tcache = true; + *arena = NULL; + return (false); + } else { + return (imallocx_flags_decode_hard(tsd, size, flags, usize, + alignment, zero, try_tcache, arena)); + } +} + +JEMALLOC_ALWAYS_INLINE_C void * +imallocx_flags(tsd_t *tsd, size_t usize, size_t alignment, bool zero, + bool try_tcache, arena_t *arena) +{ + + if (alignment != 0) { + return (ipalloct(tsd, usize, alignment, zero, try_tcache, + arena)); + } + if (zero) + return (icalloct(tsd, usize, try_tcache, arena)); + return (imalloct(tsd, usize, try_tcache, arena)); +} + +JEMALLOC_ALWAYS_INLINE_C void * +imallocx_maybe_flags(tsd_t *tsd, size_t size, int flags, size_t usize, + size_t alignment, bool zero, bool try_tcache, arena_t *arena) +{ + + if (likely(flags == 0)) + return (imalloc(tsd, size)); + return (imallocx_flags(tsd, usize, alignment, zero, try_tcache, arena)); } static void * -imallocx_prof_sample(size_t usize, size_t alignment, bool zero, bool try_tcache, - arena_t *arena, prof_thr_cnt_t *cnt) +imallocx_prof_sample(tsd_t *tsd, size_t size, int flags, size_t usize, + size_t alignment, bool zero, bool try_tcache, arena_t *arena) { void *p; - if (cnt == NULL) - return (NULL); - if (prof_promote && usize <= SMALL_MAXCLASS) { - size_t usize_promoted = (alignment == 0) ? - s2u(SMALL_MAXCLASS+1) : sa2u(SMALL_MAXCLASS+1, alignment); - assert(usize_promoted != 0); - p = imallocx(usize_promoted, alignment, zero, try_tcache, - arena); + if (usize <= SMALL_MAXCLASS) { + assert(((alignment == 0) ? s2u(LARGE_MINCLASS) : + sa2u(LARGE_MINCLASS, alignment)) == LARGE_MINCLASS); + p = imalloct(tsd, LARGE_MINCLASS, try_tcache, arena); if (p == NULL) return (NULL); arena_prof_promoted(p, usize); - } else - p = imallocx(usize, alignment, zero, try_tcache, arena); + } else { + p = imallocx_maybe_flags(tsd, size, flags, usize, alignment, + zero, try_tcache, arena); + } return (p); } JEMALLOC_ALWAYS_INLINE_C void * -imallocx_prof(size_t usize, size_t alignment, bool zero, bool try_tcache, - arena_t *arena, prof_thr_cnt_t *cnt) +imallocx_prof(tsd_t *tsd, size_t size, int flags, size_t *usize) { void *p; + size_t alignment; + bool zero; + bool try_tcache; + arena_t *arena; + prof_tctx_t *tctx; - if ((uintptr_t)cnt != (uintptr_t)1U) { - p = imallocx_prof_sample(usize, alignment, zero, try_tcache, - arena, cnt); - } else - p = imallocx(usize, alignment, zero, try_tcache, arena); - if (p == NULL) + if (unlikely(imallocx_flags_decode(tsd, size, flags, usize, &alignment, + &zero, &try_tcache, &arena))) return (NULL); - prof_malloc(p, usize, cnt); + tctx = prof_alloc_prep(tsd, *usize, true); + if (likely((uintptr_t)tctx == (uintptr_t)1U)) { + p = imallocx_maybe_flags(tsd, size, flags, *usize, alignment, + zero, try_tcache, arena); + } else if ((uintptr_t)tctx > (uintptr_t)1U) { + p = imallocx_prof_sample(tsd, size, flags, *usize, alignment, + zero, try_tcache, arena); + } else + p = NULL; + if (unlikely(p == NULL)) { + prof_alloc_rollback(tsd, tctx, true); + return (NULL); + } + prof_malloc(p, *usize, tctx); return (p); } +JEMALLOC_ALWAYS_INLINE_C void * +imallocx_no_prof(tsd_t *tsd, size_t size, int flags, size_t *usize) +{ + size_t alignment; + bool zero; + bool try_tcache; + arena_t *arena; + + if (likely(flags == 0)) { + if (config_stats || (config_valgrind && unlikely(in_valgrind))) + *usize = s2u(size); + return (imalloc(tsd, size)); + } + + if (unlikely(imallocx_flags_decode_hard(tsd, size, flags, usize, + &alignment, &zero, &try_tcache, &arena))) + return (NULL); + return (imallocx_flags(tsd, *usize, alignment, zero, try_tcache, + arena)); +} + void * je_mallocx(size_t size, int flags) { + tsd_t *tsd; void *p; size_t usize; - size_t alignment = (ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK) - & (SIZE_T_MAX-1)); - bool zero = flags & MALLOCX_ZERO; - unsigned arena_ind = ((unsigned)(flags >> 8)) - 1; - arena_t *arena; - bool try_tcache; assert(size != 0); - if (malloc_init()) + if (unlikely(malloc_init())) goto label_oom; + tsd = tsd_fetch(); - if (arena_ind != UINT_MAX) { - arena = arenas[arena_ind]; - try_tcache = false; - } else { - arena = NULL; - try_tcache = true; - } - - usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment); - assert(usize != 0); - - if (config_prof && opt_prof) { - prof_thr_cnt_t *cnt; - - PROF_ALLOC_PREP(1, usize, cnt); - p = imallocx_prof(usize, alignment, zero, try_tcache, arena, - cnt); - } else - p = imallocx(usize, alignment, zero, try_tcache, arena); - if (p == NULL) + if (config_prof && opt_prof) + p = imallocx_prof(tsd, size, flags, &usize); + else + p = imallocx_no_prof(tsd, size, flags, &usize); + if (unlikely(p == NULL)) goto label_oom; if (config_stats) { assert(usize == isalloc(p, config_prof)); - thread_allocated_tsd_get()->allocated += usize; + *tsd_thread_allocatedp_get(tsd) += usize; } UTRACE(0, size, p); - JEMALLOC_VALGRIND_MALLOC(true, p, usize, zero); + JEMALLOC_VALGRIND_MALLOC(true, p, usize, MALLOCX_ZERO_GET(flags)); return (p); label_oom: - if (config_xmalloc && opt_xmalloc) { + if (config_xmalloc && unlikely(opt_xmalloc)) { malloc_write(": Error in mallocx(): out of memory\n"); abort(); } @@ -1484,23 +1982,22 @@ label_oom: } static void * -irallocx_prof_sample(void *oldptr, size_t size, size_t alignment, size_t usize, - bool zero, bool try_tcache_alloc, bool try_tcache_dalloc, arena_t *arena, - prof_thr_cnt_t *cnt) +irallocx_prof_sample(tsd_t *tsd, void *oldptr, size_t old_usize, size_t size, + size_t alignment, size_t usize, bool zero, bool try_tcache_alloc, + bool try_tcache_dalloc, arena_t *arena, prof_tctx_t *tctx) { void *p; - if (cnt == NULL) + if (tctx == NULL) return (NULL); - if (prof_promote && usize <= SMALL_MAXCLASS) { - p = iralloct(oldptr, SMALL_MAXCLASS+1, (SMALL_MAXCLASS+1 >= - size) ? 0 : size - (SMALL_MAXCLASS+1), alignment, zero, - try_tcache_alloc, try_tcache_dalloc, arena); + if (usize <= SMALL_MAXCLASS) { + p = iralloct(tsd, oldptr, old_usize, LARGE_MINCLASS, alignment, + zero, try_tcache_alloc, try_tcache_dalloc, arena); if (p == NULL) return (NULL); arena_prof_promoted(p, usize); } else { - p = iralloct(oldptr, size, 0, alignment, zero, + p = iralloct(tsd, oldptr, old_usize, size, alignment, zero, try_tcache_alloc, try_tcache_dalloc, arena); } @@ -1508,23 +2005,27 @@ irallocx_prof_sample(void *oldptr, size_t size, size_t alignment, size_t usize, } JEMALLOC_ALWAYS_INLINE_C void * -irallocx_prof(void *oldptr, size_t old_usize, size_t size, size_t alignment, - size_t *usize, bool zero, bool try_tcache_alloc, bool try_tcache_dalloc, - arena_t *arena, prof_thr_cnt_t *cnt) +irallocx_prof(tsd_t *tsd, void *oldptr, size_t old_usize, size_t size, + size_t alignment, size_t *usize, bool zero, bool try_tcache_alloc, + bool try_tcache_dalloc, arena_t *arena) { void *p; - prof_ctx_t *old_ctx; + prof_tctx_t *old_tctx, *tctx; - old_ctx = prof_ctx_get(oldptr); - if ((uintptr_t)cnt != (uintptr_t)1U) - p = irallocx_prof_sample(oldptr, size, alignment, *usize, zero, - try_tcache_alloc, try_tcache_dalloc, arena, cnt); - else { - p = iralloct(oldptr, size, 0, alignment, zero, + old_tctx = prof_tctx_get(oldptr); + tctx = prof_alloc_prep(tsd, *usize, false); + if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { + p = irallocx_prof_sample(tsd, oldptr, old_usize, size, + alignment, *usize, zero, try_tcache_alloc, + try_tcache_dalloc, arena, tctx); + } else { + p = iralloct(tsd, oldptr, old_usize, size, alignment, zero, try_tcache_alloc, try_tcache_dalloc, arena); } - if (p == NULL) + if (unlikely(p == NULL)) { + prof_alloc_rollback(tsd, tctx, false); return (NULL); + } if (p == oldptr && alignment != 0) { /* @@ -1537,7 +2038,7 @@ irallocx_prof(void *oldptr, size_t old_usize, size_t size, size_t alignment, */ *usize = isalloc(p, config_prof); } - prof_realloc(p, *usize, cnt, old_usize, old_ctx); + prof_realloc(tsd, p, *usize, tctx, false, old_usize, old_tctx); return (p); } @@ -1546,12 +2047,12 @@ void * je_rallocx(void *ptr, size_t size, int flags) { void *p; - size_t usize, old_usize; + tsd_t *tsd; + size_t usize; + size_t old_usize; UNUSED size_t old_rzsize JEMALLOC_CC_SILENCE_INIT(0); - size_t alignment = (ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK) - & (SIZE_T_MAX-1)); + size_t alignment = MALLOCX_ALIGN_GET(flags); bool zero = flags & MALLOCX_ZERO; - unsigned arena_ind = ((unsigned)(flags >> 8)) - 1; bool try_tcache_alloc, try_tcache_dalloc; arena_t *arena; @@ -1559,56 +2060,53 @@ je_rallocx(void *ptr, size_t size, int flags) assert(size != 0); assert(malloc_initialized || IS_INITIALIZER); malloc_thread_init(); + tsd = tsd_fetch(); - if (arena_ind != UINT_MAX) { + if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) { + unsigned arena_ind = MALLOCX_ARENA_GET(flags); arena_chunk_t *chunk; try_tcache_alloc = false; chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - try_tcache_dalloc = (chunk == ptr || chunk->arena != - arenas[arena_ind]); - arena = arenas[arena_ind]; + arena = arena_get(tsd, arena_ind, true, true); + if (unlikely(arena == NULL)) + goto label_oom; + try_tcache_dalloc = (chunk == ptr || chunk->arena != arena); } else { try_tcache_alloc = true; try_tcache_dalloc = true; arena = NULL; } - if ((config_prof && opt_prof) || config_stats || - (config_valgrind && opt_valgrind)) - old_usize = isalloc(ptr, config_prof); - if (config_valgrind && opt_valgrind) + old_usize = isalloc(ptr, config_prof); + if (config_valgrind && unlikely(in_valgrind)) old_rzsize = u2rz(old_usize); if (config_prof && opt_prof) { - prof_thr_cnt_t *cnt; - usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment); assert(usize != 0); - PROF_ALLOC_PREP(1, usize, cnt); - p = irallocx_prof(ptr, old_usize, size, alignment, &usize, zero, - try_tcache_alloc, try_tcache_dalloc, arena, cnt); - if (p == NULL) + p = irallocx_prof(tsd, ptr, old_usize, size, alignment, &usize, + zero, try_tcache_alloc, try_tcache_dalloc, arena); + if (unlikely(p == NULL)) goto label_oom; } else { - p = iralloct(ptr, size, 0, alignment, zero, try_tcache_alloc, - try_tcache_dalloc, arena); - if (p == NULL) + p = iralloct(tsd, ptr, old_usize, size, alignment, zero, + try_tcache_alloc, try_tcache_dalloc, arena); + if (unlikely(p == NULL)) goto label_oom; - if (config_stats || (config_valgrind && opt_valgrind)) + if (config_stats || (config_valgrind && unlikely(in_valgrind))) usize = isalloc(p, config_prof); } if (config_stats) { - thread_allocated_t *ta; - ta = thread_allocated_tsd_get(); - ta->allocated += usize; - ta->deallocated += old_usize; + *tsd_thread_allocatedp_get(tsd) += usize; + *tsd_thread_deallocatedp_get(tsd) += old_usize; } UTRACE(ptr, size, p); - JEMALLOC_VALGRIND_REALLOC(p, usize, ptr, old_usize, old_rzsize, zero); + JEMALLOC_VALGRIND_REALLOC(true, p, usize, false, ptr, old_usize, + old_rzsize, false, zero); return (p); label_oom: - if (config_xmalloc && opt_xmalloc) { + if (config_xmalloc && unlikely(opt_xmalloc)) { malloc_write(": Error in rallocx(): out of memory\n"); abort(); } @@ -1618,11 +2116,11 @@ label_oom: JEMALLOC_ALWAYS_INLINE_C size_t ixallocx_helper(void *ptr, size_t old_usize, size_t size, size_t extra, - size_t alignment, bool zero, arena_t *arena) + size_t alignment, bool zero) { size_t usize; - if (ixalloc(ptr, size, extra, alignment, zero)) + if (ixalloc(ptr, old_usize, size, extra, alignment, zero)) return (old_usize); usize = isalloc(ptr, config_prof); @@ -1631,50 +2129,59 @@ ixallocx_helper(void *ptr, size_t old_usize, size_t size, size_t extra, static size_t ixallocx_prof_sample(void *ptr, size_t old_usize, size_t size, size_t extra, - size_t alignment, size_t max_usize, bool zero, arena_t *arena, - prof_thr_cnt_t *cnt) + size_t alignment, size_t max_usize, bool zero, prof_tctx_t *tctx) { size_t usize; - if (cnt == NULL) + if (tctx == NULL) return (old_usize); /* Use minimum usize to determine whether promotion may happen. */ - if (prof_promote && ((alignment == 0) ? s2u(size) : sa2u(size, - alignment)) <= SMALL_MAXCLASS) { - if (ixalloc(ptr, SMALL_MAXCLASS+1, (SMALL_MAXCLASS+1 >= - size+extra) ? 0 : size+extra - (SMALL_MAXCLASS+1), - alignment, zero)) + if (((alignment == 0) ? s2u(size) : sa2u(size, alignment)) <= + SMALL_MAXCLASS) { + if (ixalloc(ptr, old_usize, SMALL_MAXCLASS+1, + (SMALL_MAXCLASS+1 >= size+extra) ? 0 : size+extra - + (SMALL_MAXCLASS+1), alignment, zero)) return (old_usize); usize = isalloc(ptr, config_prof); - if (max_usize < PAGE) + if (max_usize < LARGE_MINCLASS) arena_prof_promoted(ptr, usize); } else { usize = ixallocx_helper(ptr, old_usize, size, extra, alignment, - zero, arena); + zero); } return (usize); } JEMALLOC_ALWAYS_INLINE_C size_t -ixallocx_prof(void *ptr, size_t old_usize, size_t size, size_t extra, - size_t alignment, size_t max_usize, bool zero, arena_t *arena, - prof_thr_cnt_t *cnt) +ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size, + size_t extra, size_t alignment, bool zero) { - size_t usize; - prof_ctx_t *old_ctx; + size_t max_usize, usize; + prof_tctx_t *old_tctx, *tctx; - old_ctx = prof_ctx_get(ptr); - if ((uintptr_t)cnt != (uintptr_t)1U) { + old_tctx = prof_tctx_get(ptr); + /* + * usize isn't knowable before ixalloc() returns when extra is non-zero. + * Therefore, compute its maximum possible value and use that in + * prof_alloc_prep() to decide whether to capture a backtrace. + * prof_realloc() will use the actual usize to decide whether to sample. + */ + max_usize = (alignment == 0) ? s2u(size+extra) : sa2u(size+extra, + alignment); + tctx = prof_alloc_prep(tsd, max_usize, false); + if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { usize = ixallocx_prof_sample(ptr, old_usize, size, extra, - alignment, zero, max_usize, arena, cnt); + alignment, zero, max_usize, tctx); } else { usize = ixallocx_helper(ptr, old_usize, size, extra, alignment, - zero, arena); + zero); } - if (usize == old_usize) + if (unlikely(usize == old_usize)) { + prof_alloc_rollback(tsd, tctx, false); return (usize); - prof_realloc(ptr, usize, cnt, old_usize, old_ctx); + } + prof_realloc(tsd, ptr, usize, tctx, false, old_usize, old_tctx); return (usize); } @@ -1682,57 +2189,39 @@ ixallocx_prof(void *ptr, size_t old_usize, size_t size, size_t extra, size_t je_xallocx(void *ptr, size_t size, size_t extra, int flags) { + tsd_t *tsd; size_t usize, old_usize; UNUSED size_t old_rzsize JEMALLOC_CC_SILENCE_INIT(0); - size_t alignment = (ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK) - & (SIZE_T_MAX-1)); + size_t alignment = MALLOCX_ALIGN_GET(flags); bool zero = flags & MALLOCX_ZERO; - unsigned arena_ind = ((unsigned)(flags >> 8)) - 1; - arena_t *arena; assert(ptr != NULL); assert(size != 0); assert(SIZE_T_MAX - size >= extra); assert(malloc_initialized || IS_INITIALIZER); malloc_thread_init(); - - if (arena_ind != UINT_MAX) - arena = arenas[arena_ind]; - else - arena = NULL; + tsd = tsd_fetch(); old_usize = isalloc(ptr, config_prof); - if (config_valgrind && opt_valgrind) + if (config_valgrind && unlikely(in_valgrind)) old_rzsize = u2rz(old_usize); if (config_prof && opt_prof) { - prof_thr_cnt_t *cnt; - /* - * usize isn't knowable before ixalloc() returns when extra is - * non-zero. Therefore, compute its maximum possible value and - * use that in PROF_ALLOC_PREP() to decide whether to capture a - * backtrace. prof_realloc() will use the actual usize to - * decide whether to sample. - */ - size_t max_usize = (alignment == 0) ? s2u(size+extra) : - sa2u(size+extra, alignment); - PROF_ALLOC_PREP(1, max_usize, cnt); - usize = ixallocx_prof(ptr, old_usize, size, extra, alignment, - max_usize, zero, arena, cnt); + usize = ixallocx_prof(tsd, ptr, old_usize, size, extra, + alignment, zero); } else { usize = ixallocx_helper(ptr, old_usize, size, extra, alignment, - zero, arena); + zero); } - if (usize == old_usize) + if (unlikely(usize == old_usize)) goto label_not_resized; if (config_stats) { - thread_allocated_t *ta; - ta = thread_allocated_tsd_get(); - ta->allocated += usize; - ta->deallocated += old_usize; + *tsd_thread_allocatedp_get(tsd) += usize; + *tsd_thread_deallocatedp_get(tsd) += old_usize; } - JEMALLOC_VALGRIND_REALLOC(ptr, usize, ptr, old_usize, old_rzsize, zero); + JEMALLOC_VALGRIND_REALLOC(false, ptr, usize, false, ptr, old_usize, + old_rzsize, false, zero); label_not_resized: UTRACE(ptr, size, ptr); return (usize); @@ -1759,52 +2248,84 @@ je_sallocx(const void *ptr, int flags) void je_dallocx(void *ptr, int flags) { - size_t usize; - UNUSED size_t rzsize JEMALLOC_CC_SILENCE_INIT(0); - unsigned arena_ind = ((unsigned)(flags >> 8)) - 1; + tsd_t *tsd; bool try_tcache; assert(ptr != NULL); assert(malloc_initialized || IS_INITIALIZER); - if (arena_ind != UINT_MAX) { + tsd = tsd_fetch(); + if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) { + unsigned arena_ind = MALLOCX_ARENA_GET(flags); arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - try_tcache = (chunk == ptr || chunk->arena != - arenas[arena_ind]); + arena_t *arena = arena_get(tsd, arena_ind, true, true); + /* + * If arena is NULL, the application passed an arena that has + * never been used before, which is unsupported during + * deallocation. + */ + assert(arena != NULL); + try_tcache = (chunk == ptr || chunk->arena != arena); } else try_tcache = true; UTRACE(ptr, 0, 0); - if (config_stats || config_valgrind) - usize = isalloc(ptr, config_prof); - if (config_prof && opt_prof) { - if (config_stats == false && config_valgrind == false) - usize = isalloc(ptr, config_prof); - prof_free(ptr, usize); - } - if (config_stats) - thread_allocated_tsd_get()->deallocated += usize; - if (config_valgrind && opt_valgrind) - rzsize = p2rz(ptr); - iqalloct(ptr, try_tcache); - JEMALLOC_VALGRIND_FREE(ptr, rzsize); + ifree(tsd_fetch(), ptr, try_tcache); +} + +JEMALLOC_ALWAYS_INLINE_C size_t +inallocx(size_t size, int flags) +{ + size_t usize; + + if (likely((flags & MALLOCX_LG_ALIGN_MASK) == 0)) + usize = s2u(size); + else + usize = sa2u(size, MALLOCX_ALIGN_GET_SPECIFIED(flags)); + assert(usize != 0); + return (usize); +} + +void +je_sdallocx(void *ptr, size_t size, int flags) +{ + tsd_t *tsd; + bool try_tcache; + size_t usize; + + assert(ptr != NULL); + assert(malloc_initialized || IS_INITIALIZER); + usize = inallocx(size, flags); + assert(usize == isalloc(ptr, config_prof)); + + tsd = tsd_fetch(); + if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) { + unsigned arena_ind = MALLOCX_ARENA_GET(flags); + arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + arena_t *arena = arena_get(tsd, arena_ind, true, true); + /* + * If arena is NULL, the application passed an arena that has + * never been used before, which is unsupported during + * deallocation. + */ + try_tcache = (chunk == ptr || chunk->arena != arena); + } else + try_tcache = true; + + UTRACE(ptr, 0, 0); + isfree(tsd, ptr, usize, try_tcache); } size_t je_nallocx(size_t size, int flags) { - size_t usize; - size_t alignment = (ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK) - & (SIZE_T_MAX-1)); assert(size != 0); - if (malloc_init()) + if (unlikely(malloc_init())) return (0); - usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment); - assert(usize != 0); - return (usize); + return (inallocx(size, flags)); } int @@ -1812,7 +2333,7 @@ je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { - if (malloc_init()) + if (unlikely(malloc_init())) return (EAGAIN); return (ctl_byname(name, oldp, oldlenp, newp, newlen)); @@ -1822,7 +2343,7 @@ int je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp) { - if (malloc_init()) + if (unlikely(malloc_init())) return (EAGAIN); return (ctl_nametomib(name, mibp, miblenp)); @@ -1833,7 +2354,7 @@ je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { - if (malloc_init()) + if (unlikely(malloc_init())) return (EAGAIN); return (ctl_bymib(mib, miblen, oldp, oldlenp, newp, newlen)); @@ -1867,91 +2388,6 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) * End non-standard functions. */ /******************************************************************************/ -/* - * Begin experimental functions. - */ -#ifdef JEMALLOC_EXPERIMENTAL - -int -je_allocm(void **ptr, size_t *rsize, size_t size, int flags) -{ - void *p; - - assert(ptr != NULL); - - p = je_mallocx(size, flags); - if (p == NULL) - return (ALLOCM_ERR_OOM); - if (rsize != NULL) - *rsize = isalloc(p, config_prof); - *ptr = p; - return (ALLOCM_SUCCESS); -} - -int -je_rallocm(void **ptr, size_t *rsize, size_t size, size_t extra, int flags) -{ - int ret; - bool no_move = flags & ALLOCM_NO_MOVE; - - assert(ptr != NULL); - assert(*ptr != NULL); - assert(size != 0); - assert(SIZE_T_MAX - size >= extra); - - if (no_move) { - size_t usize = je_xallocx(*ptr, size, extra, flags); - ret = (usize >= size) ? ALLOCM_SUCCESS : ALLOCM_ERR_NOT_MOVED; - if (rsize != NULL) - *rsize = usize; - } else { - void *p = je_rallocx(*ptr, size+extra, flags); - if (p != NULL) { - *ptr = p; - ret = ALLOCM_SUCCESS; - } else - ret = ALLOCM_ERR_OOM; - if (rsize != NULL) - *rsize = isalloc(*ptr, config_prof); - } - return (ret); -} - -int -je_sallocm(const void *ptr, size_t *rsize, int flags) -{ - - assert(rsize != NULL); - *rsize = je_sallocx(ptr, flags); - return (ALLOCM_SUCCESS); -} - -int -je_dallocm(void *ptr, int flags) -{ - - je_dallocx(ptr, flags); - return (ALLOCM_SUCCESS); -} - -int -je_nallocm(size_t *rsize, size_t size, int flags) -{ - size_t usize; - - usize = je_nallocx(size, flags); - if (usize == 0) - return (ALLOCM_ERR_OOM); - if (rsize != NULL) - *rsize = usize; - return (ALLOCM_SUCCESS); -} - -#endif -/* - * End experimental functions. - */ -/******************************************************************************/ /* * The following functions are used by threading libraries for protection of * malloc during fork(). @@ -1966,9 +2402,9 @@ je_nallocm(size_t *rsize, size_t size, int flags) * fork/malloc races via the following functions it registers during * initialization using pthread_atfork(), but of course that does no good if * the allocator isn't fully initialized at fork time. The following library - * constructor is a partial solution to this problem. It may still possible to - * trigger the deadlock described above, but doing so would involve forking via - * a library constructor that runs before jemalloc's runs. + * constructor is a partial solution to this problem. It may still be possible + * to trigger the deadlock described above, but doing so would involve forking + * via a library constructor that runs before jemalloc's runs. */ JEMALLOC_ATTR(constructor) static void @@ -1989,7 +2425,7 @@ _malloc_prefork(void) unsigned i; #ifdef JEMALLOC_MUTEX_INIT_CB - if (malloc_initialized == false) + if (!malloc_initialized) return; #endif assert(malloc_initialized); @@ -2018,7 +2454,7 @@ _malloc_postfork(void) unsigned i; #ifdef JEMALLOC_MUTEX_INIT_CB - if (malloc_initialized == false) + if (!malloc_initialized) return; #endif assert(malloc_initialized); @@ -2057,55 +2493,3 @@ jemalloc_postfork_child(void) } /******************************************************************************/ -/* - * The following functions are used for TLS allocation/deallocation in static - * binaries on FreeBSD. The primary difference between these and i[mcd]alloc() - * is that these avoid accessing TLS variables. - */ - -static void * -a0alloc(size_t size, bool zero) -{ - - if (malloc_init()) - return (NULL); - - if (size == 0) - size = 1; - - if (size <= arena_maxclass) - return (arena_malloc(arenas[0], size, zero, false)); - else - return (huge_malloc(size, zero, huge_dss_prec_get(arenas[0]))); -} - -void * -a0malloc(size_t size) -{ - - return (a0alloc(size, false)); -} - -void * -a0calloc(size_t num, size_t size) -{ - - return (a0alloc(num * size, true)); -} - -void -a0free(void *ptr) -{ - arena_chunk_t *chunk; - - if (ptr == NULL) - return; - - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (chunk != ptr) - arena_dalloc(chunk->arena, chunk, ptr, false); - else - huge_dalloc(ptr, true); -} - -/******************************************************************************/ diff --git a/memory/jemalloc/src/src/prof.c b/memory/jemalloc/src/src/prof.c index a51e3b1ecddd..1103cc94020a 100644 --- a/memory/jemalloc/src/src/prof.c +++ b/memory/jemalloc/src/src/prof.c @@ -14,14 +14,13 @@ /******************************************************************************/ /* Data. */ -malloc_tsd_data(, prof_tdata, prof_tdata_t *, NULL) - bool opt_prof = false; bool opt_prof_active = true; +bool opt_prof_thread_active_init = true; size_t opt_lg_prof_sample = LG_PROF_SAMPLE_DEFAULT; ssize_t opt_lg_prof_interval = LG_PROF_INTERVAL_DEFAULT; bool opt_prof_gdump = false; -bool opt_prof_final = true; +bool opt_prof_final = false; bool opt_prof_leak = false; bool opt_prof_accum = false; char opt_prof_prefix[ @@ -31,25 +30,58 @@ char opt_prof_prefix[ #endif 1]; -uint64_t prof_interval = 0; -bool prof_promote; +/* + * Initialized as opt_prof_active, and accessed via + * prof_active_[gs]et{_unlocked,}(). + */ +bool prof_active; +static malloc_mutex_t prof_active_mtx; /* - * Table of mutexes that are shared among ctx's. These are leaf locks, so - * there is no problem with using them for more than one ctx at the same time. - * The primary motivation for this sharing though is that ctx's are ephemeral, + * Initialized as opt_prof_thread_active_init, and accessed via + * prof_thread_active_init_[gs]et(). + */ +static bool prof_thread_active_init; +static malloc_mutex_t prof_thread_active_init_mtx; + +uint64_t prof_interval = 0; + +size_t lg_prof_sample; + +/* + * Table of mutexes that are shared among gctx's. These are leaf locks, so + * there is no problem with using them for more than one gctx at the same time. + * The primary motivation for this sharing though is that gctx's are ephemeral, * and destroying mutexes causes complications for systems that allocate when * creating/destroying mutexes. */ -static malloc_mutex_t *ctx_locks; -static unsigned cum_ctxs; /* Atomic counter. */ +static malloc_mutex_t *gctx_locks; +static unsigned cum_gctxs; /* Atomic counter. */ /* - * Global hash of (prof_bt_t *)-->(prof_ctx_t *). This is the master data + * Table of mutexes that are shared among tdata's. No operations require + * holding multiple tdata locks, so there is no problem with using them for more + * than one tdata at the same time, even though a gctx lock may be acquired + * while holding a tdata lock. + */ +static malloc_mutex_t *tdata_locks; + +/* + * Global hash of (prof_bt_t *)-->(prof_gctx_t *). This is the master data * structure that knows about all backtraces currently captured. */ -static ckh_t bt2ctx; -static malloc_mutex_t bt2ctx_mtx; +static ckh_t bt2gctx; +static malloc_mutex_t bt2gctx_mtx; + +/* + * Tree of all extant prof_tdata_t structures, regardless of state, + * {attached,detached,expired}. + */ +static prof_tdata_tree_t tdatas; +static malloc_mutex_t tdatas_mtx; + +static uint64_t next_thr_uid; +static malloc_mutex_t next_thr_uid_mtx; static malloc_mutex_t prof_dump_seq_mtx; static uint64_t prof_dump_seq; @@ -77,6 +109,132 @@ static int prof_dump_fd; static bool prof_booted = false; /******************************************************************************/ +/* + * Function prototypes for static functions that are referenced prior to + * definition. + */ + +static bool prof_tctx_should_destroy(prof_tctx_t *tctx); +static void prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx); +static bool prof_tdata_should_destroy(prof_tdata_t *tdata, + bool even_if_attached); +static void prof_tdata_destroy(tsd_t *tsd, prof_tdata_t *tdata, + bool even_if_attached); +static char *prof_thread_name_alloc(tsd_t *tsd, const char *thread_name); + +/******************************************************************************/ +/* Red-black trees. */ + +JEMALLOC_INLINE_C int +prof_tctx_comp(const prof_tctx_t *a, const prof_tctx_t *b) +{ + uint64_t a_uid = a->thr_uid; + uint64_t b_uid = b->thr_uid; + + return ((a_uid > b_uid) - (a_uid < b_uid)); +} + +rb_gen(static UNUSED, tctx_tree_, prof_tctx_tree_t, prof_tctx_t, + tctx_link, prof_tctx_comp) + +JEMALLOC_INLINE_C int +prof_gctx_comp(const prof_gctx_t *a, const prof_gctx_t *b) +{ + unsigned a_len = a->bt.len; + unsigned b_len = b->bt.len; + unsigned comp_len = (a_len < b_len) ? a_len : b_len; + int ret = memcmp(a->bt.vec, b->bt.vec, comp_len * sizeof(void *)); + if (ret == 0) + ret = (a_len > b_len) - (a_len < b_len); + return (ret); +} + +rb_gen(static UNUSED, gctx_tree_, prof_gctx_tree_t, prof_gctx_t, dump_link, + prof_gctx_comp) + +JEMALLOC_INLINE_C int +prof_tdata_comp(const prof_tdata_t *a, const prof_tdata_t *b) +{ + int ret; + uint64_t a_uid = a->thr_uid; + uint64_t b_uid = b->thr_uid; + + ret = ((a_uid > b_uid) - (a_uid < b_uid)); + if (ret == 0) { + uint64_t a_discrim = a->thr_discrim; + uint64_t b_discrim = b->thr_discrim; + + ret = ((a_discrim > b_discrim) - (a_discrim < b_discrim)); + } + return (ret); +} + +rb_gen(static UNUSED, tdata_tree_, prof_tdata_tree_t, prof_tdata_t, tdata_link, + prof_tdata_comp) + +/******************************************************************************/ + +void +prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated) +{ + prof_tdata_t *tdata; + + cassert(config_prof); + + if (updated) { + /* + * Compute a new sample threshold. This isn't very important in + * practice, because this function is rarely executed, so the + * potential for sample bias is minimal except in contrived + * programs. + */ + tdata = prof_tdata_get(tsd, true); + if (tdata != NULL) + prof_sample_threshold_update(tctx->tdata); + } + + if ((uintptr_t)tctx > (uintptr_t)1U) { + malloc_mutex_lock(tctx->tdata->lock); + tctx->prepared = false; + if (prof_tctx_should_destroy(tctx)) + prof_tctx_destroy(tsd, tctx); + else + malloc_mutex_unlock(tctx->tdata->lock); + } +} + +void +prof_malloc_sample_object(const void *ptr, size_t usize, prof_tctx_t *tctx) +{ + + prof_tctx_set(ptr, tctx); + + malloc_mutex_lock(tctx->tdata->lock); + tctx->cnts.curobjs++; + tctx->cnts.curbytes += usize; + if (opt_prof_accum) { + tctx->cnts.accumobjs++; + tctx->cnts.accumbytes += usize; + } + tctx->prepared = false; + malloc_mutex_unlock(tctx->tdata->lock); +} + +void +prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx) +{ + + malloc_mutex_lock(tctx->tdata->lock); + assert(tctx->cnts.curobjs > 0); + assert(tctx->cnts.curbytes >= usize); + tctx->cnts.curobjs--; + tctx->cnts.curbytes -= usize; + + if (prof_tctx_should_destroy(tctx)) + prof_tctx_destroy(tsd, tctx); + else + malloc_mutex_unlock(tctx->tdata->lock); +} void bt_init(prof_bt_t *bt, void **vec) @@ -88,109 +246,61 @@ bt_init(prof_bt_t *bt, void **vec) bt->len = 0; } -static void -bt_destroy(prof_bt_t *bt) +JEMALLOC_INLINE_C void +prof_enter(tsd_t *tsd, prof_tdata_t *tdata) { cassert(config_prof); + assert(tdata == prof_tdata_get(tsd, false)); - idalloc(bt); + if (tdata != NULL) { + assert(!tdata->enq); + tdata->enq = true; + } + + malloc_mutex_lock(&bt2gctx_mtx); } -static prof_bt_t * -bt_dup(prof_bt_t *bt) -{ - prof_bt_t *ret; - - cassert(config_prof); - - /* - * Create a single allocation that has space for vec immediately - * following the prof_bt_t structure. The backtraces that get - * stored in the backtrace caches are copied from stack-allocated - * temporary variables, so size is known at creation time. Making this - * a contiguous object improves cache locality. - */ - ret = (prof_bt_t *)imalloc(QUANTUM_CEILING(sizeof(prof_bt_t)) + - (bt->len * sizeof(void *))); - if (ret == NULL) - return (NULL); - ret->vec = (void **)((uintptr_t)ret + - QUANTUM_CEILING(sizeof(prof_bt_t))); - memcpy(ret->vec, bt->vec, bt->len * sizeof(void *)); - ret->len = bt->len; - - return (ret); -} - -static inline void -prof_enter(prof_tdata_t *prof_tdata) +JEMALLOC_INLINE_C void +prof_leave(tsd_t *tsd, prof_tdata_t *tdata) { cassert(config_prof); + assert(tdata == prof_tdata_get(tsd, false)); - assert(prof_tdata->enq == false); - prof_tdata->enq = true; + malloc_mutex_unlock(&bt2gctx_mtx); - malloc_mutex_lock(&bt2ctx_mtx); -} + if (tdata != NULL) { + bool idump, gdump; -static inline void -prof_leave(prof_tdata_t *prof_tdata) -{ - bool idump, gdump; + assert(tdata->enq); + tdata->enq = false; + idump = tdata->enq_idump; + tdata->enq_idump = false; + gdump = tdata->enq_gdump; + tdata->enq_gdump = false; - cassert(config_prof); - - malloc_mutex_unlock(&bt2ctx_mtx); - - assert(prof_tdata->enq); - prof_tdata->enq = false; - idump = prof_tdata->enq_idump; - prof_tdata->enq_idump = false; - gdump = prof_tdata->enq_gdump; - prof_tdata->enq_gdump = false; - - if (idump) - prof_idump(); - if (gdump) - prof_gdump(); + if (idump) + prof_idump(); + if (gdump) + prof_gdump(); + } } #ifdef JEMALLOC_PROF_LIBUNWIND void -prof_backtrace(prof_bt_t *bt, unsigned nignore) +prof_backtrace(prof_bt_t *bt) { - unw_context_t uc; - unw_cursor_t cursor; - unsigned i; - int err; + int nframes; cassert(config_prof); assert(bt->len == 0); assert(bt->vec != NULL); - unw_getcontext(&uc); - unw_init_local(&cursor, &uc); - - /* Throw away (nignore+1) stack frames, if that many exist. */ - for (i = 0; i < nignore + 1; i++) { - err = unw_step(&cursor); - if (err <= 0) - return; - } - - /* - * Iterate over stack frames until there are no more, or until no space - * remains in bt. - */ - for (i = 0; i < PROF_BT_MAX; i++) { - unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *)&bt->vec[i]); - bt->len++; - err = unw_step(&cursor); - if (err <= 0) - break; - } + nframes = unw_backtrace(bt->vec, PROF_BT_MAX); + if (nframes <= 0) + return; + bt->len = nframes; } #elif (defined(JEMALLOC_PROF_LIBGCC)) static _Unwind_Reason_Code @@ -206,25 +316,25 @@ static _Unwind_Reason_Code prof_unwind_callback(struct _Unwind_Context *context, void *arg) { prof_unwind_data_t *data = (prof_unwind_data_t *)arg; + void *ip; cassert(config_prof); - if (data->nignore > 0) - data->nignore--; - else { - data->bt->vec[data->bt->len] = (void *)_Unwind_GetIP(context); - data->bt->len++; - if (data->bt->len == data->max) - return (_URC_END_OF_STACK); - } + ip = (void *)_Unwind_GetIP(context); + if (ip == NULL) + return (_URC_END_OF_STACK); + data->bt->vec[data->bt->len] = ip; + data->bt->len++; + if (data->bt->len == data->max) + return (_URC_END_OF_STACK); return (_URC_NO_REASON); } void -prof_backtrace(prof_bt_t *bt, unsigned nignore) +prof_backtrace(prof_bt_t *bt) { - prof_unwind_data_t data = {bt, nignore, PROF_BT_MAX}; + prof_unwind_data_t data = {bt, PROF_BT_MAX}; cassert(config_prof); @@ -232,25 +342,22 @@ prof_backtrace(prof_bt_t *bt, unsigned nignore) } #elif (defined(JEMALLOC_PROF_GCC)) void -prof_backtrace(prof_bt_t *bt, unsigned nignore) +prof_backtrace(prof_bt_t *bt) { #define BT_FRAME(i) \ - if ((i) < nignore + PROF_BT_MAX) { \ + if ((i) < PROF_BT_MAX) { \ void *p; \ if (__builtin_frame_address(i) == 0) \ return; \ p = __builtin_return_address(i); \ if (p == NULL) \ return; \ - if (i >= nignore) { \ - bt->vec[(i) - nignore] = p; \ - bt->len = (i) - nignore + 1; \ - } \ + bt->vec[(i)] = p; \ + bt->len = (i) + 1; \ } else \ return; cassert(config_prof); - assert(nignore <= 3); BT_FRAME(0) BT_FRAME(1) @@ -392,16 +499,11 @@ prof_backtrace(prof_bt_t *bt, unsigned nignore) BT_FRAME(125) BT_FRAME(126) BT_FRAME(127) - - /* Extras to compensate for nignore. */ - BT_FRAME(128) - BT_FRAME(129) - BT_FRAME(130) #undef BT_FRAME } #else void -prof_backtrace(prof_bt_t *bt, unsigned nignore) +prof_backtrace(prof_bt_t *bt) { cassert(config_prof); @@ -410,256 +512,381 @@ prof_backtrace(prof_bt_t *bt, unsigned nignore) #endif static malloc_mutex_t * -prof_ctx_mutex_choose(void) +prof_gctx_mutex_choose(void) { - unsigned nctxs = atomic_add_u(&cum_ctxs, 1); + unsigned ngctxs = atomic_add_u(&cum_gctxs, 1); - return (&ctx_locks[(nctxs - 1) % PROF_NCTX_LOCKS]); + return (&gctx_locks[(ngctxs - 1) % PROF_NCTX_LOCKS]); } -static void -prof_ctx_init(prof_ctx_t *ctx, prof_bt_t *bt) +static malloc_mutex_t * +prof_tdata_mutex_choose(uint64_t thr_uid) { - ctx->bt = bt; - ctx->lock = prof_ctx_mutex_choose(); + return (&tdata_locks[thr_uid % PROF_NTDATA_LOCKS]); +} + +static prof_gctx_t * +prof_gctx_create(tsd_t *tsd, prof_bt_t *bt) +{ + /* + * Create a single allocation that has space for vec of length bt->len. + */ + prof_gctx_t *gctx = (prof_gctx_t *)imalloc(tsd, offsetof(prof_gctx_t, + vec) + (bt->len * sizeof(void *))); + if (gctx == NULL) + return (NULL); + gctx->lock = prof_gctx_mutex_choose(); /* * Set nlimbo to 1, in order to avoid a race condition with - * prof_ctx_merge()/prof_ctx_destroy(). + * prof_tctx_destroy()/prof_gctx_try_destroy(). */ - ctx->nlimbo = 1; - ql_elm_new(ctx, dump_link); - memset(&ctx->cnt_merged, 0, sizeof(prof_cnt_t)); - ql_new(&ctx->cnts_ql); + gctx->nlimbo = 1; + tctx_tree_new(&gctx->tctxs); + /* Duplicate bt. */ + memcpy(gctx->vec, bt->vec, bt->len * sizeof(void *)); + gctx->bt.vec = gctx->vec; + gctx->bt.len = bt->len; + return (gctx); } static void -prof_ctx_destroy(prof_ctx_t *ctx) +prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self, prof_gctx_t *gctx, + prof_tdata_t *tdata) { - prof_tdata_t *prof_tdata; cassert(config_prof); /* - * Check that ctx is still unused by any thread cache before destroying - * it. prof_lookup() increments ctx->nlimbo in order to avoid a race - * condition with this function, as does prof_ctx_merge() in order to - * avoid a race between the main body of prof_ctx_merge() and entry + * Check that gctx is still unused by any thread cache before destroying + * it. prof_lookup() increments gctx->nlimbo in order to avoid a race + * condition with this function, as does prof_tctx_destroy() in order to + * avoid a race between the main body of prof_tctx_destroy() and entry * into this function. */ - prof_tdata = prof_tdata_get(false); - assert((uintptr_t)prof_tdata > (uintptr_t)PROF_TDATA_STATE_MAX); - prof_enter(prof_tdata); - malloc_mutex_lock(ctx->lock); - if (ql_first(&ctx->cnts_ql) == NULL && ctx->cnt_merged.curobjs == 0 && - ctx->nlimbo == 1) { - assert(ctx->cnt_merged.curbytes == 0); - assert(ctx->cnt_merged.accumobjs == 0); - assert(ctx->cnt_merged.accumbytes == 0); - /* Remove ctx from bt2ctx. */ - if (ckh_remove(&bt2ctx, ctx->bt, NULL, NULL)) + prof_enter(tsd, tdata_self); + malloc_mutex_lock(gctx->lock); + assert(gctx->nlimbo != 0); + if (tctx_tree_empty(&gctx->tctxs) && gctx->nlimbo == 1) { + /* Remove gctx from bt2gctx. */ + if (ckh_remove(tsd, &bt2gctx, &gctx->bt, NULL, NULL)) not_reached(); - prof_leave(prof_tdata); - /* Destroy ctx. */ - malloc_mutex_unlock(ctx->lock); - bt_destroy(ctx->bt); - idalloc(ctx); + prof_leave(tsd, tdata_self); + /* Destroy gctx. */ + malloc_mutex_unlock(gctx->lock); + idalloc(tsd, gctx); } else { /* - * Compensate for increment in prof_ctx_merge() or + * Compensate for increment in prof_tctx_destroy() or * prof_lookup(). */ - ctx->nlimbo--; - malloc_mutex_unlock(ctx->lock); - prof_leave(prof_tdata); + gctx->nlimbo--; + malloc_mutex_unlock(gctx->lock); + prof_leave(tsd, tdata_self); } } -static void -prof_ctx_merge(prof_ctx_t *ctx, prof_thr_cnt_t *cnt) +/* tctx->tdata->lock must be held. */ +static bool +prof_tctx_should_destroy(prof_tctx_t *tctx) { - bool destroy; - cassert(config_prof); - - /* Merge cnt stats and detach from ctx. */ - malloc_mutex_lock(ctx->lock); - ctx->cnt_merged.curobjs += cnt->cnts.curobjs; - ctx->cnt_merged.curbytes += cnt->cnts.curbytes; - ctx->cnt_merged.accumobjs += cnt->cnts.accumobjs; - ctx->cnt_merged.accumbytes += cnt->cnts.accumbytes; - ql_remove(&ctx->cnts_ql, cnt, cnts_link); - if (opt_prof_accum == false && ql_first(&ctx->cnts_ql) == NULL && - ctx->cnt_merged.curobjs == 0 && ctx->nlimbo == 0) { - /* - * Increment ctx->nlimbo in order to keep another thread from - * winning the race to destroy ctx while this one has ctx->lock - * dropped. Without this, it would be possible for another - * thread to: - * - * 1) Sample an allocation associated with ctx. - * 2) Deallocate the sampled object. - * 3) Successfully prof_ctx_destroy(ctx). - * - * The result would be that ctx no longer exists by the time - * this thread accesses it in prof_ctx_destroy(). - */ - ctx->nlimbo++; - destroy = true; - } else - destroy = false; - malloc_mutex_unlock(ctx->lock); - if (destroy) - prof_ctx_destroy(ctx); + if (opt_prof_accum) + return (false); + if (tctx->cnts.curobjs != 0) + return (false); + if (tctx->prepared) + return (false); + return (true); } static bool -prof_lookup_global(prof_bt_t *bt, prof_tdata_t *prof_tdata, void **p_btkey, - prof_ctx_t **p_ctx, bool *p_new_ctx) +prof_gctx_should_destroy(prof_gctx_t *gctx) +{ + + if (opt_prof_accum) + return (false); + if (!tctx_tree_empty(&gctx->tctxs)) + return (false); + if (gctx->nlimbo != 0) + return (false); + return (true); +} + +/* tctx->tdata->lock is held upon entry, and released before return. */ +static void +prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) +{ + prof_tdata_t *tdata = tctx->tdata; + prof_gctx_t *gctx = tctx->gctx; + bool destroy_tdata, destroy_tctx, destroy_gctx; + + assert(tctx->cnts.curobjs == 0); + assert(tctx->cnts.curbytes == 0); + assert(!opt_prof_accum); + assert(tctx->cnts.accumobjs == 0); + assert(tctx->cnts.accumbytes == 0); + + ckh_remove(tsd, &tdata->bt2tctx, &gctx->bt, NULL, NULL); + destroy_tdata = prof_tdata_should_destroy(tdata, false); + malloc_mutex_unlock(tdata->lock); + + malloc_mutex_lock(gctx->lock); + if (tctx->state != prof_tctx_state_dumping) { + tctx_tree_remove(&gctx->tctxs, tctx); + destroy_tctx = true; + if (prof_gctx_should_destroy(gctx)) { + /* + * Increment gctx->nlimbo in order to keep another + * thread from winning the race to destroy gctx while + * this one has gctx->lock dropped. Without this, it + * would be possible for another thread to: + * + * 1) Sample an allocation associated with gctx. + * 2) Deallocate the sampled object. + * 3) Successfully prof_gctx_try_destroy(gctx). + * + * The result would be that gctx no longer exists by the + * time this thread accesses it in + * prof_gctx_try_destroy(). + */ + gctx->nlimbo++; + destroy_gctx = true; + } else + destroy_gctx = false; + } else { + /* + * A dumping thread needs tctx to remain valid until dumping + * has finished. Change state such that the dumping thread will + * complete destruction during a late dump iteration phase. + */ + tctx->state = prof_tctx_state_purgatory; + destroy_tctx = false; + destroy_gctx = false; + } + malloc_mutex_unlock(gctx->lock); + if (destroy_gctx) { + prof_gctx_try_destroy(tsd, prof_tdata_get(tsd, false), gctx, + tdata); + } + + if (destroy_tdata) + prof_tdata_destroy(tsd, tdata, false); + + if (destroy_tctx) + idalloc(tsd, tctx); +} + +static bool +prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, + void **p_btkey, prof_gctx_t **p_gctx, bool *p_new_gctx) { union { - prof_ctx_t *p; + prof_gctx_t *p; void *v; - } ctx; + } gctx; union { prof_bt_t *p; void *v; } btkey; - bool new_ctx; + bool new_gctx; - prof_enter(prof_tdata); - if (ckh_search(&bt2ctx, bt, &btkey.v, &ctx.v)) { + prof_enter(tsd, tdata); + if (ckh_search(&bt2gctx, bt, &btkey.v, &gctx.v)) { /* bt has never been seen before. Insert it. */ - ctx.v = imalloc(sizeof(prof_ctx_t)); - if (ctx.v == NULL) { - prof_leave(prof_tdata); + gctx.p = prof_gctx_create(tsd, bt); + if (gctx.v == NULL) { + prof_leave(tsd, tdata); return (true); } - btkey.p = bt_dup(bt); - if (btkey.v == NULL) { - prof_leave(prof_tdata); - idalloc(ctx.v); - return (true); - } - prof_ctx_init(ctx.p, btkey.p); - if (ckh_insert(&bt2ctx, btkey.v, ctx.v)) { + btkey.p = &gctx.p->bt; + if (ckh_insert(tsd, &bt2gctx, btkey.v, gctx.v)) { /* OOM. */ - prof_leave(prof_tdata); - idalloc(btkey.v); - idalloc(ctx.v); + prof_leave(tsd, tdata); + idalloc(tsd, gctx.v); return (true); } - new_ctx = true; + new_gctx = true; } else { /* * Increment nlimbo, in order to avoid a race condition with - * prof_ctx_merge()/prof_ctx_destroy(). + * prof_tctx_destroy()/prof_gctx_try_destroy(). */ - malloc_mutex_lock(ctx.p->lock); - ctx.p->nlimbo++; - malloc_mutex_unlock(ctx.p->lock); - new_ctx = false; + malloc_mutex_lock(gctx.p->lock); + gctx.p->nlimbo++; + malloc_mutex_unlock(gctx.p->lock); + new_gctx = false; } - prof_leave(prof_tdata); + prof_leave(tsd, tdata); *p_btkey = btkey.v; - *p_ctx = ctx.p; - *p_new_ctx = new_ctx; + *p_gctx = gctx.p; + *p_new_gctx = new_gctx; return (false); } -prof_thr_cnt_t * -prof_lookup(prof_bt_t *bt) +prof_tctx_t * +prof_lookup(tsd_t *tsd, prof_bt_t *bt) { union { - prof_thr_cnt_t *p; + prof_tctx_t *p; void *v; } ret; - prof_tdata_t *prof_tdata; + prof_tdata_t *tdata; + bool not_found; cassert(config_prof); - prof_tdata = prof_tdata_get(false); - if ((uintptr_t)prof_tdata <= (uintptr_t)PROF_TDATA_STATE_MAX) + tdata = prof_tdata_get(tsd, false); + if (tdata == NULL) return (NULL); - if (ckh_search(&prof_tdata->bt2cnt, bt, NULL, &ret.v)) { + malloc_mutex_lock(tdata->lock); + not_found = ckh_search(&tdata->bt2tctx, bt, NULL, &ret.v); + if (!not_found) /* Note double negative! */ + ret.p->prepared = true; + malloc_mutex_unlock(tdata->lock); + if (not_found) { void *btkey; - prof_ctx_t *ctx; - bool new_ctx; + prof_gctx_t *gctx; + bool new_gctx, error; /* * This thread's cache lacks bt. Look for it in the global * cache. */ - if (prof_lookup_global(bt, prof_tdata, &btkey, &ctx, &new_ctx)) + if (prof_lookup_global(tsd, bt, tdata, &btkey, &gctx, + &new_gctx)) return (NULL); - /* Link a prof_thd_cnt_t into ctx for this thread. */ - if (ckh_count(&prof_tdata->bt2cnt) == PROF_TCMAX) { - assert(ckh_count(&prof_tdata->bt2cnt) > 0); - /* - * Flush the least recently used cnt in order to keep - * bt2cnt from becoming too large. - */ - ret.p = ql_last(&prof_tdata->lru_ql, lru_link); - assert(ret.v != NULL); - if (ckh_remove(&prof_tdata->bt2cnt, ret.p->ctx->bt, - NULL, NULL)) - not_reached(); - ql_remove(&prof_tdata->lru_ql, ret.p, lru_link); - prof_ctx_merge(ret.p->ctx, ret.p); - /* ret can now be re-used. */ - } else { - assert(ckh_count(&prof_tdata->bt2cnt) < PROF_TCMAX); - /* Allocate and partially initialize a new cnt. */ - ret.v = imalloc(sizeof(prof_thr_cnt_t)); - if (ret.p == NULL) { - if (new_ctx) - prof_ctx_destroy(ctx); - return (NULL); - } - ql_elm_new(ret.p, cnts_link); - ql_elm_new(ret.p, lru_link); - } - /* Finish initializing ret. */ - ret.p->ctx = ctx; - ret.p->epoch = 0; - memset(&ret.p->cnts, 0, sizeof(prof_cnt_t)); - if (ckh_insert(&prof_tdata->bt2cnt, btkey, ret.v)) { - if (new_ctx) - prof_ctx_destroy(ctx); - idalloc(ret.v); + /* Link a prof_tctx_t into gctx for this thread. */ + ret.v = imalloc(tsd, sizeof(prof_tctx_t)); + if (ret.p == NULL) { + if (new_gctx) + prof_gctx_try_destroy(tsd, tdata, gctx, tdata); return (NULL); } - ql_head_insert(&prof_tdata->lru_ql, ret.p, lru_link); - malloc_mutex_lock(ctx->lock); - ql_tail_insert(&ctx->cnts_ql, ret.p, cnts_link); - ctx->nlimbo--; - malloc_mutex_unlock(ctx->lock); - } else { - /* Move ret to the front of the LRU. */ - ql_remove(&prof_tdata->lru_ql, ret.p, lru_link); - ql_head_insert(&prof_tdata->lru_ql, ret.p, lru_link); + ret.p->tdata = tdata; + ret.p->thr_uid = tdata->thr_uid; + memset(&ret.p->cnts, 0, sizeof(prof_cnt_t)); + ret.p->gctx = gctx; + ret.p->prepared = true; + ret.p->state = prof_tctx_state_initializing; + malloc_mutex_lock(tdata->lock); + error = ckh_insert(tsd, &tdata->bt2tctx, btkey, ret.v); + malloc_mutex_unlock(tdata->lock); + if (error) { + if (new_gctx) + prof_gctx_try_destroy(tsd, tdata, gctx, tdata); + idalloc(tsd, ret.v); + return (NULL); + } + malloc_mutex_lock(gctx->lock); + ret.p->state = prof_tctx_state_nominal; + tctx_tree_insert(&gctx->tctxs, ret.p); + gctx->nlimbo--; + malloc_mutex_unlock(gctx->lock); } return (ret.p); } +void +prof_sample_threshold_update(prof_tdata_t *tdata) +{ + /* + * The body of this function is compiled out unless heap profiling is + * enabled, so that it is possible to compile jemalloc with floating + * point support completely disabled. Avoiding floating point code is + * important on memory-constrained systems, but it also enables a + * workaround for versions of glibc that don't properly save/restore + * floating point registers during dynamic lazy symbol loading (which + * internally calls into whatever malloc implementation happens to be + * integrated into the application). Note that some compilers (e.g. + * gcc 4.8) may use floating point registers for fast memory moves, so + * jemalloc must be compiled with such optimizations disabled (e.g. + * -mno-sse) in order for the workaround to be complete. + */ +#ifdef JEMALLOC_PROF + uint64_t r; + double u; + + if (!config_prof) + return; + + if (lg_prof_sample == 0) { + tdata->bytes_until_sample = 0; + return; + } + + /* + * Compute sample interval as a geometrically distributed random + * variable with mean (2^lg_prof_sample). + * + * __ __ + * | log(u) | 1 + * tdata->bytes_until_sample = | -------- |, where p = --------------- + * | log(1-p) | lg_prof_sample + * 2 + * + * For more information on the math, see: + * + * Non-Uniform Random Variate Generation + * Luc Devroye + * Springer-Verlag, New York, 1986 + * pp 500 + * (http://luc.devroye.org/rnbookindex.html) + */ + prng64(r, 53, tdata->prng_state, UINT64_C(6364136223846793005), + UINT64_C(1442695040888963407)); + u = (double)r * (1.0/9007199254740992.0L); + tdata->bytes_until_sample = (uint64_t)(log(u) / + log(1.0 - (1.0 / (double)((uint64_t)1U << lg_prof_sample)))) + + (uint64_t)1U; +#endif +} + +#ifdef JEMALLOC_JET +static prof_tdata_t * +prof_tdata_count_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, void *arg) +{ + size_t *tdata_count = (size_t *)arg; + + (*tdata_count)++; + + return (NULL); +} + +size_t +prof_tdata_count(void) +{ + size_t tdata_count = 0; + + malloc_mutex_lock(&tdatas_mtx); + tdata_tree_iter(&tdatas, NULL, prof_tdata_count_iter, + (void *)&tdata_count); + malloc_mutex_unlock(&tdatas_mtx); + + return (tdata_count); +} +#endif + #ifdef JEMALLOC_JET size_t prof_bt_count(void) { size_t bt_count; - prof_tdata_t *prof_tdata; + tsd_t *tsd; + prof_tdata_t *tdata; - prof_tdata = prof_tdata_get(false); - if ((uintptr_t)prof_tdata <= (uintptr_t)PROF_TDATA_STATE_MAX) + tsd = tsd_fetch(); + tdata = prof_tdata_get(tsd, false); + if (tdata == NULL) return (0); - prof_enter(prof_tdata); - bt_count = ckh_count(&bt2ctx); - prof_leave(prof_tdata); + malloc_mutex_lock(&bt2gctx_mtx); + bt_count = ckh_count(&bt2gctx); + malloc_mutex_unlock(&bt2gctx_mtx); return (bt_count); } @@ -675,7 +902,7 @@ prof_dump_open(bool propagate_err, const char *filename) int fd; fd = creat(filename, 0644); - if (fd == -1 && propagate_err == false) { + if (fd == -1 && !propagate_err) { malloc_printf(": creat(\"%s\"), 0644) failed\n", filename); if (opt_abort) @@ -700,7 +927,7 @@ prof_dump_flush(bool propagate_err) err = write(prof_dump_fd, prof_dump_buf, prof_dump_buf_end); if (err == -1) { - if (propagate_err == false) { + if (!propagate_err) { malloc_write(": write() failed during heap " "profile flush\n"); if (opt_abort) @@ -772,141 +999,284 @@ prof_dump_printf(bool propagate_err, const char *format, ...) return (ret); } +/* tctx->tdata->lock is held. */ static void -prof_dump_ctx_prep(prof_ctx_t *ctx, prof_cnt_t *cnt_all, size_t *leak_nctx, - prof_ctx_list_t *ctx_ql) +prof_tctx_merge_tdata(prof_tctx_t *tctx, prof_tdata_t *tdata) +{ + + malloc_mutex_lock(tctx->gctx->lock); + if (tctx->state == prof_tctx_state_initializing) { + malloc_mutex_unlock(tctx->gctx->lock); + return; + } + assert(tctx->state == prof_tctx_state_nominal); + tctx->state = prof_tctx_state_dumping; + malloc_mutex_unlock(tctx->gctx->lock); + + memcpy(&tctx->dump_cnts, &tctx->cnts, sizeof(prof_cnt_t)); + + tdata->cnt_summed.curobjs += tctx->dump_cnts.curobjs; + tdata->cnt_summed.curbytes += tctx->dump_cnts.curbytes; + if (opt_prof_accum) { + tdata->cnt_summed.accumobjs += tctx->dump_cnts.accumobjs; + tdata->cnt_summed.accumbytes += tctx->dump_cnts.accumbytes; + } +} + +/* gctx->lock is held. */ +static void +prof_tctx_merge_gctx(prof_tctx_t *tctx, prof_gctx_t *gctx) +{ + + gctx->cnt_summed.curobjs += tctx->dump_cnts.curobjs; + gctx->cnt_summed.curbytes += tctx->dump_cnts.curbytes; + if (opt_prof_accum) { + gctx->cnt_summed.accumobjs += tctx->dump_cnts.accumobjs; + gctx->cnt_summed.accumbytes += tctx->dump_cnts.accumbytes; + } +} + +/* tctx->gctx is held. */ +static prof_tctx_t * +prof_tctx_merge_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) +{ + + switch (tctx->state) { + case prof_tctx_state_nominal: + /* New since dumping started; ignore. */ + break; + case prof_tctx_state_dumping: + case prof_tctx_state_purgatory: + prof_tctx_merge_gctx(tctx, tctx->gctx); + break; + default: + not_reached(); + } + + return (NULL); +} + +/* gctx->lock is held. */ +static prof_tctx_t * +prof_tctx_dump_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) +{ + bool propagate_err = *(bool *)arg; + + if (prof_dump_printf(propagate_err, + " t%"PRIu64": %"PRIu64": %"PRIu64" [%"PRIu64": %"PRIu64"]\n", + tctx->thr_uid, tctx->dump_cnts.curobjs, tctx->dump_cnts.curbytes, + tctx->dump_cnts.accumobjs, tctx->dump_cnts.accumbytes)) + return (tctx); + return (NULL); +} + +/* tctx->gctx is held. */ +static prof_tctx_t * +prof_tctx_finish_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) +{ + prof_tctx_t *ret; + + switch (tctx->state) { + case prof_tctx_state_nominal: + /* New since dumping started; ignore. */ + break; + case prof_tctx_state_dumping: + tctx->state = prof_tctx_state_nominal; + break; + case prof_tctx_state_purgatory: + ret = tctx; + goto label_return; + default: + not_reached(); + } + + ret = NULL; +label_return: + return (ret); +} + +static void +prof_dump_gctx_prep(prof_gctx_t *gctx, prof_gctx_tree_t *gctxs) { - prof_thr_cnt_t *thr_cnt; - prof_cnt_t tcnt; cassert(config_prof); - malloc_mutex_lock(ctx->lock); + malloc_mutex_lock(gctx->lock); /* - * Increment nlimbo so that ctx won't go away before dump. - * Additionally, link ctx into the dump list so that it is included in + * Increment nlimbo so that gctx won't go away before dump. + * Additionally, link gctx into the dump list so that it is included in * prof_dump()'s second pass. */ - ctx->nlimbo++; - ql_tail_insert(ctx_ql, ctx, dump_link); + gctx->nlimbo++; + gctx_tree_insert(gctxs, gctx); - memcpy(&ctx->cnt_summed, &ctx->cnt_merged, sizeof(prof_cnt_t)); - ql_foreach(thr_cnt, &ctx->cnts_ql, cnts_link) { - volatile unsigned *epoch = &thr_cnt->epoch; + memset(&gctx->cnt_summed, 0, sizeof(prof_cnt_t)); - while (true) { - unsigned epoch0 = *epoch; - - /* Make sure epoch is even. */ - if (epoch0 & 1U) - continue; - - memcpy(&tcnt, &thr_cnt->cnts, sizeof(prof_cnt_t)); - - /* Terminate if epoch didn't change while reading. */ - if (*epoch == epoch0) - break; - } - - ctx->cnt_summed.curobjs += tcnt.curobjs; - ctx->cnt_summed.curbytes += tcnt.curbytes; - if (opt_prof_accum) { - ctx->cnt_summed.accumobjs += tcnt.accumobjs; - ctx->cnt_summed.accumbytes += tcnt.accumbytes; - } - } - - if (ctx->cnt_summed.curobjs != 0) - (*leak_nctx)++; - - /* Add to cnt_all. */ - cnt_all->curobjs += ctx->cnt_summed.curobjs; - cnt_all->curbytes += ctx->cnt_summed.curbytes; - if (opt_prof_accum) { - cnt_all->accumobjs += ctx->cnt_summed.accumobjs; - cnt_all->accumbytes += ctx->cnt_summed.accumbytes; - } - - malloc_mutex_unlock(ctx->lock); + malloc_mutex_unlock(gctx->lock); } +static prof_gctx_t * +prof_gctx_merge_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *arg) +{ + size_t *leak_ngctx = (size_t *)arg; + + malloc_mutex_lock(gctx->lock); + tctx_tree_iter(&gctx->tctxs, NULL, prof_tctx_merge_iter, NULL); + if (gctx->cnt_summed.curobjs != 0) + (*leak_ngctx)++; + malloc_mutex_unlock(gctx->lock); + + return (NULL); +} + +static void +prof_gctx_finish(tsd_t *tsd, prof_gctx_tree_t *gctxs) +{ + prof_tdata_t *tdata = prof_tdata_get(tsd, false); + prof_gctx_t *gctx; + + /* + * Standard tree iteration won't work here, because as soon as we + * decrement gctx->nlimbo and unlock gctx, another thread can + * concurrently destroy it, which will corrupt the tree. Therefore, + * tear down the tree one node at a time during iteration. + */ + while ((gctx = gctx_tree_first(gctxs)) != NULL) { + gctx_tree_remove(gctxs, gctx); + malloc_mutex_lock(gctx->lock); + { + prof_tctx_t *next; + + next = NULL; + do { + prof_tctx_t *to_destroy = + tctx_tree_iter(&gctx->tctxs, next, + prof_tctx_finish_iter, NULL); + if (to_destroy != NULL) { + next = tctx_tree_next(&gctx->tctxs, + to_destroy); + tctx_tree_remove(&gctx->tctxs, + to_destroy); + idalloc(tsd, to_destroy); + } else + next = NULL; + } while (next != NULL); + } + gctx->nlimbo--; + if (prof_gctx_should_destroy(gctx)) { + gctx->nlimbo++; + malloc_mutex_unlock(gctx->lock); + prof_gctx_try_destroy(tsd, tdata, gctx, tdata); + } else + malloc_mutex_unlock(gctx->lock); + } +} + +static prof_tdata_t * +prof_tdata_merge_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, void *arg) +{ + prof_cnt_t *cnt_all = (prof_cnt_t *)arg; + + malloc_mutex_lock(tdata->lock); + if (!tdata->expired) { + size_t tabind; + union { + prof_tctx_t *p; + void *v; + } tctx; + + tdata->dumping = true; + memset(&tdata->cnt_summed, 0, sizeof(prof_cnt_t)); + for (tabind = 0; !ckh_iter(&tdata->bt2tctx, &tabind, NULL, + &tctx.v);) + prof_tctx_merge_tdata(tctx.p, tdata); + + cnt_all->curobjs += tdata->cnt_summed.curobjs; + cnt_all->curbytes += tdata->cnt_summed.curbytes; + if (opt_prof_accum) { + cnt_all->accumobjs += tdata->cnt_summed.accumobjs; + cnt_all->accumbytes += tdata->cnt_summed.accumbytes; + } + } else + tdata->dumping = false; + malloc_mutex_unlock(tdata->lock); + + return (NULL); +} + +static prof_tdata_t * +prof_tdata_dump_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, void *arg) +{ + bool propagate_err = *(bool *)arg; + + if (!tdata->dumping) + return (NULL); + + if (prof_dump_printf(propagate_err, + " t%"PRIu64": %"PRIu64": %"PRIu64" [%"PRIu64": %"PRIu64"]%s%s\n", + tdata->thr_uid, tdata->cnt_summed.curobjs, + tdata->cnt_summed.curbytes, tdata->cnt_summed.accumobjs, + tdata->cnt_summed.accumbytes, + (tdata->thread_name != NULL) ? " " : "", + (tdata->thread_name != NULL) ? tdata->thread_name : "")) + return (tdata); + return (NULL); +} + +#ifdef JEMALLOC_JET +#undef prof_dump_header +#define prof_dump_header JEMALLOC_N(prof_dump_header_impl) +#endif static bool prof_dump_header(bool propagate_err, const prof_cnt_t *cnt_all) { + bool ret; - if (opt_lg_prof_sample == 0) { - if (prof_dump_printf(propagate_err, - "heap profile: %"PRId64": %"PRId64 - " [%"PRIu64": %"PRIu64"] @ heapprofile\n", - cnt_all->curobjs, cnt_all->curbytes, - cnt_all->accumobjs, cnt_all->accumbytes)) - return (true); - } else { - if (prof_dump_printf(propagate_err, - "heap profile: %"PRId64": %"PRId64 - " [%"PRIu64": %"PRIu64"] @ heap_v2/%"PRIu64"\n", - cnt_all->curobjs, cnt_all->curbytes, - cnt_all->accumobjs, cnt_all->accumbytes, - ((uint64_t)1U << opt_lg_prof_sample))) - return (true); - } + if (prof_dump_printf(propagate_err, + "heap_v2/%"PRIu64"\n" + " t*: %"PRIu64": %"PRIu64" [%"PRIu64": %"PRIu64"]\n", + ((uint64_t)1U << lg_prof_sample), cnt_all->curobjs, + cnt_all->curbytes, cnt_all->accumobjs, cnt_all->accumbytes)) + return (true); - return (false); -} - -static void -prof_dump_ctx_cleanup_locked(prof_ctx_t *ctx, prof_ctx_list_t *ctx_ql) -{ - - ctx->nlimbo--; - ql_remove(ctx_ql, ctx, dump_link); -} - -static void -prof_dump_ctx_cleanup(prof_ctx_t *ctx, prof_ctx_list_t *ctx_ql) -{ - - malloc_mutex_lock(ctx->lock); - prof_dump_ctx_cleanup_locked(ctx, ctx_ql); - malloc_mutex_unlock(ctx->lock); + malloc_mutex_lock(&tdatas_mtx); + ret = (tdata_tree_iter(&tdatas, NULL, prof_tdata_dump_iter, + (void *)&propagate_err) != NULL); + malloc_mutex_unlock(&tdatas_mtx); + return (ret); } +#ifdef JEMALLOC_JET +#undef prof_dump_header +#define prof_dump_header JEMALLOC_N(prof_dump_header) +prof_dump_header_t *prof_dump_header = JEMALLOC_N(prof_dump_header_impl); +#endif +/* gctx->lock is held. */ static bool -prof_dump_ctx(bool propagate_err, prof_ctx_t *ctx, const prof_bt_t *bt, - prof_ctx_list_t *ctx_ql) +prof_dump_gctx(bool propagate_err, prof_gctx_t *gctx, const prof_bt_t *bt, + prof_gctx_tree_t *gctxs) { bool ret; unsigned i; cassert(config_prof); - /* - * Current statistics can sum to 0 as a result of unmerged per thread - * statistics. Additionally, interval- and growth-triggered dumps can - * occur between the time a ctx is created and when its statistics are - * filled in. Avoid dumping any ctx that is an artifact of either - * implementation detail. - */ - malloc_mutex_lock(ctx->lock); - if ((opt_prof_accum == false && ctx->cnt_summed.curobjs == 0) || - (opt_prof_accum && ctx->cnt_summed.accumobjs == 0)) { - assert(ctx->cnt_summed.curobjs == 0); - assert(ctx->cnt_summed.curbytes == 0); - assert(ctx->cnt_summed.accumobjs == 0); - assert(ctx->cnt_summed.accumbytes == 0); + /* Avoid dumping such gctx's that have no useful data. */ + if ((!opt_prof_accum && gctx->cnt_summed.curobjs == 0) || + (opt_prof_accum && gctx->cnt_summed.accumobjs == 0)) { + assert(gctx->cnt_summed.curobjs == 0); + assert(gctx->cnt_summed.curbytes == 0); + assert(gctx->cnt_summed.accumobjs == 0); + assert(gctx->cnt_summed.accumbytes == 0); ret = false; goto label_return; } - if (prof_dump_printf(propagate_err, "%"PRId64": %"PRId64 - " [%"PRIu64": %"PRIu64"] @", - ctx->cnt_summed.curobjs, ctx->cnt_summed.curbytes, - ctx->cnt_summed.accumobjs, ctx->cnt_summed.accumbytes)) { + if (prof_dump_printf(propagate_err, "@")) { ret = true; goto label_return; } - for (i = 0; i < bt->len; i++) { if (prof_dump_printf(propagate_err, " %#"PRIxPTR, (uintptr_t)bt->vec[i])) { @@ -915,15 +1285,23 @@ prof_dump_ctx(bool propagate_err, prof_ctx_t *ctx, const prof_bt_t *bt, } } - if (prof_dump_write(propagate_err, "\n")) { + if (prof_dump_printf(propagate_err, + "\n" + " t*: %"PRIu64": %"PRIu64" [%"PRIu64": %"PRIu64"]\n", + gctx->cnt_summed.curobjs, gctx->cnt_summed.curbytes, + gctx->cnt_summed.accumobjs, gctx->cnt_summed.accumbytes)) { + ret = true; + goto label_return; + } + + if (tctx_tree_iter(&gctx->tctxs, NULL, prof_tctx_dump_iter, + (void *)&propagate_err) != NULL) { ret = true; goto label_return; } ret = false; label_return: - prof_dump_ctx_cleanup_locked(ctx, ctx_ql); - malloc_mutex_unlock(ctx->lock); return (ret); } @@ -977,51 +1355,85 @@ label_return: } static void -prof_leakcheck(const prof_cnt_t *cnt_all, size_t leak_nctx, +prof_leakcheck(const prof_cnt_t *cnt_all, size_t leak_ngctx, const char *filename) { if (cnt_all->curbytes != 0) { - malloc_printf(": Leak summary: %"PRId64" byte%s, %" - PRId64" object%s, %zu context%s\n", + malloc_printf(": Leak summary: %"PRIu64" byte%s, %" + PRIu64" object%s, %zu context%s\n", cnt_all->curbytes, (cnt_all->curbytes != 1) ? "s" : "", cnt_all->curobjs, (cnt_all->curobjs != 1) ? "s" : "", - leak_nctx, (leak_nctx != 1) ? "s" : ""); + leak_ngctx, (leak_ngctx != 1) ? "s" : ""); malloc_printf( ": Run pprof on \"%s\" for leak detail\n", filename); } } -static bool -prof_dump(bool propagate_err, const char *filename, bool leakcheck) +static prof_gctx_t * +prof_gctx_dump_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *arg) { - prof_tdata_t *prof_tdata; + prof_gctx_t *ret; + bool propagate_err = *(bool *)arg; + + malloc_mutex_lock(gctx->lock); + + if (prof_dump_gctx(propagate_err, gctx, &gctx->bt, gctxs)) { + ret = gctx; + goto label_return; + } + + ret = NULL; +label_return: + malloc_mutex_unlock(gctx->lock); + return (ret); +} + +static bool +prof_dump(tsd_t *tsd, bool propagate_err, const char *filename, bool leakcheck) +{ + prof_tdata_t *tdata; prof_cnt_t cnt_all; size_t tabind; union { - prof_ctx_t *p; + prof_gctx_t *p; void *v; - } ctx; - size_t leak_nctx; - prof_ctx_list_t ctx_ql; + } gctx; + size_t leak_ngctx; + prof_gctx_tree_t gctxs; cassert(config_prof); - prof_tdata = prof_tdata_get(false); - if ((uintptr_t)prof_tdata <= (uintptr_t)PROF_TDATA_STATE_MAX) + tdata = prof_tdata_get(tsd, true); + if (tdata == NULL) return (true); malloc_mutex_lock(&prof_dump_mtx); + prof_enter(tsd, tdata); - /* Merge per thread profile stats, and sum them in cnt_all. */ + /* + * Put gctx's in limbo and clear their counters in preparation for + * summing. + */ + gctx_tree_new(&gctxs); + for (tabind = 0; !ckh_iter(&bt2gctx, &tabind, NULL, &gctx.v);) + prof_dump_gctx_prep(gctx.p, &gctxs); + + /* + * Iterate over tdatas, and for the non-expired ones snapshot their tctx + * stats and merge them into the associated gctx's. + */ memset(&cnt_all, 0, sizeof(prof_cnt_t)); - leak_nctx = 0; - ql_new(&ctx_ql); - prof_enter(prof_tdata); - for (tabind = 0; ckh_iter(&bt2ctx, &tabind, NULL, &ctx.v) == false;) - prof_dump_ctx_prep(ctx.p, &cnt_all, &leak_nctx, &ctx_ql); - prof_leave(prof_tdata); + malloc_mutex_lock(&tdatas_mtx); + tdata_tree_iter(&tdatas, NULL, prof_tdata_merge_iter, (void *)&cnt_all); + malloc_mutex_unlock(&tdatas_mtx); + + /* Merge tctx stats into gctx's. */ + leak_ngctx = 0; + gctx_tree_iter(&gctxs, NULL, prof_gctx_merge_iter, (void *)&leak_ngctx); + + prof_leave(tsd, tdata); /* Create dump file. */ if ((prof_dump_fd = prof_dump_open(propagate_err, filename)) == -1) @@ -1031,11 +1443,10 @@ prof_dump(bool propagate_err, const char *filename, bool leakcheck) if (prof_dump_header(propagate_err, &cnt_all)) goto label_write_error; - /* Dump per ctx profile stats. */ - while ((ctx.p = ql_first(&ctx_ql)) != NULL) { - if (prof_dump_ctx(propagate_err, ctx.p, ctx.p->bt, &ctx_ql)) - goto label_write_error; - } + /* Dump per gctx profile stats. */ + if (gctx_tree_iter(&gctxs, NULL, prof_gctx_dump_iter, + (void *)&propagate_err) != NULL) + goto label_write_error; /* Dump /proc//maps if possible. */ if (prof_dump_maps(propagate_err)) @@ -1044,17 +1455,17 @@ prof_dump(bool propagate_err, const char *filename, bool leakcheck) if (prof_dump_close(propagate_err)) goto label_open_close_error; + prof_gctx_finish(tsd, &gctxs); malloc_mutex_unlock(&prof_dump_mtx); if (leakcheck) - prof_leakcheck(&cnt_all, leak_nctx, filename); + prof_leakcheck(&cnt_all, leak_ngctx, filename); return (false); label_write_error: prof_dump_close(propagate_err); label_open_close_error: - while ((ctx.p = ql_first(&ctx_ql)) != NULL) - prof_dump_ctx_cleanup(ctx.p, &ctx_ql); + prof_gctx_finish(tsd, &gctxs); malloc_mutex_unlock(&prof_dump_mtx); return (true); } @@ -1084,36 +1495,40 @@ prof_dump_filename(char *filename, char v, uint64_t vseq) static void prof_fdump(void) { + tsd_t *tsd; char filename[DUMP_FILENAME_BUFSIZE]; cassert(config_prof); + assert(opt_prof_final); + assert(opt_prof_prefix[0] != '\0'); - if (prof_booted == false) + if (!prof_booted) return; + tsd = tsd_fetch(); - if (opt_prof_final && opt_prof_prefix[0] != '\0') { - malloc_mutex_lock(&prof_dump_seq_mtx); - prof_dump_filename(filename, 'f', VSEQ_INVALID); - malloc_mutex_unlock(&prof_dump_seq_mtx); - prof_dump(false, filename, opt_prof_leak); - } + malloc_mutex_lock(&prof_dump_seq_mtx); + prof_dump_filename(filename, 'f', VSEQ_INVALID); + malloc_mutex_unlock(&prof_dump_seq_mtx); + prof_dump(tsd, false, filename, opt_prof_leak); } void prof_idump(void) { - prof_tdata_t *prof_tdata; + tsd_t *tsd; + prof_tdata_t *tdata; char filename[PATH_MAX + 1]; cassert(config_prof); - if (prof_booted == false) + if (!prof_booted) return; - prof_tdata = prof_tdata_get(false); - if ((uintptr_t)prof_tdata <= (uintptr_t)PROF_TDATA_STATE_MAX) + tsd = tsd_fetch(); + tdata = prof_tdata_get(tsd, false); + if (tdata == NULL) return; - if (prof_tdata->enq) { - prof_tdata->enq_idump = true; + if (tdata->enq) { + tdata->enq_idump = true; return; } @@ -1122,19 +1537,21 @@ prof_idump(void) prof_dump_filename(filename, 'i', prof_dump_iseq); prof_dump_iseq++; malloc_mutex_unlock(&prof_dump_seq_mtx); - prof_dump(false, filename, false); + prof_dump(tsd, false, filename, false); } } bool prof_mdump(const char *filename) { + tsd_t *tsd; char filename_buf[DUMP_FILENAME_BUFSIZE]; cassert(config_prof); - if (opt_prof == false || prof_booted == false) + if (!opt_prof || !prof_booted) return (true); + tsd = tsd_fetch(); if (filename == NULL) { /* No filename specified, so automatically generate one. */ @@ -1146,24 +1563,26 @@ prof_mdump(const char *filename) malloc_mutex_unlock(&prof_dump_seq_mtx); filename = filename_buf; } - return (prof_dump(true, filename, false)); + return (prof_dump(tsd, true, filename, false)); } void prof_gdump(void) { - prof_tdata_t *prof_tdata; + tsd_t *tsd; + prof_tdata_t *tdata; char filename[DUMP_FILENAME_BUFSIZE]; cassert(config_prof); - if (prof_booted == false) + if (!prof_booted) return; - prof_tdata = prof_tdata_get(false); - if ((uintptr_t)prof_tdata <= (uintptr_t)PROF_TDATA_STATE_MAX) + tsd = tsd_fetch(); + tdata = prof_tdata_get(tsd, false); + if (tdata == NULL) return; - if (prof_tdata->enq) { - prof_tdata->enq_gdump = true; + if (tdata->enq) { + tdata->enq_gdump = true; return; } @@ -1172,7 +1591,7 @@ prof_gdump(void) prof_dump_filename(filename, 'u', prof_dump_useq); prof_dump_useq++; malloc_mutex_unlock(&prof_dump_seq_mtx); - prof_dump(false, filename, false); + prof_dump(tsd, false, filename, false); } } @@ -1199,88 +1618,345 @@ prof_bt_keycomp(const void *k1, const void *k2) return (memcmp(bt1->vec, bt2->vec, bt1->len * sizeof(void *)) == 0); } -prof_tdata_t * -prof_tdata_init(void) +JEMALLOC_INLINE_C uint64_t +prof_thr_uid_alloc(void) { - prof_tdata_t *prof_tdata; + uint64_t thr_uid; + + malloc_mutex_lock(&next_thr_uid_mtx); + thr_uid = next_thr_uid; + next_thr_uid++; + malloc_mutex_unlock(&next_thr_uid_mtx); + + return (thr_uid); +} + +static prof_tdata_t * +prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim, + char *thread_name, bool active) +{ + prof_tdata_t *tdata; cassert(config_prof); /* Initialize an empty cache for this thread. */ - prof_tdata = (prof_tdata_t *)imalloc(sizeof(prof_tdata_t)); - if (prof_tdata == NULL) + tdata = (prof_tdata_t *)imalloc(tsd, sizeof(prof_tdata_t)); + if (tdata == NULL) return (NULL); - if (ckh_new(&prof_tdata->bt2cnt, PROF_CKH_MINITEMS, + tdata->lock = prof_tdata_mutex_choose(thr_uid); + tdata->thr_uid = thr_uid; + tdata->thr_discrim = thr_discrim; + tdata->thread_name = thread_name; + tdata->attached = true; + tdata->expired = false; + + if (ckh_new(tsd, &tdata->bt2tctx, PROF_CKH_MINITEMS, prof_bt_hash, prof_bt_keycomp)) { - idalloc(prof_tdata); - return (NULL); - } - ql_new(&prof_tdata->lru_ql); - - prof_tdata->vec = imalloc(sizeof(void *) * PROF_BT_MAX); - if (prof_tdata->vec == NULL) { - ckh_delete(&prof_tdata->bt2cnt); - idalloc(prof_tdata); + idalloc(tsd, tdata); return (NULL); } - prof_tdata->prng_state = 0; - prof_tdata->threshold = 0; - prof_tdata->accum = 0; + tdata->prng_state = (uint64_t)(uintptr_t)tdata; + prof_sample_threshold_update(tdata); - prof_tdata->enq = false; - prof_tdata->enq_idump = false; - prof_tdata->enq_gdump = false; + tdata->enq = false; + tdata->enq_idump = false; + tdata->enq_gdump = false; - prof_tdata_tsd_set(&prof_tdata); + tdata->dumping = false; + tdata->active = active; - return (prof_tdata); + malloc_mutex_lock(&tdatas_mtx); + tdata_tree_insert(&tdatas, tdata); + malloc_mutex_unlock(&tdatas_mtx); + + return (tdata); +} + +prof_tdata_t * +prof_tdata_init(tsd_t *tsd) +{ + + return (prof_tdata_init_impl(tsd, prof_thr_uid_alloc(), 0, NULL, + prof_thread_active_init_get())); +} + +/* tdata->lock must be held. */ +static bool +prof_tdata_should_destroy(prof_tdata_t *tdata, bool even_if_attached) +{ + + if (tdata->attached && !even_if_attached) + return (false); + if (ckh_count(&tdata->bt2tctx) != 0) + return (false); + return (true); +} + +/* tdatas_mtx must be held. */ +static void +prof_tdata_destroy_locked(tsd_t *tsd, prof_tdata_t *tdata, + bool even_if_attached) +{ + + assert(prof_tdata_should_destroy(tdata, even_if_attached)); + assert(tsd_prof_tdata_get(tsd) != tdata); + + tdata_tree_remove(&tdatas, tdata); + + if (tdata->thread_name != NULL) + idalloc(tsd, tdata->thread_name); + ckh_delete(tsd, &tdata->bt2tctx); + idalloc(tsd, tdata); +} + +static void +prof_tdata_destroy(tsd_t *tsd, prof_tdata_t *tdata, bool even_if_attached) +{ + + malloc_mutex_lock(&tdatas_mtx); + prof_tdata_destroy_locked(tsd, tdata, even_if_attached); + malloc_mutex_unlock(&tdatas_mtx); +} + +static void +prof_tdata_detach(tsd_t *tsd, prof_tdata_t *tdata) +{ + bool destroy_tdata; + + malloc_mutex_lock(tdata->lock); + if (tdata->attached) { + destroy_tdata = prof_tdata_should_destroy(tdata, true); + /* + * Only detach if !destroy_tdata, because detaching would allow + * another thread to win the race to destroy tdata. + */ + if (!destroy_tdata) + tdata->attached = false; + tsd_prof_tdata_set(tsd, NULL); + } else + destroy_tdata = false; + malloc_mutex_unlock(tdata->lock); + if (destroy_tdata) + prof_tdata_destroy(tsd, tdata, true); +} + +prof_tdata_t * +prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata) +{ + uint64_t thr_uid = tdata->thr_uid; + uint64_t thr_discrim = tdata->thr_discrim + 1; + char *thread_name = (tdata->thread_name != NULL) ? + prof_thread_name_alloc(tsd, tdata->thread_name) : NULL; + bool active = tdata->active; + + prof_tdata_detach(tsd, tdata); + return (prof_tdata_init_impl(tsd, thr_uid, thr_discrim, thread_name, + active)); +} + +static bool +prof_tdata_expire(prof_tdata_t *tdata) +{ + bool destroy_tdata; + + malloc_mutex_lock(tdata->lock); + if (!tdata->expired) { + tdata->expired = true; + destroy_tdata = tdata->attached ? false : + prof_tdata_should_destroy(tdata, false); + } else + destroy_tdata = false; + malloc_mutex_unlock(tdata->lock); + + return (destroy_tdata); +} + +static prof_tdata_t * +prof_tdata_reset_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, void *arg) +{ + + return (prof_tdata_expire(tdata) ? tdata : NULL); } void -prof_tdata_cleanup(void *arg) +prof_reset(tsd_t *tsd, size_t lg_sample) { - prof_thr_cnt_t *cnt; - prof_tdata_t *prof_tdata = *(prof_tdata_t **)arg; + prof_tdata_t *next; - cassert(config_prof); + assert(lg_sample < (sizeof(uint64_t) << 3)); - if (prof_tdata == PROF_TDATA_STATE_REINCARNATED) { - /* - * Another destructor deallocated memory after this destructor - * was called. Reset prof_tdata to PROF_TDATA_STATE_PURGATORY - * in order to receive another callback. - */ - prof_tdata = PROF_TDATA_STATE_PURGATORY; - prof_tdata_tsd_set(&prof_tdata); - } else if (prof_tdata == PROF_TDATA_STATE_PURGATORY) { - /* - * The previous time this destructor was called, we set the key - * to PROF_TDATA_STATE_PURGATORY so that other destructors - * wouldn't cause re-creation of the prof_tdata. This time, do - * nothing, so that the destructor will not be called again. - */ - } else if (prof_tdata != NULL) { - /* - * Delete the hash table. All of its contents can still be - * iterated over via the LRU. - */ - ckh_delete(&prof_tdata->bt2cnt); - /* - * Iteratively merge cnt's into the global stats and delete - * them. - */ - while ((cnt = ql_last(&prof_tdata->lru_ql, lru_link)) != NULL) { - ql_remove(&prof_tdata->lru_ql, cnt, lru_link); - prof_ctx_merge(cnt->ctx, cnt); - idalloc(cnt); - } - idalloc(prof_tdata->vec); - idalloc(prof_tdata); - prof_tdata = PROF_TDATA_STATE_PURGATORY; - prof_tdata_tsd_set(&prof_tdata); + malloc_mutex_lock(&prof_dump_mtx); + malloc_mutex_lock(&tdatas_mtx); + + lg_prof_sample = lg_sample; + + next = NULL; + do { + prof_tdata_t *to_destroy = tdata_tree_iter(&tdatas, next, + prof_tdata_reset_iter, NULL); + if (to_destroy != NULL) { + next = tdata_tree_next(&tdatas, to_destroy); + prof_tdata_destroy_locked(tsd, to_destroy, false); + } else + next = NULL; + } while (next != NULL); + + malloc_mutex_unlock(&tdatas_mtx); + malloc_mutex_unlock(&prof_dump_mtx); +} + +void +prof_tdata_cleanup(tsd_t *tsd) +{ + prof_tdata_t *tdata; + + if (!config_prof) + return; + + tdata = tsd_prof_tdata_get(tsd); + if (tdata != NULL) + prof_tdata_detach(tsd, tdata); +} + +bool +prof_active_get(void) +{ + bool prof_active_current; + + malloc_mutex_lock(&prof_active_mtx); + prof_active_current = prof_active; + malloc_mutex_unlock(&prof_active_mtx); + return (prof_active_current); +} + +bool +prof_active_set(bool active) +{ + bool prof_active_old; + + malloc_mutex_lock(&prof_active_mtx); + prof_active_old = prof_active; + prof_active = active; + malloc_mutex_unlock(&prof_active_mtx); + return (prof_active_old); +} + +const char * +prof_thread_name_get(void) +{ + tsd_t *tsd; + prof_tdata_t *tdata; + + tsd = tsd_fetch(); + tdata = prof_tdata_get(tsd, true); + if (tdata == NULL) + return (""); + return (tdata->thread_name != NULL ? tdata->thread_name : ""); +} + +static char * +prof_thread_name_alloc(tsd_t *tsd, const char *thread_name) +{ + char *ret; + size_t size; + + if (thread_name == NULL) + return (NULL); + + size = strlen(thread_name) + 1; + if (size == 1) + return (""); + + ret = imalloc(tsd, size); + if (ret == NULL) + return (NULL); + memcpy(ret, thread_name, size); + return (ret); +} + +int +prof_thread_name_set(tsd_t *tsd, const char *thread_name) +{ + prof_tdata_t *tdata; + unsigned i; + char *s; + + tdata = prof_tdata_get(tsd, true); + if (tdata == NULL) + return (EAGAIN); + + /* Validate input. */ + if (thread_name == NULL) + return (EFAULT); + for (i = 0; thread_name[i] != '\0'; i++) { + char c = thread_name[i]; + if (!isgraph(c) && !isblank(c)) + return (EFAULT); } + + s = prof_thread_name_alloc(tsd, thread_name); + if (s == NULL) + return (EAGAIN); + + if (tdata->thread_name != NULL) { + idalloc(tsd, tdata->thread_name); + tdata->thread_name = NULL; + } + if (strlen(s) > 0) + tdata->thread_name = s; + return (0); +} + +bool +prof_thread_active_get(void) +{ + tsd_t *tsd; + prof_tdata_t *tdata; + + tsd = tsd_fetch(); + tdata = prof_tdata_get(tsd, true); + if (tdata == NULL) + return (false); + return (tdata->active); +} + +bool +prof_thread_active_set(bool active) +{ + tsd_t *tsd; + prof_tdata_t *tdata; + + tsd = tsd_fetch(); + tdata = prof_tdata_get(tsd, true); + if (tdata == NULL) + return (true); + tdata->active = active; + return (false); +} + +bool +prof_thread_active_init_get(void) +{ + bool active_init; + + malloc_mutex_lock(&prof_thread_active_init_mtx); + active_init = prof_thread_active_init; + malloc_mutex_unlock(&prof_thread_active_init_mtx); + return (active_init); +} + +bool +prof_thread_active_init_set(bool active_init) +{ + bool active_init_old; + + malloc_mutex_lock(&prof_thread_active_init_mtx); + active_init_old = prof_thread_active_init; + prof_thread_active_init = active_init; + malloc_mutex_unlock(&prof_thread_active_init_mtx); + return (active_init_old); } void @@ -1300,11 +1976,11 @@ prof_boot1(void) cassert(config_prof); /* - * opt_prof and prof_promote must be in their final state before any - * arenas are initialized, so this function must be executed early. + * opt_prof must be in its final state before any arenas are + * initialized, so this function must be executed early. */ - if (opt_prof_leak && opt_prof == false) { + if (opt_prof_leak && !opt_prof) { /* * Enable opt_prof, but in such a way that profiles are never * automatically dumped. @@ -1317,8 +1993,6 @@ prof_boot1(void) opt_lg_prof_interval); } } - - prof_promote = (opt_prof && opt_lg_prof_sample > LG_PAGE); } bool @@ -1328,36 +2002,61 @@ prof_boot2(void) cassert(config_prof); if (opt_prof) { + tsd_t *tsd; unsigned i; - if (ckh_new(&bt2ctx, PROF_CKH_MINITEMS, prof_bt_hash, + lg_prof_sample = opt_lg_prof_sample; + + prof_active = opt_prof_active; + if (malloc_mutex_init(&prof_active_mtx)) + return (true); + + prof_thread_active_init = opt_prof_thread_active_init; + if (malloc_mutex_init(&prof_thread_active_init_mtx)) + return (true); + + tsd = tsd_fetch(); + if (ckh_new(tsd, &bt2gctx, PROF_CKH_MINITEMS, prof_bt_hash, prof_bt_keycomp)) return (true); - if (malloc_mutex_init(&bt2ctx_mtx)) + if (malloc_mutex_init(&bt2gctx_mtx)) + return (true); + + tdata_tree_new(&tdatas); + if (malloc_mutex_init(&tdatas_mtx)) + return (true); + + next_thr_uid = 0; + if (malloc_mutex_init(&next_thr_uid_mtx)) return (true); - if (prof_tdata_tsd_boot()) { - malloc_write( - ": Error in pthread_key_create()\n"); - abort(); - } if (malloc_mutex_init(&prof_dump_seq_mtx)) return (true); if (malloc_mutex_init(&prof_dump_mtx)) return (true); - if (atexit(prof_fdump) != 0) { + if (opt_prof_final && opt_prof_prefix[0] != '\0' && + atexit(prof_fdump) != 0) { malloc_write(": Error in atexit()\n"); if (opt_abort) abort(); } - ctx_locks = (malloc_mutex_t *)base_alloc(PROF_NCTX_LOCKS * + gctx_locks = (malloc_mutex_t *)base_alloc(PROF_NCTX_LOCKS * sizeof(malloc_mutex_t)); - if (ctx_locks == NULL) + if (gctx_locks == NULL) return (true); for (i = 0; i < PROF_NCTX_LOCKS; i++) { - if (malloc_mutex_init(&ctx_locks[i])) + if (malloc_mutex_init(&gctx_locks[i])) + return (true); + } + + tdata_locks = (malloc_mutex_t *)base_alloc(PROF_NTDATA_LOCKS * + sizeof(malloc_mutex_t)); + if (tdata_locks == NULL) + return (true); + for (i = 0; i < PROF_NTDATA_LOCKS; i++) { + if (malloc_mutex_init(&tdata_locks[i])) return (true); } } @@ -1382,10 +2081,14 @@ prof_prefork(void) if (opt_prof) { unsigned i; - malloc_mutex_prefork(&bt2ctx_mtx); + malloc_mutex_prefork(&tdatas_mtx); + malloc_mutex_prefork(&bt2gctx_mtx); + malloc_mutex_prefork(&next_thr_uid_mtx); malloc_mutex_prefork(&prof_dump_seq_mtx); for (i = 0; i < PROF_NCTX_LOCKS; i++) - malloc_mutex_prefork(&ctx_locks[i]); + malloc_mutex_prefork(&gctx_locks[i]); + for (i = 0; i < PROF_NTDATA_LOCKS; i++) + malloc_mutex_prefork(&tdata_locks[i]); } } @@ -1396,10 +2099,14 @@ prof_postfork_parent(void) if (opt_prof) { unsigned i; + for (i = 0; i < PROF_NTDATA_LOCKS; i++) + malloc_mutex_postfork_parent(&tdata_locks[i]); for (i = 0; i < PROF_NCTX_LOCKS; i++) - malloc_mutex_postfork_parent(&ctx_locks[i]); + malloc_mutex_postfork_parent(&gctx_locks[i]); malloc_mutex_postfork_parent(&prof_dump_seq_mtx); - malloc_mutex_postfork_parent(&bt2ctx_mtx); + malloc_mutex_postfork_parent(&next_thr_uid_mtx); + malloc_mutex_postfork_parent(&bt2gctx_mtx); + malloc_mutex_postfork_parent(&tdatas_mtx); } } @@ -1410,10 +2117,14 @@ prof_postfork_child(void) if (opt_prof) { unsigned i; + for (i = 0; i < PROF_NTDATA_LOCKS; i++) + malloc_mutex_postfork_child(&tdata_locks[i]); for (i = 0; i < PROF_NCTX_LOCKS; i++) - malloc_mutex_postfork_child(&ctx_locks[i]); + malloc_mutex_postfork_child(&gctx_locks[i]); malloc_mutex_postfork_child(&prof_dump_seq_mtx); - malloc_mutex_postfork_child(&bt2ctx_mtx); + malloc_mutex_postfork_child(&next_thr_uid_mtx); + malloc_mutex_postfork_child(&bt2gctx_mtx); + malloc_mutex_postfork_child(&tdatas_mtx); } } diff --git a/memory/jemalloc/src/src/quarantine.c b/memory/jemalloc/src/src/quarantine.c index 5431511640a5..12c37e0a5f87 100644 --- a/memory/jemalloc/src/src/quarantine.c +++ b/memory/jemalloc/src/src/quarantine.c @@ -2,33 +2,31 @@ #include "jemalloc/internal/jemalloc_internal.h" /* - * quarantine pointers close to NULL are used to encode state information that + * Quarantine pointers close to NULL are used to encode state information that * is used for cleaning up during thread shutdown. */ #define QUARANTINE_STATE_REINCARNATED ((quarantine_t *)(uintptr_t)1) #define QUARANTINE_STATE_PURGATORY ((quarantine_t *)(uintptr_t)2) #define QUARANTINE_STATE_MAX QUARANTINE_STATE_PURGATORY -/******************************************************************************/ -/* Data. */ - -malloc_tsd_data(, quarantine, quarantine_t *, NULL) - /******************************************************************************/ /* Function prototypes for non-inline static functions. */ -static quarantine_t *quarantine_grow(quarantine_t *quarantine); -static void quarantine_drain_one(quarantine_t *quarantine); -static void quarantine_drain(quarantine_t *quarantine, size_t upper_bound); +static quarantine_t *quarantine_grow(tsd_t *tsd, quarantine_t *quarantine); +static void quarantine_drain_one(tsd_t *tsd, quarantine_t *quarantine); +static void quarantine_drain(tsd_t *tsd, quarantine_t *quarantine, + size_t upper_bound); /******************************************************************************/ -quarantine_t * -quarantine_init(size_t lg_maxobjs) +static quarantine_t * +quarantine_init(tsd_t *tsd, size_t lg_maxobjs) { quarantine_t *quarantine; - quarantine = (quarantine_t *)imalloc(offsetof(quarantine_t, objs) + + assert(tsd_nominal(tsd)); + + quarantine = (quarantine_t *)imalloc(tsd, offsetof(quarantine_t, objs) + ((ZU(1) << lg_maxobjs) * sizeof(quarantine_obj_t))); if (quarantine == NULL) return (NULL); @@ -37,19 +35,36 @@ quarantine_init(size_t lg_maxobjs) quarantine->first = 0; quarantine->lg_maxobjs = lg_maxobjs; - quarantine_tsd_set(&quarantine); - return (quarantine); } +void +quarantine_alloc_hook_work(tsd_t *tsd) +{ + quarantine_t *quarantine; + + if (!tsd_nominal(tsd)) + return; + + quarantine = quarantine_init(tsd, LG_MAXOBJS_INIT); + /* + * Check again whether quarantine has been initialized, because + * quarantine_init() may have triggered recursive initialization. + */ + if (tsd_quarantine_get(tsd) == NULL) + tsd_quarantine_set(tsd, quarantine); + else + idalloc(tsd, quarantine); +} + static quarantine_t * -quarantine_grow(quarantine_t *quarantine) +quarantine_grow(tsd_t *tsd, quarantine_t *quarantine) { quarantine_t *ret; - ret = quarantine_init(quarantine->lg_maxobjs + 1); + ret = quarantine_init(tsd, quarantine->lg_maxobjs + 1); if (ret == NULL) { - quarantine_drain_one(quarantine); + quarantine_drain_one(tsd, quarantine); return (quarantine); } @@ -71,17 +86,18 @@ quarantine_grow(quarantine_t *quarantine) memcpy(&ret->objs[ncopy_a], quarantine->objs, ncopy_b * sizeof(quarantine_obj_t)); } - idalloc(quarantine); + idalloc(tsd, quarantine); + tsd_quarantine_set(tsd, ret); return (ret); } static void -quarantine_drain_one(quarantine_t *quarantine) +quarantine_drain_one(tsd_t *tsd, quarantine_t *quarantine) { quarantine_obj_t *obj = &quarantine->objs[quarantine->first]; assert(obj->usize == isalloc(obj->ptr, config_prof)); - idalloc(obj->ptr); + idalloc(tsd, obj->ptr); quarantine->curbytes -= obj->usize; quarantine->curobjs--; quarantine->first = (quarantine->first + 1) & ((ZU(1) << @@ -89,15 +105,15 @@ quarantine_drain_one(quarantine_t *quarantine) } static void -quarantine_drain(quarantine_t *quarantine, size_t upper_bound) +quarantine_drain(tsd_t *tsd, quarantine_t *quarantine, size_t upper_bound) { while (quarantine->curbytes > upper_bound && quarantine->curobjs > 0) - quarantine_drain_one(quarantine); + quarantine_drain_one(tsd, quarantine); } void -quarantine(void *ptr) +quarantine(tsd_t *tsd, void *ptr) { quarantine_t *quarantine; size_t usize = isalloc(ptr, config_prof); @@ -105,17 +121,8 @@ quarantine(void *ptr) cassert(config_fill); assert(opt_quarantine); - quarantine = *quarantine_tsd_get(); - if ((uintptr_t)quarantine <= (uintptr_t)QUARANTINE_STATE_MAX) { - if (quarantine == QUARANTINE_STATE_PURGATORY) { - /* - * Make a note that quarantine() was called after - * quarantine_cleanup() was called. - */ - quarantine = QUARANTINE_STATE_REINCARNATED; - quarantine_tsd_set(&quarantine); - } - idalloc(ptr); + if ((quarantine = tsd_quarantine_get(tsd)) == NULL) { + idalloc(tsd, ptr); return; } /* @@ -125,11 +132,11 @@ quarantine(void *ptr) if (quarantine->curbytes + usize > opt_quarantine) { size_t upper_bound = (opt_quarantine >= usize) ? opt_quarantine - usize : 0; - quarantine_drain(quarantine, upper_bound); + quarantine_drain(tsd, quarantine, upper_bound); } /* Grow the quarantine ring buffer if it's full. */ if (quarantine->curobjs == (ZU(1) << quarantine->lg_maxobjs)) - quarantine = quarantine_grow(quarantine); + quarantine = quarantine_grow(tsd, quarantine); /* quarantine_grow() must free a slot if it fails to grow. */ assert(quarantine->curobjs < (ZU(1) << quarantine->lg_maxobjs)); /* Append ptr if its size doesn't exceed the quarantine size. */ @@ -141,12 +148,12 @@ quarantine(void *ptr) obj->usize = usize; quarantine->curbytes += usize; quarantine->curobjs++; - if (config_fill && opt_junk) { + if (config_fill && unlikely(opt_junk_free)) { /* * Only do redzone validation if Valgrind isn't in * operation. */ - if ((config_valgrind == false || opt_valgrind == false) + if ((!config_valgrind || likely(!in_valgrind)) && usize <= SMALL_MAXCLASS) arena_quarantine_junk_small(ptr, usize); else @@ -154,46 +161,22 @@ quarantine(void *ptr) } } else { assert(quarantine->curbytes == 0); - idalloc(ptr); + idalloc(tsd, ptr); } } void -quarantine_cleanup(void *arg) +quarantine_cleanup(tsd_t *tsd) { - quarantine_t *quarantine = *(quarantine_t **)arg; + quarantine_t *quarantine; - if (quarantine == QUARANTINE_STATE_REINCARNATED) { - /* - * Another destructor deallocated memory after this destructor - * was called. Reset quarantine to QUARANTINE_STATE_PURGATORY - * in order to receive another callback. - */ - quarantine = QUARANTINE_STATE_PURGATORY; - quarantine_tsd_set(&quarantine); - } else if (quarantine == QUARANTINE_STATE_PURGATORY) { - /* - * The previous time this destructor was called, we set the key - * to QUARANTINE_STATE_PURGATORY so that other destructors - * wouldn't cause re-creation of the quarantine. This time, do - * nothing, so that the destructor will not be called again. - */ - } else if (quarantine != NULL) { - quarantine_drain(quarantine, 0); - idalloc(quarantine); - quarantine = QUARANTINE_STATE_PURGATORY; - quarantine_tsd_set(&quarantine); + if (!config_fill) + return; + + quarantine = tsd_quarantine_get(tsd); + if (quarantine != NULL) { + quarantine_drain(tsd, quarantine, 0); + idalloc(tsd, quarantine); + tsd_quarantine_set(tsd, NULL); } } - -bool -quarantine_boot(void) -{ - - cassert(config_fill); - - if (quarantine_tsd_boot()) - return (true); - - return (false); -} diff --git a/memory/jemalloc/src/src/rtree.c b/memory/jemalloc/src/src/rtree.c index 87b0b154456f..2ff93dbe75ce 100644 --- a/memory/jemalloc/src/src/rtree.c +++ b/memory/jemalloc/src/src/rtree.c @@ -9,8 +9,10 @@ rtree_new(unsigned bits, rtree_alloc_t *alloc, rtree_dalloc_t *dalloc) assert(bits > 0 && bits <= (sizeof(uintptr_t) << 3)); - bits_per_level = jemalloc_ffs(pow2_ceil((RTREE_NODESIZE / sizeof(void *)))) - 1; - bits_in_leaf = jemalloc_ffs(pow2_ceil((RTREE_NODESIZE / sizeof(uint8_t)))) - 1; + bits_per_level = jemalloc_ffs(pow2_ceil((RTREE_NODESIZE / sizeof(void + *)))) - 1; + bits_in_leaf = jemalloc_ffs(pow2_ceil((RTREE_NODESIZE / + sizeof(uint8_t)))) - 1; if (bits > bits_in_leaf) { height = 1 + (bits - bits_in_leaf) / bits_per_level; if ((height-1) * bits_per_level + bits_in_leaf != bits) diff --git a/memory/jemalloc/src/src/stats.c b/memory/jemalloc/src/src/stats.c index bef2ab33cd4d..054f0332a258 100644 --- a/memory/jemalloc/src/src/stats.c +++ b/memory/jemalloc/src/src/stats.c @@ -48,8 +48,10 @@ static void stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, unsigned i); static void stats_arena_lruns_print(void (*write_cb)(void *, const char *), void *cbopaque, unsigned i); +static void stats_arena_hchunks_print( + void (*write_cb)(void *, const char *), void *cbopaque, unsigned i); static void stats_arena_print(void (*write_cb)(void *, const char *), - void *cbopaque, unsigned i, bool bins, bool large); + void *cbopaque, unsigned i, bool bins, bool large, bool huge); /******************************************************************************/ @@ -58,62 +60,56 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, unsigned i) { size_t page; - bool config_tcache; - unsigned nbins, j, gap_start; + bool config_tcache, in_gap; + unsigned nbins, j; CTL_GET("arenas.page", &page, size_t); CTL_GET("config.tcache", &config_tcache, bool); if (config_tcache) { malloc_cprintf(write_cb, cbopaque, - "bins: bin size regs pgs allocated nmalloc" - " ndalloc nrequests nfills nflushes" - " newruns reruns curruns\n"); + "bins: size ind allocated nmalloc" + " ndalloc nrequests curregs curruns regs" + " pgs util nfills nflushes newruns" + " reruns\n"); } else { malloc_cprintf(write_cb, cbopaque, - "bins: bin size regs pgs allocated nmalloc" - " ndalloc newruns reruns curruns\n"); + "bins: size ind allocated nmalloc" + " ndalloc nrequests curregs curruns regs" + " pgs util newruns reruns\n"); } CTL_GET("arenas.nbins", &nbins, unsigned); - for (j = 0, gap_start = UINT_MAX; j < nbins; j++) { + for (j = 0, in_gap = false; j < nbins; j++) { uint64_t nruns; CTL_IJ_GET("stats.arenas.0.bins.0.nruns", &nruns, uint64_t); - if (nruns == 0) { - if (gap_start == UINT_MAX) - gap_start = j; - } else { - size_t reg_size, run_size, allocated; + if (nruns == 0) + in_gap = true; + else { + size_t reg_size, run_size, curregs, availregs, milli; + size_t curruns; uint32_t nregs; uint64_t nmalloc, ndalloc, nrequests, nfills, nflushes; uint64_t reruns; - size_t curruns; + char util[6]; /* "x.yyy". */ - if (gap_start != UINT_MAX) { - if (j > gap_start + 1) { - /* Gap of more than one size class. */ - malloc_cprintf(write_cb, cbopaque, - "[%u..%u]\n", gap_start, - j - 1); - } else { - /* Gap of one size class. */ - malloc_cprintf(write_cb, cbopaque, - "[%u]\n", gap_start); - } - gap_start = UINT_MAX; + if (in_gap) { + malloc_cprintf(write_cb, cbopaque, + " ---\n"); + in_gap = false; } CTL_J_GET("arenas.bin.0.size", ®_size, size_t); CTL_J_GET("arenas.bin.0.nregs", &nregs, uint32_t); CTL_J_GET("arenas.bin.0.run_size", &run_size, size_t); - CTL_IJ_GET("stats.arenas.0.bins.0.allocated", - &allocated, size_t); CTL_IJ_GET("stats.arenas.0.bins.0.nmalloc", &nmalloc, uint64_t); CTL_IJ_GET("stats.arenas.0.bins.0.ndalloc", &ndalloc, uint64_t); + CTL_IJ_GET("stats.arenas.0.bins.0.curregs", + &curregs, size_t); + CTL_IJ_GET("stats.arenas.0.bins.0.nrequests", + &nrequests, uint64_t); if (config_tcache) { - CTL_IJ_GET("stats.arenas.0.bins.0.nrequests", - &nrequests, uint64_t); CTL_IJ_GET("stats.arenas.0.bins.0.nfills", &nfills, uint64_t); CTL_IJ_GET("stats.arenas.0.bins.0.nflushes", @@ -123,35 +119,47 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, uint64_t); CTL_IJ_GET("stats.arenas.0.bins.0.curruns", &curruns, size_t); + + availregs = nregs * curruns; + milli = (availregs != 0) ? (1000 * curregs) / availregs + : 1000; + assert(milli <= 1000); + if (milli < 10) { + malloc_snprintf(util, sizeof(util), "0.00%zu", + milli); + } else if (milli < 100) { + malloc_snprintf(util, sizeof(util), "0.0%zu", + milli); + } else if (milli < 1000) { + malloc_snprintf(util, sizeof(util), "0.%zu", + milli); + } else + malloc_snprintf(util, sizeof(util), "1"); + if (config_tcache) { malloc_cprintf(write_cb, cbopaque, - "%13u %5zu %4u %3zu %12zu %12"PRIu64 + "%20zu %3u %12zu %12"PRIu64" %12"PRIu64 + " %12"PRIu64" %12zu %12zu %4u %3zu %-5s" " %12"PRIu64" %12"PRIu64" %12"PRIu64 - " %12"PRIu64" %12"PRIu64" %12"PRIu64 - " %12zu\n", - j, reg_size, nregs, run_size / page, - allocated, nmalloc, ndalloc, nrequests, - nfills, nflushes, nruns, reruns, curruns); + " %12"PRIu64"\n", + reg_size, j, curregs * reg_size, nmalloc, + ndalloc, nrequests, curregs, curruns, nregs, + run_size / page, util, nfills, nflushes, + nruns, reruns); } else { malloc_cprintf(write_cb, cbopaque, - "%13u %5zu %4u %3zu %12zu %12"PRIu64 - " %12"PRIu64" %12"PRIu64" %12"PRIu64 - " %12zu\n", - j, reg_size, nregs, run_size / page, - allocated, nmalloc, ndalloc, nruns, reruns, - curruns); + "%20zu %3u %12zu %12"PRIu64" %12"PRIu64 + " %12"PRIu64" %12zu %12zu %4u %3zu %-5s" + " %12"PRIu64" %12"PRIu64"\n", + reg_size, j, curregs * reg_size, nmalloc, + ndalloc, nrequests, curregs, curruns, nregs, + run_size / page, util, nruns, reruns); } } } - if (gap_start != UINT_MAX) { - if (j > gap_start + 1) { - /* Gap of more than one size class. */ - malloc_cprintf(write_cb, cbopaque, "[%u..%u]\n", - gap_start, j - 1); - } else { - /* Gap of one size class. */ - malloc_cprintf(write_cb, cbopaque, "[%u]\n", gap_start); - } + if (in_gap) { + malloc_cprintf(write_cb, cbopaque, + " ---\n"); } } @@ -159,16 +167,15 @@ static void stats_arena_lruns_print(void (*write_cb)(void *, const char *), void *cbopaque, unsigned i) { - size_t page, nlruns, j; - ssize_t gap_start; - - CTL_GET("arenas.page", &page, size_t); + unsigned nbins, nlruns, j; + bool in_gap; malloc_cprintf(write_cb, cbopaque, - "large: size pages nmalloc ndalloc nrequests" - " curruns\n"); - CTL_GET("arenas.nlruns", &nlruns, size_t); - for (j = 0, gap_start = -1; j < nlruns; j++) { + "large: size ind allocated nmalloc ndalloc" + " nrequests curruns\n"); + CTL_GET("arenas.nbins", &nbins, unsigned); + CTL_GET("arenas.nlruns", &nlruns, unsigned); + for (j = 0, in_gap = false; j < nlruns; j++) { uint64_t nmalloc, ndalloc, nrequests; size_t run_size, curruns; @@ -178,32 +185,82 @@ stats_arena_lruns_print(void (*write_cb)(void *, const char *), void *cbopaque, uint64_t); CTL_IJ_GET("stats.arenas.0.lruns.0.nrequests", &nrequests, uint64_t); - if (nrequests == 0) { - if (gap_start == -1) - gap_start = j; - } else { + if (nrequests == 0) + in_gap = true; + else { CTL_J_GET("arenas.lrun.0.size", &run_size, size_t); CTL_IJ_GET("stats.arenas.0.lruns.0.curruns", &curruns, size_t); - if (gap_start != -1) { - malloc_cprintf(write_cb, cbopaque, "[%zu]\n", - j - gap_start); - gap_start = -1; + if (in_gap) { + malloc_cprintf(write_cb, cbopaque, + " ---\n"); + in_gap = false; } malloc_cprintf(write_cb, cbopaque, - "%13zu %5zu %12"PRIu64" %12"PRIu64" %12"PRIu64 + "%20zu %3u %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64 " %12zu\n", - run_size, run_size / page, nmalloc, ndalloc, - nrequests, curruns); + run_size, nbins + j, curruns * run_size, nmalloc, + ndalloc, nrequests, curruns); } } - if (gap_start != -1) - malloc_cprintf(write_cb, cbopaque, "[%zu]\n", j - gap_start); + if (in_gap) { + malloc_cprintf(write_cb, cbopaque, + " ---\n"); + } +} + +static void +stats_arena_hchunks_print(void (*write_cb)(void *, const char *), + void *cbopaque, unsigned i) +{ + unsigned nbins, nlruns, nhchunks, j; + bool in_gap; + + malloc_cprintf(write_cb, cbopaque, + "huge: size ind allocated nmalloc ndalloc" + " nrequests curhchunks\n"); + CTL_GET("arenas.nbins", &nbins, unsigned); + CTL_GET("arenas.nlruns", &nlruns, unsigned); + CTL_GET("arenas.nhchunks", &nhchunks, unsigned); + for (j = 0, in_gap = false; j < nhchunks; j++) { + uint64_t nmalloc, ndalloc, nrequests; + size_t hchunk_size, curhchunks; + + CTL_IJ_GET("stats.arenas.0.hchunks.0.nmalloc", &nmalloc, + uint64_t); + CTL_IJ_GET("stats.arenas.0.hchunks.0.ndalloc", &ndalloc, + uint64_t); + CTL_IJ_GET("stats.arenas.0.hchunks.0.nrequests", &nrequests, + uint64_t); + if (nrequests == 0) + in_gap = true; + else { + CTL_J_GET("arenas.hchunk.0.size", &hchunk_size, + size_t); + CTL_IJ_GET("stats.arenas.0.hchunks.0.curhchunks", + &curhchunks, size_t); + if (in_gap) { + malloc_cprintf(write_cb, cbopaque, + " ---\n"); + in_gap = false; + } + malloc_cprintf(write_cb, cbopaque, + "%20zu %3u %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64 + " %12zu\n", + hchunk_size, nbins + nlruns + j, + curhchunks * hchunk_size, nmalloc, ndalloc, + nrequests, curhchunks); + } + } + if (in_gap) { + malloc_cprintf(write_cb, cbopaque, + " ---\n"); + } } static void stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, - unsigned i, bool bins, bool large) + unsigned i, bool bins, bool large, bool huge) { unsigned nthreads; const char *dss; @@ -213,6 +270,8 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, uint64_t small_nmalloc, small_ndalloc, small_nrequests; size_t large_allocated; uint64_t large_nmalloc, large_ndalloc, large_nrequests; + size_t huge_allocated; + uint64_t huge_nmalloc, huge_ndalloc, huge_nrequests; CTL_GET("arenas.page", &page, size_t); @@ -234,35 +293,51 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, nmadvise, nmadvise == 1 ? "" : "s", purged); malloc_cprintf(write_cb, cbopaque, - " allocated nmalloc ndalloc nrequests\n"); + " allocated nmalloc ndalloc" + " nrequests\n"); CTL_I_GET("stats.arenas.0.small.allocated", &small_allocated, size_t); CTL_I_GET("stats.arenas.0.small.nmalloc", &small_nmalloc, uint64_t); CTL_I_GET("stats.arenas.0.small.ndalloc", &small_ndalloc, uint64_t); CTL_I_GET("stats.arenas.0.small.nrequests", &small_nrequests, uint64_t); malloc_cprintf(write_cb, cbopaque, - "small: %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64"\n", + "small: %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64 + "\n", small_allocated, small_nmalloc, small_ndalloc, small_nrequests); CTL_I_GET("stats.arenas.0.large.allocated", &large_allocated, size_t); CTL_I_GET("stats.arenas.0.large.nmalloc", &large_nmalloc, uint64_t); CTL_I_GET("stats.arenas.0.large.ndalloc", &large_ndalloc, uint64_t); CTL_I_GET("stats.arenas.0.large.nrequests", &large_nrequests, uint64_t); malloc_cprintf(write_cb, cbopaque, - "large: %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64"\n", + "large: %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64 + "\n", large_allocated, large_nmalloc, large_ndalloc, large_nrequests); + CTL_I_GET("stats.arenas.0.huge.allocated", &huge_allocated, size_t); + CTL_I_GET("stats.arenas.0.huge.nmalloc", &huge_nmalloc, uint64_t); + CTL_I_GET("stats.arenas.0.huge.ndalloc", &huge_ndalloc, uint64_t); + CTL_I_GET("stats.arenas.0.huge.nrequests", &huge_nrequests, uint64_t); malloc_cprintf(write_cb, cbopaque, - "total: %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64"\n", - small_allocated + large_allocated, - small_nmalloc + large_nmalloc, - small_ndalloc + large_ndalloc, - small_nrequests + large_nrequests); - malloc_cprintf(write_cb, cbopaque, "active: %12zu\n", pactive * page); + "huge: %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64 + "\n", + huge_allocated, huge_nmalloc, huge_ndalloc, huge_nrequests); + malloc_cprintf(write_cb, cbopaque, + "total: %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64 + "\n", + small_allocated + large_allocated + huge_allocated, + small_nmalloc + large_nmalloc + huge_nmalloc, + small_ndalloc + large_ndalloc + huge_ndalloc, + small_nrequests + large_nrequests + huge_nrequests); + malloc_cprintf(write_cb, cbopaque, "active: %12zu\n", + pactive * page); CTL_I_GET("stats.arenas.0.mapped", &mapped, size_t); - malloc_cprintf(write_cb, cbopaque, "mapped: %12zu\n", mapped); + malloc_cprintf(write_cb, cbopaque, "mapped: %12zu\n", + mapped); if (bins) stats_arena_bins_print(write_cb, cbopaque, i); if (large) stats_arena_lruns_print(write_cb, cbopaque, i); + if (huge) + stats_arena_hchunks_print(write_cb, cbopaque, i); } void @@ -277,6 +352,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, bool unmerged = true; bool bins = true; bool large = true; + bool huge = true; /* * Refresh stats, in case mallctl() was called by the application. @@ -319,6 +395,9 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, case 'l': large = false; break; + case 'h': + huge = false; + break; default:; } } @@ -327,7 +406,6 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "___ Begin jemalloc statistics ___\n"); if (general) { - int err; const char *cpv; bool bv; unsigned uv; @@ -346,26 +424,31 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, bv ? "enabled" : "disabled"); #define OPT_WRITE_BOOL(n) \ - if ((err = je_mallctl("opt."#n, &bv, &bsz, NULL, 0)) \ - == 0) { \ + if (je_mallctl("opt."#n, &bv, &bsz, NULL, 0) == 0) { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %s\n", bv ? "true" : "false"); \ } +#define OPT_WRITE_BOOL_MUTABLE(n, m) { \ + bool bv2; \ + if (je_mallctl("opt."#n, &bv, &bsz, NULL, 0) == 0 && \ + je_mallctl(#m, &bv2, &bsz, NULL, 0) == 0) { \ + malloc_cprintf(write_cb, cbopaque, \ + " opt."#n": %s ("#m": %s)\n", bv ? "true" \ + : "false", bv2 ? "true" : "false"); \ + } \ +} #define OPT_WRITE_SIZE_T(n) \ - if ((err = je_mallctl("opt."#n, &sv, &ssz, NULL, 0)) \ - == 0) { \ + if (je_mallctl("opt."#n, &sv, &ssz, NULL, 0) == 0) { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %zu\n", sv); \ } #define OPT_WRITE_SSIZE_T(n) \ - if ((err = je_mallctl("opt."#n, &ssv, &sssz, NULL, 0)) \ - == 0) { \ + if (je_mallctl("opt."#n, &ssv, &sssz, NULL, 0) == 0) { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %zd\n", ssv); \ } #define OPT_WRITE_CHAR_P(n) \ - if ((err = je_mallctl("opt."#n, &cpv, &cpsz, NULL, 0)) \ - == 0) { \ + if (je_mallctl("opt."#n, &cpv, &cpsz, NULL, 0) == 0) { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": \"%s\"\n", cpv); \ } @@ -389,7 +472,9 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, OPT_WRITE_SSIZE_T(lg_tcache_max) OPT_WRITE_BOOL(prof) OPT_WRITE_CHAR_P(prof_prefix) - OPT_WRITE_BOOL(prof_active) + OPT_WRITE_BOOL_MUTABLE(prof_active, prof.active) + OPT_WRITE_BOOL_MUTABLE(prof_thread_active_init, + prof.thread_active_init) OPT_WRITE_SSIZE_T(lg_prof_sample) OPT_WRITE_BOOL(prof_accum) OPT_WRITE_SSIZE_T(lg_prof_interval) @@ -398,6 +483,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, OPT_WRITE_BOOL(prof_leak) #undef OPT_WRITE_BOOL +#undef OPT_WRITE_BOOL_MUTABLE #undef OPT_WRITE_SIZE_T #undef OPT_WRITE_SSIZE_T #undef OPT_WRITE_CHAR_P @@ -425,14 +511,12 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "Min active:dirty page ratio per arena: N/A\n"); } - if ((err = je_mallctl("arenas.tcache_max", &sv, &ssz, NULL, 0)) - == 0) { + if (je_mallctl("arenas.tcache_max", &sv, &ssz, NULL, 0) == 0) { malloc_cprintf(write_cb, cbopaque, "Maximum thread-cached size class: %zu\n", sv); } - if ((err = je_mallctl("opt.prof", &bv, &bsz, NULL, 0)) == 0 && - bv) { - CTL_GET("opt.lg_prof_sample", &sv, size_t); + if (je_mallctl("opt.prof", &bv, &bsz, NULL, 0) == 0 && bv) { + CTL_GET("prof.lg_sample", &sv, size_t); malloc_cprintf(write_cb, cbopaque, "Average profile sample interval: %"PRIu64 " (2^%zu)\n", (((uint64_t)1U) << sv), sv); @@ -458,8 +542,6 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, size_t allocated, active, mapped; size_t chunks_current, chunks_high; uint64_t chunks_total; - size_t huge_allocated; - uint64_t huge_nmalloc, huge_ndalloc; CTL_GET("stats.cactive", &cactive, size_t *); CTL_GET("stats.allocated", &allocated, size_t); @@ -481,16 +563,6 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, " %13"PRIu64" %12zu %12zu\n", chunks_total, chunks_high, chunks_current); - /* Print huge stats. */ - CTL_GET("stats.huge.nmalloc", &huge_nmalloc, uint64_t); - CTL_GET("stats.huge.ndalloc", &huge_ndalloc, uint64_t); - CTL_GET("stats.huge.allocated", &huge_allocated, size_t); - malloc_cprintf(write_cb, cbopaque, - "huge: nmalloc ndalloc allocated\n"); - malloc_cprintf(write_cb, cbopaque, - " %12"PRIu64" %12"PRIu64" %12zu\n", - huge_nmalloc, huge_ndalloc, huge_allocated); - if (merged) { unsigned narenas; @@ -508,12 +580,12 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, ninitialized++; } - if (ninitialized > 1 || unmerged == false) { + if (ninitialized > 1 || !unmerged) { /* Print merged arena stats. */ malloc_cprintf(write_cb, cbopaque, "\nMerged arenas stats:\n"); stats_arena_print(write_cb, cbopaque, - narenas, bins, large); + narenas, bins, large, huge); } } } @@ -539,7 +611,8 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, cbopaque, "\narenas[%u]:\n", i); stats_arena_print(write_cb, - cbopaque, i, bins, large); + cbopaque, i, bins, large, + huge); } } } diff --git a/memory/jemalloc/src/src/tcache.c b/memory/jemalloc/src/src/tcache.c index 6de92960b2df..34224ec4a195 100644 --- a/memory/jemalloc/src/src/tcache.c +++ b/memory/jemalloc/src/src/tcache.c @@ -4,9 +4,6 @@ /******************************************************************************/ /* Data. */ -malloc_tsd_data(, tcache, tcache_t *, NULL) -malloc_tsd_data(, tcache_enabled, tcache_enabled_t, tcache_enabled_default) - bool opt_tcache = true; ssize_t opt_lg_tcache_max = LG_TCACHE_MAXCLASS_DEFAULT; @@ -27,7 +24,7 @@ size_t tcache_salloc(const void *ptr) void tcache_event_hard(tcache_t *tcache) { - size_t binind = tcache->next_gc_bin; + index_t binind = tcache->next_gc_bin; tcache_bin_t *tbin = &tcache->tbins[binind]; tcache_bin_info_t *tbin_info = &tcache_bin_info[binind]; @@ -65,7 +62,7 @@ tcache_event_hard(tcache_t *tcache) } void * -tcache_alloc_small_hard(tcache_t *tcache, tcache_bin_t *tbin, size_t binind) +tcache_alloc_small_hard(tcache_t *tcache, tcache_bin_t *tbin, index_t binind) { void *ret; @@ -79,7 +76,7 @@ tcache_alloc_small_hard(tcache_t *tcache, tcache_bin_t *tbin, size_t binind) } void -tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem, +tcache_bin_flush_small(tcache_bin_t *tbin, index_t binind, unsigned rem, tcache_t *tcache) { void *ptr; @@ -104,7 +101,7 @@ tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem, malloc_mutex_lock(&bin->lock); if (config_stats && arena == tcache->arena) { - assert(merged_stats == false); + assert(!merged_stats); merged_stats = true; bin->stats.nflushes++; bin->stats.nrequests += tbin->tstats.nrequests; @@ -118,14 +115,10 @@ tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem, if (chunk->arena == arena) { size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - arena_chunk_map_t *mapelm = - arena_mapp_get(chunk, pageind); - if (config_fill && opt_junk) { - arena_alloc_junk_small(ptr, - &arena_bin_info[binind], true); - } - arena_dalloc_bin_locked(arena, chunk, ptr, - mapelm); + arena_chunk_map_bits_t *bitselm = + arena_bitselm_get(chunk, pageind); + arena_dalloc_bin_junked_locked(arena, chunk, + ptr, bitselm); } else { /* * This object was allocated via a different @@ -139,7 +132,7 @@ tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem, } malloc_mutex_unlock(&bin->lock); } - if (config_stats && merged_stats == false) { + if (config_stats && !merged_stats) { /* * The flush loop didn't happen to flush to this thread's * arena, so the stats didn't get merged. Manually do so now. @@ -160,7 +153,7 @@ tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem, } void -tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem, +tcache_bin_flush_large(tcache_bin_t *tbin, index_t binind, unsigned rem, tcache_t *tcache) { void *ptr; @@ -200,9 +193,10 @@ tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem, ptr = tbin->avail[i]; assert(ptr != NULL); chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (chunk->arena == arena) - arena_dalloc_large_locked(arena, chunk, ptr); - else { + if (chunk->arena == arena) { + arena_dalloc_large_junked_locked(arena, chunk, + ptr); + } else { /* * This object was allocated via a different * arena than the one that is currently locked. @@ -217,7 +211,7 @@ tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem, if (config_prof && idump) prof_idump(); } - if (config_stats && merged_stats == false) { + if (config_stats && !merged_stats) { /* * The flush loop didn't happen to flush to this thread's * arena, so the stats didn't get merged. Manually do so now. @@ -252,6 +246,14 @@ tcache_arena_associate(tcache_t *tcache, arena_t *arena) tcache->arena = arena; } +void +tcache_arena_reassociate(tcache_t *tcache, arena_t *arena) +{ + + tcache_arena_dissociate(tcache); + tcache_arena_associate(tcache, arena); +} + void tcache_arena_dissociate(tcache_t *tcache) { @@ -266,7 +268,23 @@ tcache_arena_dissociate(tcache_t *tcache) } tcache_t * -tcache_create(arena_t *arena) +tcache_get_hard(tsd_t *tsd) +{ + arena_t *arena; + + if (!tcache_enabled_get()) { + if (tsd_nominal(tsd)) + tcache_enabled_set(false); /* Memoize. */ + return (NULL); + } + arena = arena_choose(tsd, NULL); + if (unlikely(arena == NULL)) + return (NULL); + return (tcache_create(tsd, arena)); +} + +tcache_t * +tcache_create(tsd_t *tsd, arena_t *arena) { tcache_t *tcache; size_t size, stack_offset; @@ -277,23 +295,10 @@ tcache_create(arena_t *arena) size = PTR_CEILING(size); stack_offset = size; size += stack_nelms * sizeof(void *); - /* - * Round up to the nearest multiple of the cacheline size, in order to - * avoid the possibility of false cacheline sharing. - * - * That this works relies on the same logic as in ipalloc(), but we - * cannot directly call ipalloc() here due to tcache bootstrapping - * issues. - */ - size = (size + CACHELINE_MASK) & (-CACHELINE); - - if (size <= SMALL_MAXCLASS) - tcache = (tcache_t *)arena_malloc_small(arena, size, true); - else if (size <= tcache_maxclass) - tcache = (tcache_t *)arena_malloc_large(arena, size, true); - else - tcache = (tcache_t *)icalloct(size, false, arena); + /* Avoid false cacheline sharing. */ + size = sa2u(size, CACHELINE); + tcache = ipalloct(tsd, size, CACHELINE, true, false, arena); if (tcache == NULL) return (NULL); @@ -307,16 +312,13 @@ tcache_create(arena_t *arena) stack_offset += tcache_bin_info[i].ncached_max * sizeof(void *); } - tcache_tsd_set(&tcache); - return (tcache); } -void -tcache_destroy(tcache_t *tcache) +static void +tcache_destroy(tsd_t *tsd, tcache_t *tcache) { unsigned i; - size_t tcache_size; tcache_arena_dissociate(tcache); @@ -351,54 +353,30 @@ tcache_destroy(tcache_t *tcache) arena_prof_accum(tcache->arena, tcache->prof_accumbytes)) prof_idump(); - tcache_size = arena_salloc(tcache, false); - if (tcache_size <= SMALL_MAXCLASS) { - arena_chunk_t *chunk = CHUNK_ADDR2BASE(tcache); - arena_t *arena = chunk->arena; - size_t pageind = ((uintptr_t)tcache - (uintptr_t)chunk) >> - LG_PAGE; - arena_chunk_map_t *mapelm = arena_mapp_get(chunk, pageind); - - arena_dalloc_bin(arena, chunk, tcache, pageind, mapelm); - } else if (tcache_size <= tcache_maxclass) { - arena_chunk_t *chunk = CHUNK_ADDR2BASE(tcache); - arena_t *arena = chunk->arena; - - arena_dalloc_large(arena, chunk, tcache); - } else - idalloct(tcache, false); + idalloct(tsd, tcache, false); } void -tcache_thread_cleanup(void *arg) +tcache_cleanup(tsd_t *tsd) { - tcache_t *tcache = *(tcache_t **)arg; + tcache_t *tcache; - if (tcache == TCACHE_STATE_DISABLED) { - /* Do nothing. */ - } else if (tcache == TCACHE_STATE_REINCARNATED) { - /* - * Another destructor called an allocator function after this - * destructor was called. Reset tcache to - * TCACHE_STATE_PURGATORY in order to receive another callback. - */ - tcache = TCACHE_STATE_PURGATORY; - tcache_tsd_set(&tcache); - } else if (tcache == TCACHE_STATE_PURGATORY) { - /* - * The previous time this destructor was called, we set the key - * to TCACHE_STATE_PURGATORY so that other destructors wouldn't - * cause re-creation of the tcache. This time, do nothing, so - * that the destructor will not be called again. - */ - } else if (tcache != NULL) { - assert(tcache != TCACHE_STATE_PURGATORY); - tcache_destroy(tcache); - tcache = TCACHE_STATE_PURGATORY; - tcache_tsd_set(&tcache); + if (!config_tcache) + return; + + if ((tcache = tsd_tcache_get(tsd)) != NULL) { + tcache_destroy(tsd, tcache); + tsd_tcache_set(tsd, NULL); } } +void +tcache_enabled_cleanup(tsd_t *tsd) +{ + + /* Do nothing. */ +} + /* Caller must own arena->lock. */ void tcache_stats_merge(tcache_t *tcache, arena_t *arena) @@ -427,7 +405,7 @@ tcache_stats_merge(tcache_t *tcache, arena_t *arena) } bool -tcache_boot0(void) +tcache_boot(void) { unsigned i; @@ -467,13 +445,3 @@ tcache_boot0(void) return (false); } - -bool -tcache_boot1(void) -{ - - if (tcache_tsd_boot() || tcache_enabled_tsd_boot()) - return (true); - - return (false); -} diff --git a/memory/jemalloc/src/src/tsd.c b/memory/jemalloc/src/src/tsd.c index 700caabfe477..59253fe3a502 100644 --- a/memory/jemalloc/src/src/tsd.c +++ b/memory/jemalloc/src/src/tsd.c @@ -7,21 +7,22 @@ static unsigned ncleanups; static malloc_tsd_cleanup_t cleanups[MALLOC_TSD_CLEANUPS_MAX]; +malloc_tsd_data(, , tsd_t, TSD_INITIALIZER) + /******************************************************************************/ void * malloc_tsd_malloc(size_t size) { - /* Avoid choose_arena() in order to dodge bootstrapping issues. */ - return (arena_malloc(arenas[0], size, false, false)); + return (a0malloc(CACHELINE_CEILING(size))); } void malloc_tsd_dalloc(void *wrapper) { - idalloct(wrapper, false); + a0free(wrapper); } void @@ -67,10 +68,58 @@ malloc_tsd_cleanup_register(bool (*f)(void)) } void -malloc_tsd_boot(void) +tsd_cleanup(void *arg) +{ + tsd_t *tsd = (tsd_t *)arg; + + switch (tsd->state) { + case tsd_state_nominal: +#define O(n, t) \ + n##_cleanup(tsd); +MALLOC_TSD +#undef O + tsd->state = tsd_state_purgatory; + tsd_set(tsd); + break; + case tsd_state_purgatory: + /* + * The previous time this destructor was called, we set the + * state to tsd_state_purgatory so that other destructors + * wouldn't cause re-creation of the tsd. This time, do + * nothing, and do not request another callback. + */ + break; + case tsd_state_reincarnated: + /* + * Another destructor deallocated memory after this destructor + * was called. Reset state to tsd_state_purgatory and request + * another callback. + */ + tsd->state = tsd_state_purgatory; + tsd_set(tsd); + break; + default: + not_reached(); + } +} + +bool +malloc_tsd_boot0(void) { ncleanups = 0; + if (tsd_boot0()) + return (true); + *tsd_arenas_cache_bypassp_get(tsd_fetch()) = true; + return (false); +} + +void +malloc_tsd_boot1(void) +{ + + tsd_boot1(); + *tsd_arenas_cache_bypassp_get(tsd_fetch()) = false; } #ifdef _WIN32 diff --git a/memory/jemalloc/src/src/util.c b/memory/jemalloc/src/src/util.c index 95e22c893383..bfd86af8d8ce 100644 --- a/memory/jemalloc/src/src/util.c +++ b/memory/jemalloc/src/src/util.c @@ -266,7 +266,7 @@ d2s(intmax_t x, char sign, char *s, size_t *slen_p) sign = '-'; switch (sign) { case '-': - if (neg == false) + if (!neg) break; /* Fall through. */ case ' ': @@ -329,7 +329,7 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) /* Left padding. */ \ size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \ (size_t)width - slen : 0); \ - if (left_justify == false && pad_len != 0) { \ + if (!left_justify && pad_len != 0) { \ size_t j; \ for (j = 0; j < pad_len; j++) \ APPEND_C(' '); \ @@ -381,7 +381,7 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) case 'p': /* Synthetic; used for %p. */ \ val = va_arg(ap, uintptr_t); \ break; \ - default: \ + default: \ not_reached(); \ val = 0; \ } \ @@ -406,19 +406,19 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) while (true) { switch (*f) { case '#': - assert(alt_form == false); + assert(!alt_form); alt_form = true; break; case '-': - assert(left_justify == false); + assert(!left_justify); left_justify = true; break; case ' ': - assert(plus_space == false); + assert(!plus_space); plus_space = true; break; case '+': - assert(plus_plus == false); + assert(!plus_plus); plus_plus = true; break; default: goto label_width; diff --git a/memory/jemalloc/src/src/valgrind.c b/memory/jemalloc/src/src/valgrind.c new file mode 100644 index 000000000000..8e7ef3a2e63b --- /dev/null +++ b/memory/jemalloc/src/src/valgrind.c @@ -0,0 +1,34 @@ +#include "jemalloc/internal/jemalloc_internal.h" +#ifndef JEMALLOC_VALGRIND +# error "This source file is for Valgrind integration." +#endif + +#include + +void +valgrind_make_mem_noaccess(void *ptr, size_t usize) +{ + + VALGRIND_MAKE_MEM_NOACCESS(ptr, usize); +} + +void +valgrind_make_mem_undefined(void *ptr, size_t usize) +{ + + VALGRIND_MAKE_MEM_UNDEFINED(ptr, usize); +} + +void +valgrind_make_mem_defined(void *ptr, size_t usize) +{ + + VALGRIND_MAKE_MEM_DEFINED(ptr, usize); +} + +void +valgrind_freelike_block(void *ptr, size_t usize) +{ + + VALGRIND_FREELIKE_BLOCK(ptr, usize); +} diff --git a/memory/jemalloc/src/src/zone.c b/memory/jemalloc/src/src/zone.c index a722287b2e9c..12e1734a9ebb 100644 --- a/memory/jemalloc/src/src/zone.c +++ b/memory/jemalloc/src/src/zone.c @@ -258,13 +258,13 @@ register_zone(void) /* * On OSX 10.6, having the default purgeable zone appear before * the default zone makes some things crash because it thinks it - * owns the default zone allocated pointers. We thus unregister/ - * re-register it in order to ensure it's always after the - * default zone. On OSX < 10.6, there is no purgeable zone, so - * this does nothing. On OSX >= 10.6, unregistering replaces the - * purgeable zone with the last registered zone above, i.e the - * default zone. Registering it again then puts it at the end, - * obviously after the default zone. + * owns the default zone allocated pointers. We thus + * unregister/re-register it in order to ensure it's always + * after the default zone. On OSX < 10.6, there is no purgeable + * zone, so this does nothing. On OSX >= 10.6, unregistering + * replaces the purgeable zone with the last registered zone + * above, i.e. the default zone. Registering it again then puts + * it at the end, obviously after the default zone. */ if (purgeable_zone) { malloc_zone_unregister(purgeable_zone); diff --git a/memory/jemalloc/src/test/include/test/btalloc.h b/memory/jemalloc/src/test/include/test/btalloc.h new file mode 100644 index 000000000000..c3f9d4df730e --- /dev/null +++ b/memory/jemalloc/src/test/include/test/btalloc.h @@ -0,0 +1,31 @@ +/* btalloc() provides a mechanism for allocating via permuted backtraces. */ +void *btalloc(size_t size, unsigned bits); + +#define btalloc_n_proto(n) \ +void *btalloc_##n(size_t size, unsigned bits); +btalloc_n_proto(0) +btalloc_n_proto(1) + +#define btalloc_n_gen(n) \ +void * \ +btalloc_##n(size_t size, unsigned bits) \ +{ \ + void *p; \ + \ + if (bits == 0) \ + p = mallocx(size, 0); \ + else { \ + switch (bits & 0x1U) { \ + case 0: \ + p = (btalloc_0(size, bits >> 1)); \ + break; \ + case 1: \ + p = (btalloc_1(size, bits >> 1)); \ + break; \ + default: not_reached(); \ + } \ + } \ + /* Intentionally sabotage tail call optimization. */ \ + assert_ptr_not_null(p, "Unexpected mallocx() failure"); \ + return (p); \ +} diff --git a/memory/jemalloc/src/test/include/test/jemalloc_test.h.in b/memory/jemalloc/src/test/include/test/jemalloc_test.h.in index 730a55dba236..6018e58ac12d 100644 --- a/memory/jemalloc/src/test/include/test/jemalloc_test.h.in +++ b/memory/jemalloc/src/test/include/test/jemalloc_test.h.in @@ -5,6 +5,7 @@ #include #include #include +#include #ifdef _WIN32 # include @@ -132,10 +133,12 @@ /* * Common test utilities. */ +#include "test/btalloc.h" #include "test/math.h" #include "test/mtx.h" #include "test/mq.h" #include "test/test.h" +#include "test/timer.h" #include "test/thd.h" #define MEXP 19937 #include "test/SFMT.h" diff --git a/memory/jemalloc/src/test/include/test/jemalloc_test_defs.h.in b/memory/jemalloc/src/test/include/test/jemalloc_test_defs.h.in index 18a9773d705e..5cc8532a3488 100644 --- a/memory/jemalloc/src/test/include/test/jemalloc_test_defs.h.in +++ b/memory/jemalloc/src/test/include/test/jemalloc_test_defs.h.in @@ -1,5 +1,9 @@ #include "jemalloc/internal/jemalloc_internal_defs.h" +#include "jemalloc/internal/jemalloc_internal_decls.h" -/* For use by SFMT. */ +/* + * For use by SFMT. configure.ac doesn't actually define HAVE_SSE2 because its + * dependencies are notoriously unportable in practice. + */ #undef HAVE_SSE2 #undef HAVE_ALTIVEC diff --git a/memory/jemalloc/src/test/include/test/math.h b/memory/jemalloc/src/test/include/test/math.h index a862ed7db24a..b057b29a1d2a 100644 --- a/memory/jemalloc/src/test/include/test/math.h +++ b/memory/jemalloc/src/test/include/test/math.h @@ -299,7 +299,7 @@ pt_chi2(double p, double df, double ln_gamma_df_2) /* * Given a value p in [0..1] and Gamma distribution shape and scale parameters, - * compute the upper limit on the definite integeral from [0..z] that satisfies + * compute the upper limit on the definite integral from [0..z] that satisfies * p. */ JEMALLOC_INLINE double diff --git a/memory/jemalloc/src/test/include/test/test.h b/memory/jemalloc/src/test/include/test/test.h index a32ec07c4c51..f55bafce677a 100644 --- a/memory/jemalloc/src/test/include/test/test.h +++ b/memory/jemalloc/src/test/include/test/test.h @@ -1,6 +1,6 @@ #define ASSERT_BUFSIZE 256 -#define assert_cmp(t, a, b, cmp, neg_cmp, pri, fmt...) do { \ +#define assert_cmp(t, a, b, cmp, neg_cmp, pri, ...) do { \ t a_ = (a); \ t b_ = (b); \ if (!(a_ cmp b_)) { \ @@ -12,205 +12,205 @@ "%"pri" "#neg_cmp" %"pri": ", \ __func__, __FILE__, __LINE__, \ #a, #b, a_, b_); \ - malloc_snprintf(message, sizeof(message), fmt); \ + malloc_snprintf(message, sizeof(message), __VA_ARGS__); \ p_test_fail(prefix, message); \ } \ } while (0) -#define assert_ptr_eq(a, b, fmt...) assert_cmp(void *, a, b, ==, \ - !=, "p", fmt) -#define assert_ptr_ne(a, b, fmt...) assert_cmp(void *, a, b, !=, \ - ==, "p", fmt) -#define assert_ptr_null(a, fmt...) assert_cmp(void *, a, NULL, ==, \ - !=, "p", fmt) -#define assert_ptr_not_null(a, fmt...) assert_cmp(void *, a, NULL, !=, \ - ==, "p", fmt) +#define assert_ptr_eq(a, b, ...) assert_cmp(void *, a, b, ==, \ + !=, "p", __VA_ARGS__) +#define assert_ptr_ne(a, b, ...) assert_cmp(void *, a, b, !=, \ + ==, "p", __VA_ARGS__) +#define assert_ptr_null(a, ...) assert_cmp(void *, a, NULL, ==, \ + !=, "p", __VA_ARGS__) +#define assert_ptr_not_null(a, ...) assert_cmp(void *, a, NULL, !=, \ + ==, "p", __VA_ARGS__) -#define assert_c_eq(a, b, fmt...) assert_cmp(char, a, b, ==, !=, "c", fmt) -#define assert_c_ne(a, b, fmt...) assert_cmp(char, a, b, !=, ==, "c", fmt) -#define assert_c_lt(a, b, fmt...) assert_cmp(char, a, b, <, >=, "c", fmt) -#define assert_c_le(a, b, fmt...) assert_cmp(char, a, b, <=, >, "c", fmt) -#define assert_c_ge(a, b, fmt...) assert_cmp(char, a, b, >=, <, "c", fmt) -#define assert_c_gt(a, b, fmt...) assert_cmp(char, a, b, >, <=, "c", fmt) +#define assert_c_eq(a, b, ...) assert_cmp(char, a, b, ==, !=, "c", __VA_ARGS__) +#define assert_c_ne(a, b, ...) assert_cmp(char, a, b, !=, ==, "c", __VA_ARGS__) +#define assert_c_lt(a, b, ...) assert_cmp(char, a, b, <, >=, "c", __VA_ARGS__) +#define assert_c_le(a, b, ...) assert_cmp(char, a, b, <=, >, "c", __VA_ARGS__) +#define assert_c_ge(a, b, ...) assert_cmp(char, a, b, >=, <, "c", __VA_ARGS__) +#define assert_c_gt(a, b, ...) assert_cmp(char, a, b, >, <=, "c", __VA_ARGS__) -#define assert_x_eq(a, b, fmt...) assert_cmp(int, a, b, ==, !=, "#x", fmt) -#define assert_x_ne(a, b, fmt...) assert_cmp(int, a, b, !=, ==, "#x", fmt) -#define assert_x_lt(a, b, fmt...) assert_cmp(int, a, b, <, >=, "#x", fmt) -#define assert_x_le(a, b, fmt...) assert_cmp(int, a, b, <=, >, "#x", fmt) -#define assert_x_ge(a, b, fmt...) assert_cmp(int, a, b, >=, <, "#x", fmt) -#define assert_x_gt(a, b, fmt...) assert_cmp(int, a, b, >, <=, "#x", fmt) +#define assert_x_eq(a, b, ...) assert_cmp(int, a, b, ==, !=, "#x", __VA_ARGS__) +#define assert_x_ne(a, b, ...) assert_cmp(int, a, b, !=, ==, "#x", __VA_ARGS__) +#define assert_x_lt(a, b, ...) assert_cmp(int, a, b, <, >=, "#x", __VA_ARGS__) +#define assert_x_le(a, b, ...) assert_cmp(int, a, b, <=, >, "#x", __VA_ARGS__) +#define assert_x_ge(a, b, ...) assert_cmp(int, a, b, >=, <, "#x", __VA_ARGS__) +#define assert_x_gt(a, b, ...) assert_cmp(int, a, b, >, <=, "#x", __VA_ARGS__) -#define assert_d_eq(a, b, fmt...) assert_cmp(int, a, b, ==, !=, "d", fmt) -#define assert_d_ne(a, b, fmt...) assert_cmp(int, a, b, !=, ==, "d", fmt) -#define assert_d_lt(a, b, fmt...) assert_cmp(int, a, b, <, >=, "d", fmt) -#define assert_d_le(a, b, fmt...) assert_cmp(int, a, b, <=, >, "d", fmt) -#define assert_d_ge(a, b, fmt...) assert_cmp(int, a, b, >=, <, "d", fmt) -#define assert_d_gt(a, b, fmt...) assert_cmp(int, a, b, >, <=, "d", fmt) +#define assert_d_eq(a, b, ...) assert_cmp(int, a, b, ==, !=, "d", __VA_ARGS__) +#define assert_d_ne(a, b, ...) assert_cmp(int, a, b, !=, ==, "d", __VA_ARGS__) +#define assert_d_lt(a, b, ...) assert_cmp(int, a, b, <, >=, "d", __VA_ARGS__) +#define assert_d_le(a, b, ...) assert_cmp(int, a, b, <=, >, "d", __VA_ARGS__) +#define assert_d_ge(a, b, ...) assert_cmp(int, a, b, >=, <, "d", __VA_ARGS__) +#define assert_d_gt(a, b, ...) assert_cmp(int, a, b, >, <=, "d", __VA_ARGS__) -#define assert_u_eq(a, b, fmt...) assert_cmp(int, a, b, ==, !=, "u", fmt) -#define assert_u_ne(a, b, fmt...) assert_cmp(int, a, b, !=, ==, "u", fmt) -#define assert_u_lt(a, b, fmt...) assert_cmp(int, a, b, <, >=, "u", fmt) -#define assert_u_le(a, b, fmt...) assert_cmp(int, a, b, <=, >, "u", fmt) -#define assert_u_ge(a, b, fmt...) assert_cmp(int, a, b, >=, <, "u", fmt) -#define assert_u_gt(a, b, fmt...) assert_cmp(int, a, b, >, <=, "u", fmt) +#define assert_u_eq(a, b, ...) assert_cmp(int, a, b, ==, !=, "u", __VA_ARGS__) +#define assert_u_ne(a, b, ...) assert_cmp(int, a, b, !=, ==, "u", __VA_ARGS__) +#define assert_u_lt(a, b, ...) assert_cmp(int, a, b, <, >=, "u", __VA_ARGS__) +#define assert_u_le(a, b, ...) assert_cmp(int, a, b, <=, >, "u", __VA_ARGS__) +#define assert_u_ge(a, b, ...) assert_cmp(int, a, b, >=, <, "u", __VA_ARGS__) +#define assert_u_gt(a, b, ...) assert_cmp(int, a, b, >, <=, "u", __VA_ARGS__) -#define assert_ld_eq(a, b, fmt...) assert_cmp(long, a, b, ==, \ - !=, "ld", fmt) -#define assert_ld_ne(a, b, fmt...) assert_cmp(long, a, b, !=, \ - ==, "ld", fmt) -#define assert_ld_lt(a, b, fmt...) assert_cmp(long, a, b, <, \ - >=, "ld", fmt) -#define assert_ld_le(a, b, fmt...) assert_cmp(long, a, b, <=, \ - >, "ld", fmt) -#define assert_ld_ge(a, b, fmt...) assert_cmp(long, a, b, >=, \ - <, "ld", fmt) -#define assert_ld_gt(a, b, fmt...) assert_cmp(long, a, b, >, \ - <=, "ld", fmt) +#define assert_ld_eq(a, b, ...) assert_cmp(long, a, b, ==, \ + !=, "ld", __VA_ARGS__) +#define assert_ld_ne(a, b, ...) assert_cmp(long, a, b, !=, \ + ==, "ld", __VA_ARGS__) +#define assert_ld_lt(a, b, ...) assert_cmp(long, a, b, <, \ + >=, "ld", __VA_ARGS__) +#define assert_ld_le(a, b, ...) assert_cmp(long, a, b, <=, \ + >, "ld", __VA_ARGS__) +#define assert_ld_ge(a, b, ...) assert_cmp(long, a, b, >=, \ + <, "ld", __VA_ARGS__) +#define assert_ld_gt(a, b, ...) assert_cmp(long, a, b, >, \ + <=, "ld", __VA_ARGS__) -#define assert_lu_eq(a, b, fmt...) assert_cmp(unsigned long, \ - a, b, ==, !=, "lu", fmt) -#define assert_lu_ne(a, b, fmt...) assert_cmp(unsigned long, \ - a, b, !=, ==, "lu", fmt) -#define assert_lu_lt(a, b, fmt...) assert_cmp(unsigned long, \ - a, b, <, >=, "lu", fmt) -#define assert_lu_le(a, b, fmt...) assert_cmp(unsigned long, \ - a, b, <=, >, "lu", fmt) -#define assert_lu_ge(a, b, fmt...) assert_cmp(unsigned long, \ - a, b, >=, <, "lu", fmt) -#define assert_lu_gt(a, b, fmt...) assert_cmp(unsigned long, \ - a, b, >, <=, "lu", fmt) +#define assert_lu_eq(a, b, ...) assert_cmp(unsigned long, \ + a, b, ==, !=, "lu", __VA_ARGS__) +#define assert_lu_ne(a, b, ...) assert_cmp(unsigned long, \ + a, b, !=, ==, "lu", __VA_ARGS__) +#define assert_lu_lt(a, b, ...) assert_cmp(unsigned long, \ + a, b, <, >=, "lu", __VA_ARGS__) +#define assert_lu_le(a, b, ...) assert_cmp(unsigned long, \ + a, b, <=, >, "lu", __VA_ARGS__) +#define assert_lu_ge(a, b, ...) assert_cmp(unsigned long, \ + a, b, >=, <, "lu", __VA_ARGS__) +#define assert_lu_gt(a, b, ...) assert_cmp(unsigned long, \ + a, b, >, <=, "lu", __VA_ARGS__) -#define assert_qd_eq(a, b, fmt...) assert_cmp(long long, a, b, ==, \ - !=, "qd", fmt) -#define assert_qd_ne(a, b, fmt...) assert_cmp(long long, a, b, !=, \ - ==, "qd", fmt) -#define assert_qd_lt(a, b, fmt...) assert_cmp(long long, a, b, <, \ - >=, "qd", fmt) -#define assert_qd_le(a, b, fmt...) assert_cmp(long long, a, b, <=, \ - >, "qd", fmt) -#define assert_qd_ge(a, b, fmt...) assert_cmp(long long, a, b, >=, \ - <, "qd", fmt) -#define assert_qd_gt(a, b, fmt...) assert_cmp(long long, a, b, >, \ - <=, "qd", fmt) +#define assert_qd_eq(a, b, ...) assert_cmp(long long, a, b, ==, \ + !=, "qd", __VA_ARGS__) +#define assert_qd_ne(a, b, ...) assert_cmp(long long, a, b, !=, \ + ==, "qd", __VA_ARGS__) +#define assert_qd_lt(a, b, ...) assert_cmp(long long, a, b, <, \ + >=, "qd", __VA_ARGS__) +#define assert_qd_le(a, b, ...) assert_cmp(long long, a, b, <=, \ + >, "qd", __VA_ARGS__) +#define assert_qd_ge(a, b, ...) assert_cmp(long long, a, b, >=, \ + <, "qd", __VA_ARGS__) +#define assert_qd_gt(a, b, ...) assert_cmp(long long, a, b, >, \ + <=, "qd", __VA_ARGS__) -#define assert_qu_eq(a, b, fmt...) assert_cmp(unsigned long long, \ - a, b, ==, !=, "qu", fmt) -#define assert_qu_ne(a, b, fmt...) assert_cmp(unsigned long long, \ - a, b, !=, ==, "qu", fmt) -#define assert_qu_lt(a, b, fmt...) assert_cmp(unsigned long long, \ - a, b, <, >=, "qu", fmt) -#define assert_qu_le(a, b, fmt...) assert_cmp(unsigned long long, \ - a, b, <=, >, "qu", fmt) -#define assert_qu_ge(a, b, fmt...) assert_cmp(unsigned long long, \ - a, b, >=, <, "qu", fmt) -#define assert_qu_gt(a, b, fmt...) assert_cmp(unsigned long long, \ - a, b, >, <=, "qu", fmt) +#define assert_qu_eq(a, b, ...) assert_cmp(unsigned long long, \ + a, b, ==, !=, "qu", __VA_ARGS__) +#define assert_qu_ne(a, b, ...) assert_cmp(unsigned long long, \ + a, b, !=, ==, "qu", __VA_ARGS__) +#define assert_qu_lt(a, b, ...) assert_cmp(unsigned long long, \ + a, b, <, >=, "qu", __VA_ARGS__) +#define assert_qu_le(a, b, ...) assert_cmp(unsigned long long, \ + a, b, <=, >, "qu", __VA_ARGS__) +#define assert_qu_ge(a, b, ...) assert_cmp(unsigned long long, \ + a, b, >=, <, "qu", __VA_ARGS__) +#define assert_qu_gt(a, b, ...) assert_cmp(unsigned long long, \ + a, b, >, <=, "qu", __VA_ARGS__) -#define assert_jd_eq(a, b, fmt...) assert_cmp(intmax_t, a, b, ==, \ - !=, "jd", fmt) -#define assert_jd_ne(a, b, fmt...) assert_cmp(intmax_t, a, b, !=, \ - ==, "jd", fmt) -#define assert_jd_lt(a, b, fmt...) assert_cmp(intmax_t, a, b, <, \ - >=, "jd", fmt) -#define assert_jd_le(a, b, fmt...) assert_cmp(intmax_t, a, b, <=, \ - >, "jd", fmt) -#define assert_jd_ge(a, b, fmt...) assert_cmp(intmax_t, a, b, >=, \ - <, "jd", fmt) -#define assert_jd_gt(a, b, fmt...) assert_cmp(intmax_t, a, b, >, \ - <=, "jd", fmt) +#define assert_jd_eq(a, b, ...) assert_cmp(intmax_t, a, b, ==, \ + !=, "jd", __VA_ARGS__) +#define assert_jd_ne(a, b, ...) assert_cmp(intmax_t, a, b, !=, \ + ==, "jd", __VA_ARGS__) +#define assert_jd_lt(a, b, ...) assert_cmp(intmax_t, a, b, <, \ + >=, "jd", __VA_ARGS__) +#define assert_jd_le(a, b, ...) assert_cmp(intmax_t, a, b, <=, \ + >, "jd", __VA_ARGS__) +#define assert_jd_ge(a, b, ...) assert_cmp(intmax_t, a, b, >=, \ + <, "jd", __VA_ARGS__) +#define assert_jd_gt(a, b, ...) assert_cmp(intmax_t, a, b, >, \ + <=, "jd", __VA_ARGS__) -#define assert_ju_eq(a, b, fmt...) assert_cmp(uintmax_t, a, b, ==, \ - !=, "ju", fmt) -#define assert_ju_ne(a, b, fmt...) assert_cmp(uintmax_t, a, b, !=, \ - ==, "ju", fmt) -#define assert_ju_lt(a, b, fmt...) assert_cmp(uintmax_t, a, b, <, \ - >=, "ju", fmt) -#define assert_ju_le(a, b, fmt...) assert_cmp(uintmax_t, a, b, <=, \ - >, "ju", fmt) -#define assert_ju_ge(a, b, fmt...) assert_cmp(uintmax_t, a, b, >=, \ - <, "ju", fmt) -#define assert_ju_gt(a, b, fmt...) assert_cmp(uintmax_t, a, b, >, \ - <=, "ju", fmt) +#define assert_ju_eq(a, b, ...) assert_cmp(uintmax_t, a, b, ==, \ + !=, "ju", __VA_ARGS__) +#define assert_ju_ne(a, b, ...) assert_cmp(uintmax_t, a, b, !=, \ + ==, "ju", __VA_ARGS__) +#define assert_ju_lt(a, b, ...) assert_cmp(uintmax_t, a, b, <, \ + >=, "ju", __VA_ARGS__) +#define assert_ju_le(a, b, ...) assert_cmp(uintmax_t, a, b, <=, \ + >, "ju", __VA_ARGS__) +#define assert_ju_ge(a, b, ...) assert_cmp(uintmax_t, a, b, >=, \ + <, "ju", __VA_ARGS__) +#define assert_ju_gt(a, b, ...) assert_cmp(uintmax_t, a, b, >, \ + <=, "ju", __VA_ARGS__) -#define assert_zd_eq(a, b, fmt...) assert_cmp(ssize_t, a, b, ==, \ - !=, "zd", fmt) -#define assert_zd_ne(a, b, fmt...) assert_cmp(ssize_t, a, b, !=, \ - ==, "zd", fmt) -#define assert_zd_lt(a, b, fmt...) assert_cmp(ssize_t, a, b, <, \ - >=, "zd", fmt) -#define assert_zd_le(a, b, fmt...) assert_cmp(ssize_t, a, b, <=, \ - >, "zd", fmt) -#define assert_zd_ge(a, b, fmt...) assert_cmp(ssize_t, a, b, >=, \ - <, "zd", fmt) -#define assert_zd_gt(a, b, fmt...) assert_cmp(ssize_t, a, b, >, \ - <=, "zd", fmt) +#define assert_zd_eq(a, b, ...) assert_cmp(ssize_t, a, b, ==, \ + !=, "zd", __VA_ARGS__) +#define assert_zd_ne(a, b, ...) assert_cmp(ssize_t, a, b, !=, \ + ==, "zd", __VA_ARGS__) +#define assert_zd_lt(a, b, ...) assert_cmp(ssize_t, a, b, <, \ + >=, "zd", __VA_ARGS__) +#define assert_zd_le(a, b, ...) assert_cmp(ssize_t, a, b, <=, \ + >, "zd", __VA_ARGS__) +#define assert_zd_ge(a, b, ...) assert_cmp(ssize_t, a, b, >=, \ + <, "zd", __VA_ARGS__) +#define assert_zd_gt(a, b, ...) assert_cmp(ssize_t, a, b, >, \ + <=, "zd", __VA_ARGS__) -#define assert_zu_eq(a, b, fmt...) assert_cmp(size_t, a, b, ==, \ - !=, "zu", fmt) -#define assert_zu_ne(a, b, fmt...) assert_cmp(size_t, a, b, !=, \ - ==, "zu", fmt) -#define assert_zu_lt(a, b, fmt...) assert_cmp(size_t, a, b, <, \ - >=, "zu", fmt) -#define assert_zu_le(a, b, fmt...) assert_cmp(size_t, a, b, <=, \ - >, "zu", fmt) -#define assert_zu_ge(a, b, fmt...) assert_cmp(size_t, a, b, >=, \ - <, "zu", fmt) -#define assert_zu_gt(a, b, fmt...) assert_cmp(size_t, a, b, >, \ - <=, "zu", fmt) +#define assert_zu_eq(a, b, ...) assert_cmp(size_t, a, b, ==, \ + !=, "zu", __VA_ARGS__) +#define assert_zu_ne(a, b, ...) assert_cmp(size_t, a, b, !=, \ + ==, "zu", __VA_ARGS__) +#define assert_zu_lt(a, b, ...) assert_cmp(size_t, a, b, <, \ + >=, "zu", __VA_ARGS__) +#define assert_zu_le(a, b, ...) assert_cmp(size_t, a, b, <=, \ + >, "zu", __VA_ARGS__) +#define assert_zu_ge(a, b, ...) assert_cmp(size_t, a, b, >=, \ + <, "zu", __VA_ARGS__) +#define assert_zu_gt(a, b, ...) assert_cmp(size_t, a, b, >, \ + <=, "zu", __VA_ARGS__) -#define assert_d32_eq(a, b, fmt...) assert_cmp(int32_t, a, b, ==, \ - !=, PRId32, fmt) -#define assert_d32_ne(a, b, fmt...) assert_cmp(int32_t, a, b, !=, \ - ==, PRId32, fmt) -#define assert_d32_lt(a, b, fmt...) assert_cmp(int32_t, a, b, <, \ - >=, PRId32, fmt) -#define assert_d32_le(a, b, fmt...) assert_cmp(int32_t, a, b, <=, \ - >, PRId32, fmt) -#define assert_d32_ge(a, b, fmt...) assert_cmp(int32_t, a, b, >=, \ - <, PRId32, fmt) -#define assert_d32_gt(a, b, fmt...) assert_cmp(int32_t, a, b, >, \ - <=, PRId32, fmt) +#define assert_d32_eq(a, b, ...) assert_cmp(int32_t, a, b, ==, \ + !=, PRId32, __VA_ARGS__) +#define assert_d32_ne(a, b, ...) assert_cmp(int32_t, a, b, !=, \ + ==, PRId32, __VA_ARGS__) +#define assert_d32_lt(a, b, ...) assert_cmp(int32_t, a, b, <, \ + >=, PRId32, __VA_ARGS__) +#define assert_d32_le(a, b, ...) assert_cmp(int32_t, a, b, <=, \ + >, PRId32, __VA_ARGS__) +#define assert_d32_ge(a, b, ...) assert_cmp(int32_t, a, b, >=, \ + <, PRId32, __VA_ARGS__) +#define assert_d32_gt(a, b, ...) assert_cmp(int32_t, a, b, >, \ + <=, PRId32, __VA_ARGS__) -#define assert_u32_eq(a, b, fmt...) assert_cmp(uint32_t, a, b, ==, \ - !=, PRIu32, fmt) -#define assert_u32_ne(a, b, fmt...) assert_cmp(uint32_t, a, b, !=, \ - ==, PRIu32, fmt) -#define assert_u32_lt(a, b, fmt...) assert_cmp(uint32_t, a, b, <, \ - >=, PRIu32, fmt) -#define assert_u32_le(a, b, fmt...) assert_cmp(uint32_t, a, b, <=, \ - >, PRIu32, fmt) -#define assert_u32_ge(a, b, fmt...) assert_cmp(uint32_t, a, b, >=, \ - <, PRIu32, fmt) -#define assert_u32_gt(a, b, fmt...) assert_cmp(uint32_t, a, b, >, \ - <=, PRIu32, fmt) +#define assert_u32_eq(a, b, ...) assert_cmp(uint32_t, a, b, ==, \ + !=, PRIu32, __VA_ARGS__) +#define assert_u32_ne(a, b, ...) assert_cmp(uint32_t, a, b, !=, \ + ==, PRIu32, __VA_ARGS__) +#define assert_u32_lt(a, b, ...) assert_cmp(uint32_t, a, b, <, \ + >=, PRIu32, __VA_ARGS__) +#define assert_u32_le(a, b, ...) assert_cmp(uint32_t, a, b, <=, \ + >, PRIu32, __VA_ARGS__) +#define assert_u32_ge(a, b, ...) assert_cmp(uint32_t, a, b, >=, \ + <, PRIu32, __VA_ARGS__) +#define assert_u32_gt(a, b, ...) assert_cmp(uint32_t, a, b, >, \ + <=, PRIu32, __VA_ARGS__) -#define assert_d64_eq(a, b, fmt...) assert_cmp(int64_t, a, b, ==, \ - !=, PRId64, fmt) -#define assert_d64_ne(a, b, fmt...) assert_cmp(int64_t, a, b, !=, \ - ==, PRId64, fmt) -#define assert_d64_lt(a, b, fmt...) assert_cmp(int64_t, a, b, <, \ - >=, PRId64, fmt) -#define assert_d64_le(a, b, fmt...) assert_cmp(int64_t, a, b, <=, \ - >, PRId64, fmt) -#define assert_d64_ge(a, b, fmt...) assert_cmp(int64_t, a, b, >=, \ - <, PRId64, fmt) -#define assert_d64_gt(a, b, fmt...) assert_cmp(int64_t, a, b, >, \ - <=, PRId64, fmt) +#define assert_d64_eq(a, b, ...) assert_cmp(int64_t, a, b, ==, \ + !=, PRId64, __VA_ARGS__) +#define assert_d64_ne(a, b, ...) assert_cmp(int64_t, a, b, !=, \ + ==, PRId64, __VA_ARGS__) +#define assert_d64_lt(a, b, ...) assert_cmp(int64_t, a, b, <, \ + >=, PRId64, __VA_ARGS__) +#define assert_d64_le(a, b, ...) assert_cmp(int64_t, a, b, <=, \ + >, PRId64, __VA_ARGS__) +#define assert_d64_ge(a, b, ...) assert_cmp(int64_t, a, b, >=, \ + <, PRId64, __VA_ARGS__) +#define assert_d64_gt(a, b, ...) assert_cmp(int64_t, a, b, >, \ + <=, PRId64, __VA_ARGS__) -#define assert_u64_eq(a, b, fmt...) assert_cmp(uint64_t, a, b, ==, \ - !=, PRIu64, fmt) -#define assert_u64_ne(a, b, fmt...) assert_cmp(uint64_t, a, b, !=, \ - ==, PRIu64, fmt) -#define assert_u64_lt(a, b, fmt...) assert_cmp(uint64_t, a, b, <, \ - >=, PRIu64, fmt) -#define assert_u64_le(a, b, fmt...) assert_cmp(uint64_t, a, b, <=, \ - >, PRIu64, fmt) -#define assert_u64_ge(a, b, fmt...) assert_cmp(uint64_t, a, b, >=, \ - <, PRIu64, fmt) -#define assert_u64_gt(a, b, fmt...) assert_cmp(uint64_t, a, b, >, \ - <=, PRIu64, fmt) +#define assert_u64_eq(a, b, ...) assert_cmp(uint64_t, a, b, ==, \ + !=, PRIu64, __VA_ARGS__) +#define assert_u64_ne(a, b, ...) assert_cmp(uint64_t, a, b, !=, \ + ==, PRIu64, __VA_ARGS__) +#define assert_u64_lt(a, b, ...) assert_cmp(uint64_t, a, b, <, \ + >=, PRIu64, __VA_ARGS__) +#define assert_u64_le(a, b, ...) assert_cmp(uint64_t, a, b, <=, \ + >, PRIu64, __VA_ARGS__) +#define assert_u64_ge(a, b, ...) assert_cmp(uint64_t, a, b, >=, \ + <, PRIu64, __VA_ARGS__) +#define assert_u64_gt(a, b, ...) assert_cmp(uint64_t, a, b, >, \ + <=, PRIu64, __VA_ARGS__) -#define assert_b_eq(a, b, fmt...) do { \ +#define assert_b_eq(a, b, ...) do { \ bool a_ = (a); \ bool b_ = (b); \ if (!(a_ == b_)) { \ @@ -222,11 +222,11 @@ __func__, __FILE__, __LINE__, \ #a, #b, a_ ? "true" : "false", \ b_ ? "true" : "false"); \ - malloc_snprintf(message, sizeof(message), fmt); \ + malloc_snprintf(message, sizeof(message), __VA_ARGS__); \ p_test_fail(prefix, message); \ } \ } while (0) -#define assert_b_ne(a, b, fmt...) do { \ +#define assert_b_ne(a, b, ...) do { \ bool a_ = (a); \ bool b_ = (b); \ if (!(a_ != b_)) { \ @@ -238,14 +238,14 @@ __func__, __FILE__, __LINE__, \ #a, #b, a_ ? "true" : "false", \ b_ ? "true" : "false"); \ - malloc_snprintf(message, sizeof(message), fmt); \ + malloc_snprintf(message, sizeof(message), __VA_ARGS__); \ p_test_fail(prefix, message); \ } \ } while (0) -#define assert_true(a, fmt...) assert_b_eq(a, true, fmt) -#define assert_false(a, fmt...) assert_b_eq(a, false, fmt) +#define assert_true(a, ...) assert_b_eq(a, true, __VA_ARGS__) +#define assert_false(a, ...) assert_b_eq(a, false, __VA_ARGS__) -#define assert_str_eq(a, b, fmt...) do { \ +#define assert_str_eq(a, b, ...) do { \ if (strcmp((a), (b))) { \ char prefix[ASSERT_BUFSIZE]; \ char message[ASSERT_BUFSIZE]; \ @@ -254,11 +254,11 @@ "(%s) same as (%s) --> " \ "\"%s\" differs from \"%s\": ", \ __func__, __FILE__, __LINE__, #a, #b, a, b); \ - malloc_snprintf(message, sizeof(message), fmt); \ + malloc_snprintf(message, sizeof(message), __VA_ARGS__); \ p_test_fail(prefix, message); \ } \ } while (0) -#define assert_str_ne(a, b, fmt...) do { \ +#define assert_str_ne(a, b, ...) do { \ if (!strcmp((a), (b))) { \ char prefix[ASSERT_BUFSIZE]; \ char message[ASSERT_BUFSIZE]; \ @@ -267,18 +267,18 @@ "(%s) differs from (%s) --> " \ "\"%s\" same as \"%s\": ", \ __func__, __FILE__, __LINE__, #a, #b, a, b); \ - malloc_snprintf(message, sizeof(message), fmt); \ + malloc_snprintf(message, sizeof(message), __VA_ARGS__); \ p_test_fail(prefix, message); \ } \ } while (0) -#define assert_not_reached(fmt...) do { \ +#define assert_not_reached(...) do { \ char prefix[ASSERT_BUFSIZE]; \ char message[ASSERT_BUFSIZE]; \ malloc_snprintf(prefix, sizeof(prefix), \ "%s:%s:%d: Unreachable code reached: ", \ __func__, __FILE__, __LINE__); \ - malloc_snprintf(message, sizeof(message), fmt); \ + malloc_snprintf(message, sizeof(message), __VA_ARGS__); \ p_test_fail(prefix, message); \ } while (0) @@ -308,8 +308,8 @@ label_test_end: \ p_test_fini(); \ } -#define test(tests...) \ - p_test(tests, NULL) +#define test(...) \ + p_test(__VA_ARGS__, NULL) #define test_skip_if(e) do { \ if (e) { \ @@ -323,7 +323,7 @@ void test_skip(const char *format, ...) JEMALLOC_ATTR(format(printf, 1, 2)); void test_fail(const char *format, ...) JEMALLOC_ATTR(format(printf, 1, 2)); /* For private use by macros. */ -test_status_t p_test(test_t* t, ...); +test_status_t p_test(test_t *t, ...); void p_test_init(const char *name); void p_test_fini(void); void p_test_fail(const char *prefix, const char *message); diff --git a/memory/jemalloc/src/test/include/test/thd.h b/memory/jemalloc/src/test/include/test/thd.h index f941d7a752fe..47a51262e990 100644 --- a/memory/jemalloc/src/test/include/test/thd.h +++ b/memory/jemalloc/src/test/include/test/thd.h @@ -1,4 +1,4 @@ -/* Abstraction layer for threading in tests */ +/* Abstraction layer for threading in tests. */ #ifdef _WIN32 typedef HANDLE thd_t; #else diff --git a/memory/jemalloc/src/test/include/test/timer.h b/memory/jemalloc/src/test/include/test/timer.h new file mode 100644 index 000000000000..496072ac1472 --- /dev/null +++ b/memory/jemalloc/src/test/include/test/timer.h @@ -0,0 +1,13 @@ +/* Simple timer, for use in benchmark reporting. */ + +#include + +typedef struct { + struct timeval tv0; + struct timeval tv1; +} timedelta_t; + +void timer_start(timedelta_t *timer); +void timer_stop(timedelta_t *timer); +uint64_t timer_usec(const timedelta_t *timer); +void timer_ratio(timedelta_t *a, timedelta_t *b, char *buf, size_t buflen); diff --git a/memory/jemalloc/src/test/integration/MALLOCX_ARENA.c b/memory/jemalloc/src/test/integration/MALLOCX_ARENA.c index 71cf6f255e84..30c203ae657a 100644 --- a/memory/jemalloc/src/test/integration/MALLOCX_ARENA.c +++ b/memory/jemalloc/src/test/integration/MALLOCX_ARENA.c @@ -2,6 +2,14 @@ #define NTHREADS 10 +static bool have_dss = +#ifdef JEMALLOC_DSS + true +#else + false +#endif + ; + void * thd_start(void *arg) { @@ -18,13 +26,16 @@ thd_start(void *arg) size_t mib[3]; size_t miblen = sizeof(mib) / sizeof(size_t); const char *dss_precs[] = {"disabled", "primary", "secondary"}; - const char *dss = dss_precs[thread_ind % - (sizeof(dss_precs)/sizeof(char*))]; + unsigned prec_ind = thread_ind % + (sizeof(dss_precs)/sizeof(char*)); + const char *dss = dss_precs[prec_ind]; + int expected_err = (have_dss || prec_ind == 0) ? 0 : EFAULT; assert_d_eq(mallctlnametomib("arena.0.dss", mib, &miblen), 0, "Error in mallctlnametomib()"); mib[1] = arena_ind; assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&dss, - sizeof(const char *)), 0, "Error in mallctlbymib()"); + sizeof(const char *)), expected_err, + "Error in mallctlbymib()"); } p = mallocx(1, MALLOCX_ARENA(arena_ind)); @@ -34,7 +45,7 @@ thd_start(void *arg) return (NULL); } -TEST_BEGIN(test_ALLOCM_ARENA) +TEST_BEGIN(test_MALLOCX_ARENA) { thd_t thds[NTHREADS]; unsigned i; @@ -54,5 +65,5 @@ main(void) { return (test( - test_ALLOCM_ARENA)); + test_MALLOCX_ARENA)); } diff --git a/memory/jemalloc/src/test/integration/allocm.c b/memory/jemalloc/src/test/integration/allocm.c deleted file mode 100644 index 7b4ea0c2c65f..000000000000 --- a/memory/jemalloc/src/test/integration/allocm.c +++ /dev/null @@ -1,107 +0,0 @@ -#include "test/jemalloc_test.h" - -#define CHUNK 0x400000 -#define MAXALIGN (((size_t)1) << 25) -#define NITER 4 - -TEST_BEGIN(test_basic) -{ - size_t nsz, rsz, sz; - void *p; - - sz = 42; - nsz = 0; - assert_d_eq(nallocm(&nsz, sz, 0), ALLOCM_SUCCESS, - "Unexpected nallocm() error"); - rsz = 0; - assert_d_eq(allocm(&p, &rsz, sz, 0), ALLOCM_SUCCESS, - "Unexpected allocm() error"); - assert_zu_ge(rsz, sz, "Real size smaller than expected"); - assert_zu_eq(nsz, rsz, "nallocm()/allocm() rsize mismatch"); - assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS, - "Unexpected dallocm() error"); - - assert_d_eq(allocm(&p, NULL, sz, 0), ALLOCM_SUCCESS, - "Unexpected allocm() error"); - assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS, - "Unexpected dallocm() error"); - - nsz = 0; - assert_d_eq(nallocm(&nsz, sz, ALLOCM_ZERO), ALLOCM_SUCCESS, - "Unexpected nallocm() error"); - rsz = 0; - assert_d_eq(allocm(&p, &rsz, sz, ALLOCM_ZERO), ALLOCM_SUCCESS, - "Unexpected allocm() error"); - assert_zu_eq(nsz, rsz, "nallocm()/allocm() rsize mismatch"); - assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS, - "Unexpected dallocm() error"); -} -TEST_END - -TEST_BEGIN(test_alignment_and_size) -{ - int r; - size_t nsz, rsz, sz, alignment, total; - unsigned i; - void *ps[NITER]; - - for (i = 0; i < NITER; i++) - ps[i] = NULL; - - for (alignment = 8; - alignment <= MAXALIGN; - alignment <<= 1) { - total = 0; - for (sz = 1; - sz < 3 * alignment && sz < (1U << 31); - sz += (alignment >> (LG_SIZEOF_PTR-1)) - 1) { - for (i = 0; i < NITER; i++) { - nsz = 0; - r = nallocm(&nsz, sz, ALLOCM_ALIGN(alignment) | - ALLOCM_ZERO); - assert_d_eq(r, ALLOCM_SUCCESS, - "nallocm() error for alignment=%zu, " - "size=%zu (%#zx): %d", - alignment, sz, sz, r); - rsz = 0; - r = allocm(&ps[i], &rsz, sz, - ALLOCM_ALIGN(alignment) | ALLOCM_ZERO); - assert_d_eq(r, ALLOCM_SUCCESS, - "allocm() error for alignment=%zu, " - "size=%zu (%#zx): %d", - alignment, sz, sz, r); - assert_zu_ge(rsz, sz, - "Real size smaller than expected for " - "alignment=%zu, size=%zu", alignment, sz); - assert_zu_eq(nsz, rsz, - "nallocm()/allocm() rsize mismatch for " - "alignment=%zu, size=%zu", alignment, sz); - assert_ptr_null( - (void *)((uintptr_t)ps[i] & (alignment-1)), - "%p inadequately aligned for" - " alignment=%zu, size=%zu", ps[i], - alignment, sz); - sallocm(ps[i], &rsz, 0); - total += rsz; - if (total >= (MAXALIGN << 1)) - break; - } - for (i = 0; i < NITER; i++) { - if (ps[i] != NULL) { - dallocm(ps[i], 0); - ps[i] = NULL; - } - } - } - } -} -TEST_END - -int -main(void) -{ - - return (test( - test_basic, - test_alignment_and_size)); -} diff --git a/memory/jemalloc/src/test/integration/chunk.c b/memory/jemalloc/src/test/integration/chunk.c new file mode 100644 index 000000000000..89938504eed5 --- /dev/null +++ b/memory/jemalloc/src/test/integration/chunk.c @@ -0,0 +1,59 @@ +#include "test/jemalloc_test.h" + +chunk_alloc_t *old_alloc; +chunk_dalloc_t *old_dalloc; + +bool +chunk_dalloc(void *chunk, size_t size, unsigned arena_ind) +{ + + return (old_dalloc(chunk, size, arena_ind)); +} + +void * +chunk_alloc(void *new_addr, size_t size, size_t alignment, bool *zero, + unsigned arena_ind) +{ + + return (old_alloc(new_addr, size, alignment, zero, arena_ind)); +} + +TEST_BEGIN(test_chunk) +{ + void *p; + chunk_alloc_t *new_alloc; + chunk_dalloc_t *new_dalloc; + size_t old_size, new_size; + + new_alloc = chunk_alloc; + new_dalloc = chunk_dalloc; + old_size = sizeof(chunk_alloc_t *); + new_size = sizeof(chunk_alloc_t *); + + assert_d_eq(mallctl("arena.0.chunk.alloc", &old_alloc, + &old_size, &new_alloc, new_size), 0, + "Unexpected alloc error"); + assert_ptr_ne(old_alloc, new_alloc, + "Unexpected alloc error"); + assert_d_eq(mallctl("arena.0.chunk.dalloc", &old_dalloc, &old_size, + &new_dalloc, new_size), 0, "Unexpected dalloc error"); + assert_ptr_ne(old_dalloc, new_dalloc, "Unexpected dalloc error"); + + p = mallocx(42, 0); + assert_ptr_ne(p, NULL, "Unexpected alloc error"); + free(p); + + assert_d_eq(mallctl("arena.0.chunk.alloc", NULL, + NULL, &old_alloc, old_size), 0, + "Unexpected alloc error"); + assert_d_eq(mallctl("arena.0.chunk.dalloc", NULL, NULL, &old_dalloc, + old_size), 0, "Unexpected dalloc error"); +} +TEST_END + +int +main(void) +{ + + return (test(test_chunk)); +} diff --git a/memory/jemalloc/src/test/integration/mremap.c b/memory/jemalloc/src/test/integration/mremap.c deleted file mode 100644 index a7fb7ef0abf8..000000000000 --- a/memory/jemalloc/src/test/integration/mremap.c +++ /dev/null @@ -1,45 +0,0 @@ -#include "test/jemalloc_test.h" - -TEST_BEGIN(test_mremap) -{ - int err; - size_t sz, lg_chunk, chunksize, i; - char *p, *q; - - sz = sizeof(lg_chunk); - err = mallctl("opt.lg_chunk", &lg_chunk, &sz, NULL, 0); - assert_d_eq(err, 0, "Error in mallctl(): %s", strerror(err)); - chunksize = ((size_t)1U) << lg_chunk; - - p = (char *)malloc(chunksize); - assert_ptr_not_null(p, "malloc(%zu) --> %p", chunksize, p); - memset(p, 'a', chunksize); - - q = (char *)realloc(p, chunksize * 2); - assert_ptr_not_null(q, "realloc(%p, %zu) --> %p", p, chunksize * 2, - q); - for (i = 0; i < chunksize; i++) { - assert_c_eq(q[i], 'a', - "realloc() should preserve existing bytes across copies"); - } - - p = q; - - q = (char *)realloc(p, chunksize); - assert_ptr_not_null(q, "realloc(%p, %zu) --> %p", p, chunksize, q); - for (i = 0; i < chunksize; i++) { - assert_c_eq(q[i], 'a', - "realloc() should preserve existing bytes across copies"); - } - - free(q); -} -TEST_END - -int -main(void) -{ - - return (test( - test_mremap)); -} diff --git a/memory/jemalloc/src/test/integration/rallocm.c b/memory/jemalloc/src/test/integration/rallocm.c deleted file mode 100644 index 33c11bb7cf6f..000000000000 --- a/memory/jemalloc/src/test/integration/rallocm.c +++ /dev/null @@ -1,111 +0,0 @@ -#include "test/jemalloc_test.h" - -TEST_BEGIN(test_same_size) -{ - void *p, *q; - size_t sz, tsz; - - assert_d_eq(allocm(&p, &sz, 42, 0), ALLOCM_SUCCESS, - "Unexpected allocm() error"); - - q = p; - assert_d_eq(rallocm(&q, &tsz, sz, 0, ALLOCM_NO_MOVE), ALLOCM_SUCCESS, - "Unexpected rallocm() error"); - assert_ptr_eq(q, p, "Unexpected object move"); - assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz); - - assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS, - "Unexpected dallocm() error"); -} -TEST_END - -TEST_BEGIN(test_extra_no_move) -{ - void *p, *q; - size_t sz, tsz; - - assert_d_eq(allocm(&p, &sz, 42, 0), ALLOCM_SUCCESS, - "Unexpected allocm() error"); - - q = p; - assert_d_eq(rallocm(&q, &tsz, sz, sz-42, ALLOCM_NO_MOVE), - ALLOCM_SUCCESS, "Unexpected rallocm() error"); - assert_ptr_eq(q, p, "Unexpected object move"); - assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz); - - assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS, - "Unexpected dallocm() error"); -} -TEST_END - -TEST_BEGIN(test_no_move_fail) -{ - void *p, *q; - size_t sz, tsz; - - assert_d_eq(allocm(&p, &sz, 42, 0), ALLOCM_SUCCESS, - "Unexpected allocm() error"); - - q = p; - assert_d_eq(rallocm(&q, &tsz, sz + 5, 0, ALLOCM_NO_MOVE), - ALLOCM_ERR_NOT_MOVED, "Unexpected rallocm() result"); - assert_ptr_eq(q, p, "Unexpected object move"); - assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz); - - assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS, - "Unexpected dallocm() error"); -} -TEST_END - -TEST_BEGIN(test_grow_and_shrink) -{ - void *p, *q; - size_t tsz; -#define NCYCLES 3 - unsigned i, j; -#define NSZS 2500 - size_t szs[NSZS]; -#define MAXSZ ZU(12 * 1024 * 1024) - - assert_d_eq(allocm(&p, &szs[0], 1, 0), ALLOCM_SUCCESS, - "Unexpected allocm() error"); - - for (i = 0; i < NCYCLES; i++) { - for (j = 1; j < NSZS && szs[j-1] < MAXSZ; j++) { - q = p; - assert_d_eq(rallocm(&q, &szs[j], szs[j-1]+1, 0, 0), - ALLOCM_SUCCESS, - "Unexpected rallocm() error for size=%zu-->%zu", - szs[j-1], szs[j-1]+1); - assert_zu_ne(szs[j], szs[j-1]+1, - "Expected size to at least: %zu", szs[j-1]+1); - p = q; - } - - for (j--; j > 0; j--) { - q = p; - assert_d_eq(rallocm(&q, &tsz, szs[j-1], 0, 0), - ALLOCM_SUCCESS, - "Unexpected rallocm() error for size=%zu-->%zu", - szs[j], szs[j-1]); - assert_zu_eq(tsz, szs[j-1], - "Expected size=%zu, got size=%zu", szs[j-1], tsz); - p = q; - } - } - - assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS, - "Unexpected dallocm() error"); -} -TEST_END - -int -main(void) -{ - - return (test( - test_same_size, - test_extra_no_move, - test_no_move_fail, - test_grow_and_shrink)); -} diff --git a/memory/jemalloc/src/test/integration/rallocx.c b/memory/jemalloc/src/test/integration/rallocx.c index ee21aedff70e..b69807298c07 100644 --- a/memory/jemalloc/src/test/integration/rallocx.c +++ b/memory/jemalloc/src/test/integration/rallocx.c @@ -95,7 +95,8 @@ TEST_BEGIN(test_zero) "Expected zeroed memory"); } if (psz != qsz) { - memset(q+psz, FILL_BYTE, qsz-psz); + memset((void *)((uintptr_t)q+psz), FILL_BYTE, + qsz-psz); psz = qsz; } p = q; @@ -159,8 +160,9 @@ TEST_BEGIN(test_lg_align_and_zero) } else { assert_false(validate_fill(q, 0, 0, MAX_VALIDATE), "Expected zeroed memory"); - assert_false(validate_fill(q+sz-MAX_VALIDATE, 0, 0, - MAX_VALIDATE), "Expected zeroed memory"); + assert_false(validate_fill( + (void *)((uintptr_t)q+sz-MAX_VALIDATE), + 0, 0, MAX_VALIDATE), "Expected zeroed memory"); } p = q; } diff --git a/memory/jemalloc/src/test/integration/sdallocx.c b/memory/jemalloc/src/test/integration/sdallocx.c new file mode 100644 index 000000000000..b84817d767aa --- /dev/null +++ b/memory/jemalloc/src/test/integration/sdallocx.c @@ -0,0 +1,57 @@ +#include "test/jemalloc_test.h" + +#define MAXALIGN (((size_t)1) << 25) +#define NITER 4 + +TEST_BEGIN(test_basic) +{ + void *ptr = mallocx(64, 0); + sdallocx(ptr, 64, 0); +} +TEST_END + +TEST_BEGIN(test_alignment_and_size) +{ + size_t nsz, sz, alignment, total; + unsigned i; + void *ps[NITER]; + + for (i = 0; i < NITER; i++) + ps[i] = NULL; + + for (alignment = 8; + alignment <= MAXALIGN; + alignment <<= 1) { + total = 0; + for (sz = 1; + sz < 3 * alignment && sz < (1U << 31); + sz += (alignment >> (LG_SIZEOF_PTR-1)) - 1) { + for (i = 0; i < NITER; i++) { + nsz = nallocx(sz, MALLOCX_ALIGN(alignment) | + MALLOCX_ZERO); + ps[i] = mallocx(sz, MALLOCX_ALIGN(alignment) | + MALLOCX_ZERO); + total += nsz; + if (total >= (MAXALIGN << 1)) + break; + } + for (i = 0; i < NITER; i++) { + if (ps[i] != NULL) { + sdallocx(ps[i], sz, + MALLOCX_ALIGN(alignment)); + ps[i] = NULL; + } + } + } + } +} +TEST_END + +int +main(void) +{ + + return (test( + test_basic, + test_alignment_and_size)); +} diff --git a/memory/jemalloc/src/test/src/SFMT.c b/memory/jemalloc/src/test/src/SFMT.c index e6f8deecb378..80cabe05eebf 100644 --- a/memory/jemalloc/src/test/src/SFMT.c +++ b/memory/jemalloc/src/test/src/SFMT.c @@ -463,11 +463,11 @@ uint32_t gen_rand32_range(sfmt_t *ctx, uint32_t limit) { above = 0xffffffffU - (0xffffffffU % limit); while (1) { - ret = gen_rand32(ctx); - if (ret < above) { - ret %= limit; - break; - } + ret = gen_rand32(ctx); + if (ret < above) { + ret %= limit; + break; + } } return ret; } @@ -511,13 +511,13 @@ uint64_t gen_rand64(sfmt_t *ctx) { uint64_t gen_rand64_range(sfmt_t *ctx, uint64_t limit) { uint64_t ret, above; - above = 0xffffffffffffffffLLU - (0xffffffffffffffffLLU % limit); + above = KQU(0xffffffffffffffff) - (KQU(0xffffffffffffffff) % limit); while (1) { - ret = gen_rand64(ctx); - if (ret < above) { - ret %= limit; - break; - } + ret = gen_rand64(ctx); + if (ret < above) { + ret %= limit; + break; + } } return ret; } diff --git a/memory/jemalloc/src/test/src/btalloc.c b/memory/jemalloc/src/test/src/btalloc.c new file mode 100644 index 000000000000..9a253d9784c0 --- /dev/null +++ b/memory/jemalloc/src/test/src/btalloc.c @@ -0,0 +1,8 @@ +#include "test/jemalloc_test.h" + +void * +btalloc(size_t size, unsigned bits) +{ + + return (btalloc_0(size, bits)); +} diff --git a/memory/jemalloc/src/test/src/btalloc_0.c b/memory/jemalloc/src/test/src/btalloc_0.c new file mode 100644 index 000000000000..77d8904ea912 --- /dev/null +++ b/memory/jemalloc/src/test/src/btalloc_0.c @@ -0,0 +1,3 @@ +#include "test/jemalloc_test.h" + +btalloc_n_gen(0) diff --git a/memory/jemalloc/src/test/src/btalloc_1.c b/memory/jemalloc/src/test/src/btalloc_1.c new file mode 100644 index 000000000000..4c126c309dd4 --- /dev/null +++ b/memory/jemalloc/src/test/src/btalloc_1.c @@ -0,0 +1,3 @@ +#include "test/jemalloc_test.h" + +btalloc_n_gen(1) diff --git a/memory/jemalloc/src/test/src/mtx.c b/memory/jemalloc/src/test/src/mtx.c index 41b95d59de80..73bd02f6df11 100644 --- a/memory/jemalloc/src/test/src/mtx.c +++ b/memory/jemalloc/src/test/src/mtx.c @@ -1,5 +1,9 @@ #include "test/jemalloc_test.h" +#ifndef _CRT_SPINCOUNT +#define _CRT_SPINCOUNT 4000 +#endif + bool mtx_init(mtx_t *mtx) { diff --git a/memory/jemalloc/src/test/src/test.c b/memory/jemalloc/src/test/src/test.c index 528d858317a1..0f8bd4947105 100644 --- a/memory/jemalloc/src/test/src/test.c +++ b/memory/jemalloc/src/test/src/test.c @@ -61,13 +61,26 @@ p_test_fini(void) } test_status_t -p_test(test_t* t, ...) +p_test(test_t *t, ...) { - test_status_t ret = test_status_pass; + test_status_t ret; va_list ap; + /* + * Make sure initialization occurs prior to running tests. Tests are + * special because they may use internal facilities prior to triggering + * initialization as a side effect of calling into the public API. This + * is a final safety that works even if jemalloc_constructor() doesn't + * run, as for MSVC builds. + */ + if (nallocx(1, 0) == 0) { + malloc_printf("Initialization error"); + return (test_status_fail); + } + + ret = test_status_pass; va_start(ap, t); - for (; t != NULL; t = va_arg(ap, test_t*)) { + for (; t != NULL; t = va_arg(ap, test_t *)) { t(); if (test_status > ret) ret = test_status; diff --git a/memory/jemalloc/src/test/src/thd.c b/memory/jemalloc/src/test/src/thd.c index 233242a161e2..c9d0065869b3 100644 --- a/memory/jemalloc/src/test/src/thd.c +++ b/memory/jemalloc/src/test/src/thd.c @@ -14,7 +14,11 @@ void thd_join(thd_t thd, void **ret) { - WaitForSingleObject(thd, INFINITE); + if (WaitForSingleObject(thd, INFINITE) == WAIT_OBJECT_0 && ret) { + DWORD exit_code; + GetExitCodeThread(thd, (LPDWORD) &exit_code); + *ret = (void *)(uintptr_t)exit_code; + } } #else diff --git a/memory/jemalloc/src/test/src/timer.c b/memory/jemalloc/src/test/src/timer.c new file mode 100644 index 000000000000..36fbedd48952 --- /dev/null +++ b/memory/jemalloc/src/test/src/timer.c @@ -0,0 +1,57 @@ +#include "test/jemalloc_test.h" + +void +timer_start(timedelta_t *timer) +{ + + gettimeofday(&timer->tv0, NULL); +} + +void +timer_stop(timedelta_t *timer) +{ + + gettimeofday(&timer->tv1, NULL); +} + +uint64_t +timer_usec(const timedelta_t *timer) +{ + + return (((timer->tv1.tv_sec - timer->tv0.tv_sec) * 1000000) + + timer->tv1.tv_usec - timer->tv0.tv_usec); +} + +void +timer_ratio(timedelta_t *a, timedelta_t *b, char *buf, size_t buflen) +{ + uint64_t t0 = timer_usec(a); + uint64_t t1 = timer_usec(b); + uint64_t mult; + unsigned i = 0; + unsigned j; + int n; + + /* Whole. */ + n = malloc_snprintf(&buf[i], buflen-i, "%"PRIu64, t0 / t1); + i += n; + if (i >= buflen) + return; + mult = 1; + for (j = 0; j < n; j++) + mult *= 10; + + /* Decimal. */ + n = malloc_snprintf(&buf[i], buflen-i, "."); + i += n; + + /* Fraction. */ + while (i < buflen-1) { + uint64_t round = (i+1 == buflen-1 && ((t0 * mult * 10 / t1) % 10 + >= 5)) ? 1 : 0; + n = malloc_snprintf(&buf[i], buflen-i, + "%"PRIu64, (t0 * mult / t1) % 10 + round); + i += n; + mult *= 10; + } +} diff --git a/memory/jemalloc/src/test/stress/microbench.c b/memory/jemalloc/src/test/stress/microbench.c new file mode 100644 index 000000000000..aefbe6a76361 --- /dev/null +++ b/memory/jemalloc/src/test/stress/microbench.c @@ -0,0 +1,181 @@ +#include "test/jemalloc_test.h" + +JEMALLOC_INLINE_C void +time_func(timedelta_t *timer, uint64_t nwarmup, uint64_t niter, void (*func)(void)) +{ + uint64_t i; + + for (i = 0; i < nwarmup; i++) + func(); + timer_start(timer); + for (i = 0; i < niter; i++) + func(); + timer_stop(timer); +} + +void +compare_funcs(uint64_t nwarmup, uint64_t niter, const char *name_a, + void (*func_a), const char *name_b, void (*func_b)) +{ + timedelta_t timer_a, timer_b; + char ratio_buf[6]; + void *p; + + p = mallocx(1, 0); + if (p == NULL) { + test_fail("Unexpected mallocx() failure"); + return; + } + + time_func(&timer_a, nwarmup, niter, func_a); + time_func(&timer_b, nwarmup, niter, func_b); + + timer_ratio(&timer_a, &timer_b, ratio_buf, sizeof(ratio_buf)); + malloc_printf("%"PRIu64" iterations, %s=%"PRIu64"us, " + "%s=%"PRIu64"us, ratio=1:%s\n", + niter, name_a, timer_usec(&timer_a), name_b, timer_usec(&timer_b), + ratio_buf); + + dallocx(p, 0); +} + +static void +malloc_free(void) +{ + /* The compiler can optimize away free(malloc(1))! */ + void *p = malloc(1); + if (p == NULL) { + test_fail("Unexpected malloc() failure"); + return; + } + free(p); +} + +static void +mallocx_free(void) +{ + void *p = mallocx(1, 0); + if (p == NULL) { + test_fail("Unexpected mallocx() failure"); + return; + } + free(p); +} + +TEST_BEGIN(test_malloc_vs_mallocx) +{ + + compare_funcs(10*1000*1000, 100*1000*1000, "malloc", + malloc_free, "mallocx", mallocx_free); +} +TEST_END + +static void +malloc_dallocx(void) +{ + void *p = malloc(1); + if (p == NULL) { + test_fail("Unexpected malloc() failure"); + return; + } + dallocx(p, 0); +} + +static void +malloc_sdallocx(void) +{ + void *p = malloc(1); + if (p == NULL) { + test_fail("Unexpected malloc() failure"); + return; + } + sdallocx(p, 1, 0); +} + +TEST_BEGIN(test_free_vs_dallocx) +{ + + compare_funcs(10*1000*1000, 100*1000*1000, "free", malloc_free, + "dallocx", malloc_dallocx); +} +TEST_END + +TEST_BEGIN(test_dallocx_vs_sdallocx) +{ + + compare_funcs(10*1000*1000, 100*1000*1000, "dallocx", malloc_dallocx, + "sdallocx", malloc_sdallocx); +} +TEST_END + +static void +malloc_mus_free(void) +{ + void *p; + + p = malloc(1); + if (p == NULL) { + test_fail("Unexpected malloc() failure"); + return; + } + malloc_usable_size(p); + free(p); +} + +static void +malloc_sallocx_free(void) +{ + void *p; + + p = malloc(1); + if (p == NULL) { + test_fail("Unexpected malloc() failure"); + return; + } + if (sallocx(p, 0) < 1) + test_fail("Unexpected sallocx() failure"); + free(p); +} + +TEST_BEGIN(test_mus_vs_sallocx) +{ + + compare_funcs(10*1000*1000, 100*1000*1000, "malloc_usable_size", + malloc_mus_free, "sallocx", malloc_sallocx_free); +} +TEST_END + +static void +malloc_nallocx_free(void) +{ + void *p; + + p = malloc(1); + if (p == NULL) { + test_fail("Unexpected malloc() failure"); + return; + } + if (nallocx(1, 0) < 1) + test_fail("Unexpected nallocx() failure"); + free(p); +} + +TEST_BEGIN(test_sallocx_vs_nallocx) +{ + + compare_funcs(10*1000*1000, 100*1000*1000, "sallocx", + malloc_sallocx_free, "nallocx", malloc_nallocx_free); +} +TEST_END + +int +main(void) +{ + + return (test( + test_malloc_vs_mallocx, + test_free_vs_dallocx, + test_dallocx_vs_sdallocx, + test_mus_vs_sallocx, + test_sallocx_vs_nallocx)); +} diff --git a/memory/jemalloc/src/test/unit/SFMT.c b/memory/jemalloc/src/test/unit/SFMT.c index c57bd68df3d8..88b31f6efdb8 100644 --- a/memory/jemalloc/src/test/unit/SFMT.c +++ b/memory/jemalloc/src/test/unit/SFMT.c @@ -445,1008 +445,1008 @@ static const uint32_t init_by_array_32_expected[] = { 2750138839U, 3518055702U, 733072558U, 4169325400U, 788493625U }; static const uint64_t init_gen_rand_64_expected[] = { - QU(16924766246869039260LLU), QU( 8201438687333352714LLU), - QU( 2265290287015001750LLU), QU(18397264611805473832LLU), - QU( 3375255223302384358LLU), QU( 6345559975416828796LLU), - QU(18229739242790328073LLU), QU( 7596792742098800905LLU), - QU( 255338647169685981LLU), QU( 2052747240048610300LLU), - QU(18328151576097299343LLU), QU(12472905421133796567LLU), - QU(11315245349717600863LLU), QU(16594110197775871209LLU), - QU(15708751964632456450LLU), QU(10452031272054632535LLU), - QU(11097646720811454386LLU), QU( 4556090668445745441LLU), - QU(17116187693090663106LLU), QU(14931526836144510645LLU), - QU( 9190752218020552591LLU), QU( 9625800285771901401LLU), - QU(13995141077659972832LLU), QU( 5194209094927829625LLU), - QU( 4156788379151063303LLU), QU( 8523452593770139494LLU), - QU(14082382103049296727LLU), QU( 2462601863986088483LLU), - QU( 3030583461592840678LLU), QU( 5221622077872827681LLU), - QU( 3084210671228981236LLU), QU(13956758381389953823LLU), - QU(13503889856213423831LLU), QU(15696904024189836170LLU), - QU( 4612584152877036206LLU), QU( 6231135538447867881LLU), - QU(10172457294158869468LLU), QU( 6452258628466708150LLU), - QU(14044432824917330221LLU), QU( 370168364480044279LLU), - QU(10102144686427193359LLU), QU( 667870489994776076LLU), - QU( 2732271956925885858LLU), QU(18027788905977284151LLU), - QU(15009842788582923859LLU), QU( 7136357960180199542LLU), - QU(15901736243475578127LLU), QU(16951293785352615701LLU), - QU(10551492125243691632LLU), QU(17668869969146434804LLU), - QU(13646002971174390445LLU), QU( 9804471050759613248LLU), - QU( 5511670439655935493LLU), QU(18103342091070400926LLU), - QU(17224512747665137533LLU), QU(15534627482992618168LLU), - QU( 1423813266186582647LLU), QU(15821176807932930024LLU), - QU( 30323369733607156LLU), QU(11599382494723479403LLU), - QU( 653856076586810062LLU), QU( 3176437395144899659LLU), - QU(14028076268147963917LLU), QU(16156398271809666195LLU), - QU( 3166955484848201676LLU), QU( 5746805620136919390LLU), - QU(17297845208891256593LLU), QU(11691653183226428483LLU), - QU(17900026146506981577LLU), QU(15387382115755971042LLU), - QU(16923567681040845943LLU), QU( 8039057517199388606LLU), - QU(11748409241468629263LLU), QU( 794358245539076095LLU), - QU(13438501964693401242LLU), QU(14036803236515618962LLU), - QU( 5252311215205424721LLU), QU(17806589612915509081LLU), - QU( 6802767092397596006LLU), QU(14212120431184557140LLU), - QU( 1072951366761385712LLU), QU(13098491780722836296LLU), - QU( 9466676828710797353LLU), QU(12673056849042830081LLU), - QU(12763726623645357580LLU), QU(16468961652999309493LLU), - QU(15305979875636438926LLU), QU(17444713151223449734LLU), - QU( 5692214267627883674LLU), QU(13049589139196151505LLU), - QU( 880115207831670745LLU), QU( 1776529075789695498LLU), - QU(16695225897801466485LLU), QU(10666901778795346845LLU), - QU( 6164389346722833869LLU), QU( 2863817793264300475LLU), - QU( 9464049921886304754LLU), QU( 3993566636740015468LLU), - QU( 9983749692528514136LLU), QU(16375286075057755211LLU), - QU(16042643417005440820LLU), QU(11445419662923489877LLU), - QU( 7999038846885158836LLU), QU( 6721913661721511535LLU), - QU( 5363052654139357320LLU), QU( 1817788761173584205LLU), - QU(13290974386445856444LLU), QU( 4650350818937984680LLU), - QU( 8219183528102484836LLU), QU( 1569862923500819899LLU), - QU( 4189359732136641860LLU), QU(14202822961683148583LLU), - QU( 4457498315309429058LLU), QU(13089067387019074834LLU), - QU(11075517153328927293LLU), QU(10277016248336668389LLU), - QU( 7070509725324401122LLU), QU(17808892017780289380LLU), - QU(13143367339909287349LLU), QU( 1377743745360085151LLU), - QU( 5749341807421286485LLU), QU(14832814616770931325LLU), - QU( 7688820635324359492LLU), QU(10960474011539770045LLU), - QU( 81970066653179790LLU), QU(12619476072607878022LLU), - QU( 4419566616271201744LLU), QU(15147917311750568503LLU), - QU( 5549739182852706345LLU), QU( 7308198397975204770LLU), - QU(13580425496671289278LLU), QU(17070764785210130301LLU), - QU( 8202832846285604405LLU), QU( 6873046287640887249LLU), - QU( 6927424434308206114LLU), QU( 6139014645937224874LLU), - QU(10290373645978487639LLU), QU(15904261291701523804LLU), - QU( 9628743442057826883LLU), QU(18383429096255546714LLU), - QU( 4977413265753686967LLU), QU( 7714317492425012869LLU), - QU( 9025232586309926193LLU), QU(14627338359776709107LLU), - QU(14759849896467790763LLU), QU(10931129435864423252LLU), - QU( 4588456988775014359LLU), QU(10699388531797056724LLU), - QU( 468652268869238792LLU), QU( 5755943035328078086LLU), - QU( 2102437379988580216LLU), QU( 9986312786506674028LLU), - QU( 2654207180040945604LLU), QU( 8726634790559960062LLU), - QU( 100497234871808137LLU), QU( 2800137176951425819LLU), - QU( 6076627612918553487LLU), QU( 5780186919186152796LLU), - QU( 8179183595769929098LLU), QU( 6009426283716221169LLU), - QU( 2796662551397449358LLU), QU( 1756961367041986764LLU), - QU( 6972897917355606205LLU), QU(14524774345368968243LLU), - QU( 2773529684745706940LLU), QU( 4853632376213075959LLU), - QU( 4198177923731358102LLU), QU( 8271224913084139776LLU), - QU( 2741753121611092226LLU), QU(16782366145996731181LLU), - QU(15426125238972640790LLU), QU(13595497100671260342LLU), - QU( 3173531022836259898LLU), QU( 6573264560319511662LLU), - QU(18041111951511157441LLU), QU( 2351433581833135952LLU), - QU( 3113255578908173487LLU), QU( 1739371330877858784LLU), - QU(16046126562789165480LLU), QU( 8072101652214192925LLU), - QU(15267091584090664910LLU), QU( 9309579200403648940LLU), - QU( 5218892439752408722LLU), QU(14492477246004337115LLU), - QU(17431037586679770619LLU), QU( 7385248135963250480LLU), - QU( 9580144956565560660LLU), QU( 4919546228040008720LLU), - QU(15261542469145035584LLU), QU(18233297270822253102LLU), - QU( 5453248417992302857LLU), QU( 9309519155931460285LLU), - QU(10342813012345291756LLU), QU(15676085186784762381LLU), - QU(15912092950691300645LLU), QU( 9371053121499003195LLU), - QU( 9897186478226866746LLU), QU(14061858287188196327LLU), - QU( 122575971620788119LLU), QU(12146750969116317754LLU), - QU( 4438317272813245201LLU), QU( 8332576791009527119LLU), - QU(13907785691786542057LLU), QU(10374194887283287467LLU), - QU( 2098798755649059566LLU), QU( 3416235197748288894LLU), - QU( 8688269957320773484LLU), QU( 7503964602397371571LLU), - QU(16724977015147478236LLU), QU( 9461512855439858184LLU), - QU(13259049744534534727LLU), QU( 3583094952542899294LLU), - QU( 8764245731305528292LLU), QU(13240823595462088985LLU), - QU(13716141617617910448LLU), QU(18114969519935960955LLU), - QU( 2297553615798302206LLU), QU( 4585521442944663362LLU), - QU(17776858680630198686LLU), QU( 4685873229192163363LLU), - QU( 152558080671135627LLU), QU(15424900540842670088LLU), - QU(13229630297130024108LLU), QU(17530268788245718717LLU), - QU(16675633913065714144LLU), QU( 3158912717897568068LLU), - QU(15399132185380087288LLU), QU( 7401418744515677872LLU), - QU(13135412922344398535LLU), QU( 6385314346100509511LLU), - QU(13962867001134161139LLU), QU(10272780155442671999LLU), - QU(12894856086597769142LLU), QU(13340877795287554994LLU), - QU(12913630602094607396LLU), QU(12543167911119793857LLU), - QU(17343570372251873096LLU), QU(10959487764494150545LLU), - QU( 6966737953093821128LLU), QU(13780699135496988601LLU), - QU( 4405070719380142046LLU), QU(14923788365607284982LLU), - QU( 2869487678905148380LLU), QU( 6416272754197188403LLU), - QU(15017380475943612591LLU), QU( 1995636220918429487LLU), - QU( 3402016804620122716LLU), QU(15800188663407057080LLU), - QU(11362369990390932882LLU), QU(15262183501637986147LLU), - QU(10239175385387371494LLU), QU( 9352042420365748334LLU), - QU( 1682457034285119875LLU), QU( 1724710651376289644LLU), - QU( 2038157098893817966LLU), QU( 9897825558324608773LLU), - QU( 1477666236519164736LLU), QU(16835397314511233640LLU), - QU(10370866327005346508LLU), QU(10157504370660621982LLU), - QU(12113904045335882069LLU), QU(13326444439742783008LLU), - QU(11302769043000765804LLU), QU(13594979923955228484LLU), - QU(11779351762613475968LLU), QU( 3786101619539298383LLU), - QU( 8021122969180846063LLU), QU(15745904401162500495LLU), - QU(10762168465993897267LLU), QU(13552058957896319026LLU), - QU(11200228655252462013LLU), QU( 5035370357337441226LLU), - QU( 7593918984545500013LLU), QU( 5418554918361528700LLU), - QU( 4858270799405446371LLU), QU( 9974659566876282544LLU), - QU(18227595922273957859LLU), QU( 2772778443635656220LLU), - QU(14285143053182085385LLU), QU( 9939700992429600469LLU), - QU(12756185904545598068LLU), QU( 2020783375367345262LLU), - QU( 57026775058331227LLU), QU( 950827867930065454LLU), - QU( 6602279670145371217LLU), QU( 2291171535443566929LLU), - QU( 5832380724425010313LLU), QU( 1220343904715982285LLU), - QU(17045542598598037633LLU), QU(15460481779702820971LLU), - QU(13948388779949365130LLU), QU(13975040175430829518LLU), - QU(17477538238425541763LLU), QU(11104663041851745725LLU), - QU(15860992957141157587LLU), QU(14529434633012950138LLU), - QU( 2504838019075394203LLU), QU( 7512113882611121886LLU), - QU( 4859973559980886617LLU), QU( 1258601555703250219LLU), - QU(15594548157514316394LLU), QU( 4516730171963773048LLU), - QU(11380103193905031983LLU), QU( 6809282239982353344LLU), - QU(18045256930420065002LLU), QU( 2453702683108791859LLU), - QU( 977214582986981460LLU), QU( 2006410402232713466LLU), - QU( 6192236267216378358LLU), QU( 3429468402195675253LLU), - QU(18146933153017348921LLU), QU(17369978576367231139LLU), - QU( 1246940717230386603LLU), QU(11335758870083327110LLU), - QU(14166488801730353682LLU), QU( 9008573127269635732LLU), - QU(10776025389820643815LLU), QU(15087605441903942962LLU), - QU( 1359542462712147922LLU), QU(13898874411226454206LLU), - QU(17911176066536804411LLU), QU( 9435590428600085274LLU), - QU( 294488509967864007LLU), QU( 8890111397567922046LLU), - QU( 7987823476034328778LLU), QU(13263827582440967651LLU), - QU( 7503774813106751573LLU), QU(14974747296185646837LLU), - QU( 8504765037032103375LLU), QU(17340303357444536213LLU), - QU( 7704610912964485743LLU), QU( 8107533670327205061LLU), - QU( 9062969835083315985LLU), QU(16968963142126734184LLU), - QU(12958041214190810180LLU), QU( 2720170147759570200LLU), - QU( 2986358963942189566LLU), QU(14884226322219356580LLU), - QU( 286224325144368520LLU), QU(11313800433154279797LLU), - QU(18366849528439673248LLU), QU(17899725929482368789LLU), - QU( 3730004284609106799LLU), QU( 1654474302052767205LLU), - QU( 5006698007047077032LLU), QU( 8196893913601182838LLU), - QU(15214541774425211640LLU), QU(17391346045606626073LLU), - QU( 8369003584076969089LLU), QU( 3939046733368550293LLU), - QU(10178639720308707785LLU), QU( 2180248669304388697LLU), - QU( 62894391300126322LLU), QU( 9205708961736223191LLU), - QU( 6837431058165360438LLU), QU( 3150743890848308214LLU), - QU(17849330658111464583LLU), QU(12214815643135450865LLU), - QU(13410713840519603402LLU), QU( 3200778126692046802LLU), - QU(13354780043041779313LLU), QU( 800850022756886036LLU), - QU(15660052933953067433LLU), QU( 6572823544154375676LLU), - QU(11030281857015819266LLU), QU(12682241941471433835LLU), - QU(11654136407300274693LLU), QU( 4517795492388641109LLU), - QU( 9757017371504524244LLU), QU(17833043400781889277LLU), - QU(12685085201747792227LLU), QU(10408057728835019573LLU), - QU( 98370418513455221LLU), QU( 6732663555696848598LLU), - QU(13248530959948529780LLU), QU( 3530441401230622826LLU), - QU(18188251992895660615LLU), QU( 1847918354186383756LLU), - QU( 1127392190402660921LLU), QU(11293734643143819463LLU), - QU( 3015506344578682982LLU), QU(13852645444071153329LLU), - QU( 2121359659091349142LLU), QU( 1294604376116677694LLU), - QU( 5616576231286352318LLU), QU( 7112502442954235625LLU), - QU(11676228199551561689LLU), QU(12925182803007305359LLU), - QU( 7852375518160493082LLU), QU( 1136513130539296154LLU), - QU( 5636923900916593195LLU), QU( 3221077517612607747LLU), - QU(17784790465798152513LLU), QU( 3554210049056995938LLU), - QU(17476839685878225874LLU), QU( 3206836372585575732LLU), - QU( 2765333945644823430LLU), QU(10080070903718799528LLU), - QU( 5412370818878286353LLU), QU( 9689685887726257728LLU), - QU( 8236117509123533998LLU), QU( 1951139137165040214LLU), - QU( 4492205209227980349LLU), QU(16541291230861602967LLU), - QU( 1424371548301437940LLU), QU( 9117562079669206794LLU), - QU(14374681563251691625LLU), QU(13873164030199921303LLU), - QU( 6680317946770936731LLU), QU(15586334026918276214LLU), - QU(10896213950976109802LLU), QU( 9506261949596413689LLU), - QU( 9903949574308040616LLU), QU( 6038397344557204470LLU), - QU( 174601465422373648LLU), QU(15946141191338238030LLU), - QU(17142225620992044937LLU), QU( 7552030283784477064LLU), - QU( 2947372384532947997LLU), QU( 510797021688197711LLU), - QU( 4962499439249363461LLU), QU( 23770320158385357LLU), - QU( 959774499105138124LLU), QU( 1468396011518788276LLU), - QU( 2015698006852312308LLU), QU( 4149400718489980136LLU), - QU( 5992916099522371188LLU), QU(10819182935265531076LLU), - QU(16189787999192351131LLU), QU( 342833961790261950LLU), - QU(12470830319550495336LLU), QU(18128495041912812501LLU), - QU( 1193600899723524337LLU), QU( 9056793666590079770LLU), - QU( 2154021227041669041LLU), QU( 4963570213951235735LLU), - QU( 4865075960209211409LLU), QU( 2097724599039942963LLU), - QU( 2024080278583179845LLU), QU(11527054549196576736LLU), - QU(10650256084182390252LLU), QU( 4808408648695766755LLU), - QU( 1642839215013788844LLU), QU(10607187948250398390LLU), - QU( 7076868166085913508LLU), QU( 730522571106887032LLU), - QU(12500579240208524895LLU), QU( 4484390097311355324LLU), - QU(15145801330700623870LLU), QU( 8055827661392944028LLU), - QU( 5865092976832712268LLU), QU(15159212508053625143LLU), - QU( 3560964582876483341LLU), QU( 4070052741344438280LLU), - QU( 6032585709886855634LLU), QU(15643262320904604873LLU), - QU( 2565119772293371111LLU), QU( 318314293065348260LLU), - QU(15047458749141511872LLU), QU( 7772788389811528730LLU), - QU( 7081187494343801976LLU), QU( 6465136009467253947LLU), - QU(10425940692543362069LLU), QU( 554608190318339115LLU), - QU(14796699860302125214LLU), QU( 1638153134431111443LLU), - QU(10336967447052276248LLU), QU( 8412308070396592958LLU), - QU( 4004557277152051226LLU), QU( 8143598997278774834LLU), - QU(16413323996508783221LLU), QU(13139418758033994949LLU), - QU( 9772709138335006667LLU), QU( 2818167159287157659LLU), - QU(17091740573832523669LLU), QU(14629199013130751608LLU), - QU(18268322711500338185LLU), QU( 8290963415675493063LLU), - QU( 8830864907452542588LLU), QU( 1614839084637494849LLU), - QU(14855358500870422231LLU), QU( 3472996748392519937LLU), - QU(15317151166268877716LLU), QU( 5825895018698400362LLU), - QU(16730208429367544129LLU), QU(10481156578141202800LLU), - QU( 4746166512382823750LLU), QU(12720876014472464998LLU), - QU( 8825177124486735972LLU), QU(13733447296837467838LLU), - QU( 6412293741681359625LLU), QU( 8313213138756135033LLU), - QU(11421481194803712517LLU), QU( 7997007691544174032LLU), - QU( 6812963847917605930LLU), QU( 9683091901227558641LLU), - QU(14703594165860324713LLU), QU( 1775476144519618309LLU), - QU( 2724283288516469519LLU), QU( 717642555185856868LLU), - QU( 8736402192215092346LLU), QU(11878800336431381021LLU), - QU( 4348816066017061293LLU), QU( 6115112756583631307LLU), - QU( 9176597239667142976LLU), QU(12615622714894259204LLU), - QU(10283406711301385987LLU), QU( 5111762509485379420LLU), - QU( 3118290051198688449LLU), QU( 7345123071632232145LLU), - QU( 9176423451688682359LLU), QU( 4843865456157868971LLU), - QU(12008036363752566088LLU), QU(12058837181919397720LLU), - QU( 2145073958457347366LLU), QU( 1526504881672818067LLU), - QU( 3488830105567134848LLU), QU(13208362960674805143LLU), - QU( 4077549672899572192LLU), QU( 7770995684693818365LLU), - QU( 1398532341546313593LLU), QU(12711859908703927840LLU), - QU( 1417561172594446813LLU), QU(17045191024194170604LLU), - QU( 4101933177604931713LLU), QU(14708428834203480320LLU), - QU(17447509264469407724LLU), QU(14314821973983434255LLU), - QU(17990472271061617265LLU), QU( 5087756685841673942LLU), - QU(12797820586893859939LLU), QU( 1778128952671092879LLU), - QU( 3535918530508665898LLU), QU( 9035729701042481301LLU), - QU(14808661568277079962LLU), QU(14587345077537747914LLU), - QU(11920080002323122708LLU), QU( 6426515805197278753LLU), - QU( 3295612216725984831LLU), QU(11040722532100876120LLU), - QU(12305952936387598754LLU), QU(16097391899742004253LLU), - QU( 4908537335606182208LLU), QU(12446674552196795504LLU), - QU(16010497855816895177LLU), QU( 9194378874788615551LLU), - QU( 3382957529567613384LLU), QU( 5154647600754974077LLU), - QU( 9801822865328396141LLU), QU( 9023662173919288143LLU), - QU(17623115353825147868LLU), QU( 8238115767443015816LLU), - QU(15811444159859002560LLU), QU( 9085612528904059661LLU), - QU( 6888601089398614254LLU), QU( 258252992894160189LLU), - QU( 6704363880792428622LLU), QU( 6114966032147235763LLU), - QU(11075393882690261875LLU), QU( 8797664238933620407LLU), - QU( 5901892006476726920LLU), QU( 5309780159285518958LLU), - QU(14940808387240817367LLU), QU(14642032021449656698LLU), - QU( 9808256672068504139LLU), QU( 3670135111380607658LLU), - QU(11211211097845960152LLU), QU( 1474304506716695808LLU), - QU(15843166204506876239LLU), QU( 7661051252471780561LLU), - QU(10170905502249418476LLU), QU( 7801416045582028589LLU), - QU( 2763981484737053050LLU), QU( 9491377905499253054LLU), - QU(16201395896336915095LLU), QU( 9256513756442782198LLU), - QU( 5411283157972456034LLU), QU( 5059433122288321676LLU), - QU( 4327408006721123357LLU), QU( 9278544078834433377LLU), - QU( 7601527110882281612LLU), QU(11848295896975505251LLU), - QU(12096998801094735560LLU), QU(14773480339823506413LLU), - QU(15586227433895802149LLU), QU(12786541257830242872LLU), - QU( 6904692985140503067LLU), QU( 5309011515263103959LLU), - QU(12105257191179371066LLU), QU(14654380212442225037LLU), - QU( 2556774974190695009LLU), QU( 4461297399927600261LLU), - QU(14888225660915118646LLU), QU(14915459341148291824LLU), - QU( 2738802166252327631LLU), QU( 6047155789239131512LLU), - QU(12920545353217010338LLU), QU(10697617257007840205LLU), - QU( 2751585253158203504LLU), QU(13252729159780047496LLU), - QU(14700326134672815469LLU), QU(14082527904374600529LLU), - QU(16852962273496542070LLU), QU(17446675504235853907LLU), - QU(15019600398527572311LLU), QU(12312781346344081551LLU), - QU(14524667935039810450LLU), QU( 5634005663377195738LLU), - QU(11375574739525000569LLU), QU( 2423665396433260040LLU), - QU( 5222836914796015410LLU), QU( 4397666386492647387LLU), - QU( 4619294441691707638LLU), QU( 665088602354770716LLU), - QU(13246495665281593610LLU), QU( 6564144270549729409LLU), - QU(10223216188145661688LLU), QU( 3961556907299230585LLU), - QU(11543262515492439914LLU), QU(16118031437285993790LLU), - QU( 7143417964520166465LLU), QU(13295053515909486772LLU), - QU( 40434666004899675LLU), QU(17127804194038347164LLU), - QU( 8599165966560586269LLU), QU( 8214016749011284903LLU), - QU(13725130352140465239LLU), QU( 5467254474431726291LLU), - QU( 7748584297438219877LLU), QU(16933551114829772472LLU), - QU( 2169618439506799400LLU), QU( 2169787627665113463LLU), - QU(17314493571267943764LLU), QU(18053575102911354912LLU), - QU(11928303275378476973LLU), QU(11593850925061715550LLU), - QU(17782269923473589362LLU), QU( 3280235307704747039LLU), - QU( 6145343578598685149LLU), QU(17080117031114086090LLU), - QU(18066839902983594755LLU), QU( 6517508430331020706LLU), - QU( 8092908893950411541LLU), QU(12558378233386153732LLU), - QU( 4476532167973132976LLU), QU(16081642430367025016LLU), - QU( 4233154094369139361LLU), QU( 8693630486693161027LLU), - QU(11244959343027742285LLU), QU(12273503967768513508LLU), - QU(14108978636385284876LLU), QU( 7242414665378826984LLU), - QU( 6561316938846562432LLU), QU( 8601038474994665795LLU), - QU(17532942353612365904LLU), QU(17940076637020912186LLU), - QU( 7340260368823171304LLU), QU( 7061807613916067905LLU), - QU(10561734935039519326LLU), QU(17990796503724650862LLU), - QU( 6208732943911827159LLU), QU( 359077562804090617LLU), - QU(14177751537784403113LLU), QU(10659599444915362902LLU), - QU(15081727220615085833LLU), QU(13417573895659757486LLU), - QU(15513842342017811524LLU), QU(11814141516204288231LLU), - QU( 1827312513875101814LLU), QU( 2804611699894603103LLU), - QU(17116500469975602763LLU), QU(12270191815211952087LLU), - QU(12256358467786024988LLU), QU(18435021722453971267LLU), - QU( 671330264390865618LLU), QU( 476504300460286050LLU), - QU(16465470901027093441LLU), QU( 4047724406247136402LLU), - QU( 1322305451411883346LLU), QU( 1388308688834322280LLU), - QU( 7303989085269758176LLU), QU( 9323792664765233642LLU), - QU( 4542762575316368936LLU), QU(17342696132794337618LLU), - QU( 4588025054768498379LLU), QU(13415475057390330804LLU), - QU(17880279491733405570LLU), QU(10610553400618620353LLU), - QU( 3180842072658960139LLU), QU(13002966655454270120LLU), - QU( 1665301181064982826LLU), QU( 7083673946791258979LLU), - QU( 190522247122496820LLU), QU(17388280237250677740LLU), - QU( 8430770379923642945LLU), QU(12987180971921668584LLU), - QU( 2311086108365390642LLU), QU( 2870984383579822345LLU), - QU(14014682609164653318LLU), QU(14467187293062251484LLU), - QU( 192186361147413298LLU), QU(15171951713531796524LLU), - QU( 9900305495015948728LLU), QU(17958004775615466344LLU), - QU(14346380954498606514LLU), QU(18040047357617407096LLU), - QU( 5035237584833424532LLU), QU(15089555460613972287LLU), - QU( 4131411873749729831LLU), QU( 1329013581168250330LLU), - QU(10095353333051193949LLU), QU(10749518561022462716LLU), - QU( 9050611429810755847LLU), QU(15022028840236655649LLU), - QU( 8775554279239748298LLU), QU(13105754025489230502LLU), - QU(15471300118574167585LLU), QU( 89864764002355628LLU), - QU( 8776416323420466637LLU), QU( 5280258630612040891LLU), - QU( 2719174488591862912LLU), QU( 7599309137399661994LLU), - QU(15012887256778039979LLU), QU(14062981725630928925LLU), - QU(12038536286991689603LLU), QU( 7089756544681775245LLU), - QU(10376661532744718039LLU), QU( 1265198725901533130LLU), - QU(13807996727081142408LLU), QU( 2935019626765036403LLU), - QU( 7651672460680700141LLU), QU( 3644093016200370795LLU), - QU( 2840982578090080674LLU), QU(17956262740157449201LLU), - QU(18267979450492880548LLU), QU(11799503659796848070LLU), - QU( 9942537025669672388LLU), QU(11886606816406990297LLU), - QU( 5488594946437447576LLU), QU( 7226714353282744302LLU), - QU( 3784851653123877043LLU), QU( 878018453244803041LLU), - QU(12110022586268616085LLU), QU( 734072179404675123LLU), - QU(11869573627998248542LLU), QU( 469150421297783998LLU), - QU( 260151124912803804LLU), QU(11639179410120968649LLU), - QU( 9318165193840846253LLU), QU(12795671722734758075LLU), - QU(15318410297267253933LLU), QU( 691524703570062620LLU), - QU( 5837129010576994601LLU), QU(15045963859726941052LLU), - QU( 5850056944932238169LLU), QU(12017434144750943807LLU), - QU( 7447139064928956574LLU), QU( 3101711812658245019LLU), - QU(16052940704474982954LLU), QU(18195745945986994042LLU), - QU( 8932252132785575659LLU), QU(13390817488106794834LLU), - QU(11582771836502517453LLU), QU( 4964411326683611686LLU), - QU( 2195093981702694011LLU), QU(14145229538389675669LLU), - QU(16459605532062271798LLU), QU( 866316924816482864LLU), - QU( 4593041209937286377LLU), QU( 8415491391910972138LLU), - QU( 4171236715600528969LLU), QU(16637569303336782889LLU), - QU( 2002011073439212680LLU), QU(17695124661097601411LLU), - QU( 4627687053598611702LLU), QU( 7895831936020190403LLU), - QU( 8455951300917267802LLU), QU( 2923861649108534854LLU), - QU( 8344557563927786255LLU), QU( 6408671940373352556LLU), - QU(12210227354536675772LLU), QU(14294804157294222295LLU), - QU(10103022425071085127LLU), QU(10092959489504123771LLU), - QU( 6554774405376736268LLU), QU(12629917718410641774LLU), - QU( 6260933257596067126LLU), QU( 2460827021439369673LLU), - QU( 2541962996717103668LLU), QU( 597377203127351475LLU), - QU( 5316984203117315309LLU), QU( 4811211393563241961LLU), - QU(13119698597255811641LLU), QU( 8048691512862388981LLU), - QU(10216818971194073842LLU), QU( 4612229970165291764LLU), - QU(10000980798419974770LLU), QU( 6877640812402540687LLU), - QU( 1488727563290436992LLU), QU( 2227774069895697318LLU), - QU(11237754507523316593LLU), QU(13478948605382290972LLU), - QU( 1963583846976858124LLU), QU( 5512309205269276457LLU), - QU( 3972770164717652347LLU), QU( 3841751276198975037LLU), - QU(10283343042181903117LLU), QU( 8564001259792872199LLU), - QU(16472187244722489221LLU), QU( 8953493499268945921LLU), - QU( 3518747340357279580LLU), QU( 4003157546223963073LLU), - QU( 3270305958289814590LLU), QU( 3966704458129482496LLU), - QU( 8122141865926661939LLU), QU(14627734748099506653LLU), - QU(13064426990862560568LLU), QU( 2414079187889870829LLU), - QU( 5378461209354225306LLU), QU(10841985740128255566LLU), - QU( 538582442885401738LLU), QU( 7535089183482905946LLU), - QU(16117559957598879095LLU), QU( 8477890721414539741LLU), - QU( 1459127491209533386LLU), QU(17035126360733620462LLU), - QU( 8517668552872379126LLU), QU(10292151468337355014LLU), - QU(17081267732745344157LLU), QU(13751455337946087178LLU), - QU(14026945459523832966LLU), QU( 6653278775061723516LLU), - QU(10619085543856390441LLU), QU( 2196343631481122885LLU), - QU(10045966074702826136LLU), QU(10082317330452718282LLU), - QU( 5920859259504831242LLU), QU( 9951879073426540617LLU), - QU( 7074696649151414158LLU), QU(15808193543879464318LLU), - QU( 7385247772746953374LLU), QU( 3192003544283864292LLU), - QU(18153684490917593847LLU), QU(12423498260668568905LLU), - QU(10957758099756378169LLU), QU(11488762179911016040LLU), - QU( 2099931186465333782LLU), QU(11180979581250294432LLU), - QU( 8098916250668367933LLU), QU( 3529200436790763465LLU), - QU(12988418908674681745LLU), QU( 6147567275954808580LLU), - QU( 3207503344604030989LLU), QU(10761592604898615360LLU), - QU( 229854861031893504LLU), QU( 8809853962667144291LLU), - QU(13957364469005693860LLU), QU( 7634287665224495886LLU), - QU(12353487366976556874LLU), QU( 1134423796317152034LLU), - QU( 2088992471334107068LLU), QU( 7393372127190799698LLU), - QU( 1845367839871058391LLU), QU( 207922563987322884LLU), - QU(11960870813159944976LLU), QU(12182120053317317363LLU), - QU(17307358132571709283LLU), QU(13871081155552824936LLU), - QU(18304446751741566262LLU), QU( 7178705220184302849LLU), - QU(10929605677758824425LLU), QU(16446976977835806844LLU), - QU(13723874412159769044LLU), QU( 6942854352100915216LLU), - QU( 1726308474365729390LLU), QU( 2150078766445323155LLU), - QU(15345558947919656626LLU), QU(12145453828874527201LLU), - QU( 2054448620739726849LLU), QU( 2740102003352628137LLU), - QU(11294462163577610655LLU), QU( 756164283387413743LLU), - QU(17841144758438810880LLU), QU(10802406021185415861LLU), - QU( 8716455530476737846LLU), QU( 6321788834517649606LLU), - QU(14681322910577468426LLU), QU(17330043563884336387LLU), - QU(12701802180050071614LLU), QU(14695105111079727151LLU), - QU( 5112098511654172830LLU), QU( 4957505496794139973LLU), - QU( 8270979451952045982LLU), QU(12307685939199120969LLU), - QU(12425799408953443032LLU), QU( 8376410143634796588LLU), - QU(16621778679680060464LLU), QU( 3580497854566660073LLU), - QU( 1122515747803382416LLU), QU( 857664980960597599LLU), - QU( 6343640119895925918LLU), QU(12878473260854462891LLU), - QU(10036813920765722626LLU), QU(14451335468363173812LLU), - QU( 5476809692401102807LLU), QU(16442255173514366342LLU), - QU(13060203194757167104LLU), QU(14354124071243177715LLU), - QU(15961249405696125227LLU), QU(13703893649690872584LLU), - QU( 363907326340340064LLU), QU( 6247455540491754842LLU), - QU(12242249332757832361LLU), QU( 156065475679796717LLU), - QU( 9351116235749732355LLU), QU( 4590350628677701405LLU), - QU( 1671195940982350389LLU), QU(13501398458898451905LLU), - QU( 6526341991225002255LLU), QU( 1689782913778157592LLU), - QU( 7439222350869010334LLU), QU(13975150263226478308LLU), - QU(11411961169932682710LLU), QU(17204271834833847277LLU), - QU( 541534742544435367LLU), QU( 6591191931218949684LLU), - QU( 2645454775478232486LLU), QU( 4322857481256485321LLU), - QU( 8477416487553065110LLU), QU(12902505428548435048LLU), - QU( 971445777981341415LLU), QU(14995104682744976712LLU), - QU( 4243341648807158063LLU), QU( 8695061252721927661LLU), - QU( 5028202003270177222LLU), QU( 2289257340915567840LLU), - QU(13870416345121866007LLU), QU(13994481698072092233LLU), - QU( 6912785400753196481LLU), QU( 2278309315841980139LLU), - QU( 4329765449648304839LLU), QU( 5963108095785485298LLU), - QU( 4880024847478722478LLU), QU(16015608779890240947LLU), - QU( 1866679034261393544LLU), QU( 914821179919731519LLU), - QU( 9643404035648760131LLU), QU( 2418114953615593915LLU), - QU( 944756836073702374LLU), QU(15186388048737296834LLU), - QU( 7723355336128442206LLU), QU( 7500747479679599691LLU), - QU(18013961306453293634LLU), QU( 2315274808095756456LLU), - QU(13655308255424029566LLU), QU(17203800273561677098LLU), - QU( 1382158694422087756LLU), QU( 5090390250309588976LLU), - QU( 517170818384213989LLU), QU( 1612709252627729621LLU), - QU( 1330118955572449606LLU), QU( 300922478056709885LLU), - QU(18115693291289091987LLU), QU(13491407109725238321LLU), - QU(15293714633593827320LLU), QU( 5151539373053314504LLU), - QU( 5951523243743139207LLU), QU(14459112015249527975LLU), - QU( 5456113959000700739LLU), QU( 3877918438464873016LLU), - QU(12534071654260163555LLU), QU(15871678376893555041LLU), - QU(11005484805712025549LLU), QU(16353066973143374252LLU), - QU( 4358331472063256685LLU), QU( 8268349332210859288LLU), - QU(12485161590939658075LLU), QU(13955993592854471343LLU), - QU( 5911446886848367039LLU), QU(14925834086813706974LLU), - QU( 6590362597857994805LLU), QU( 1280544923533661875LLU), - QU( 1637756018947988164LLU), QU( 4734090064512686329LLU), - QU(16693705263131485912LLU), QU( 6834882340494360958LLU), - QU( 8120732176159658505LLU), QU( 2244371958905329346LLU), - QU(10447499707729734021LLU), QU( 7318742361446942194LLU), - QU( 8032857516355555296LLU), QU(14023605983059313116LLU), - QU( 1032336061815461376LLU), QU( 9840995337876562612LLU), - QU( 9869256223029203587LLU), QU(12227975697177267636LLU), - QU(12728115115844186033LLU), QU( 7752058479783205470LLU), - QU( 729733219713393087LLU), QU(12954017801239007622LLU) + KQU(16924766246869039260), KQU( 8201438687333352714), + KQU( 2265290287015001750), KQU(18397264611805473832), + KQU( 3375255223302384358), KQU( 6345559975416828796), + KQU(18229739242790328073), KQU( 7596792742098800905), + KQU( 255338647169685981), KQU( 2052747240048610300), + KQU(18328151576097299343), KQU(12472905421133796567), + KQU(11315245349717600863), KQU(16594110197775871209), + KQU(15708751964632456450), KQU(10452031272054632535), + KQU(11097646720811454386), KQU( 4556090668445745441), + KQU(17116187693090663106), KQU(14931526836144510645), + KQU( 9190752218020552591), KQU( 9625800285771901401), + KQU(13995141077659972832), KQU( 5194209094927829625), + KQU( 4156788379151063303), KQU( 8523452593770139494), + KQU(14082382103049296727), KQU( 2462601863986088483), + KQU( 3030583461592840678), KQU( 5221622077872827681), + KQU( 3084210671228981236), KQU(13956758381389953823), + KQU(13503889856213423831), KQU(15696904024189836170), + KQU( 4612584152877036206), KQU( 6231135538447867881), + KQU(10172457294158869468), KQU( 6452258628466708150), + KQU(14044432824917330221), KQU( 370168364480044279), + KQU(10102144686427193359), KQU( 667870489994776076), + KQU( 2732271956925885858), KQU(18027788905977284151), + KQU(15009842788582923859), KQU( 7136357960180199542), + KQU(15901736243475578127), KQU(16951293785352615701), + KQU(10551492125243691632), KQU(17668869969146434804), + KQU(13646002971174390445), KQU( 9804471050759613248), + KQU( 5511670439655935493), KQU(18103342091070400926), + KQU(17224512747665137533), KQU(15534627482992618168), + KQU( 1423813266186582647), KQU(15821176807932930024), + KQU( 30323369733607156), KQU(11599382494723479403), + KQU( 653856076586810062), KQU( 3176437395144899659), + KQU(14028076268147963917), KQU(16156398271809666195), + KQU( 3166955484848201676), KQU( 5746805620136919390), + KQU(17297845208891256593), KQU(11691653183226428483), + KQU(17900026146506981577), KQU(15387382115755971042), + KQU(16923567681040845943), KQU( 8039057517199388606), + KQU(11748409241468629263), KQU( 794358245539076095), + KQU(13438501964693401242), KQU(14036803236515618962), + KQU( 5252311215205424721), KQU(17806589612915509081), + KQU( 6802767092397596006), KQU(14212120431184557140), + KQU( 1072951366761385712), KQU(13098491780722836296), + KQU( 9466676828710797353), KQU(12673056849042830081), + KQU(12763726623645357580), KQU(16468961652999309493), + KQU(15305979875636438926), KQU(17444713151223449734), + KQU( 5692214267627883674), KQU(13049589139196151505), + KQU( 880115207831670745), KQU( 1776529075789695498), + KQU(16695225897801466485), KQU(10666901778795346845), + KQU( 6164389346722833869), KQU( 2863817793264300475), + KQU( 9464049921886304754), KQU( 3993566636740015468), + KQU( 9983749692528514136), KQU(16375286075057755211), + KQU(16042643417005440820), KQU(11445419662923489877), + KQU( 7999038846885158836), KQU( 6721913661721511535), + KQU( 5363052654139357320), KQU( 1817788761173584205), + KQU(13290974386445856444), KQU( 4650350818937984680), + KQU( 8219183528102484836), KQU( 1569862923500819899), + KQU( 4189359732136641860), KQU(14202822961683148583), + KQU( 4457498315309429058), KQU(13089067387019074834), + KQU(11075517153328927293), KQU(10277016248336668389), + KQU( 7070509725324401122), KQU(17808892017780289380), + KQU(13143367339909287349), KQU( 1377743745360085151), + KQU( 5749341807421286485), KQU(14832814616770931325), + KQU( 7688820635324359492), KQU(10960474011539770045), + KQU( 81970066653179790), KQU(12619476072607878022), + KQU( 4419566616271201744), KQU(15147917311750568503), + KQU( 5549739182852706345), KQU( 7308198397975204770), + KQU(13580425496671289278), KQU(17070764785210130301), + KQU( 8202832846285604405), KQU( 6873046287640887249), + KQU( 6927424434308206114), KQU( 6139014645937224874), + KQU(10290373645978487639), KQU(15904261291701523804), + KQU( 9628743442057826883), KQU(18383429096255546714), + KQU( 4977413265753686967), KQU( 7714317492425012869), + KQU( 9025232586309926193), KQU(14627338359776709107), + KQU(14759849896467790763), KQU(10931129435864423252), + KQU( 4588456988775014359), KQU(10699388531797056724), + KQU( 468652268869238792), KQU( 5755943035328078086), + KQU( 2102437379988580216), KQU( 9986312786506674028), + KQU( 2654207180040945604), KQU( 8726634790559960062), + KQU( 100497234871808137), KQU( 2800137176951425819), + KQU( 6076627612918553487), KQU( 5780186919186152796), + KQU( 8179183595769929098), KQU( 6009426283716221169), + KQU( 2796662551397449358), KQU( 1756961367041986764), + KQU( 6972897917355606205), KQU(14524774345368968243), + KQU( 2773529684745706940), KQU( 4853632376213075959), + KQU( 4198177923731358102), KQU( 8271224913084139776), + KQU( 2741753121611092226), KQU(16782366145996731181), + KQU(15426125238972640790), KQU(13595497100671260342), + KQU( 3173531022836259898), KQU( 6573264560319511662), + KQU(18041111951511157441), KQU( 2351433581833135952), + KQU( 3113255578908173487), KQU( 1739371330877858784), + KQU(16046126562789165480), KQU( 8072101652214192925), + KQU(15267091584090664910), KQU( 9309579200403648940), + KQU( 5218892439752408722), KQU(14492477246004337115), + KQU(17431037586679770619), KQU( 7385248135963250480), + KQU( 9580144956565560660), KQU( 4919546228040008720), + KQU(15261542469145035584), KQU(18233297270822253102), + KQU( 5453248417992302857), KQU( 9309519155931460285), + KQU(10342813012345291756), KQU(15676085186784762381), + KQU(15912092950691300645), KQU( 9371053121499003195), + KQU( 9897186478226866746), KQU(14061858287188196327), + KQU( 122575971620788119), KQU(12146750969116317754), + KQU( 4438317272813245201), KQU( 8332576791009527119), + KQU(13907785691786542057), KQU(10374194887283287467), + KQU( 2098798755649059566), KQU( 3416235197748288894), + KQU( 8688269957320773484), KQU( 7503964602397371571), + KQU(16724977015147478236), KQU( 9461512855439858184), + KQU(13259049744534534727), KQU( 3583094952542899294), + KQU( 8764245731305528292), KQU(13240823595462088985), + KQU(13716141617617910448), KQU(18114969519935960955), + KQU( 2297553615798302206), KQU( 4585521442944663362), + KQU(17776858680630198686), KQU( 4685873229192163363), + KQU( 152558080671135627), KQU(15424900540842670088), + KQU(13229630297130024108), KQU(17530268788245718717), + KQU(16675633913065714144), KQU( 3158912717897568068), + KQU(15399132185380087288), KQU( 7401418744515677872), + KQU(13135412922344398535), KQU( 6385314346100509511), + KQU(13962867001134161139), KQU(10272780155442671999), + KQU(12894856086597769142), KQU(13340877795287554994), + KQU(12913630602094607396), KQU(12543167911119793857), + KQU(17343570372251873096), KQU(10959487764494150545), + KQU( 6966737953093821128), KQU(13780699135496988601), + KQU( 4405070719380142046), KQU(14923788365607284982), + KQU( 2869487678905148380), KQU( 6416272754197188403), + KQU(15017380475943612591), KQU( 1995636220918429487), + KQU( 3402016804620122716), KQU(15800188663407057080), + KQU(11362369990390932882), KQU(15262183501637986147), + KQU(10239175385387371494), KQU( 9352042420365748334), + KQU( 1682457034285119875), KQU( 1724710651376289644), + KQU( 2038157098893817966), KQU( 9897825558324608773), + KQU( 1477666236519164736), KQU(16835397314511233640), + KQU(10370866327005346508), KQU(10157504370660621982), + KQU(12113904045335882069), KQU(13326444439742783008), + KQU(11302769043000765804), KQU(13594979923955228484), + KQU(11779351762613475968), KQU( 3786101619539298383), + KQU( 8021122969180846063), KQU(15745904401162500495), + KQU(10762168465993897267), KQU(13552058957896319026), + KQU(11200228655252462013), KQU( 5035370357337441226), + KQU( 7593918984545500013), KQU( 5418554918361528700), + KQU( 4858270799405446371), KQU( 9974659566876282544), + KQU(18227595922273957859), KQU( 2772778443635656220), + KQU(14285143053182085385), KQU( 9939700992429600469), + KQU(12756185904545598068), KQU( 2020783375367345262), + KQU( 57026775058331227), KQU( 950827867930065454), + KQU( 6602279670145371217), KQU( 2291171535443566929), + KQU( 5832380724425010313), KQU( 1220343904715982285), + KQU(17045542598598037633), KQU(15460481779702820971), + KQU(13948388779949365130), KQU(13975040175430829518), + KQU(17477538238425541763), KQU(11104663041851745725), + KQU(15860992957141157587), KQU(14529434633012950138), + KQU( 2504838019075394203), KQU( 7512113882611121886), + KQU( 4859973559980886617), KQU( 1258601555703250219), + KQU(15594548157514316394), KQU( 4516730171963773048), + KQU(11380103193905031983), KQU( 6809282239982353344), + KQU(18045256930420065002), KQU( 2453702683108791859), + KQU( 977214582986981460), KQU( 2006410402232713466), + KQU( 6192236267216378358), KQU( 3429468402195675253), + KQU(18146933153017348921), KQU(17369978576367231139), + KQU( 1246940717230386603), KQU(11335758870083327110), + KQU(14166488801730353682), KQU( 9008573127269635732), + KQU(10776025389820643815), KQU(15087605441903942962), + KQU( 1359542462712147922), KQU(13898874411226454206), + KQU(17911176066536804411), KQU( 9435590428600085274), + KQU( 294488509967864007), KQU( 8890111397567922046), + KQU( 7987823476034328778), KQU(13263827582440967651), + KQU( 7503774813106751573), KQU(14974747296185646837), + KQU( 8504765037032103375), KQU(17340303357444536213), + KQU( 7704610912964485743), KQU( 8107533670327205061), + KQU( 9062969835083315985), KQU(16968963142126734184), + KQU(12958041214190810180), KQU( 2720170147759570200), + KQU( 2986358963942189566), KQU(14884226322219356580), + KQU( 286224325144368520), KQU(11313800433154279797), + KQU(18366849528439673248), KQU(17899725929482368789), + KQU( 3730004284609106799), KQU( 1654474302052767205), + KQU( 5006698007047077032), KQU( 8196893913601182838), + KQU(15214541774425211640), KQU(17391346045606626073), + KQU( 8369003584076969089), KQU( 3939046733368550293), + KQU(10178639720308707785), KQU( 2180248669304388697), + KQU( 62894391300126322), KQU( 9205708961736223191), + KQU( 6837431058165360438), KQU( 3150743890848308214), + KQU(17849330658111464583), KQU(12214815643135450865), + KQU(13410713840519603402), KQU( 3200778126692046802), + KQU(13354780043041779313), KQU( 800850022756886036), + KQU(15660052933953067433), KQU( 6572823544154375676), + KQU(11030281857015819266), KQU(12682241941471433835), + KQU(11654136407300274693), KQU( 4517795492388641109), + KQU( 9757017371504524244), KQU(17833043400781889277), + KQU(12685085201747792227), KQU(10408057728835019573), + KQU( 98370418513455221), KQU( 6732663555696848598), + KQU(13248530959948529780), KQU( 3530441401230622826), + KQU(18188251992895660615), KQU( 1847918354186383756), + KQU( 1127392190402660921), KQU(11293734643143819463), + KQU( 3015506344578682982), KQU(13852645444071153329), + KQU( 2121359659091349142), KQU( 1294604376116677694), + KQU( 5616576231286352318), KQU( 7112502442954235625), + KQU(11676228199551561689), KQU(12925182803007305359), + KQU( 7852375518160493082), KQU( 1136513130539296154), + KQU( 5636923900916593195), KQU( 3221077517612607747), + KQU(17784790465798152513), KQU( 3554210049056995938), + KQU(17476839685878225874), KQU( 3206836372585575732), + KQU( 2765333945644823430), KQU(10080070903718799528), + KQU( 5412370818878286353), KQU( 9689685887726257728), + KQU( 8236117509123533998), KQU( 1951139137165040214), + KQU( 4492205209227980349), KQU(16541291230861602967), + KQU( 1424371548301437940), KQU( 9117562079669206794), + KQU(14374681563251691625), KQU(13873164030199921303), + KQU( 6680317946770936731), KQU(15586334026918276214), + KQU(10896213950976109802), KQU( 9506261949596413689), + KQU( 9903949574308040616), KQU( 6038397344557204470), + KQU( 174601465422373648), KQU(15946141191338238030), + KQU(17142225620992044937), KQU( 7552030283784477064), + KQU( 2947372384532947997), KQU( 510797021688197711), + KQU( 4962499439249363461), KQU( 23770320158385357), + KQU( 959774499105138124), KQU( 1468396011518788276), + KQU( 2015698006852312308), KQU( 4149400718489980136), + KQU( 5992916099522371188), KQU(10819182935265531076), + KQU(16189787999192351131), KQU( 342833961790261950), + KQU(12470830319550495336), KQU(18128495041912812501), + KQU( 1193600899723524337), KQU( 9056793666590079770), + KQU( 2154021227041669041), KQU( 4963570213951235735), + KQU( 4865075960209211409), KQU( 2097724599039942963), + KQU( 2024080278583179845), KQU(11527054549196576736), + KQU(10650256084182390252), KQU( 4808408648695766755), + KQU( 1642839215013788844), KQU(10607187948250398390), + KQU( 7076868166085913508), KQU( 730522571106887032), + KQU(12500579240208524895), KQU( 4484390097311355324), + KQU(15145801330700623870), KQU( 8055827661392944028), + KQU( 5865092976832712268), KQU(15159212508053625143), + KQU( 3560964582876483341), KQU( 4070052741344438280), + KQU( 6032585709886855634), KQU(15643262320904604873), + KQU( 2565119772293371111), KQU( 318314293065348260), + KQU(15047458749141511872), KQU( 7772788389811528730), + KQU( 7081187494343801976), KQU( 6465136009467253947), + KQU(10425940692543362069), KQU( 554608190318339115), + KQU(14796699860302125214), KQU( 1638153134431111443), + KQU(10336967447052276248), KQU( 8412308070396592958), + KQU( 4004557277152051226), KQU( 8143598997278774834), + KQU(16413323996508783221), KQU(13139418758033994949), + KQU( 9772709138335006667), KQU( 2818167159287157659), + KQU(17091740573832523669), KQU(14629199013130751608), + KQU(18268322711500338185), KQU( 8290963415675493063), + KQU( 8830864907452542588), KQU( 1614839084637494849), + KQU(14855358500870422231), KQU( 3472996748392519937), + KQU(15317151166268877716), KQU( 5825895018698400362), + KQU(16730208429367544129), KQU(10481156578141202800), + KQU( 4746166512382823750), KQU(12720876014472464998), + KQU( 8825177124486735972), KQU(13733447296837467838), + KQU( 6412293741681359625), KQU( 8313213138756135033), + KQU(11421481194803712517), KQU( 7997007691544174032), + KQU( 6812963847917605930), KQU( 9683091901227558641), + KQU(14703594165860324713), KQU( 1775476144519618309), + KQU( 2724283288516469519), KQU( 717642555185856868), + KQU( 8736402192215092346), KQU(11878800336431381021), + KQU( 4348816066017061293), KQU( 6115112756583631307), + KQU( 9176597239667142976), KQU(12615622714894259204), + KQU(10283406711301385987), KQU( 5111762509485379420), + KQU( 3118290051198688449), KQU( 7345123071632232145), + KQU( 9176423451688682359), KQU( 4843865456157868971), + KQU(12008036363752566088), KQU(12058837181919397720), + KQU( 2145073958457347366), KQU( 1526504881672818067), + KQU( 3488830105567134848), KQU(13208362960674805143), + KQU( 4077549672899572192), KQU( 7770995684693818365), + KQU( 1398532341546313593), KQU(12711859908703927840), + KQU( 1417561172594446813), KQU(17045191024194170604), + KQU( 4101933177604931713), KQU(14708428834203480320), + KQU(17447509264469407724), KQU(14314821973983434255), + KQU(17990472271061617265), KQU( 5087756685841673942), + KQU(12797820586893859939), KQU( 1778128952671092879), + KQU( 3535918530508665898), KQU( 9035729701042481301), + KQU(14808661568277079962), KQU(14587345077537747914), + KQU(11920080002323122708), KQU( 6426515805197278753), + KQU( 3295612216725984831), KQU(11040722532100876120), + KQU(12305952936387598754), KQU(16097391899742004253), + KQU( 4908537335606182208), KQU(12446674552196795504), + KQU(16010497855816895177), KQU( 9194378874788615551), + KQU( 3382957529567613384), KQU( 5154647600754974077), + KQU( 9801822865328396141), KQU( 9023662173919288143), + KQU(17623115353825147868), KQU( 8238115767443015816), + KQU(15811444159859002560), KQU( 9085612528904059661), + KQU( 6888601089398614254), KQU( 258252992894160189), + KQU( 6704363880792428622), KQU( 6114966032147235763), + KQU(11075393882690261875), KQU( 8797664238933620407), + KQU( 5901892006476726920), KQU( 5309780159285518958), + KQU(14940808387240817367), KQU(14642032021449656698), + KQU( 9808256672068504139), KQU( 3670135111380607658), + KQU(11211211097845960152), KQU( 1474304506716695808), + KQU(15843166204506876239), KQU( 7661051252471780561), + KQU(10170905502249418476), KQU( 7801416045582028589), + KQU( 2763981484737053050), KQU( 9491377905499253054), + KQU(16201395896336915095), KQU( 9256513756442782198), + KQU( 5411283157972456034), KQU( 5059433122288321676), + KQU( 4327408006721123357), KQU( 9278544078834433377), + KQU( 7601527110882281612), KQU(11848295896975505251), + KQU(12096998801094735560), KQU(14773480339823506413), + KQU(15586227433895802149), KQU(12786541257830242872), + KQU( 6904692985140503067), KQU( 5309011515263103959), + KQU(12105257191179371066), KQU(14654380212442225037), + KQU( 2556774974190695009), KQU( 4461297399927600261), + KQU(14888225660915118646), KQU(14915459341148291824), + KQU( 2738802166252327631), KQU( 6047155789239131512), + KQU(12920545353217010338), KQU(10697617257007840205), + KQU( 2751585253158203504), KQU(13252729159780047496), + KQU(14700326134672815469), KQU(14082527904374600529), + KQU(16852962273496542070), KQU(17446675504235853907), + KQU(15019600398527572311), KQU(12312781346344081551), + KQU(14524667935039810450), KQU( 5634005663377195738), + KQU(11375574739525000569), KQU( 2423665396433260040), + KQU( 5222836914796015410), KQU( 4397666386492647387), + KQU( 4619294441691707638), KQU( 665088602354770716), + KQU(13246495665281593610), KQU( 6564144270549729409), + KQU(10223216188145661688), KQU( 3961556907299230585), + KQU(11543262515492439914), KQU(16118031437285993790), + KQU( 7143417964520166465), KQU(13295053515909486772), + KQU( 40434666004899675), KQU(17127804194038347164), + KQU( 8599165966560586269), KQU( 8214016749011284903), + KQU(13725130352140465239), KQU( 5467254474431726291), + KQU( 7748584297438219877), KQU(16933551114829772472), + KQU( 2169618439506799400), KQU( 2169787627665113463), + KQU(17314493571267943764), KQU(18053575102911354912), + KQU(11928303275378476973), KQU(11593850925061715550), + KQU(17782269923473589362), KQU( 3280235307704747039), + KQU( 6145343578598685149), KQU(17080117031114086090), + KQU(18066839902983594755), KQU( 6517508430331020706), + KQU( 8092908893950411541), KQU(12558378233386153732), + KQU( 4476532167973132976), KQU(16081642430367025016), + KQU( 4233154094369139361), KQU( 8693630486693161027), + KQU(11244959343027742285), KQU(12273503967768513508), + KQU(14108978636385284876), KQU( 7242414665378826984), + KQU( 6561316938846562432), KQU( 8601038474994665795), + KQU(17532942353612365904), KQU(17940076637020912186), + KQU( 7340260368823171304), KQU( 7061807613916067905), + KQU(10561734935039519326), KQU(17990796503724650862), + KQU( 6208732943911827159), KQU( 359077562804090617), + KQU(14177751537784403113), KQU(10659599444915362902), + KQU(15081727220615085833), KQU(13417573895659757486), + KQU(15513842342017811524), KQU(11814141516204288231), + KQU( 1827312513875101814), KQU( 2804611699894603103), + KQU(17116500469975602763), KQU(12270191815211952087), + KQU(12256358467786024988), KQU(18435021722453971267), + KQU( 671330264390865618), KQU( 476504300460286050), + KQU(16465470901027093441), KQU( 4047724406247136402), + KQU( 1322305451411883346), KQU( 1388308688834322280), + KQU( 7303989085269758176), KQU( 9323792664765233642), + KQU( 4542762575316368936), KQU(17342696132794337618), + KQU( 4588025054768498379), KQU(13415475057390330804), + KQU(17880279491733405570), KQU(10610553400618620353), + KQU( 3180842072658960139), KQU(13002966655454270120), + KQU( 1665301181064982826), KQU( 7083673946791258979), + KQU( 190522247122496820), KQU(17388280237250677740), + KQU( 8430770379923642945), KQU(12987180971921668584), + KQU( 2311086108365390642), KQU( 2870984383579822345), + KQU(14014682609164653318), KQU(14467187293062251484), + KQU( 192186361147413298), KQU(15171951713531796524), + KQU( 9900305495015948728), KQU(17958004775615466344), + KQU(14346380954498606514), KQU(18040047357617407096), + KQU( 5035237584833424532), KQU(15089555460613972287), + KQU( 4131411873749729831), KQU( 1329013581168250330), + KQU(10095353333051193949), KQU(10749518561022462716), + KQU( 9050611429810755847), KQU(15022028840236655649), + KQU( 8775554279239748298), KQU(13105754025489230502), + KQU(15471300118574167585), KQU( 89864764002355628), + KQU( 8776416323420466637), KQU( 5280258630612040891), + KQU( 2719174488591862912), KQU( 7599309137399661994), + KQU(15012887256778039979), KQU(14062981725630928925), + KQU(12038536286991689603), KQU( 7089756544681775245), + KQU(10376661532744718039), KQU( 1265198725901533130), + KQU(13807996727081142408), KQU( 2935019626765036403), + KQU( 7651672460680700141), KQU( 3644093016200370795), + KQU( 2840982578090080674), KQU(17956262740157449201), + KQU(18267979450492880548), KQU(11799503659796848070), + KQU( 9942537025669672388), KQU(11886606816406990297), + KQU( 5488594946437447576), KQU( 7226714353282744302), + KQU( 3784851653123877043), KQU( 878018453244803041), + KQU(12110022586268616085), KQU( 734072179404675123), + KQU(11869573627998248542), KQU( 469150421297783998), + KQU( 260151124912803804), KQU(11639179410120968649), + KQU( 9318165193840846253), KQU(12795671722734758075), + KQU(15318410297267253933), KQU( 691524703570062620), + KQU( 5837129010576994601), KQU(15045963859726941052), + KQU( 5850056944932238169), KQU(12017434144750943807), + KQU( 7447139064928956574), KQU( 3101711812658245019), + KQU(16052940704474982954), KQU(18195745945986994042), + KQU( 8932252132785575659), KQU(13390817488106794834), + KQU(11582771836502517453), KQU( 4964411326683611686), + KQU( 2195093981702694011), KQU(14145229538389675669), + KQU(16459605532062271798), KQU( 866316924816482864), + KQU( 4593041209937286377), KQU( 8415491391910972138), + KQU( 4171236715600528969), KQU(16637569303336782889), + KQU( 2002011073439212680), KQU(17695124661097601411), + KQU( 4627687053598611702), KQU( 7895831936020190403), + KQU( 8455951300917267802), KQU( 2923861649108534854), + KQU( 8344557563927786255), KQU( 6408671940373352556), + KQU(12210227354536675772), KQU(14294804157294222295), + KQU(10103022425071085127), KQU(10092959489504123771), + KQU( 6554774405376736268), KQU(12629917718410641774), + KQU( 6260933257596067126), KQU( 2460827021439369673), + KQU( 2541962996717103668), KQU( 597377203127351475), + KQU( 5316984203117315309), KQU( 4811211393563241961), + KQU(13119698597255811641), KQU( 8048691512862388981), + KQU(10216818971194073842), KQU( 4612229970165291764), + KQU(10000980798419974770), KQU( 6877640812402540687), + KQU( 1488727563290436992), KQU( 2227774069895697318), + KQU(11237754507523316593), KQU(13478948605382290972), + KQU( 1963583846976858124), KQU( 5512309205269276457), + KQU( 3972770164717652347), KQU( 3841751276198975037), + KQU(10283343042181903117), KQU( 8564001259792872199), + KQU(16472187244722489221), KQU( 8953493499268945921), + KQU( 3518747340357279580), KQU( 4003157546223963073), + KQU( 3270305958289814590), KQU( 3966704458129482496), + KQU( 8122141865926661939), KQU(14627734748099506653), + KQU(13064426990862560568), KQU( 2414079187889870829), + KQU( 5378461209354225306), KQU(10841985740128255566), + KQU( 538582442885401738), KQU( 7535089183482905946), + KQU(16117559957598879095), KQU( 8477890721414539741), + KQU( 1459127491209533386), KQU(17035126360733620462), + KQU( 8517668552872379126), KQU(10292151468337355014), + KQU(17081267732745344157), KQU(13751455337946087178), + KQU(14026945459523832966), KQU( 6653278775061723516), + KQU(10619085543856390441), KQU( 2196343631481122885), + KQU(10045966074702826136), KQU(10082317330452718282), + KQU( 5920859259504831242), KQU( 9951879073426540617), + KQU( 7074696649151414158), KQU(15808193543879464318), + KQU( 7385247772746953374), KQU( 3192003544283864292), + KQU(18153684490917593847), KQU(12423498260668568905), + KQU(10957758099756378169), KQU(11488762179911016040), + KQU( 2099931186465333782), KQU(11180979581250294432), + KQU( 8098916250668367933), KQU( 3529200436790763465), + KQU(12988418908674681745), KQU( 6147567275954808580), + KQU( 3207503344604030989), KQU(10761592604898615360), + KQU( 229854861031893504), KQU( 8809853962667144291), + KQU(13957364469005693860), KQU( 7634287665224495886), + KQU(12353487366976556874), KQU( 1134423796317152034), + KQU( 2088992471334107068), KQU( 7393372127190799698), + KQU( 1845367839871058391), KQU( 207922563987322884), + KQU(11960870813159944976), KQU(12182120053317317363), + KQU(17307358132571709283), KQU(13871081155552824936), + KQU(18304446751741566262), KQU( 7178705220184302849), + KQU(10929605677758824425), KQU(16446976977835806844), + KQU(13723874412159769044), KQU( 6942854352100915216), + KQU( 1726308474365729390), KQU( 2150078766445323155), + KQU(15345558947919656626), KQU(12145453828874527201), + KQU( 2054448620739726849), KQU( 2740102003352628137), + KQU(11294462163577610655), KQU( 756164283387413743), + KQU(17841144758438810880), KQU(10802406021185415861), + KQU( 8716455530476737846), KQU( 6321788834517649606), + KQU(14681322910577468426), KQU(17330043563884336387), + KQU(12701802180050071614), KQU(14695105111079727151), + KQU( 5112098511654172830), KQU( 4957505496794139973), + KQU( 8270979451952045982), KQU(12307685939199120969), + KQU(12425799408953443032), KQU( 8376410143634796588), + KQU(16621778679680060464), KQU( 3580497854566660073), + KQU( 1122515747803382416), KQU( 857664980960597599), + KQU( 6343640119895925918), KQU(12878473260854462891), + KQU(10036813920765722626), KQU(14451335468363173812), + KQU( 5476809692401102807), KQU(16442255173514366342), + KQU(13060203194757167104), KQU(14354124071243177715), + KQU(15961249405696125227), KQU(13703893649690872584), + KQU( 363907326340340064), KQU( 6247455540491754842), + KQU(12242249332757832361), KQU( 156065475679796717), + KQU( 9351116235749732355), KQU( 4590350628677701405), + KQU( 1671195940982350389), KQU(13501398458898451905), + KQU( 6526341991225002255), KQU( 1689782913778157592), + KQU( 7439222350869010334), KQU(13975150263226478308), + KQU(11411961169932682710), KQU(17204271834833847277), + KQU( 541534742544435367), KQU( 6591191931218949684), + KQU( 2645454775478232486), KQU( 4322857481256485321), + KQU( 8477416487553065110), KQU(12902505428548435048), + KQU( 971445777981341415), KQU(14995104682744976712), + KQU( 4243341648807158063), KQU( 8695061252721927661), + KQU( 5028202003270177222), KQU( 2289257340915567840), + KQU(13870416345121866007), KQU(13994481698072092233), + KQU( 6912785400753196481), KQU( 2278309315841980139), + KQU( 4329765449648304839), KQU( 5963108095785485298), + KQU( 4880024847478722478), KQU(16015608779890240947), + KQU( 1866679034261393544), KQU( 914821179919731519), + KQU( 9643404035648760131), KQU( 2418114953615593915), + KQU( 944756836073702374), KQU(15186388048737296834), + KQU( 7723355336128442206), KQU( 7500747479679599691), + KQU(18013961306453293634), KQU( 2315274808095756456), + KQU(13655308255424029566), KQU(17203800273561677098), + KQU( 1382158694422087756), KQU( 5090390250309588976), + KQU( 517170818384213989), KQU( 1612709252627729621), + KQU( 1330118955572449606), KQU( 300922478056709885), + KQU(18115693291289091987), KQU(13491407109725238321), + KQU(15293714633593827320), KQU( 5151539373053314504), + KQU( 5951523243743139207), KQU(14459112015249527975), + KQU( 5456113959000700739), KQU( 3877918438464873016), + KQU(12534071654260163555), KQU(15871678376893555041), + KQU(11005484805712025549), KQU(16353066973143374252), + KQU( 4358331472063256685), KQU( 8268349332210859288), + KQU(12485161590939658075), KQU(13955993592854471343), + KQU( 5911446886848367039), KQU(14925834086813706974), + KQU( 6590362597857994805), KQU( 1280544923533661875), + KQU( 1637756018947988164), KQU( 4734090064512686329), + KQU(16693705263131485912), KQU( 6834882340494360958), + KQU( 8120732176159658505), KQU( 2244371958905329346), + KQU(10447499707729734021), KQU( 7318742361446942194), + KQU( 8032857516355555296), KQU(14023605983059313116), + KQU( 1032336061815461376), KQU( 9840995337876562612), + KQU( 9869256223029203587), KQU(12227975697177267636), + KQU(12728115115844186033), KQU( 7752058479783205470), + KQU( 729733219713393087), KQU(12954017801239007622) }; static const uint64_t init_by_array_64_expected[] = { - QU( 2100341266307895239LLU), QU( 8344256300489757943LLU), - QU(15687933285484243894LLU), QU( 8268620370277076319LLU), - QU(12371852309826545459LLU), QU( 8800491541730110238LLU), - QU(18113268950100835773LLU), QU( 2886823658884438119LLU), - QU( 3293667307248180724LLU), QU( 9307928143300172731LLU), - QU( 7688082017574293629LLU), QU( 900986224735166665LLU), - QU( 9977972710722265039LLU), QU( 6008205004994830552LLU), - QU( 546909104521689292LLU), QU( 7428471521869107594LLU), - QU(14777563419314721179LLU), QU(16116143076567350053LLU), - QU( 5322685342003142329LLU), QU( 4200427048445863473LLU), - QU( 4693092150132559146LLU), QU(13671425863759338582LLU), - QU( 6747117460737639916LLU), QU( 4732666080236551150LLU), - QU( 5912839950611941263LLU), QU( 3903717554504704909LLU), - QU( 2615667650256786818LLU), QU(10844129913887006352LLU), - QU(13786467861810997820LLU), QU(14267853002994021570LLU), - QU(13767807302847237439LLU), QU(16407963253707224617LLU), - QU( 4802498363698583497LLU), QU( 2523802839317209764LLU), - QU( 3822579397797475589LLU), QU( 8950320572212130610LLU), - QU( 3745623504978342534LLU), QU(16092609066068482806LLU), - QU( 9817016950274642398LLU), QU(10591660660323829098LLU), - QU(11751606650792815920LLU), QU( 5122873818577122211LLU), - QU(17209553764913936624LLU), QU( 6249057709284380343LLU), - QU(15088791264695071830LLU), QU(15344673071709851930LLU), - QU( 4345751415293646084LLU), QU( 2542865750703067928LLU), - QU(13520525127852368784LLU), QU(18294188662880997241LLU), - QU( 3871781938044881523LLU), QU( 2873487268122812184LLU), - QU(15099676759482679005LLU), QU(15442599127239350490LLU), - QU( 6311893274367710888LLU), QU( 3286118760484672933LLU), - QU( 4146067961333542189LLU), QU(13303942567897208770LLU), - QU( 8196013722255630418LLU), QU( 4437815439340979989LLU), - QU(15433791533450605135LLU), QU( 4254828956815687049LLU), - QU( 1310903207708286015LLU), QU(10529182764462398549LLU), - QU(14900231311660638810LLU), QU( 9727017277104609793LLU), - QU( 1821308310948199033LLU), QU(11628861435066772084LLU), - QU( 9469019138491546924LLU), QU( 3145812670532604988LLU), - QU( 9938468915045491919LLU), QU( 1562447430672662142LLU), - QU(13963995266697989134LLU), QU( 3356884357625028695LLU), - QU( 4499850304584309747LLU), QU( 8456825817023658122LLU), - QU(10859039922814285279LLU), QU( 8099512337972526555LLU), - QU( 348006375109672149LLU), QU(11919893998241688603LLU), - QU( 1104199577402948826LLU), QU(16689191854356060289LLU), - QU(10992552041730168078LLU), QU( 7243733172705465836LLU), - QU( 5668075606180319560LLU), QU(18182847037333286970LLU), - QU( 4290215357664631322LLU), QU( 4061414220791828613LLU), - QU(13006291061652989604LLU), QU( 7140491178917128798LLU), - QU(12703446217663283481LLU), QU( 5500220597564558267LLU), - QU(10330551509971296358LLU), QU(15958554768648714492LLU), - QU( 5174555954515360045LLU), QU( 1731318837687577735LLU), - QU( 3557700801048354857LLU), QU(13764012341928616198LLU), - QU(13115166194379119043LLU), QU( 7989321021560255519LLU), - QU( 2103584280905877040LLU), QU( 9230788662155228488LLU), - QU(16396629323325547654LLU), QU( 657926409811318051LLU), - QU(15046700264391400727LLU), QU( 5120132858771880830LLU), - QU( 7934160097989028561LLU), QU( 6963121488531976245LLU), - QU(17412329602621742089LLU), QU(15144843053931774092LLU), - QU(17204176651763054532LLU), QU(13166595387554065870LLU), - QU( 8590377810513960213LLU), QU( 5834365135373991938LLU), - QU( 7640913007182226243LLU), QU( 3479394703859418425LLU), - QU(16402784452644521040LLU), QU( 4993979809687083980LLU), - QU(13254522168097688865LLU), QU(15643659095244365219LLU), - QU( 5881437660538424982LLU), QU(11174892200618987379LLU), - QU( 254409966159711077LLU), QU(17158413043140549909LLU), - QU( 3638048789290376272LLU), QU( 1376816930299489190LLU), - QU( 4622462095217761923LLU), QU(15086407973010263515LLU), - QU(13253971772784692238LLU), QU( 5270549043541649236LLU), - QU(11182714186805411604LLU), QU(12283846437495577140LLU), - QU( 5297647149908953219LLU), QU(10047451738316836654LLU), - QU( 4938228100367874746LLU), QU(12328523025304077923LLU), - QU( 3601049438595312361LLU), QU( 9313624118352733770LLU), - QU(13322966086117661798LLU), QU(16660005705644029394LLU), - QU(11337677526988872373LLU), QU(13869299102574417795LLU), - QU(15642043183045645437LLU), QU( 3021755569085880019LLU), - QU( 4979741767761188161LLU), QU(13679979092079279587LLU), - QU( 3344685842861071743LLU), QU(13947960059899588104LLU), - QU( 305806934293368007LLU), QU( 5749173929201650029LLU), - QU(11123724852118844098LLU), QU(15128987688788879802LLU), - QU(15251651211024665009LLU), QU( 7689925933816577776LLU), - QU(16732804392695859449LLU), QU(17087345401014078468LLU), - QU(14315108589159048871LLU), QU( 4820700266619778917LLU), - QU(16709637539357958441LLU), QU( 4936227875177351374LLU), - QU( 2137907697912987247LLU), QU(11628565601408395420LLU), - QU( 2333250549241556786LLU), QU( 5711200379577778637LLU), - QU( 5170680131529031729LLU), QU(12620392043061335164LLU), - QU( 95363390101096078LLU), QU( 5487981914081709462LLU), - QU( 1763109823981838620LLU), QU( 3395861271473224396LLU), - QU( 1300496844282213595LLU), QU( 6894316212820232902LLU), - QU(10673859651135576674LLU), QU( 5911839658857903252LLU), - QU(17407110743387299102LLU), QU( 8257427154623140385LLU), - QU(11389003026741800267LLU), QU( 4070043211095013717LLU), - QU(11663806997145259025LLU), QU(15265598950648798210LLU), - QU( 630585789434030934LLU), QU( 3524446529213587334LLU), - QU( 7186424168495184211LLU), QU(10806585451386379021LLU), - QU(11120017753500499273LLU), QU( 1586837651387701301LLU), - QU(17530454400954415544LLU), QU( 9991670045077880430LLU), - QU( 7550997268990730180LLU), QU( 8640249196597379304LLU), - QU( 3522203892786893823LLU), QU(10401116549878854788LLU), - QU(13690285544733124852LLU), QU( 8295785675455774586LLU), - QU(15535716172155117603LLU), QU( 3112108583723722511LLU), - QU(17633179955339271113LLU), QU(18154208056063759375LLU), - QU( 1866409236285815666LLU), QU(13326075895396412882LLU), - QU( 8756261842948020025LLU), QU( 6281852999868439131LLU), - QU(15087653361275292858LLU), QU(10333923911152949397LLU), - QU( 5265567645757408500LLU), QU(12728041843210352184LLU), - QU( 6347959327507828759LLU), QU( 154112802625564758LLU), - QU(18235228308679780218LLU), QU( 3253805274673352418LLU), - QU( 4849171610689031197LLU), QU(17948529398340432518LLU), - QU(13803510475637409167LLU), QU(13506570190409883095LLU), - QU(15870801273282960805LLU), QU( 8451286481299170773LLU), - QU( 9562190620034457541LLU), QU( 8518905387449138364LLU), - QU(12681306401363385655LLU), QU( 3788073690559762558LLU), - QU( 5256820289573487769LLU), QU( 2752021372314875467LLU), - QU( 6354035166862520716LLU), QU( 4328956378309739069LLU), - QU( 449087441228269600LLU), QU( 5533508742653090868LLU), - QU( 1260389420404746988LLU), QU(18175394473289055097LLU), - QU( 1535467109660399420LLU), QU( 8818894282874061442LLU), - QU(12140873243824811213LLU), QU(15031386653823014946LLU), - QU( 1286028221456149232LLU), QU( 6329608889367858784LLU), - QU( 9419654354945132725LLU), QU( 6094576547061672379LLU), - QU(17706217251847450255LLU), QU( 1733495073065878126LLU), - QU(16918923754607552663LLU), QU( 8881949849954945044LLU), - QU(12938977706896313891LLU), QU(14043628638299793407LLU), - QU(18393874581723718233LLU), QU( 6886318534846892044LLU), - QU(14577870878038334081LLU), QU(13541558383439414119LLU), - QU(13570472158807588273LLU), QU(18300760537910283361LLU), - QU( 818368572800609205LLU), QU( 1417000585112573219LLU), - QU(12337533143867683655LLU), QU(12433180994702314480LLU), - QU( 778190005829189083LLU), QU(13667356216206524711LLU), - QU( 9866149895295225230LLU), QU(11043240490417111999LLU), - QU( 1123933826541378598LLU), QU( 6469631933605123610LLU), - QU(14508554074431980040LLU), QU(13918931242962026714LLU), - QU( 2870785929342348285LLU), QU(14786362626740736974LLU), - QU(13176680060902695786LLU), QU( 9591778613541679456LLU), - QU( 9097662885117436706LLU), QU( 749262234240924947LLU), - QU( 1944844067793307093LLU), QU( 4339214904577487742LLU), - QU( 8009584152961946551LLU), QU(16073159501225501777LLU), - QU( 3335870590499306217LLU), QU(17088312653151202847LLU), - QU( 3108893142681931848LLU), QU(16636841767202792021LLU), - QU(10423316431118400637LLU), QU( 8008357368674443506LLU), - QU(11340015231914677875LLU), QU(17687896501594936090LLU), - QU(15173627921763199958LLU), QU( 542569482243721959LLU), - QU(15071714982769812975LLU), QU( 4466624872151386956LLU), - QU( 1901780715602332461LLU), QU( 9822227742154351098LLU), - QU( 1479332892928648780LLU), QU( 6981611948382474400LLU), - QU( 7620824924456077376LLU), QU(14095973329429406782LLU), - QU( 7902744005696185404LLU), QU(15830577219375036920LLU), - QU(10287076667317764416LLU), QU(12334872764071724025LLU), - QU( 4419302088133544331LLU), QU(14455842851266090520LLU), - QU(12488077416504654222LLU), QU( 7953892017701886766LLU), - QU( 6331484925529519007LLU), QU( 4902145853785030022LLU), - QU(17010159216096443073LLU), QU(11945354668653886087LLU), - QU(15112022728645230829LLU), QU(17363484484522986742LLU), - QU( 4423497825896692887LLU), QU( 8155489510809067471LLU), - QU( 258966605622576285LLU), QU( 5462958075742020534LLU), - QU( 6763710214913276228LLU), QU( 2368935183451109054LLU), - QU(14209506165246453811LLU), QU( 2646257040978514881LLU), - QU( 3776001911922207672LLU), QU( 1419304601390147631LLU), - QU(14987366598022458284LLU), QU( 3977770701065815721LLU), - QU( 730820417451838898LLU), QU( 3982991703612885327LLU), - QU( 2803544519671388477LLU), QU(17067667221114424649LLU), - QU( 2922555119737867166LLU), QU( 1989477584121460932LLU), - QU(15020387605892337354LLU), QU( 9293277796427533547LLU), - QU(10722181424063557247LLU), QU(16704542332047511651LLU), - QU( 5008286236142089514LLU), QU(16174732308747382540LLU), - QU(17597019485798338402LLU), QU(13081745199110622093LLU), - QU( 8850305883842258115LLU), QU(12723629125624589005LLU), - QU( 8140566453402805978LLU), QU(15356684607680935061LLU), - QU(14222190387342648650LLU), QU(11134610460665975178LLU), - QU( 1259799058620984266LLU), QU(13281656268025610041LLU), - QU( 298262561068153992LLU), QU(12277871700239212922LLU), - QU(13911297774719779438LLU), QU(16556727962761474934LLU), - QU(17903010316654728010LLU), QU( 9682617699648434744LLU), - QU(14757681836838592850LLU), QU( 1327242446558524473LLU), - QU(11126645098780572792LLU), QU( 1883602329313221774LLU), - QU( 2543897783922776873LLU), QU(15029168513767772842LLU), - QU(12710270651039129878LLU), QU(16118202956069604504LLU), - QU(15010759372168680524LLU), QU( 2296827082251923948LLU), - QU(10793729742623518101LLU), QU(13829764151845413046LLU), - QU(17769301223184451213LLU), QU( 3118268169210783372LLU), - QU(17626204544105123127LLU), QU( 7416718488974352644LLU), - QU(10450751996212925994LLU), QU( 9352529519128770586LLU), - QU( 259347569641110140LLU), QU( 8048588892269692697LLU), - QU( 1774414152306494058LLU), QU(10669548347214355622LLU), - QU(13061992253816795081LLU), QU(18432677803063861659LLU), - QU( 8879191055593984333LLU), QU(12433753195199268041LLU), - QU(14919392415439730602LLU), QU( 6612848378595332963LLU), - QU( 6320986812036143628LLU), QU(10465592420226092859LLU), - QU( 4196009278962570808LLU), QU( 3747816564473572224LLU), - QU(17941203486133732898LLU), QU( 2350310037040505198LLU), - QU( 5811779859134370113LLU), QU(10492109599506195126LLU), - QU( 7699650690179541274LLU), QU( 1954338494306022961LLU), - QU(14095816969027231152LLU), QU( 5841346919964852061LLU), - QU(14945969510148214735LLU), QU( 3680200305887550992LLU), - QU( 6218047466131695792LLU), QU( 8242165745175775096LLU), - QU(11021371934053307357LLU), QU( 1265099502753169797LLU), - QU( 4644347436111321718LLU), QU( 3609296916782832859LLU), - QU( 8109807992218521571LLU), QU(18387884215648662020LLU), - QU(14656324896296392902LLU), QU(17386819091238216751LLU), - QU(17788300878582317152LLU), QU( 7919446259742399591LLU), - QU( 4466613134576358004LLU), QU(12928181023667938509LLU), - QU(13147446154454932030LLU), QU(16552129038252734620LLU), - QU( 8395299403738822450LLU), QU(11313817655275361164LLU), - QU( 434258809499511718LLU), QU( 2074882104954788676LLU), - QU( 7929892178759395518LLU), QU( 9006461629105745388LLU), - QU( 5176475650000323086LLU), QU(11128357033468341069LLU), - QU(12026158851559118955LLU), QU(14699716249471156500LLU), - QU( 448982497120206757LLU), QU( 4156475356685519900LLU), - QU( 6063816103417215727LLU), QU(10073289387954971479LLU), - QU( 8174466846138590962LLU), QU( 2675777452363449006LLU), - QU( 9090685420572474281LLU), QU( 6659652652765562060LLU), - QU(12923120304018106621LLU), QU(11117480560334526775LLU), - QU( 937910473424587511LLU), QU( 1838692113502346645LLU), - QU(11133914074648726180LLU), QU( 7922600945143884053LLU), - QU(13435287702700959550LLU), QU( 5287964921251123332LLU), - QU(11354875374575318947LLU), QU(17955724760748238133LLU), - QU(13728617396297106512LLU), QU( 4107449660118101255LLU), - QU( 1210269794886589623LLU), QU(11408687205733456282LLU), - QU( 4538354710392677887LLU), QU(13566803319341319267LLU), - QU(17870798107734050771LLU), QU( 3354318982568089135LLU), - QU( 9034450839405133651LLU), QU(13087431795753424314LLU), - QU( 950333102820688239LLU), QU( 1968360654535604116LLU), - QU(16840551645563314995LLU), QU( 8867501803892924995LLU), - QU(11395388644490626845LLU), QU( 1529815836300732204LLU), - QU(13330848522996608842LLU), QU( 1813432878817504265LLU), - QU( 2336867432693429560LLU), QU(15192805445973385902LLU), - QU( 2528593071076407877LLU), QU( 128459777936689248LLU), - QU( 9976345382867214866LLU), QU( 6208885766767996043LLU), - QU(14982349522273141706LLU), QU( 3099654362410737822LLU), - QU(13776700761947297661LLU), QU( 8806185470684925550LLU), - QU( 8151717890410585321LLU), QU( 640860591588072925LLU), - QU(14592096303937307465LLU), QU( 9056472419613564846LLU), - QU(14861544647742266352LLU), QU(12703771500398470216LLU), - QU( 3142372800384138465LLU), QU( 6201105606917248196LLU), - QU(18337516409359270184LLU), QU(15042268695665115339LLU), - QU(15188246541383283846LLU), QU(12800028693090114519LLU), - QU( 5992859621101493472LLU), QU(18278043971816803521LLU), - QU( 9002773075219424560LLU), QU( 7325707116943598353LLU), - QU( 7930571931248040822LLU), QU( 5645275869617023448LLU), - QU( 7266107455295958487LLU), QU( 4363664528273524411LLU), - QU(14313875763787479809LLU), QU(17059695613553486802LLU), - QU( 9247761425889940932LLU), QU(13704726459237593128LLU), - QU( 2701312427328909832LLU), QU(17235532008287243115LLU), - QU(14093147761491729538LLU), QU( 6247352273768386516LLU), - QU( 8268710048153268415LLU), QU( 7985295214477182083LLU), - QU(15624495190888896807LLU), QU( 3772753430045262788LLU), - QU( 9133991620474991698LLU), QU( 5665791943316256028LLU), - QU( 7551996832462193473LLU), QU(13163729206798953877LLU), - QU( 9263532074153846374LLU), QU( 1015460703698618353LLU), - QU(17929874696989519390LLU), QU(18257884721466153847LLU), - QU(16271867543011222991LLU), QU( 3905971519021791941LLU), - QU(16814488397137052085LLU), QU( 1321197685504621613LLU), - QU( 2870359191894002181LLU), QU(14317282970323395450LLU), - QU(13663920845511074366LLU), QU( 2052463995796539594LLU), - QU(14126345686431444337LLU), QU( 1727572121947022534LLU), - QU(17793552254485594241LLU), QU( 6738857418849205750LLU), - QU( 1282987123157442952LLU), QU(16655480021581159251LLU), - QU( 6784587032080183866LLU), QU(14726758805359965162LLU), - QU( 7577995933961987349LLU), QU(12539609320311114036LLU), - QU(10789773033385439494LLU), QU( 8517001497411158227LLU), - QU(10075543932136339710LLU), QU(14838152340938811081LLU), - QU( 9560840631794044194LLU), QU(17445736541454117475LLU), - QU(10633026464336393186LLU), QU(15705729708242246293LLU), - QU( 1117517596891411098LLU), QU( 4305657943415886942LLU), - QU( 4948856840533979263LLU), QU(16071681989041789593LLU), - QU(13723031429272486527LLU), QU( 7639567622306509462LLU), - QU(12670424537483090390LLU), QU( 9715223453097197134LLU), - QU( 5457173389992686394LLU), QU( 289857129276135145LLU), - QU(17048610270521972512LLU), QU( 692768013309835485LLU), - QU(14823232360546632057LLU), QU(18218002361317895936LLU), - QU( 3281724260212650204LLU), QU(16453957266549513795LLU), - QU( 8592711109774511881LLU), QU( 929825123473369579LLU), - QU(15966784769764367791LLU), QU( 9627344291450607588LLU), - QU(10849555504977813287LLU), QU( 9234566913936339275LLU), - QU( 6413807690366911210LLU), QU(10862389016184219267LLU), - QU(13842504799335374048LLU), QU( 1531994113376881174LLU), - QU( 2081314867544364459LLU), QU(16430628791616959932LLU), - QU( 8314714038654394368LLU), QU( 9155473892098431813LLU), - QU(12577843786670475704LLU), QU( 4399161106452401017LLU), - QU( 1668083091682623186LLU), QU( 1741383777203714216LLU), - QU( 2162597285417794374LLU), QU(15841980159165218736LLU), - QU( 1971354603551467079LLU), QU( 1206714764913205968LLU), - QU( 4790860439591272330LLU), QU(14699375615594055799LLU), - QU( 8374423871657449988LLU), QU(10950685736472937738LLU), - QU( 697344331343267176LLU), QU(10084998763118059810LLU), - QU(12897369539795983124LLU), QU(12351260292144383605LLU), - QU( 1268810970176811234LLU), QU( 7406287800414582768LLU), - QU( 516169557043807831LLU), QU( 5077568278710520380LLU), - QU( 3828791738309039304LLU), QU( 7721974069946943610LLU), - QU( 3534670260981096460LLU), QU( 4865792189600584891LLU), - QU(16892578493734337298LLU), QU( 9161499464278042590LLU), - QU(11976149624067055931LLU), QU(13219479887277343990LLU), - QU(14161556738111500680LLU), QU(14670715255011223056LLU), - QU( 4671205678403576558LLU), QU(12633022931454259781LLU), - QU(14821376219869187646LLU), QU( 751181776484317028LLU), - QU( 2192211308839047070LLU), QU(11787306362361245189LLU), - QU(10672375120744095707LLU), QU( 4601972328345244467LLU), - QU(15457217788831125879LLU), QU( 8464345256775460809LLU), - QU(10191938789487159478LLU), QU( 6184348739615197613LLU), - QU(11425436778806882100LLU), QU( 2739227089124319793LLU), - QU( 461464518456000551LLU), QU( 4689850170029177442LLU), - QU( 6120307814374078625LLU), QU(11153579230681708671LLU), - QU( 7891721473905347926LLU), QU(10281646937824872400LLU), - QU( 3026099648191332248LLU), QU( 8666750296953273818LLU), - QU(14978499698844363232LLU), QU(13303395102890132065LLU), - QU( 8182358205292864080LLU), QU(10560547713972971291LLU), - QU(11981635489418959093LLU), QU( 3134621354935288409LLU), - QU(11580681977404383968LLU), QU(14205530317404088650LLU), - QU( 5997789011854923157LLU), QU(13659151593432238041LLU), - QU(11664332114338865086LLU), QU( 7490351383220929386LLU), - QU( 7189290499881530378LLU), QU(15039262734271020220LLU), - QU( 2057217285976980055LLU), QU( 555570804905355739LLU), - QU(11235311968348555110LLU), QU(13824557146269603217LLU), - QU(16906788840653099693LLU), QU( 7222878245455661677LLU), - QU( 5245139444332423756LLU), QU( 4723748462805674292LLU), - QU(12216509815698568612LLU), QU(17402362976648951187LLU), - QU(17389614836810366768LLU), QU( 4880936484146667711LLU), - QU( 9085007839292639880LLU), QU(13837353458498535449LLU), - QU(11914419854360366677LLU), QU(16595890135313864103LLU), - QU( 6313969847197627222LLU), QU(18296909792163910431LLU), - QU(10041780113382084042LLU), QU( 2499478551172884794LLU), - QU(11057894246241189489LLU), QU( 9742243032389068555LLU), - QU(12838934582673196228LLU), QU(13437023235248490367LLU), - QU(13372420669446163240LLU), QU( 6752564244716909224LLU), - QU( 7157333073400313737LLU), QU(12230281516370654308LLU), - QU( 1182884552219419117LLU), QU( 2955125381312499218LLU), - QU(10308827097079443249LLU), QU( 1337648572986534958LLU), - QU(16378788590020343939LLU), QU( 108619126514420935LLU), - QU( 3990981009621629188LLU), QU( 5460953070230946410LLU), - QU( 9703328329366531883LLU), QU(13166631489188077236LLU), - QU( 1104768831213675170LLU), QU( 3447930458553877908LLU), - QU( 8067172487769945676LLU), QU( 5445802098190775347LLU), - QU( 3244840981648973873LLU), QU(17314668322981950060LLU), - QU( 5006812527827763807LLU), QU(18158695070225526260LLU), - QU( 2824536478852417853LLU), QU(13974775809127519886LLU), - QU( 9814362769074067392LLU), QU(17276205156374862128LLU), - QU(11361680725379306967LLU), QU( 3422581970382012542LLU), - QU(11003189603753241266LLU), QU(11194292945277862261LLU), - QU( 6839623313908521348LLU), QU(11935326462707324634LLU), - QU( 1611456788685878444LLU), QU(13112620989475558907LLU), - QU( 517659108904450427LLU), QU(13558114318574407624LLU), - QU(15699089742731633077LLU), QU( 4988979278862685458LLU), - QU( 8111373583056521297LLU), QU( 3891258746615399627LLU), - QU( 8137298251469718086LLU), QU(12748663295624701649LLU), - QU( 4389835683495292062LLU), QU( 5775217872128831729LLU), - QU( 9462091896405534927LLU), QU( 8498124108820263989LLU), - QU( 8059131278842839525LLU), QU(10503167994254090892LLU), - QU(11613153541070396656LLU), QU(18069248738504647790LLU), - QU( 570657419109768508LLU), QU( 3950574167771159665LLU), - QU( 5514655599604313077LLU), QU( 2908460854428484165LLU), - QU(10777722615935663114LLU), QU(12007363304839279486LLU), - QU( 9800646187569484767LLU), QU( 8795423564889864287LLU), - QU(14257396680131028419LLU), QU( 6405465117315096498LLU), - QU( 7939411072208774878LLU), QU(17577572378528990006LLU), - QU(14785873806715994850LLU), QU(16770572680854747390LLU), - QU(18127549474419396481LLU), QU(11637013449455757750LLU), - QU(14371851933996761086LLU), QU( 3601181063650110280LLU), - QU( 4126442845019316144LLU), QU(10198287239244320669LLU), - QU(18000169628555379659LLU), QU(18392482400739978269LLU), - QU( 6219919037686919957LLU), QU( 3610085377719446052LLU), - QU( 2513925039981776336LLU), QU(16679413537926716955LLU), - QU(12903302131714909434LLU), QU( 5581145789762985009LLU), - QU(12325955044293303233LLU), QU(17216111180742141204LLU), - QU( 6321919595276545740LLU), QU( 3507521147216174501LLU), - QU( 9659194593319481840LLU), QU(11473976005975358326LLU), - QU(14742730101435987026LLU), QU( 492845897709954780LLU), - QU(16976371186162599676LLU), QU(17712703422837648655LLU), - QU( 9881254778587061697LLU), QU( 8413223156302299551LLU), - QU( 1563841828254089168LLU), QU( 9996032758786671975LLU), - QU( 138877700583772667LLU), QU(13003043368574995989LLU), - QU( 4390573668650456587LLU), QU( 8610287390568126755LLU), - QU(15126904974266642199LLU), QU( 6703637238986057662LLU), - QU( 2873075592956810157LLU), QU( 6035080933946049418LLU), - QU(13382846581202353014LLU), QU( 7303971031814642463LLU), - QU(18418024405307444267LLU), QU( 5847096731675404647LLU), - QU( 4035880699639842500LLU), QU(11525348625112218478LLU), - QU( 3041162365459574102LLU), QU( 2604734487727986558LLU), - QU(15526341771636983145LLU), QU(14556052310697370254LLU), - QU(12997787077930808155LLU), QU( 9601806501755554499LLU), - QU(11349677952521423389LLU), QU(14956777807644899350LLU), - QU(16559736957742852721LLU), QU(12360828274778140726LLU), - QU( 6685373272009662513LLU), QU(16932258748055324130LLU), - QU(15918051131954158508LLU), QU( 1692312913140790144LLU), - QU( 546653826801637367LLU), QU( 5341587076045986652LLU), - QU(14975057236342585662LLU), QU(12374976357340622412LLU), - QU(10328833995181940552LLU), QU(12831807101710443149LLU), - QU(10548514914382545716LLU), QU( 2217806727199715993LLU), - QU(12627067369242845138LLU), QU( 4598965364035438158LLU), - QU( 150923352751318171LLU), QU(14274109544442257283LLU), - QU( 4696661475093863031LLU), QU( 1505764114384654516LLU), - QU(10699185831891495147LLU), QU( 2392353847713620519LLU), - QU( 3652870166711788383LLU), QU( 8640653276221911108LLU), - QU( 3894077592275889704LLU), QU( 4918592872135964845LLU), - QU(16379121273281400789LLU), QU(12058465483591683656LLU), - QU(11250106829302924945LLU), QU( 1147537556296983005LLU), - QU( 6376342756004613268LLU), QU(14967128191709280506LLU), - QU(18007449949790627628LLU), QU( 9497178279316537841LLU), - QU( 7920174844809394893LLU), QU(10037752595255719907LLU), - QU(15875342784985217697LLU), QU(15311615921712850696LLU), - QU( 9552902652110992950LLU), QU(14054979450099721140LLU), - QU( 5998709773566417349LLU), QU(18027910339276320187LLU), - QU( 8223099053868585554LLU), QU( 7842270354824999767LLU), - QU( 4896315688770080292LLU), QU(12969320296569787895LLU), - QU( 2674321489185759961LLU), QU( 4053615936864718439LLU), - QU(11349775270588617578LLU), QU( 4743019256284553975LLU), - QU( 5602100217469723769LLU), QU(14398995691411527813LLU), - QU( 7412170493796825470LLU), QU( 836262406131744846LLU), - QU( 8231086633845153022LLU), QU( 5161377920438552287LLU), - QU( 8828731196169924949LLU), QU(16211142246465502680LLU), - QU( 3307990879253687818LLU), QU( 5193405406899782022LLU), - QU( 8510842117467566693LLU), QU( 6070955181022405365LLU), - QU(14482950231361409799LLU), QU(12585159371331138077LLU), - QU( 3511537678933588148LLU), QU( 2041849474531116417LLU), - QU(10944936685095345792LLU), QU(18303116923079107729LLU), - QU( 2720566371239725320LLU), QU( 4958672473562397622LLU), - QU( 3032326668253243412LLU), QU(13689418691726908338LLU), - QU( 1895205511728843996LLU), QU( 8146303515271990527LLU), - QU(16507343500056113480LLU), QU( 473996939105902919LLU), - QU( 9897686885246881481LLU), QU(14606433762712790575LLU), - QU( 6732796251605566368LLU), QU( 1399778120855368916LLU), - QU( 935023885182833777LLU), QU(16066282816186753477LLU), - QU( 7291270991820612055LLU), QU(17530230393129853844LLU), - QU(10223493623477451366LLU), QU(15841725630495676683LLU), - QU(17379567246435515824LLU), QU( 8588251429375561971LLU), - QU(18339511210887206423LLU), QU(17349587430725976100LLU), - QU(12244876521394838088LLU), QU( 6382187714147161259LLU), - QU(12335807181848950831LLU), QU(16948885622305460665LLU), - QU(13755097796371520506LLU), QU(14806740373324947801LLU), - QU( 4828699633859287703LLU), QU( 8209879281452301604LLU), - QU(12435716669553736437LLU), QU(13970976859588452131LLU), - QU( 6233960842566773148LLU), QU(12507096267900505759LLU), - QU( 1198713114381279421LLU), QU(14989862731124149015LLU), - QU(15932189508707978949LLU), QU( 2526406641432708722LLU), - QU( 29187427817271982LLU), QU( 1499802773054556353LLU), - QU(10816638187021897173LLU), QU( 5436139270839738132LLU), - QU( 6659882287036010082LLU), QU( 2154048955317173697LLU), - QU(10887317019333757642LLU), QU(16281091802634424955LLU), - QU(10754549879915384901LLU), QU(10760611745769249815LLU), - QU( 2161505946972504002LLU), QU( 5243132808986265107LLU), - QU(10129852179873415416LLU), QU( 710339480008649081LLU), - QU( 7802129453068808528LLU), QU(17967213567178907213LLU), - QU(15730859124668605599LLU), QU(13058356168962376502LLU), - QU( 3701224985413645909LLU), QU(14464065869149109264LLU), - QU( 9959272418844311646LLU), QU(10157426099515958752LLU), - QU(14013736814538268528LLU), QU(17797456992065653951LLU), - QU(17418878140257344806LLU), QU(15457429073540561521LLU), - QU( 2184426881360949378LLU), QU( 2062193041154712416LLU), - QU( 8553463347406931661LLU), QU( 4913057625202871854LLU), - QU( 2668943682126618425LLU), QU(17064444737891172288LLU), - QU( 4997115903913298637LLU), QU(12019402608892327416LLU), - QU(17603584559765897352LLU), QU(11367529582073647975LLU), - QU( 8211476043518436050LLU), QU( 8676849804070323674LLU), - QU(18431829230394475730LLU), QU(10490177861361247904LLU), - QU( 9508720602025651349LLU), QU( 7409627448555722700LLU), - QU( 5804047018862729008LLU), QU(11943858176893142594LLU), - QU(11908095418933847092LLU), QU( 5415449345715887652LLU), - QU( 1554022699166156407LLU), QU( 9073322106406017161LLU), - QU( 7080630967969047082LLU), QU(18049736940860732943LLU), - QU(12748714242594196794LLU), QU( 1226992415735156741LLU), - QU(17900981019609531193LLU), QU(11720739744008710999LLU), - QU( 3006400683394775434LLU), QU(11347974011751996028LLU), - QU( 3316999628257954608LLU), QU( 8384484563557639101LLU), - QU(18117794685961729767LLU), QU( 1900145025596618194LLU), - QU(17459527840632892676LLU), QU( 5634784101865710994LLU), - QU( 7918619300292897158LLU), QU( 3146577625026301350LLU), - QU( 9955212856499068767LLU), QU( 1873995843681746975LLU), - QU( 1561487759967972194LLU), QU( 8322718804375878474LLU), - QU(11300284215327028366LLU), QU( 4667391032508998982LLU), - QU( 9820104494306625580LLU), QU(17922397968599970610LLU), - QU( 1784690461886786712LLU), QU(14940365084341346821LLU), - QU( 5348719575594186181LLU), QU(10720419084507855261LLU), - QU(14210394354145143274LLU), QU( 2426468692164000131LLU), - QU(16271062114607059202LLU), QU(14851904092357070247LLU), - QU( 6524493015693121897LLU), QU( 9825473835127138531LLU), - QU(14222500616268569578LLU), QU(15521484052007487468LLU), - QU(14462579404124614699LLU), QU(11012375590820665520LLU), - QU(11625327350536084927LLU), QU(14452017765243785417LLU), - QU( 9989342263518766305LLU), QU( 3640105471101803790LLU), - QU( 4749866455897513242LLU), QU(13963064946736312044LLU), - QU(10007416591973223791LLU), QU(18314132234717431115LLU), - QU( 3286596588617483450LLU), QU( 7726163455370818765LLU), - QU( 7575454721115379328LLU), QU( 5308331576437663422LLU), - QU(18288821894903530934LLU), QU( 8028405805410554106LLU), - QU(15744019832103296628LLU), QU( 149765559630932100LLU), - QU( 6137705557200071977LLU), QU(14513416315434803615LLU), - QU(11665702820128984473LLU), QU( 218926670505601386LLU), - QU( 6868675028717769519LLU), QU(15282016569441512302LLU), - QU( 5707000497782960236LLU), QU( 6671120586555079567LLU), - QU( 2194098052618985448LLU), QU(16849577895477330978LLU), - QU(12957148471017466283LLU), QU( 1997805535404859393LLU), - QU( 1180721060263860490LLU), QU(13206391310193756958LLU), - QU(12980208674461861797LLU), QU( 3825967775058875366LLU), - QU(17543433670782042631LLU), QU( 1518339070120322730LLU), - QU(16344584340890991669LLU), QU( 2611327165318529819LLU), - QU(11265022723283422529LLU), QU( 4001552800373196817LLU), - QU(14509595890079346161LLU), QU( 3528717165416234562LLU), - QU(18153222571501914072LLU), QU( 9387182977209744425LLU), - QU(10064342315985580021LLU), QU(11373678413215253977LLU), - QU( 2308457853228798099LLU), QU( 9729042942839545302LLU), - QU( 7833785471140127746LLU), QU( 6351049900319844436LLU), - QU(14454610627133496067LLU), QU(12533175683634819111LLU), - QU(15570163926716513029LLU), QU(13356980519185762498LLU) + KQU( 2100341266307895239), KQU( 8344256300489757943), + KQU(15687933285484243894), KQU( 8268620370277076319), + KQU(12371852309826545459), KQU( 8800491541730110238), + KQU(18113268950100835773), KQU( 2886823658884438119), + KQU( 3293667307248180724), KQU( 9307928143300172731), + KQU( 7688082017574293629), KQU( 900986224735166665), + KQU( 9977972710722265039), KQU( 6008205004994830552), + KQU( 546909104521689292), KQU( 7428471521869107594), + KQU(14777563419314721179), KQU(16116143076567350053), + KQU( 5322685342003142329), KQU( 4200427048445863473), + KQU( 4693092150132559146), KQU(13671425863759338582), + KQU( 6747117460737639916), KQU( 4732666080236551150), + KQU( 5912839950611941263), KQU( 3903717554504704909), + KQU( 2615667650256786818), KQU(10844129913887006352), + KQU(13786467861810997820), KQU(14267853002994021570), + KQU(13767807302847237439), KQU(16407963253707224617), + KQU( 4802498363698583497), KQU( 2523802839317209764), + KQU( 3822579397797475589), KQU( 8950320572212130610), + KQU( 3745623504978342534), KQU(16092609066068482806), + KQU( 9817016950274642398), KQU(10591660660323829098), + KQU(11751606650792815920), KQU( 5122873818577122211), + KQU(17209553764913936624), KQU( 6249057709284380343), + KQU(15088791264695071830), KQU(15344673071709851930), + KQU( 4345751415293646084), KQU( 2542865750703067928), + KQU(13520525127852368784), KQU(18294188662880997241), + KQU( 3871781938044881523), KQU( 2873487268122812184), + KQU(15099676759482679005), KQU(15442599127239350490), + KQU( 6311893274367710888), KQU( 3286118760484672933), + KQU( 4146067961333542189), KQU(13303942567897208770), + KQU( 8196013722255630418), KQU( 4437815439340979989), + KQU(15433791533450605135), KQU( 4254828956815687049), + KQU( 1310903207708286015), KQU(10529182764462398549), + KQU(14900231311660638810), KQU( 9727017277104609793), + KQU( 1821308310948199033), KQU(11628861435066772084), + KQU( 9469019138491546924), KQU( 3145812670532604988), + KQU( 9938468915045491919), KQU( 1562447430672662142), + KQU(13963995266697989134), KQU( 3356884357625028695), + KQU( 4499850304584309747), KQU( 8456825817023658122), + KQU(10859039922814285279), KQU( 8099512337972526555), + KQU( 348006375109672149), KQU(11919893998241688603), + KQU( 1104199577402948826), KQU(16689191854356060289), + KQU(10992552041730168078), KQU( 7243733172705465836), + KQU( 5668075606180319560), KQU(18182847037333286970), + KQU( 4290215357664631322), KQU( 4061414220791828613), + KQU(13006291061652989604), KQU( 7140491178917128798), + KQU(12703446217663283481), KQU( 5500220597564558267), + KQU(10330551509971296358), KQU(15958554768648714492), + KQU( 5174555954515360045), KQU( 1731318837687577735), + KQU( 3557700801048354857), KQU(13764012341928616198), + KQU(13115166194379119043), KQU( 7989321021560255519), + KQU( 2103584280905877040), KQU( 9230788662155228488), + KQU(16396629323325547654), KQU( 657926409811318051), + KQU(15046700264391400727), KQU( 5120132858771880830), + KQU( 7934160097989028561), KQU( 6963121488531976245), + KQU(17412329602621742089), KQU(15144843053931774092), + KQU(17204176651763054532), KQU(13166595387554065870), + KQU( 8590377810513960213), KQU( 5834365135373991938), + KQU( 7640913007182226243), KQU( 3479394703859418425), + KQU(16402784452644521040), KQU( 4993979809687083980), + KQU(13254522168097688865), KQU(15643659095244365219), + KQU( 5881437660538424982), KQU(11174892200618987379), + KQU( 254409966159711077), KQU(17158413043140549909), + KQU( 3638048789290376272), KQU( 1376816930299489190), + KQU( 4622462095217761923), KQU(15086407973010263515), + KQU(13253971772784692238), KQU( 5270549043541649236), + KQU(11182714186805411604), KQU(12283846437495577140), + KQU( 5297647149908953219), KQU(10047451738316836654), + KQU( 4938228100367874746), KQU(12328523025304077923), + KQU( 3601049438595312361), KQU( 9313624118352733770), + KQU(13322966086117661798), KQU(16660005705644029394), + KQU(11337677526988872373), KQU(13869299102574417795), + KQU(15642043183045645437), KQU( 3021755569085880019), + KQU( 4979741767761188161), KQU(13679979092079279587), + KQU( 3344685842861071743), KQU(13947960059899588104), + KQU( 305806934293368007), KQU( 5749173929201650029), + KQU(11123724852118844098), KQU(15128987688788879802), + KQU(15251651211024665009), KQU( 7689925933816577776), + KQU(16732804392695859449), KQU(17087345401014078468), + KQU(14315108589159048871), KQU( 4820700266619778917), + KQU(16709637539357958441), KQU( 4936227875177351374), + KQU( 2137907697912987247), KQU(11628565601408395420), + KQU( 2333250549241556786), KQU( 5711200379577778637), + KQU( 5170680131529031729), KQU(12620392043061335164), + KQU( 95363390101096078), KQU( 5487981914081709462), + KQU( 1763109823981838620), KQU( 3395861271473224396), + KQU( 1300496844282213595), KQU( 6894316212820232902), + KQU(10673859651135576674), KQU( 5911839658857903252), + KQU(17407110743387299102), KQU( 8257427154623140385), + KQU(11389003026741800267), KQU( 4070043211095013717), + KQU(11663806997145259025), KQU(15265598950648798210), + KQU( 630585789434030934), KQU( 3524446529213587334), + KQU( 7186424168495184211), KQU(10806585451386379021), + KQU(11120017753500499273), KQU( 1586837651387701301), + KQU(17530454400954415544), KQU( 9991670045077880430), + KQU( 7550997268990730180), KQU( 8640249196597379304), + KQU( 3522203892786893823), KQU(10401116549878854788), + KQU(13690285544733124852), KQU( 8295785675455774586), + KQU(15535716172155117603), KQU( 3112108583723722511), + KQU(17633179955339271113), KQU(18154208056063759375), + KQU( 1866409236285815666), KQU(13326075895396412882), + KQU( 8756261842948020025), KQU( 6281852999868439131), + KQU(15087653361275292858), KQU(10333923911152949397), + KQU( 5265567645757408500), KQU(12728041843210352184), + KQU( 6347959327507828759), KQU( 154112802625564758), + KQU(18235228308679780218), KQU( 3253805274673352418), + KQU( 4849171610689031197), KQU(17948529398340432518), + KQU(13803510475637409167), KQU(13506570190409883095), + KQU(15870801273282960805), KQU( 8451286481299170773), + KQU( 9562190620034457541), KQU( 8518905387449138364), + KQU(12681306401363385655), KQU( 3788073690559762558), + KQU( 5256820289573487769), KQU( 2752021372314875467), + KQU( 6354035166862520716), KQU( 4328956378309739069), + KQU( 449087441228269600), KQU( 5533508742653090868), + KQU( 1260389420404746988), KQU(18175394473289055097), + KQU( 1535467109660399420), KQU( 8818894282874061442), + KQU(12140873243824811213), KQU(15031386653823014946), + KQU( 1286028221456149232), KQU( 6329608889367858784), + KQU( 9419654354945132725), KQU( 6094576547061672379), + KQU(17706217251847450255), KQU( 1733495073065878126), + KQU(16918923754607552663), KQU( 8881949849954945044), + KQU(12938977706896313891), KQU(14043628638299793407), + KQU(18393874581723718233), KQU( 6886318534846892044), + KQU(14577870878038334081), KQU(13541558383439414119), + KQU(13570472158807588273), KQU(18300760537910283361), + KQU( 818368572800609205), KQU( 1417000585112573219), + KQU(12337533143867683655), KQU(12433180994702314480), + KQU( 778190005829189083), KQU(13667356216206524711), + KQU( 9866149895295225230), KQU(11043240490417111999), + KQU( 1123933826541378598), KQU( 6469631933605123610), + KQU(14508554074431980040), KQU(13918931242962026714), + KQU( 2870785929342348285), KQU(14786362626740736974), + KQU(13176680060902695786), KQU( 9591778613541679456), + KQU( 9097662885117436706), KQU( 749262234240924947), + KQU( 1944844067793307093), KQU( 4339214904577487742), + KQU( 8009584152961946551), KQU(16073159501225501777), + KQU( 3335870590499306217), KQU(17088312653151202847), + KQU( 3108893142681931848), KQU(16636841767202792021), + KQU(10423316431118400637), KQU( 8008357368674443506), + KQU(11340015231914677875), KQU(17687896501594936090), + KQU(15173627921763199958), KQU( 542569482243721959), + KQU(15071714982769812975), KQU( 4466624872151386956), + KQU( 1901780715602332461), KQU( 9822227742154351098), + KQU( 1479332892928648780), KQU( 6981611948382474400), + KQU( 7620824924456077376), KQU(14095973329429406782), + KQU( 7902744005696185404), KQU(15830577219375036920), + KQU(10287076667317764416), KQU(12334872764071724025), + KQU( 4419302088133544331), KQU(14455842851266090520), + KQU(12488077416504654222), KQU( 7953892017701886766), + KQU( 6331484925529519007), KQU( 4902145853785030022), + KQU(17010159216096443073), KQU(11945354668653886087), + KQU(15112022728645230829), KQU(17363484484522986742), + KQU( 4423497825896692887), KQU( 8155489510809067471), + KQU( 258966605622576285), KQU( 5462958075742020534), + KQU( 6763710214913276228), KQU( 2368935183451109054), + KQU(14209506165246453811), KQU( 2646257040978514881), + KQU( 3776001911922207672), KQU( 1419304601390147631), + KQU(14987366598022458284), KQU( 3977770701065815721), + KQU( 730820417451838898), KQU( 3982991703612885327), + KQU( 2803544519671388477), KQU(17067667221114424649), + KQU( 2922555119737867166), KQU( 1989477584121460932), + KQU(15020387605892337354), KQU( 9293277796427533547), + KQU(10722181424063557247), KQU(16704542332047511651), + KQU( 5008286236142089514), KQU(16174732308747382540), + KQU(17597019485798338402), KQU(13081745199110622093), + KQU( 8850305883842258115), KQU(12723629125624589005), + KQU( 8140566453402805978), KQU(15356684607680935061), + KQU(14222190387342648650), KQU(11134610460665975178), + KQU( 1259799058620984266), KQU(13281656268025610041), + KQU( 298262561068153992), KQU(12277871700239212922), + KQU(13911297774719779438), KQU(16556727962761474934), + KQU(17903010316654728010), KQU( 9682617699648434744), + KQU(14757681836838592850), KQU( 1327242446558524473), + KQU(11126645098780572792), KQU( 1883602329313221774), + KQU( 2543897783922776873), KQU(15029168513767772842), + KQU(12710270651039129878), KQU(16118202956069604504), + KQU(15010759372168680524), KQU( 2296827082251923948), + KQU(10793729742623518101), KQU(13829764151845413046), + KQU(17769301223184451213), KQU( 3118268169210783372), + KQU(17626204544105123127), KQU( 7416718488974352644), + KQU(10450751996212925994), KQU( 9352529519128770586), + KQU( 259347569641110140), KQU( 8048588892269692697), + KQU( 1774414152306494058), KQU(10669548347214355622), + KQU(13061992253816795081), KQU(18432677803063861659), + KQU( 8879191055593984333), KQU(12433753195199268041), + KQU(14919392415439730602), KQU( 6612848378595332963), + KQU( 6320986812036143628), KQU(10465592420226092859), + KQU( 4196009278962570808), KQU( 3747816564473572224), + KQU(17941203486133732898), KQU( 2350310037040505198), + KQU( 5811779859134370113), KQU(10492109599506195126), + KQU( 7699650690179541274), KQU( 1954338494306022961), + KQU(14095816969027231152), KQU( 5841346919964852061), + KQU(14945969510148214735), KQU( 3680200305887550992), + KQU( 6218047466131695792), KQU( 8242165745175775096), + KQU(11021371934053307357), KQU( 1265099502753169797), + KQU( 4644347436111321718), KQU( 3609296916782832859), + KQU( 8109807992218521571), KQU(18387884215648662020), + KQU(14656324896296392902), KQU(17386819091238216751), + KQU(17788300878582317152), KQU( 7919446259742399591), + KQU( 4466613134576358004), KQU(12928181023667938509), + KQU(13147446154454932030), KQU(16552129038252734620), + KQU( 8395299403738822450), KQU(11313817655275361164), + KQU( 434258809499511718), KQU( 2074882104954788676), + KQU( 7929892178759395518), KQU( 9006461629105745388), + KQU( 5176475650000323086), KQU(11128357033468341069), + KQU(12026158851559118955), KQU(14699716249471156500), + KQU( 448982497120206757), KQU( 4156475356685519900), + KQU( 6063816103417215727), KQU(10073289387954971479), + KQU( 8174466846138590962), KQU( 2675777452363449006), + KQU( 9090685420572474281), KQU( 6659652652765562060), + KQU(12923120304018106621), KQU(11117480560334526775), + KQU( 937910473424587511), KQU( 1838692113502346645), + KQU(11133914074648726180), KQU( 7922600945143884053), + KQU(13435287702700959550), KQU( 5287964921251123332), + KQU(11354875374575318947), KQU(17955724760748238133), + KQU(13728617396297106512), KQU( 4107449660118101255), + KQU( 1210269794886589623), KQU(11408687205733456282), + KQU( 4538354710392677887), KQU(13566803319341319267), + KQU(17870798107734050771), KQU( 3354318982568089135), + KQU( 9034450839405133651), KQU(13087431795753424314), + KQU( 950333102820688239), KQU( 1968360654535604116), + KQU(16840551645563314995), KQU( 8867501803892924995), + KQU(11395388644490626845), KQU( 1529815836300732204), + KQU(13330848522996608842), KQU( 1813432878817504265), + KQU( 2336867432693429560), KQU(15192805445973385902), + KQU( 2528593071076407877), KQU( 128459777936689248), + KQU( 9976345382867214866), KQU( 6208885766767996043), + KQU(14982349522273141706), KQU( 3099654362410737822), + KQU(13776700761947297661), KQU( 8806185470684925550), + KQU( 8151717890410585321), KQU( 640860591588072925), + KQU(14592096303937307465), KQU( 9056472419613564846), + KQU(14861544647742266352), KQU(12703771500398470216), + KQU( 3142372800384138465), KQU( 6201105606917248196), + KQU(18337516409359270184), KQU(15042268695665115339), + KQU(15188246541383283846), KQU(12800028693090114519), + KQU( 5992859621101493472), KQU(18278043971816803521), + KQU( 9002773075219424560), KQU( 7325707116943598353), + KQU( 7930571931248040822), KQU( 5645275869617023448), + KQU( 7266107455295958487), KQU( 4363664528273524411), + KQU(14313875763787479809), KQU(17059695613553486802), + KQU( 9247761425889940932), KQU(13704726459237593128), + KQU( 2701312427328909832), KQU(17235532008287243115), + KQU(14093147761491729538), KQU( 6247352273768386516), + KQU( 8268710048153268415), KQU( 7985295214477182083), + KQU(15624495190888896807), KQU( 3772753430045262788), + KQU( 9133991620474991698), KQU( 5665791943316256028), + KQU( 7551996832462193473), KQU(13163729206798953877), + KQU( 9263532074153846374), KQU( 1015460703698618353), + KQU(17929874696989519390), KQU(18257884721466153847), + KQU(16271867543011222991), KQU( 3905971519021791941), + KQU(16814488397137052085), KQU( 1321197685504621613), + KQU( 2870359191894002181), KQU(14317282970323395450), + KQU(13663920845511074366), KQU( 2052463995796539594), + KQU(14126345686431444337), KQU( 1727572121947022534), + KQU(17793552254485594241), KQU( 6738857418849205750), + KQU( 1282987123157442952), KQU(16655480021581159251), + KQU( 6784587032080183866), KQU(14726758805359965162), + KQU( 7577995933961987349), KQU(12539609320311114036), + KQU(10789773033385439494), KQU( 8517001497411158227), + KQU(10075543932136339710), KQU(14838152340938811081), + KQU( 9560840631794044194), KQU(17445736541454117475), + KQU(10633026464336393186), KQU(15705729708242246293), + KQU( 1117517596891411098), KQU( 4305657943415886942), + KQU( 4948856840533979263), KQU(16071681989041789593), + KQU(13723031429272486527), KQU( 7639567622306509462), + KQU(12670424537483090390), KQU( 9715223453097197134), + KQU( 5457173389992686394), KQU( 289857129276135145), + KQU(17048610270521972512), KQU( 692768013309835485), + KQU(14823232360546632057), KQU(18218002361317895936), + KQU( 3281724260212650204), KQU(16453957266549513795), + KQU( 8592711109774511881), KQU( 929825123473369579), + KQU(15966784769764367791), KQU( 9627344291450607588), + KQU(10849555504977813287), KQU( 9234566913936339275), + KQU( 6413807690366911210), KQU(10862389016184219267), + KQU(13842504799335374048), KQU( 1531994113376881174), + KQU( 2081314867544364459), KQU(16430628791616959932), + KQU( 8314714038654394368), KQU( 9155473892098431813), + KQU(12577843786670475704), KQU( 4399161106452401017), + KQU( 1668083091682623186), KQU( 1741383777203714216), + KQU( 2162597285417794374), KQU(15841980159165218736), + KQU( 1971354603551467079), KQU( 1206714764913205968), + KQU( 4790860439591272330), KQU(14699375615594055799), + KQU( 8374423871657449988), KQU(10950685736472937738), + KQU( 697344331343267176), KQU(10084998763118059810), + KQU(12897369539795983124), KQU(12351260292144383605), + KQU( 1268810970176811234), KQU( 7406287800414582768), + KQU( 516169557043807831), KQU( 5077568278710520380), + KQU( 3828791738309039304), KQU( 7721974069946943610), + KQU( 3534670260981096460), KQU( 4865792189600584891), + KQU(16892578493734337298), KQU( 9161499464278042590), + KQU(11976149624067055931), KQU(13219479887277343990), + KQU(14161556738111500680), KQU(14670715255011223056), + KQU( 4671205678403576558), KQU(12633022931454259781), + KQU(14821376219869187646), KQU( 751181776484317028), + KQU( 2192211308839047070), KQU(11787306362361245189), + KQU(10672375120744095707), KQU( 4601972328345244467), + KQU(15457217788831125879), KQU( 8464345256775460809), + KQU(10191938789487159478), KQU( 6184348739615197613), + KQU(11425436778806882100), KQU( 2739227089124319793), + KQU( 461464518456000551), KQU( 4689850170029177442), + KQU( 6120307814374078625), KQU(11153579230681708671), + KQU( 7891721473905347926), KQU(10281646937824872400), + KQU( 3026099648191332248), KQU( 8666750296953273818), + KQU(14978499698844363232), KQU(13303395102890132065), + KQU( 8182358205292864080), KQU(10560547713972971291), + KQU(11981635489418959093), KQU( 3134621354935288409), + KQU(11580681977404383968), KQU(14205530317404088650), + KQU( 5997789011854923157), KQU(13659151593432238041), + KQU(11664332114338865086), KQU( 7490351383220929386), + KQU( 7189290499881530378), KQU(15039262734271020220), + KQU( 2057217285976980055), KQU( 555570804905355739), + KQU(11235311968348555110), KQU(13824557146269603217), + KQU(16906788840653099693), KQU( 7222878245455661677), + KQU( 5245139444332423756), KQU( 4723748462805674292), + KQU(12216509815698568612), KQU(17402362976648951187), + KQU(17389614836810366768), KQU( 4880936484146667711), + KQU( 9085007839292639880), KQU(13837353458498535449), + KQU(11914419854360366677), KQU(16595890135313864103), + KQU( 6313969847197627222), KQU(18296909792163910431), + KQU(10041780113382084042), KQU( 2499478551172884794), + KQU(11057894246241189489), KQU( 9742243032389068555), + KQU(12838934582673196228), KQU(13437023235248490367), + KQU(13372420669446163240), KQU( 6752564244716909224), + KQU( 7157333073400313737), KQU(12230281516370654308), + KQU( 1182884552219419117), KQU( 2955125381312499218), + KQU(10308827097079443249), KQU( 1337648572986534958), + KQU(16378788590020343939), KQU( 108619126514420935), + KQU( 3990981009621629188), KQU( 5460953070230946410), + KQU( 9703328329366531883), KQU(13166631489188077236), + KQU( 1104768831213675170), KQU( 3447930458553877908), + KQU( 8067172487769945676), KQU( 5445802098190775347), + KQU( 3244840981648973873), KQU(17314668322981950060), + KQU( 5006812527827763807), KQU(18158695070225526260), + KQU( 2824536478852417853), KQU(13974775809127519886), + KQU( 9814362769074067392), KQU(17276205156374862128), + KQU(11361680725379306967), KQU( 3422581970382012542), + KQU(11003189603753241266), KQU(11194292945277862261), + KQU( 6839623313908521348), KQU(11935326462707324634), + KQU( 1611456788685878444), KQU(13112620989475558907), + KQU( 517659108904450427), KQU(13558114318574407624), + KQU(15699089742731633077), KQU( 4988979278862685458), + KQU( 8111373583056521297), KQU( 3891258746615399627), + KQU( 8137298251469718086), KQU(12748663295624701649), + KQU( 4389835683495292062), KQU( 5775217872128831729), + KQU( 9462091896405534927), KQU( 8498124108820263989), + KQU( 8059131278842839525), KQU(10503167994254090892), + KQU(11613153541070396656), KQU(18069248738504647790), + KQU( 570657419109768508), KQU( 3950574167771159665), + KQU( 5514655599604313077), KQU( 2908460854428484165), + KQU(10777722615935663114), KQU(12007363304839279486), + KQU( 9800646187569484767), KQU( 8795423564889864287), + KQU(14257396680131028419), KQU( 6405465117315096498), + KQU( 7939411072208774878), KQU(17577572378528990006), + KQU(14785873806715994850), KQU(16770572680854747390), + KQU(18127549474419396481), KQU(11637013449455757750), + KQU(14371851933996761086), KQU( 3601181063650110280), + KQU( 4126442845019316144), KQU(10198287239244320669), + KQU(18000169628555379659), KQU(18392482400739978269), + KQU( 6219919037686919957), KQU( 3610085377719446052), + KQU( 2513925039981776336), KQU(16679413537926716955), + KQU(12903302131714909434), KQU( 5581145789762985009), + KQU(12325955044293303233), KQU(17216111180742141204), + KQU( 6321919595276545740), KQU( 3507521147216174501), + KQU( 9659194593319481840), KQU(11473976005975358326), + KQU(14742730101435987026), KQU( 492845897709954780), + KQU(16976371186162599676), KQU(17712703422837648655), + KQU( 9881254778587061697), KQU( 8413223156302299551), + KQU( 1563841828254089168), KQU( 9996032758786671975), + KQU( 138877700583772667), KQU(13003043368574995989), + KQU( 4390573668650456587), KQU( 8610287390568126755), + KQU(15126904974266642199), KQU( 6703637238986057662), + KQU( 2873075592956810157), KQU( 6035080933946049418), + KQU(13382846581202353014), KQU( 7303971031814642463), + KQU(18418024405307444267), KQU( 5847096731675404647), + KQU( 4035880699639842500), KQU(11525348625112218478), + KQU( 3041162365459574102), KQU( 2604734487727986558), + KQU(15526341771636983145), KQU(14556052310697370254), + KQU(12997787077930808155), KQU( 9601806501755554499), + KQU(11349677952521423389), KQU(14956777807644899350), + KQU(16559736957742852721), KQU(12360828274778140726), + KQU( 6685373272009662513), KQU(16932258748055324130), + KQU(15918051131954158508), KQU( 1692312913140790144), + KQU( 546653826801637367), KQU( 5341587076045986652), + KQU(14975057236342585662), KQU(12374976357340622412), + KQU(10328833995181940552), KQU(12831807101710443149), + KQU(10548514914382545716), KQU( 2217806727199715993), + KQU(12627067369242845138), KQU( 4598965364035438158), + KQU( 150923352751318171), KQU(14274109544442257283), + KQU( 4696661475093863031), KQU( 1505764114384654516), + KQU(10699185831891495147), KQU( 2392353847713620519), + KQU( 3652870166711788383), KQU( 8640653276221911108), + KQU( 3894077592275889704), KQU( 4918592872135964845), + KQU(16379121273281400789), KQU(12058465483591683656), + KQU(11250106829302924945), KQU( 1147537556296983005), + KQU( 6376342756004613268), KQU(14967128191709280506), + KQU(18007449949790627628), KQU( 9497178279316537841), + KQU( 7920174844809394893), KQU(10037752595255719907), + KQU(15875342784985217697), KQU(15311615921712850696), + KQU( 9552902652110992950), KQU(14054979450099721140), + KQU( 5998709773566417349), KQU(18027910339276320187), + KQU( 8223099053868585554), KQU( 7842270354824999767), + KQU( 4896315688770080292), KQU(12969320296569787895), + KQU( 2674321489185759961), KQU( 4053615936864718439), + KQU(11349775270588617578), KQU( 4743019256284553975), + KQU( 5602100217469723769), KQU(14398995691411527813), + KQU( 7412170493796825470), KQU( 836262406131744846), + KQU( 8231086633845153022), KQU( 5161377920438552287), + KQU( 8828731196169924949), KQU(16211142246465502680), + KQU( 3307990879253687818), KQU( 5193405406899782022), + KQU( 8510842117467566693), KQU( 6070955181022405365), + KQU(14482950231361409799), KQU(12585159371331138077), + KQU( 3511537678933588148), KQU( 2041849474531116417), + KQU(10944936685095345792), KQU(18303116923079107729), + KQU( 2720566371239725320), KQU( 4958672473562397622), + KQU( 3032326668253243412), KQU(13689418691726908338), + KQU( 1895205511728843996), KQU( 8146303515271990527), + KQU(16507343500056113480), KQU( 473996939105902919), + KQU( 9897686885246881481), KQU(14606433762712790575), + KQU( 6732796251605566368), KQU( 1399778120855368916), + KQU( 935023885182833777), KQU(16066282816186753477), + KQU( 7291270991820612055), KQU(17530230393129853844), + KQU(10223493623477451366), KQU(15841725630495676683), + KQU(17379567246435515824), KQU( 8588251429375561971), + KQU(18339511210887206423), KQU(17349587430725976100), + KQU(12244876521394838088), KQU( 6382187714147161259), + KQU(12335807181848950831), KQU(16948885622305460665), + KQU(13755097796371520506), KQU(14806740373324947801), + KQU( 4828699633859287703), KQU( 8209879281452301604), + KQU(12435716669553736437), KQU(13970976859588452131), + KQU( 6233960842566773148), KQU(12507096267900505759), + KQU( 1198713114381279421), KQU(14989862731124149015), + KQU(15932189508707978949), KQU( 2526406641432708722), + KQU( 29187427817271982), KQU( 1499802773054556353), + KQU(10816638187021897173), KQU( 5436139270839738132), + KQU( 6659882287036010082), KQU( 2154048955317173697), + KQU(10887317019333757642), KQU(16281091802634424955), + KQU(10754549879915384901), KQU(10760611745769249815), + KQU( 2161505946972504002), KQU( 5243132808986265107), + KQU(10129852179873415416), KQU( 710339480008649081), + KQU( 7802129453068808528), KQU(17967213567178907213), + KQU(15730859124668605599), KQU(13058356168962376502), + KQU( 3701224985413645909), KQU(14464065869149109264), + KQU( 9959272418844311646), KQU(10157426099515958752), + KQU(14013736814538268528), KQU(17797456992065653951), + KQU(17418878140257344806), KQU(15457429073540561521), + KQU( 2184426881360949378), KQU( 2062193041154712416), + KQU( 8553463347406931661), KQU( 4913057625202871854), + KQU( 2668943682126618425), KQU(17064444737891172288), + KQU( 4997115903913298637), KQU(12019402608892327416), + KQU(17603584559765897352), KQU(11367529582073647975), + KQU( 8211476043518436050), KQU( 8676849804070323674), + KQU(18431829230394475730), KQU(10490177861361247904), + KQU( 9508720602025651349), KQU( 7409627448555722700), + KQU( 5804047018862729008), KQU(11943858176893142594), + KQU(11908095418933847092), KQU( 5415449345715887652), + KQU( 1554022699166156407), KQU( 9073322106406017161), + KQU( 7080630967969047082), KQU(18049736940860732943), + KQU(12748714242594196794), KQU( 1226992415735156741), + KQU(17900981019609531193), KQU(11720739744008710999), + KQU( 3006400683394775434), KQU(11347974011751996028), + KQU( 3316999628257954608), KQU( 8384484563557639101), + KQU(18117794685961729767), KQU( 1900145025596618194), + KQU(17459527840632892676), KQU( 5634784101865710994), + KQU( 7918619300292897158), KQU( 3146577625026301350), + KQU( 9955212856499068767), KQU( 1873995843681746975), + KQU( 1561487759967972194), KQU( 8322718804375878474), + KQU(11300284215327028366), KQU( 4667391032508998982), + KQU( 9820104494306625580), KQU(17922397968599970610), + KQU( 1784690461886786712), KQU(14940365084341346821), + KQU( 5348719575594186181), KQU(10720419084507855261), + KQU(14210394354145143274), KQU( 2426468692164000131), + KQU(16271062114607059202), KQU(14851904092357070247), + KQU( 6524493015693121897), KQU( 9825473835127138531), + KQU(14222500616268569578), KQU(15521484052007487468), + KQU(14462579404124614699), KQU(11012375590820665520), + KQU(11625327350536084927), KQU(14452017765243785417), + KQU( 9989342263518766305), KQU( 3640105471101803790), + KQU( 4749866455897513242), KQU(13963064946736312044), + KQU(10007416591973223791), KQU(18314132234717431115), + KQU( 3286596588617483450), KQU( 7726163455370818765), + KQU( 7575454721115379328), KQU( 5308331576437663422), + KQU(18288821894903530934), KQU( 8028405805410554106), + KQU(15744019832103296628), KQU( 149765559630932100), + KQU( 6137705557200071977), KQU(14513416315434803615), + KQU(11665702820128984473), KQU( 218926670505601386), + KQU( 6868675028717769519), KQU(15282016569441512302), + KQU( 5707000497782960236), KQU( 6671120586555079567), + KQU( 2194098052618985448), KQU(16849577895477330978), + KQU(12957148471017466283), KQU( 1997805535404859393), + KQU( 1180721060263860490), KQU(13206391310193756958), + KQU(12980208674461861797), KQU( 3825967775058875366), + KQU(17543433670782042631), KQU( 1518339070120322730), + KQU(16344584340890991669), KQU( 2611327165318529819), + KQU(11265022723283422529), KQU( 4001552800373196817), + KQU(14509595890079346161), KQU( 3528717165416234562), + KQU(18153222571501914072), KQU( 9387182977209744425), + KQU(10064342315985580021), KQU(11373678413215253977), + KQU( 2308457853228798099), KQU( 9729042942839545302), + KQU( 7833785471140127746), KQU( 6351049900319844436), + KQU(14454610627133496067), KQU(12533175683634819111), + KQU(15570163926716513029), KQU(13356980519185762498) }; TEST_BEGIN(test_gen_rand_32) diff --git a/memory/jemalloc/src/test/unit/atomic.c b/memory/jemalloc/src/test/unit/atomic.c new file mode 100644 index 000000000000..eb6136c79403 --- /dev/null +++ b/memory/jemalloc/src/test/unit/atomic.c @@ -0,0 +1,97 @@ +#include "test/jemalloc_test.h" + +#define TEST_STRUCT(p, t) \ +struct p##_test_s { \ + t accum0; \ + t x; \ +}; \ +typedef struct p##_test_s p##_test_t; + +#define TEST_BODY(p, t, PRI) do { \ + const p##_test_t tests[] = { \ + {-1, -1}, \ + {-1, 0}, \ + {-1, 1}, \ + \ + { 0, -1}, \ + { 0, 0}, \ + { 0, 1}, \ + \ + { 1, -1}, \ + { 1, 0}, \ + { 1, 1}, \ + \ + {0, -(1 << 22)}, \ + {0, (1 << 22)}, \ + {(1 << 22), -(1 << 22)}, \ + {(1 << 22), (1 << 22)} \ + }; \ + unsigned i; \ + \ + for (i = 0; i < sizeof(tests)/sizeof(p##_test_t); i++) { \ + t accum = tests[i].accum0; \ + assert_u64_eq(atomic_read_##p(&accum), tests[i].accum0, \ + "i=%u", i); \ + assert_u64_eq(atomic_add_##p(&accum, tests[i].x), \ + tests[i].accum0 + tests[i].x, \ + "i=%u, accum=%#"PRI", x=%#"PRI, \ + i, tests[i].accum0, tests[i].x); \ + assert_u64_eq(atomic_read_##p(&accum), accum, \ + "i=%u", i); \ + \ + accum = tests[i].accum0; \ + assert_u64_eq(atomic_sub_##p(&accum, tests[i].x), \ + tests[i].accum0 - tests[i].x, \ + "i=%u, accum=%#"PRI", x=%#"PRI, \ + i, tests[i].accum0, tests[i].x); \ + assert_u64_eq(atomic_read_##p(&accum), accum, \ + "i=%u", i); \ + } \ +} while (0) + +TEST_STRUCT(uint64, uint64_t) +TEST_BEGIN(test_atomic_uint64) +{ + +#if !(LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) + test_skip("64-bit atomic operations not supported"); +#else + TEST_BODY(uint64, uint64_t, PRIx64); +#endif +} +TEST_END + +TEST_STRUCT(uint32, uint32_t) +TEST_BEGIN(test_atomic_uint32) +{ + + TEST_BODY(uint32, uint32_t, PRIx32); +} +TEST_END + +TEST_STRUCT(z, size_t) +TEST_BEGIN(test_atomic_z) +{ + + TEST_BODY(z, size_t, "zx"); +} +TEST_END + +TEST_STRUCT(u, unsigned) +TEST_BEGIN(test_atomic_u) +{ + + TEST_BODY(u, unsigned, "x"); +} +TEST_END + +int +main(void) +{ + + return (test( + test_atomic_uint64, + test_atomic_uint32, + test_atomic_z, + test_atomic_u)); +} diff --git a/memory/jemalloc/src/test/unit/bitmap.c b/memory/jemalloc/src/test/unit/bitmap.c index 8086b8885fc8..4ea94f857521 100644 --- a/memory/jemalloc/src/test/unit/bitmap.c +++ b/memory/jemalloc/src/test/unit/bitmap.c @@ -1,17 +1,11 @@ #include "test/jemalloc_test.h" -#if (LG_BITMAP_MAXBITS > 12) -# define MAXBITS 4500 -#else -# define MAXBITS (1U << LG_BITMAP_MAXBITS) -#endif - TEST_BEGIN(test_bitmap_size) { size_t i, prev_size; prev_size = 0; - for (i = 1; i <= MAXBITS; i++) { + for (i = 1; i <= BITMAP_MAXBITS; i++) { size_t size = bitmap_size(i); assert_true(size >= prev_size, "Bitmap size is smaller than expected"); @@ -24,7 +18,7 @@ TEST_BEGIN(test_bitmap_init) { size_t i; - for (i = 1; i <= MAXBITS; i++) { + for (i = 1; i <= BITMAP_MAXBITS; i++) { bitmap_info_t binfo; bitmap_info_init(&binfo, i); { @@ -47,7 +41,7 @@ TEST_BEGIN(test_bitmap_set) { size_t i; - for (i = 1; i <= MAXBITS; i++) { + for (i = 1; i <= BITMAP_MAXBITS; i++) { bitmap_info_t binfo; bitmap_info_init(&binfo, i); { @@ -70,7 +64,7 @@ TEST_BEGIN(test_bitmap_unset) { size_t i; - for (i = 1; i <= MAXBITS; i++) { + for (i = 1; i <= BITMAP_MAXBITS; i++) { bitmap_info_t binfo; bitmap_info_init(&binfo, i); { @@ -99,7 +93,7 @@ TEST_BEGIN(test_bitmap_sfu) { size_t i; - for (i = 1; i <= MAXBITS; i++) { + for (i = 1; i <= BITMAP_MAXBITS; i++) { bitmap_info_t binfo; bitmap_info_init(&binfo, i); { diff --git a/memory/jemalloc/src/test/unit/ckh.c b/memory/jemalloc/src/test/unit/ckh.c index b214c279a5e9..c2126487257c 100644 --- a/memory/jemalloc/src/test/unit/ckh.c +++ b/memory/jemalloc/src/test/unit/ckh.c @@ -2,20 +2,24 @@ TEST_BEGIN(test_new_delete) { + tsd_t *tsd; ckh_t ckh; - assert_false(ckh_new(&ckh, 2, ckh_string_hash, ckh_string_keycomp), - "Unexpected ckh_new() error"); - ckh_delete(&ckh); + tsd = tsd_fetch(); - assert_false(ckh_new(&ckh, 3, ckh_pointer_hash, ckh_pointer_keycomp), + assert_false(ckh_new(tsd, &ckh, 2, ckh_string_hash, ckh_string_keycomp), "Unexpected ckh_new() error"); - ckh_delete(&ckh); + ckh_delete(tsd, &ckh); + + assert_false(ckh_new(tsd, &ckh, 3, ckh_pointer_hash, + ckh_pointer_keycomp), "Unexpected ckh_new() error"); + ckh_delete(tsd, &ckh); } TEST_END TEST_BEGIN(test_count_insert_search_remove) { + tsd_t *tsd; ckh_t ckh; const char *strs[] = { "a string", @@ -26,7 +30,9 @@ TEST_BEGIN(test_count_insert_search_remove) const char *missing = "A string not in the hash table."; size_t i; - assert_false(ckh_new(&ckh, 2, ckh_string_hash, ckh_string_keycomp), + tsd = tsd_fetch(); + + assert_false(ckh_new(tsd, &ckh, 2, ckh_string_hash, ckh_string_keycomp), "Unexpected ckh_new() error"); assert_zu_eq(ckh_count(&ckh), 0, "ckh_count() should return %zu, but it returned %zu", ZU(0), @@ -34,7 +40,7 @@ TEST_BEGIN(test_count_insert_search_remove) /* Insert. */ for (i = 0; i < sizeof(strs)/sizeof(const char *); i++) { - ckh_insert(&ckh, strs[i], strs[i]); + ckh_insert(tsd, &ckh, strs[i], strs[i]); assert_zu_eq(ckh_count(&ckh), i+1, "ckh_count() should return %zu, but it returned %zu", i+1, ckh_count(&ckh)); @@ -79,7 +85,7 @@ TEST_BEGIN(test_count_insert_search_remove) vp = (i & 2) ? &v.p : NULL; k.p = NULL; v.p = NULL; - assert_false(ckh_remove(&ckh, strs[i], kp, vp), + assert_false(ckh_remove(tsd, &ckh, strs[i], kp, vp), "Unexpected ckh_remove() error"); ks = (i & 1) ? strs[i] : (const char *)NULL; @@ -95,20 +101,23 @@ TEST_BEGIN(test_count_insert_search_remove) ckh_count(&ckh)); } - ckh_delete(&ckh); + ckh_delete(tsd, &ckh); } TEST_END TEST_BEGIN(test_insert_iter_remove) { #define NITEMS ZU(1000) + tsd_t *tsd; ckh_t ckh; void **p[NITEMS]; void *q, *r; size_t i; - assert_false(ckh_new(&ckh, 2, ckh_pointer_hash, ckh_pointer_keycomp), - "Unexpected ckh_new() error"); + tsd = tsd_fetch(); + + assert_false(ckh_new(tsd, &ckh, 2, ckh_pointer_hash, + ckh_pointer_keycomp), "Unexpected ckh_new() error"); for (i = 0; i < NITEMS; i++) { p[i] = mallocx(i+1, 0); @@ -119,7 +128,7 @@ TEST_BEGIN(test_insert_iter_remove) size_t j; for (j = i; j < NITEMS; j++) { - assert_false(ckh_insert(&ckh, p[j], p[j]), + assert_false(ckh_insert(tsd, &ckh, p[j], p[j]), "Unexpected ckh_insert() failure"); assert_false(ckh_search(&ckh, p[j], &q, &r), "Unexpected ckh_search() failure"); @@ -134,13 +143,13 @@ TEST_BEGIN(test_insert_iter_remove) for (j = i + 1; j < NITEMS; j++) { assert_false(ckh_search(&ckh, p[j], NULL, NULL), "Unexpected ckh_search() failure"); - assert_false(ckh_remove(&ckh, p[j], &q, &r), + assert_false(ckh_remove(tsd, &ckh, p[j], &q, &r), "Unexpected ckh_remove() failure"); assert_ptr_eq(p[j], q, "Key pointer mismatch"); assert_ptr_eq(p[j], r, "Value pointer mismatch"); assert_true(ckh_search(&ckh, p[j], NULL, NULL), "Unexpected ckh_search() success"); - assert_true(ckh_remove(&ckh, p[j], &q, &r), + assert_true(ckh_remove(tsd, &ckh, p[j], &q, &r), "Unexpected ckh_remove() success"); } @@ -150,8 +159,7 @@ TEST_BEGIN(test_insert_iter_remove) memset(seen, 0, sizeof(seen)); - for (tabind = 0; ckh_iter(&ckh, &tabind, &q, &r) == - false;) { + for (tabind = 0; !ckh_iter(&ckh, &tabind, &q, &r);) { size_t k; assert_ptr_eq(q, r, "Key and val not equal"); @@ -176,13 +184,13 @@ TEST_BEGIN(test_insert_iter_remove) for (i = 0; i < NITEMS; i++) { assert_false(ckh_search(&ckh, p[i], NULL, NULL), "Unexpected ckh_search() failure"); - assert_false(ckh_remove(&ckh, p[i], &q, &r), + assert_false(ckh_remove(tsd, &ckh, p[i], &q, &r), "Unexpected ckh_remove() failure"); assert_ptr_eq(p[i], q, "Key pointer mismatch"); assert_ptr_eq(p[i], r, "Value pointer mismatch"); assert_true(ckh_search(&ckh, p[i], NULL, NULL), "Unexpected ckh_search() success"); - assert_true(ckh_remove(&ckh, p[i], &q, &r), + assert_true(ckh_remove(tsd, &ckh, p[i], &q, &r), "Unexpected ckh_remove() success"); dallocx(p[i], 0); } @@ -190,7 +198,7 @@ TEST_BEGIN(test_insert_iter_remove) assert_zu_eq(ckh_count(&ckh), 0, "ckh_count() should return %zu, but it returned %zu", ZU(0), ckh_count(&ckh)); - ckh_delete(&ckh); + ckh_delete(tsd, &ckh); #undef NITEMS } TEST_END diff --git a/memory/jemalloc/src/test/unit/hash.c b/memory/jemalloc/src/test/unit/hash.c index abb394ac0771..77a8cede92ad 100644 --- a/memory/jemalloc/src/test/unit/hash.c +++ b/memory/jemalloc/src/test/unit/hash.c @@ -64,8 +64,8 @@ hash_variant_verify(hash_variant_t variant) { const size_t hashbytes = hash_variant_bits(variant) / 8; uint8_t key[256]; - uint8_t hashes[hashbytes * 256]; - uint8_t final[hashbytes]; + VARIABLE_ARRAY(uint8_t, hashes, hashbytes * 256); + VARIABLE_ARRAY(uint8_t, final, hashbytes); unsigned i; uint32_t computed, expected; diff --git a/memory/jemalloc/src/test/unit/junk.c b/memory/jemalloc/src/test/unit/junk.c index 85bbf9e2bd35..733f661eef6f 100644 --- a/memory/jemalloc/src/test/unit/junk.c +++ b/memory/jemalloc/src/test/unit/junk.c @@ -1,14 +1,26 @@ #include "test/jemalloc_test.h" #ifdef JEMALLOC_FILL +# ifndef JEMALLOC_TEST_JUNK_OPT +# define JEMALLOC_TEST_JUNK_OPT "junk:true" +# endif const char *malloc_conf = - "abort:false,junk:true,zero:false,redzone:true,quarantine:0"; + "abort:false,zero:false,redzone:true,quarantine:0," JEMALLOC_TEST_JUNK_OPT; #endif static arena_dalloc_junk_small_t *arena_dalloc_junk_small_orig; static arena_dalloc_junk_large_t *arena_dalloc_junk_large_orig; static huge_dalloc_junk_t *huge_dalloc_junk_orig; -static void *most_recently_junked; +static void *watch_for_junking; +static bool saw_junking; + +static void +watch_junking(void *p) +{ + + watch_for_junking = p; + saw_junking = false; +} static void arena_dalloc_junk_small_intercept(void *ptr, arena_bin_info_t *bin_info) @@ -21,7 +33,8 @@ arena_dalloc_junk_small_intercept(void *ptr, arena_bin_info_t *bin_info) "Missing junk fill for byte %zu/%zu of deallocated region", i, bin_info->reg_size); } - most_recently_junked = ptr; + if (ptr == watch_for_junking) + saw_junking = true; } static void @@ -35,7 +48,8 @@ arena_dalloc_junk_large_intercept(void *ptr, size_t usize) "Missing junk fill for byte %zu/%zu of deallocated region", i, usize); } - most_recently_junked = ptr; + if (ptr == watch_for_junking) + saw_junking = true; } static void @@ -48,7 +62,8 @@ huge_dalloc_junk_intercept(void *ptr, size_t usize) * enough that it doesn't make sense to duplicate the decision logic in * test code, so don't actually check that the region is junk-filled. */ - most_recently_junked = ptr; + if (ptr == watch_for_junking) + saw_junking = true; } static void @@ -57,12 +72,14 @@ test_junk(size_t sz_min, size_t sz_max) char *s; size_t sz_prev, sz, i; - arena_dalloc_junk_small_orig = arena_dalloc_junk_small; - arena_dalloc_junk_small = arena_dalloc_junk_small_intercept; - arena_dalloc_junk_large_orig = arena_dalloc_junk_large; - arena_dalloc_junk_large = arena_dalloc_junk_large_intercept; - huge_dalloc_junk_orig = huge_dalloc_junk; - huge_dalloc_junk = huge_dalloc_junk_intercept; + if (opt_junk_free) { + arena_dalloc_junk_small_orig = arena_dalloc_junk_small; + arena_dalloc_junk_small = arena_dalloc_junk_small_intercept; + arena_dalloc_junk_large_orig = arena_dalloc_junk_large; + arena_dalloc_junk_large = arena_dalloc_junk_large_intercept; + huge_dalloc_junk_orig = huge_dalloc_junk; + huge_dalloc_junk = huge_dalloc_junk_intercept; + } sz_prev = 0; s = (char *)mallocx(sz_min, 0); @@ -80,34 +97,35 @@ test_junk(size_t sz_min, size_t sz_max) } for (i = sz_prev; i < sz; i++) { - assert_c_eq(s[i], 0xa5, - "Newly allocated byte %zu/%zu isn't junk-filled", - i, sz); + if (opt_junk_alloc) { + assert_c_eq(s[i], 0xa5, + "Newly allocated byte %zu/%zu isn't " + "junk-filled", i, sz); + } s[i] = 'a'; } if (xallocx(s, sz+1, 0, 0) == sz) { - void *junked = (void *)s; - + watch_junking(s); s = (char *)rallocx(s, sz+1, 0); assert_ptr_not_null((void *)s, "Unexpected rallocx() failure"); - if (!config_mremap || sz+1 <= arena_maxclass) { - assert_ptr_eq(most_recently_junked, junked, - "Expected region of size %zu to be " - "junk-filled", - sz); - } + assert_true(!opt_junk_free || saw_junking, + "Expected region of size %zu to be junk-filled", + sz); } } + watch_junking(s); dallocx(s, 0); - assert_ptr_eq(most_recently_junked, (void *)s, + assert_true(!opt_junk_free || saw_junking, "Expected region of size %zu to be junk-filled", sz); - arena_dalloc_junk_small = arena_dalloc_junk_small_orig; - arena_dalloc_junk_large = arena_dalloc_junk_large_orig; - huge_dalloc_junk = huge_dalloc_junk_orig; + if (opt_junk_free) { + arena_dalloc_junk_small = arena_dalloc_junk_small_orig; + arena_dalloc_junk_large = arena_dalloc_junk_large_orig; + huge_dalloc_junk = huge_dalloc_junk_orig; + } } TEST_BEGIN(test_junk_small) @@ -137,13 +155,25 @@ TEST_END arena_ralloc_junk_large_t *arena_ralloc_junk_large_orig; static void *most_recently_trimmed; +static size_t +shrink_size(size_t size) +{ + size_t shrink_size; + + for (shrink_size = size - 1; nallocx(shrink_size, 0) == size; + shrink_size--) + ; /* Do nothing. */ + + return (shrink_size); +} + static void arena_ralloc_junk_large_intercept(void *ptr, size_t old_usize, size_t usize) { arena_ralloc_junk_large_orig(ptr, old_usize, usize); assert_zu_eq(old_usize, arena_maxclass, "Unexpected old_usize"); - assert_zu_eq(usize, arena_maxclass-PAGE, "Unexpected usize"); + assert_zu_eq(usize, shrink_size(arena_maxclass), "Unexpected usize"); most_recently_trimmed = ptr; } @@ -157,7 +187,7 @@ TEST_BEGIN(test_junk_large_ralloc_shrink) arena_ralloc_junk_large_orig = arena_ralloc_junk_large; arena_ralloc_junk_large = arena_ralloc_junk_large_intercept; - p2 = rallocx(p1, arena_maxclass-PAGE, 0); + p2 = rallocx(p1, shrink_size(arena_maxclass), 0); assert_ptr_eq(p1, p2, "Unexpected move during shrink"); arena_ralloc_junk_large = arena_ralloc_junk_large_orig; @@ -183,6 +213,7 @@ TEST_BEGIN(test_junk_redzone) arena_redzone_corruption_t *arena_redzone_corruption_orig; test_skip_if(!config_fill); + test_skip_if(!opt_junk_alloc || !opt_junk_free); arena_redzone_corruption_orig = arena_redzone_corruption; arena_redzone_corruption = arena_redzone_corruption_replacement; @@ -213,6 +244,7 @@ int main(void) { + assert(opt_junk_alloc || opt_junk_free); return (test( test_junk_small, test_junk_large, diff --git a/memory/jemalloc/src/test/unit/junk_alloc.c b/memory/jemalloc/src/test/unit/junk_alloc.c new file mode 100644 index 000000000000..8db3331d2ade --- /dev/null +++ b/memory/jemalloc/src/test/unit/junk_alloc.c @@ -0,0 +1,3 @@ +#define JEMALLOC_TEST_JUNK_OPT "junk:alloc" +#include "junk.c" +#undef JEMALLOC_TEST_JUNK_OPT diff --git a/memory/jemalloc/src/test/unit/junk_free.c b/memory/jemalloc/src/test/unit/junk_free.c new file mode 100644 index 000000000000..482a61d070a1 --- /dev/null +++ b/memory/jemalloc/src/test/unit/junk_free.c @@ -0,0 +1,3 @@ +#define JEMALLOC_TEST_JUNK_OPT "junk:free" +#include "junk.c" +#undef JEMALLOC_TEST_JUNK_OPT diff --git a/memory/jemalloc/src/test/unit/lg_chunk.c b/memory/jemalloc/src/test/unit/lg_chunk.c new file mode 100644 index 000000000000..7f0b31cec36a --- /dev/null +++ b/memory/jemalloc/src/test/unit/lg_chunk.c @@ -0,0 +1,26 @@ +#include "test/jemalloc_test.h" + +/* + * Make sure that opt.lg_chunk clamping is sufficient. In practice, this test + * program will fail a debug assertion during initialization and abort (rather + * than the test soft-failing) if clamping is insufficient. + */ +const char *malloc_conf = "lg_chunk:0"; + +TEST_BEGIN(test_lg_chunk_clamp) +{ + void *p; + + p = mallocx(1, 0); + assert_ptr_not_null(p, "Unexpected mallocx() failure"); + dallocx(p, 0); +} +TEST_END + +int +main(void) +{ + + return (test( + test_lg_chunk_clamp)); +} diff --git a/memory/jemalloc/src/test/unit/mallctl.c b/memory/jemalloc/src/test/unit/mallctl.c index 31fb81057641..f4b7d1ab8470 100644 --- a/memory/jemalloc/src/test/unit/mallctl.c +++ b/memory/jemalloc/src/test/unit/mallctl.c @@ -127,10 +127,8 @@ TEST_BEGIN(test_mallctl_config) } while (0) TEST_MALLCTL_CONFIG(debug); - TEST_MALLCTL_CONFIG(dss); TEST_MALLCTL_CONFIG(fill); TEST_MALLCTL_CONFIG(lazy_lock); - TEST_MALLCTL_CONFIG(mremap); TEST_MALLCTL_CONFIG(munmap); TEST_MALLCTL_CONFIG(prof); TEST_MALLCTL_CONFIG(prof_libgcc); @@ -166,12 +164,11 @@ TEST_BEGIN(test_mallctl_opt) TEST_MALLCTL_OPT(size_t, narenas, always); TEST_MALLCTL_OPT(ssize_t, lg_dirty_mult, always); TEST_MALLCTL_OPT(bool, stats_print, always); - TEST_MALLCTL_OPT(bool, junk, fill); + TEST_MALLCTL_OPT(const char *, junk, fill); TEST_MALLCTL_OPT(size_t, quarantine, fill); TEST_MALLCTL_OPT(bool, redzone, fill); TEST_MALLCTL_OPT(bool, zero, fill); TEST_MALLCTL_OPT(bool, utrace, utrace); - TEST_MALLCTL_OPT(bool, valgrind, valgrind); TEST_MALLCTL_OPT(bool, xmalloc, xmalloc); TEST_MALLCTL_OPT(bool, tcache, tcache); TEST_MALLCTL_OPT(size_t, lg_tcache_max, tcache); @@ -255,27 +252,41 @@ TEST_BEGIN(test_arena_i_dss) { const char *dss_prec_old, *dss_prec_new; size_t sz = sizeof(dss_prec_old); + size_t mib[3]; + size_t miblen; - dss_prec_new = "primary"; - assert_d_eq(mallctl("arena.0.dss", &dss_prec_old, &sz, &dss_prec_new, + miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("arena.0.dss", mib, &miblen), 0, + "Unexpected mallctlnametomib() error"); + + dss_prec_new = "disabled"; + assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, &dss_prec_new, sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure"); assert_str_ne(dss_prec_old, "primary", "Unexpected default for dss precedence"); - assert_d_eq(mallctl("arena.0.dss", &dss_prec_new, &sz, &dss_prec_old, + assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_new, &sz, &dss_prec_old, sizeof(dss_prec_old)), 0, "Unexpected mallctl() failure"); -} -TEST_END -TEST_BEGIN(test_arenas_purge) -{ - unsigned arena = 0; - - assert_d_eq(mallctl("arenas.purge", NULL, NULL, &arena, sizeof(arena)), - 0, "Unexpected mallctl() failure"); - - assert_d_eq(mallctl("arenas.purge", NULL, NULL, NULL, 0), 0, + assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); + assert_str_ne(dss_prec_old, "primary", + "Unexpected value for dss precedence"); + + mib[1] = narenas_total_get(); + dss_prec_new = "disabled"; + assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, &dss_prec_new, + sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure"); + assert_str_ne(dss_prec_old, "primary", + "Unexpected default for dss precedence"); + + assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_new, &sz, &dss_prec_old, + sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure"); + + assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, NULL, 0), 0, + "Unexpected mallctl() failure"); + assert_str_ne(dss_prec_old, "primary", + "Unexpected value for dss precedence"); } TEST_END @@ -287,7 +298,7 @@ TEST_BEGIN(test_arenas_initialized) assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); { - bool initialized[narenas]; + VARIABLE_ARRAY(bool, initialized, narenas); sz = narenas * sizeof(bool); assert_d_eq(mallctl("arenas.initialized", initialized, &sz, @@ -310,7 +321,8 @@ TEST_BEGIN(test_arenas_constants) TEST_ARENAS_CONSTANT(size_t, quantum, QUANTUM); TEST_ARENAS_CONSTANT(size_t, page, PAGE); TEST_ARENAS_CONSTANT(unsigned, nbins, NBINS); - TEST_ARENAS_CONSTANT(size_t, nlruns, nlclasses); + TEST_ARENAS_CONSTANT(unsigned, nlruns, nlclasses); + TEST_ARENAS_CONSTANT(unsigned, nhchunks, nhclasses); #undef TEST_ARENAS_CONSTANT } @@ -346,12 +358,29 @@ TEST_BEGIN(test_arenas_lrun_constants) assert_zu_eq(name, expected, "Incorrect "#name" size"); \ } while (0) - TEST_ARENAS_LRUN_CONSTANT(size_t, size, (1 << LG_PAGE)); + TEST_ARENAS_LRUN_CONSTANT(size_t, size, LARGE_MINCLASS); #undef TEST_ARENAS_LRUN_CONSTANT } TEST_END +TEST_BEGIN(test_arenas_hchunk_constants) +{ + +#define TEST_ARENAS_HCHUNK_CONSTANT(t, name, expected) do { \ + t name; \ + size_t sz = sizeof(t); \ + assert_d_eq(mallctl("arenas.hchunk.0."#name, &name, &sz, NULL, \ + 0), 0, "Unexpected mallctl() failure"); \ + assert_zu_eq(name, expected, "Incorrect "#name" size"); \ +} while (0) + + TEST_ARENAS_HCHUNK_CONSTANT(size_t, size, chunksize); + +#undef TEST_ARENAS_HCHUNK_CONSTANT +} +TEST_END + TEST_BEGIN(test_arenas_extend) { unsigned narenas_before, arena, narenas_after; @@ -405,11 +434,11 @@ main(void) test_thread_arena, test_arena_i_purge, test_arena_i_dss, - test_arenas_purge, test_arenas_initialized, test_arenas_constants, test_arenas_bin_constants, test_arenas_lrun_constants, + test_arenas_hchunk_constants, test_arenas_extend, test_stats_arenas)); } diff --git a/memory/jemalloc/src/test/unit/math.c b/memory/jemalloc/src/test/unit/math.c index a1b288ea19c0..ebec77a62d52 100644 --- a/memory/jemalloc/src/test/unit/math.c +++ b/memory/jemalloc/src/test/unit/math.c @@ -3,6 +3,12 @@ #define MAX_REL_ERR 1.0e-9 #define MAX_ABS_ERR 1.0e-9 +#include + +#ifndef INFINITY +#define INFINITY (DBL_MAX + DBL_MAX) +#endif + static bool double_eq_rel(double a, double b, double max_rel_err, double max_abs_err) { diff --git a/memory/jemalloc/src/test/unit/mq.c b/memory/jemalloc/src/test/unit/mq.c index f57e96af1cb4..bde2a480b6bf 100644 --- a/memory/jemalloc/src/test/unit/mq.c +++ b/memory/jemalloc/src/test/unit/mq.c @@ -54,7 +54,7 @@ thd_sender_start(void *arg) mq_msg_t *msg; void *p; p = mallocx(sizeof(mq_msg_t), 0); - assert_ptr_not_null(p, "Unexpected allocm() failure"); + assert_ptr_not_null(p, "Unexpected mallocx() failure"); msg = (mq_msg_t *)p; mq_put(mq, msg); } @@ -85,6 +85,7 @@ TEST_END int main(void) { + return (test( test_mq_basic, test_mq_threaded)); diff --git a/memory/jemalloc/src/test/unit/prof_accum.c b/memory/jemalloc/src/test/unit/prof_accum.c index 050a8a7ee5d0..fd229e0fd279 100644 --- a/memory/jemalloc/src/test/unit/prof_accum.c +++ b/memory/jemalloc/src/test/unit/prof_accum.c @@ -1,4 +1,9 @@ -#include "prof_accum.h" +#include "test/jemalloc_test.h" + +#define NTHREADS 4 +#define NALLOCS_PER_THREAD 50 +#define DUMP_INTERVAL 1 +#define BT_COUNT_CHECK_INTERVAL 5 #ifdef JEMALLOC_PROF const char *malloc_conf = @@ -20,7 +25,7 @@ static void * alloc_from_permuted_backtrace(unsigned thd_ind, unsigned iteration) { - return (alloc_0(thd_ind*NALLOCS_PER_THREAD + iteration)); + return (btalloc(1, thd_ind*NALLOCS_PER_THREAD + iteration)); } static void * diff --git a/memory/jemalloc/src/test/unit/prof_accum.h b/memory/jemalloc/src/test/unit/prof_accum.h deleted file mode 100644 index 109d86b598dd..000000000000 --- a/memory/jemalloc/src/test/unit/prof_accum.h +++ /dev/null @@ -1,35 +0,0 @@ -#include "test/jemalloc_test.h" - -#define NTHREADS 4 -#define NALLOCS_PER_THREAD 50 -#define DUMP_INTERVAL 1 -#define BT_COUNT_CHECK_INTERVAL 5 - -#define alloc_n_proto(n) \ -void *alloc_##n(unsigned bits); -alloc_n_proto(0) -alloc_n_proto(1) - -#define alloc_n_gen(n) \ -void * \ -alloc_##n(unsigned bits) \ -{ \ - void *p; \ - \ - if (bits == 0) \ - p = mallocx(1, 0); \ - else { \ - switch (bits & 0x1U) { \ - case 0: \ - p = (alloc_0(bits >> 1)); \ - break; \ - case 1: \ - p = (alloc_1(bits >> 1)); \ - break; \ - default: not_reached(); \ - } \ - } \ - /* Intentionally sabotage tail call optimization. */ \ - assert_ptr_not_null(p, "Unexpected mallocx() failure"); \ - return (p); \ -} diff --git a/memory/jemalloc/src/test/unit/prof_accum_a.c b/memory/jemalloc/src/test/unit/prof_accum_a.c deleted file mode 100644 index 42ad521d8dfe..000000000000 --- a/memory/jemalloc/src/test/unit/prof_accum_a.c +++ /dev/null @@ -1,3 +0,0 @@ -#include "prof_accum.h" - -alloc_n_gen(0) diff --git a/memory/jemalloc/src/test/unit/prof_accum_b.c b/memory/jemalloc/src/test/unit/prof_accum_b.c deleted file mode 100644 index 60d9dab6a8e9..000000000000 --- a/memory/jemalloc/src/test/unit/prof_accum_b.c +++ /dev/null @@ -1,3 +0,0 @@ -#include "prof_accum.h" - -alloc_n_gen(1) diff --git a/memory/jemalloc/src/test/unit/prof_active.c b/memory/jemalloc/src/test/unit/prof_active.c new file mode 100644 index 000000000000..814909572925 --- /dev/null +++ b/memory/jemalloc/src/test/unit/prof_active.c @@ -0,0 +1,136 @@ +#include "test/jemalloc_test.h" + +#ifdef JEMALLOC_PROF +const char *malloc_conf = + "prof:true,prof_thread_active_init:false,lg_prof_sample:0"; +#endif + +static void +mallctl_bool_get(const char *name, bool expected, const char *func, int line) +{ + bool old; + size_t sz; + + sz = sizeof(old); + assert_d_eq(mallctl(name, &old, &sz, NULL, 0), 0, + "%s():%d: Unexpected mallctl failure reading %s", func, line, name); + assert_b_eq(old, expected, "%s():%d: Unexpected %s value", func, line, + name); +} + +static void +mallctl_bool_set(const char *name, bool old_expected, bool val_new, + const char *func, int line) +{ + bool old; + size_t sz; + + sz = sizeof(old); + assert_d_eq(mallctl(name, &old, &sz, &val_new, sizeof(val_new)), 0, + "%s():%d: Unexpected mallctl failure reading/writing %s", func, + line, name); + assert_b_eq(old, old_expected, "%s():%d: Unexpected %s value", func, + line, name); +} + +static void +mallctl_prof_active_get_impl(bool prof_active_old_expected, const char *func, + int line) +{ + + mallctl_bool_get("prof.active", prof_active_old_expected, func, line); +} +#define mallctl_prof_active_get(a) \ + mallctl_prof_active_get_impl(a, __func__, __LINE__) + +static void +mallctl_prof_active_set_impl(bool prof_active_old_expected, + bool prof_active_new, const char *func, int line) +{ + + mallctl_bool_set("prof.active", prof_active_old_expected, + prof_active_new, func, line); +} +#define mallctl_prof_active_set(a, b) \ + mallctl_prof_active_set_impl(a, b, __func__, __LINE__) + +static void +mallctl_thread_prof_active_get_impl(bool thread_prof_active_old_expected, + const char *func, int line) +{ + + mallctl_bool_get("thread.prof.active", thread_prof_active_old_expected, + func, line); +} +#define mallctl_thread_prof_active_get(a) \ + mallctl_thread_prof_active_get_impl(a, __func__, __LINE__) + +static void +mallctl_thread_prof_active_set_impl(bool thread_prof_active_old_expected, + bool thread_prof_active_new, const char *func, int line) +{ + + mallctl_bool_set("thread.prof.active", thread_prof_active_old_expected, + thread_prof_active_new, func, line); +} +#define mallctl_thread_prof_active_set(a, b) \ + mallctl_thread_prof_active_set_impl(a, b, __func__, __LINE__) + +static void +prof_sampling_probe_impl(bool expect_sample, const char *func, int line) +{ + void *p; + size_t expected_backtraces = expect_sample ? 1 : 0; + + assert_zu_eq(prof_bt_count(), 0, "%s():%d: Expected 0 backtraces", func, + line); + p = mallocx(1, 0); + assert_ptr_not_null(p, "Unexpected mallocx() failure"); + assert_zu_eq(prof_bt_count(), expected_backtraces, + "%s():%d: Unexpected backtrace count", func, line); + dallocx(p, 0); +} +#define prof_sampling_probe(a) \ + prof_sampling_probe_impl(a, __func__, __LINE__) + +TEST_BEGIN(test_prof_active) +{ + + test_skip_if(!config_prof); + + mallctl_prof_active_get(true); + mallctl_thread_prof_active_get(false); + + mallctl_prof_active_set(true, true); + mallctl_thread_prof_active_set(false, false); + /* prof.active, !thread.prof.active. */ + prof_sampling_probe(false); + + mallctl_prof_active_set(true, false); + mallctl_thread_prof_active_set(false, false); + /* !prof.active, !thread.prof.active. */ + prof_sampling_probe(false); + + mallctl_prof_active_set(false, false); + mallctl_thread_prof_active_set(false, true); + /* !prof.active, thread.prof.active. */ + prof_sampling_probe(false); + + mallctl_prof_active_set(false, true); + mallctl_thread_prof_active_set(true, true); + /* prof.active, thread.prof.active. */ + prof_sampling_probe(true); + + /* Restore settings. */ + mallctl_prof_active_set(true, true); + mallctl_thread_prof_active_set(true, false); +} +TEST_END + +int +main(void) +{ + + return (test( + test_prof_active)); +} diff --git a/memory/jemalloc/src/test/unit/prof_reset.c b/memory/jemalloc/src/test/unit/prof_reset.c new file mode 100644 index 000000000000..3af1964294a9 --- /dev/null +++ b/memory/jemalloc/src/test/unit/prof_reset.c @@ -0,0 +1,236 @@ +#include "test/jemalloc_test.h" + +#ifdef JEMALLOC_PROF +const char *malloc_conf = + "prof:true,prof_active:false,lg_prof_sample:0"; +#endif + +static int +prof_dump_open_intercept(bool propagate_err, const char *filename) +{ + int fd; + + fd = open("/dev/null", O_WRONLY); + assert_d_ne(fd, -1, "Unexpected open() failure"); + + return (fd); +} + +TEST_BEGIN(test_prof_reset_basic) +{ + size_t lg_prof_sample_orig, lg_prof_sample, lg_prof_sample_next; + size_t sz; + unsigned i; + + test_skip_if(!config_prof); + + sz = sizeof(size_t); + assert_d_eq(mallctl("opt.lg_prof_sample", &lg_prof_sample_orig, &sz, + NULL, 0), 0, + "Unexpected mallctl failure while reading profiling sample rate"); + assert_zu_eq(lg_prof_sample_orig, 0, + "Unexpected profiling sample rate"); + sz = sizeof(size_t); + assert_d_eq(mallctl("prof.lg_sample", &lg_prof_sample, &sz, NULL, 0), 0, + "Unexpected mallctl failure while reading profiling sample rate"); + assert_zu_eq(lg_prof_sample_orig, lg_prof_sample, + "Unexpected disagreement between \"opt.lg_prof_sample\" and " + "\"prof.lg_sample\""); + + /* Test simple resets. */ + for (i = 0; i < 2; i++) { + assert_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0), 0, + "Unexpected mallctl failure while resetting profile data"); + sz = sizeof(size_t); + assert_d_eq(mallctl("prof.lg_sample", &lg_prof_sample, &sz, + NULL, 0), 0, "Unexpected mallctl failure while reading " + "profiling sample rate"); + assert_zu_eq(lg_prof_sample_orig, lg_prof_sample, + "Unexpected profile sample rate change"); + } + + /* Test resets with prof.lg_sample changes. */ + lg_prof_sample_next = 1; + for (i = 0; i < 2; i++) { + assert_d_eq(mallctl("prof.reset", NULL, NULL, + &lg_prof_sample_next, sizeof(size_t)), 0, + "Unexpected mallctl failure while resetting profile data"); + sz = sizeof(size_t); + assert_d_eq(mallctl("prof.lg_sample", &lg_prof_sample, &sz, + NULL, 0), 0, "Unexpected mallctl failure while reading " + "profiling sample rate"); + assert_zu_eq(lg_prof_sample, lg_prof_sample_next, + "Expected profile sample rate change"); + lg_prof_sample_next = lg_prof_sample_orig; + } + + /* Make sure the test code restored prof.lg_sample. */ + sz = sizeof(size_t); + assert_d_eq(mallctl("prof.lg_sample", &lg_prof_sample, &sz, NULL, 0), 0, + "Unexpected mallctl failure while reading profiling sample rate"); + assert_zu_eq(lg_prof_sample_orig, lg_prof_sample, + "Unexpected disagreement between \"opt.lg_prof_sample\" and " + "\"prof.lg_sample\""); +} +TEST_END + +bool prof_dump_header_intercepted = false; +prof_cnt_t cnt_all_copy = {0, 0, 0, 0}; +static bool +prof_dump_header_intercept(bool propagate_err, const prof_cnt_t *cnt_all) +{ + + prof_dump_header_intercepted = true; + memcpy(&cnt_all_copy, cnt_all, sizeof(prof_cnt_t)); + + return (false); +} + +TEST_BEGIN(test_prof_reset_cleanup) +{ + bool active; + void *p; + prof_dump_header_t *prof_dump_header_orig; + + test_skip_if(!config_prof); + + active = true; + assert_d_eq(mallctl("prof.active", NULL, NULL, &active, sizeof(active)), + 0, "Unexpected mallctl failure while activating profiling"); + + assert_zu_eq(prof_bt_count(), 0, "Expected 0 backtraces"); + p = mallocx(1, 0); + assert_ptr_not_null(p, "Unexpected mallocx() failure"); + assert_zu_eq(prof_bt_count(), 1, "Expected 1 backtrace"); + + prof_dump_header_orig = prof_dump_header; + prof_dump_header = prof_dump_header_intercept; + assert_false(prof_dump_header_intercepted, "Unexpected intercept"); + + assert_d_eq(mallctl("prof.dump", NULL, NULL, NULL, 0), + 0, "Unexpected error while dumping heap profile"); + assert_true(prof_dump_header_intercepted, "Expected intercept"); + assert_u64_eq(cnt_all_copy.curobjs, 1, "Expected 1 allocation"); + + assert_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0), 0, + "Unexpected error while resetting heap profile data"); + assert_d_eq(mallctl("prof.dump", NULL, NULL, NULL, 0), + 0, "Unexpected error while dumping heap profile"); + assert_u64_eq(cnt_all_copy.curobjs, 0, "Expected 0 allocations"); + assert_zu_eq(prof_bt_count(), 1, "Expected 1 backtrace"); + + prof_dump_header = prof_dump_header_orig; + + dallocx(p, 0); + assert_zu_eq(prof_bt_count(), 0, "Expected 0 backtraces"); + + active = false; + assert_d_eq(mallctl("prof.active", NULL, NULL, &active, sizeof(active)), + 0, "Unexpected mallctl failure while deactivating profiling"); +} +TEST_END + +#define NTHREADS 4 +#define NALLOCS_PER_THREAD (1U << 13) +#define OBJ_RING_BUF_COUNT 1531 +#define RESET_INTERVAL (1U << 10) +#define DUMP_INTERVAL 3677 +static void * +thd_start(void *varg) +{ + unsigned thd_ind = *(unsigned *)varg; + unsigned i; + void *objs[OBJ_RING_BUF_COUNT]; + + memset(objs, 0, sizeof(objs)); + + for (i = 0; i < NALLOCS_PER_THREAD; i++) { + if (i % RESET_INTERVAL == 0) { + assert_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0), + 0, "Unexpected error while resetting heap profile " + "data"); + } + + if (i % DUMP_INTERVAL == 0) { + assert_d_eq(mallctl("prof.dump", NULL, NULL, NULL, 0), + 0, "Unexpected error while dumping heap profile"); + } + + { + void **pp = &objs[i % OBJ_RING_BUF_COUNT]; + if (*pp != NULL) { + dallocx(*pp, 0); + *pp = NULL; + } + *pp = btalloc(1, thd_ind*NALLOCS_PER_THREAD + i); + assert_ptr_not_null(*pp, + "Unexpected btalloc() failure"); + } + } + + /* Clean up any remaining objects. */ + for (i = 0; i < OBJ_RING_BUF_COUNT; i++) { + void **pp = &objs[i % OBJ_RING_BUF_COUNT]; + if (*pp != NULL) { + dallocx(*pp, 0); + *pp = NULL; + } + } + + return (NULL); +} + +TEST_BEGIN(test_prof_reset) +{ + bool active; + thd_t thds[NTHREADS]; + unsigned thd_args[NTHREADS]; + unsigned i; + size_t bt_count, tdata_count; + + test_skip_if(!config_prof); + + bt_count = prof_bt_count(); + assert_zu_eq(bt_count, 0, + "Unexpected pre-existing tdata structures"); + tdata_count = prof_tdata_count(); + + active = true; + assert_d_eq(mallctl("prof.active", NULL, NULL, &active, sizeof(active)), + 0, "Unexpected mallctl failure while activating profiling"); + + for (i = 0; i < NTHREADS; i++) { + thd_args[i] = i; + thd_create(&thds[i], thd_start, (void *)&thd_args[i]); + } + for (i = 0; i < NTHREADS; i++) + thd_join(thds[i], NULL); + + assert_zu_eq(prof_bt_count(), bt_count, + "Unexpected bactrace count change"); + assert_zu_eq(prof_tdata_count(), tdata_count, + "Unexpected remaining tdata structures"); + + active = false; + assert_d_eq(mallctl("prof.active", NULL, NULL, &active, sizeof(active)), + 0, "Unexpected mallctl failure while deactivating profiling"); +} +TEST_END +#undef NTHREADS +#undef NALLOCS_PER_THREAD +#undef OBJ_RING_BUF_COUNT +#undef RESET_INTERVAL +#undef DUMP_INTERVAL + +int +main(void) +{ + + /* Intercept dumping prior to running any tests. */ + prof_dump_open = prof_dump_open_intercept; + + return (test( + test_prof_reset_basic, + test_prof_reset_cleanup, + test_prof_reset)); +} diff --git a/memory/jemalloc/src/test/unit/prof_thread_name.c b/memory/jemalloc/src/test/unit/prof_thread_name.c new file mode 100644 index 000000000000..f501158d7de0 --- /dev/null +++ b/memory/jemalloc/src/test/unit/prof_thread_name.c @@ -0,0 +1,129 @@ +#include "test/jemalloc_test.h" + +#ifdef JEMALLOC_PROF +const char *malloc_conf = "prof:true,prof_active:false"; +#endif + +static void +mallctl_thread_name_get_impl(const char *thread_name_expected, const char *func, + int line) +{ + const char *thread_name_old; + size_t sz; + + sz = sizeof(thread_name_old); + assert_d_eq(mallctl("thread.prof.name", &thread_name_old, &sz, NULL, 0), + 0, "%s():%d: Unexpected mallctl failure reading thread.prof.name", + func, line); + assert_str_eq(thread_name_old, thread_name_expected, + "%s():%d: Unexpected thread.prof.name value", func, line); +} +#define mallctl_thread_name_get(a) \ + mallctl_thread_name_get_impl(a, __func__, __LINE__) + +static void +mallctl_thread_name_set_impl(const char *thread_name, const char *func, + int line) +{ + + assert_d_eq(mallctl("thread.prof.name", NULL, NULL, &thread_name, + sizeof(thread_name)), 0, + "%s():%d: Unexpected mallctl failure reading thread.prof.name", + func, line); + mallctl_thread_name_get_impl(thread_name, func, line); +} +#define mallctl_thread_name_set(a) \ + mallctl_thread_name_set_impl(a, __func__, __LINE__) + +TEST_BEGIN(test_prof_thread_name_validation) +{ + const char *thread_name; + + test_skip_if(!config_prof); + + mallctl_thread_name_get(""); + mallctl_thread_name_set("hi there"); + + /* NULL input shouldn't be allowed. */ + thread_name = NULL; + assert_d_eq(mallctl("thread.prof.name", NULL, NULL, &thread_name, + sizeof(thread_name)), EFAULT, + "Unexpected mallctl result writing \"%s\" to thread.prof.name", + thread_name); + + /* '\n' shouldn't be allowed. */ + thread_name = "hi\nthere"; + assert_d_eq(mallctl("thread.prof.name", NULL, NULL, &thread_name, + sizeof(thread_name)), EFAULT, + "Unexpected mallctl result writing \"%s\" to thread.prof.name", + thread_name); + + /* Simultaneous read/write shouldn't be allowed. */ + { + const char *thread_name_old; + size_t sz; + + sz = sizeof(thread_name_old); + assert_d_eq(mallctl("thread.prof.name", &thread_name_old, &sz, + &thread_name, sizeof(thread_name)), EPERM, + "Unexpected mallctl result writing \"%s\" to " + "thread.prof.name", thread_name); + } + + mallctl_thread_name_set(""); +} +TEST_END + +#define NTHREADS 4 +#define NRESET 25 +static void * +thd_start(void *varg) +{ + unsigned thd_ind = *(unsigned *)varg; + char thread_name[16] = ""; + unsigned i; + + malloc_snprintf(thread_name, sizeof(thread_name), "thread %u", thd_ind); + + mallctl_thread_name_get(""); + mallctl_thread_name_set(thread_name); + + for (i = 0; i < NRESET; i++) { + assert_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0), 0, + "Unexpected error while resetting heap profile data"); + mallctl_thread_name_get(thread_name); + } + + mallctl_thread_name_set(thread_name); + mallctl_thread_name_set(""); + + return (NULL); +} + +TEST_BEGIN(test_prof_thread_name_threaded) +{ + thd_t thds[NTHREADS]; + unsigned thd_args[NTHREADS]; + unsigned i; + + test_skip_if(!config_prof); + + for (i = 0; i < NTHREADS; i++) { + thd_args[i] = i; + thd_create(&thds[i], thd_start, (void *)&thd_args[i]); + } + for (i = 0; i < NTHREADS; i++) + thd_join(thds[i], NULL); +} +TEST_END +#undef NTHREADS +#undef NRESET + +int +main(void) +{ + + return (test( + test_prof_thread_name_validation, + test_prof_thread_name_threaded)); +} diff --git a/memory/jemalloc/src/test/unit/rb.c b/memory/jemalloc/src/test/unit/rb.c index b737485a7c6c..b38eb0e33f3b 100644 --- a/memory/jemalloc/src/test/unit/rb.c +++ b/memory/jemalloc/src/test/unit/rb.c @@ -5,7 +5,7 @@ for (rbp_bh_t = (a_rbt)->rbt_root, (r_height) = 0; \ rbp_bh_t != &(a_rbt)->rbt_nil; \ rbp_bh_t = rbtn_left_get(a_type, a_field, rbp_bh_t)) { \ - if (rbtn_red_get(a_type, a_field, rbp_bh_t) == false) { \ + if (!rbtn_red_get(a_type, a_field, rbp_bh_t)) { \ (r_height)++; \ } \ } \ @@ -49,6 +49,7 @@ TEST_BEGIN(test_rb_empty) tree_new(&tree); + assert_true(tree_empty(&tree), "Tree should be empty"); assert_ptr_null(tree_first(&tree), "Unexpected node"); assert_ptr_null(tree_last(&tree), "Unexpected node"); @@ -74,7 +75,7 @@ tree_recurse(node_t *node, unsigned black_height, unsigned black_depth, node_t *left_node = rbtn_left_get(node_t, link, node); node_t *right_node = rbtn_right_get(node_t, link, node); - if (rbtn_red_get(node_t, link, node) == false) + if (!rbtn_red_get(node_t, link, node)) black_depth++; /* Red nodes must be interleaved with black nodes. */ @@ -265,6 +266,8 @@ TEST_BEGIN(test_rb_random) assert_u_eq(tree_iterate_reverse(&tree), k+1, "Unexpected node iteration count"); + assert_false(tree_empty(&tree), + "Tree should not be empty"); assert_ptr_not_null(tree_first(&tree), "Tree should not be empty"); assert_ptr_not_null(tree_last(&tree), diff --git a/memory/jemalloc/src/test/unit/rtree.c b/memory/jemalloc/src/test/unit/rtree.c index 5463055fe92a..77a947d60fdf 100644 --- a/memory/jemalloc/src/test/unit/rtree.c +++ b/memory/jemalloc/src/test/unit/rtree.c @@ -5,7 +5,7 @@ TEST_BEGIN(test_rtree_get_empty) unsigned i; for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) { - rtree_t *rtree = rtree_new(i, imalloc, idalloc); + rtree_t *rtree = rtree_new(i, malloc, free); assert_u_eq(rtree_get(rtree, 0), 0, "rtree_get() should return NULL for empty tree"); rtree_delete(rtree); @@ -18,7 +18,7 @@ TEST_BEGIN(test_rtree_extrema) unsigned i; for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) { - rtree_t *rtree = rtree_new(i, imalloc, idalloc); + rtree_t *rtree = rtree_new(i, malloc, free); rtree_set(rtree, 0, 1); assert_u_eq(rtree_get(rtree, 0), 1, @@ -40,7 +40,7 @@ TEST_BEGIN(test_rtree_bits) for (i = 1; i < (sizeof(uintptr_t) << 3); i++) { uintptr_t keys[] = {0, 1, (((uintptr_t)1) << (sizeof(uintptr_t)*8-i)) - 1}; - rtree_t *rtree = rtree_new(i, imalloc, idalloc); + rtree_t *rtree = rtree_new(i, malloc, free); for (j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) { rtree_set(rtree, keys[j], 1); @@ -73,7 +73,7 @@ TEST_BEGIN(test_rtree_random) sfmt = init_gen_rand(SEED); for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) { - rtree_t *rtree = rtree_new(i, imalloc, idalloc); + rtree_t *rtree = rtree_new(i, malloc, free); uintptr_t keys[NSET]; unsigned j; diff --git a/memory/jemalloc/src/test/unit/stats.c b/memory/jemalloc/src/test/unit/stats.c index 03a55c7fdce9..946e737009ae 100644 --- a/memory/jemalloc/src/test/unit/stats.c +++ b/memory/jemalloc/src/test/unit/stats.c @@ -60,7 +60,7 @@ TEST_BEGIN(test_stats_huge) void *p; uint64_t epoch; size_t allocated; - uint64_t nmalloc, ndalloc; + uint64_t nmalloc, ndalloc, nrequests; size_t sz; int expected = config_stats ? 0 : ENOENT; @@ -71,19 +71,23 @@ TEST_BEGIN(test_stats_huge) "Unexpected mallctl() failure"); sz = sizeof(size_t); - assert_d_eq(mallctl("stats.huge.allocated", &allocated, &sz, NULL, 0), - expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.huge.allocated", &allocated, &sz, + NULL, 0), expected, "Unexpected mallctl() result"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.huge.nmalloc", &nmalloc, &sz, NULL, 0), - expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.huge.ndalloc", &ndalloc, &sz, NULL, 0), - expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.huge.nmalloc", &nmalloc, &sz, NULL, + 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.huge.ndalloc", &ndalloc, &sz, NULL, + 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.huge.nrequests", &nrequests, &sz, + NULL, 0), expected, "Unexpected mallctl() result"); if (config_stats) { assert_zu_gt(allocated, 0, "allocated should be greater than zero"); assert_u64_ge(nmalloc, ndalloc, "nmalloc should be at least as large as ndalloc"); + assert_u64_le(nmalloc, nrequests, + "nmalloc should no larger than nrequests"); } dallocx(p, 0); @@ -93,7 +97,7 @@ TEST_END TEST_BEGIN(test_stats_arenas_summary) { unsigned arena; - void *small, *large; + void *little, *large, *huge; uint64_t epoch; size_t sz; int expected = config_stats ? 0 : ENOENT; @@ -104,10 +108,12 @@ TEST_BEGIN(test_stats_arenas_summary) assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)), 0, "Unexpected mallctl() failure"); - small = mallocx(SMALL_MAXCLASS, 0); - assert_ptr_not_null(small, "Unexpected mallocx() failure"); + little = mallocx(SMALL_MAXCLASS, 0); + assert_ptr_not_null(little, "Unexpected mallocx() failure"); large = mallocx(arena_maxclass, 0); assert_ptr_not_null(large, "Unexpected mallocx() failure"); + huge = mallocx(chunksize, 0); + assert_ptr_not_null(huge, "Unexpected mallocx() failure"); assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl() failure"); @@ -133,8 +139,9 @@ TEST_BEGIN(test_stats_arenas_summary) "nmadvise should be no greater than purged"); } - dallocx(small, 0); + dallocx(little, 0); dallocx(large, 0); + dallocx(huge, 0); } TEST_END @@ -247,11 +254,51 @@ TEST_BEGIN(test_stats_arenas_large) } TEST_END +TEST_BEGIN(test_stats_arenas_huge) +{ + unsigned arena; + void *p; + size_t sz, allocated; + uint64_t epoch, nmalloc, ndalloc; + int expected = config_stats ? 0 : ENOENT; + + arena = 0; + assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)), + 0, "Unexpected mallctl() failure"); + + p = mallocx(chunksize, 0); + assert_ptr_not_null(p, "Unexpected mallocx() failure"); + + assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, + "Unexpected mallctl() failure"); + + sz = sizeof(size_t); + assert_d_eq(mallctl("stats.arenas.0.huge.allocated", &allocated, &sz, + NULL, 0), expected, "Unexpected mallctl() result"); + sz = sizeof(uint64_t); + assert_d_eq(mallctl("stats.arenas.0.huge.nmalloc", &nmalloc, &sz, + NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.huge.ndalloc", &ndalloc, &sz, + NULL, 0), expected, "Unexpected mallctl() result"); + + if (config_stats) { + assert_zu_gt(allocated, 0, + "allocated should be greater than zero"); + assert_zu_gt(nmalloc, 0, + "nmalloc should be greater than zero"); + assert_zu_ge(nmalloc, ndalloc, + "nmalloc should be at least as large as ndalloc"); + } + + dallocx(p, 0); +} +TEST_END + TEST_BEGIN(test_stats_arenas_bins) { unsigned arena; void *p; - size_t sz, allocated, curruns; + size_t sz, curruns, curregs; uint64_t epoch, nmalloc, ndalloc, nrequests, nfills, nflushes; uint64_t nruns, nreruns; int expected = config_stats ? 0 : ENOENT; @@ -269,9 +316,6 @@ TEST_BEGIN(test_stats_arenas_bins) assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, "Unexpected mallctl() failure"); - sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.bins.0.allocated", &allocated, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); sz = sizeof(uint64_t); assert_d_eq(mallctl("stats.arenas.0.bins.0.nmalloc", &nmalloc, &sz, NULL, 0), expected, "Unexpected mallctl() result"); @@ -279,7 +323,11 @@ TEST_BEGIN(test_stats_arenas_bins) NULL, 0), expected, "Unexpected mallctl() result"); assert_d_eq(mallctl("stats.arenas.0.bins.0.nrequests", &nrequests, &sz, NULL, 0), expected, "Unexpected mallctl() result"); + sz = sizeof(size_t); + assert_d_eq(mallctl("stats.arenas.0.bins.0.curregs", &curregs, &sz, + NULL, 0), expected, "Unexpected mallctl() result"); + sz = sizeof(uint64_t); assert_d_eq(mallctl("stats.arenas.0.bins.0.nfills", &nfills, &sz, NULL, 0), config_tcache ? expected : ENOENT, "Unexpected mallctl() result"); @@ -296,14 +344,14 @@ TEST_BEGIN(test_stats_arenas_bins) NULL, 0), expected, "Unexpected mallctl() result"); if (config_stats) { - assert_zu_gt(allocated, 0, - "allocated should be greater than zero"); assert_u64_gt(nmalloc, 0, "nmalloc should be greater than zero"); assert_u64_ge(nmalloc, ndalloc, "nmalloc should be at least as large as ndalloc"); assert_u64_gt(nrequests, 0, "nrequests should be greater than zero"); + assert_zu_gt(curregs, 0, + "allocated should be greater than zero"); if (config_tcache) { assert_u64_gt(nfills, 0, "At least one fill should have occurred"); @@ -332,7 +380,7 @@ TEST_BEGIN(test_stats_arenas_lruns) assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)), 0, "Unexpected mallctl() failure"); - p = mallocx(SMALL_MAXCLASS+1, 0); + p = mallocx(LARGE_MINCLASS, 0); assert_ptr_not_null(p, "Unexpected mallocx() failure"); assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, @@ -364,6 +412,46 @@ TEST_BEGIN(test_stats_arenas_lruns) } TEST_END +TEST_BEGIN(test_stats_arenas_hchunks) +{ + unsigned arena; + void *p; + uint64_t epoch, nmalloc, ndalloc; + size_t curhchunks, sz; + int expected = config_stats ? 0 : ENOENT; + + arena = 0; + assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)), + 0, "Unexpected mallctl() failure"); + + p = mallocx(chunksize, 0); + assert_ptr_not_null(p, "Unexpected mallocx() failure"); + + assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, + "Unexpected mallctl() failure"); + + sz = sizeof(uint64_t); + assert_d_eq(mallctl("stats.arenas.0.hchunks.0.nmalloc", &nmalloc, &sz, + NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.hchunks.0.ndalloc", &ndalloc, &sz, + NULL, 0), expected, "Unexpected mallctl() result"); + sz = sizeof(size_t); + assert_d_eq(mallctl("stats.arenas.0.hchunks.0.curhchunks", &curhchunks, + &sz, NULL, 0), expected, "Unexpected mallctl() result"); + + if (config_stats) { + assert_u64_gt(nmalloc, 0, + "nmalloc should be greater than zero"); + assert_u64_ge(nmalloc, ndalloc, + "nmalloc should be at least as large as ndalloc"); + assert_u64_gt(curhchunks, 0, + "At least one chunk should be currently allocated"); + } + + dallocx(p, 0); +} +TEST_END + int main(void) { @@ -375,6 +463,8 @@ main(void) test_stats_arenas_summary, test_stats_arenas_small, test_stats_arenas_large, + test_stats_arenas_huge, test_stats_arenas_bins, - test_stats_arenas_lruns)); + test_stats_arenas_lruns, + test_stats_arenas_hchunks)); } diff --git a/memory/jemalloc/src/test/unit/tsd.c b/memory/jemalloc/src/test/unit/tsd.c index f421c1a3cff7..b031c484e090 100644 --- a/memory/jemalloc/src/test/unit/tsd.c +++ b/memory/jemalloc/src/test/unit/tsd.c @@ -6,21 +6,51 @@ typedef unsigned int data_t; static bool data_cleanup_executed; +malloc_tsd_types(data_, data_t) +malloc_tsd_protos(, data_, data_t) + void data_cleanup(void *arg) { data_t *data = (data_t *)arg; - assert_x_eq(*data, THREAD_DATA, - "Argument passed into cleanup function should match tsd value"); + if (!data_cleanup_executed) { + assert_x_eq(*data, THREAD_DATA, + "Argument passed into cleanup function should match tsd " + "value"); + } data_cleanup_executed = true; + + /* + * Allocate during cleanup for two rounds, in order to assure that + * jemalloc's internal tsd reinitialization happens. + */ + switch (*data) { + case THREAD_DATA: + *data = 1; + data_tsd_set(data); + break; + case 1: + *data = 2; + data_tsd_set(data); + break; + case 2: + return; + default: + not_reached(); + } + + { + void *p = mallocx(1, 0); + assert_ptr_not_null(p, "Unexpeced mallocx() failure"); + dallocx(p, 0); + } } -malloc_tsd_protos(, data, data_t) -malloc_tsd_externs(data, data_t) +malloc_tsd_externs(data_, data_t) #define DATA_INIT 0x12345678 -malloc_tsd_data(, data, data_t, DATA_INIT) -malloc_tsd_funcs(, data, data_t, DATA_INIT, data_cleanup) +malloc_tsd_data(, data_, data_t, DATA_INIT) +malloc_tsd_funcs(, data_, data_t, DATA_INIT, data_cleanup) static void * thd_start(void *arg) diff --git a/memory/jemalloc/src/test/unit/util.c b/memory/jemalloc/src/test/unit/util.c index dc3cfe8a9db1..8ab39a458193 100644 --- a/memory/jemalloc/src/test/unit/util.c +++ b/memory/jemalloc/src/test/unit/util.c @@ -52,8 +52,8 @@ TEST_BEGIN(test_malloc_strtoumax) const char *expected_errno_name; uintmax_t expected_x; }; -#define ERR(e) e, #e -#define UMAX(x) ((uintmax_t)x##ULL) +#define ERR(e) e, #e +#define KUMAX(x) ((uintmax_t)x##ULL) struct test_s tests[] = { {"0", "0", -1, ERR(EINVAL), UINTMAX_MAX}, {"0", "0", 1, ERR(EINVAL), UINTMAX_MAX}, @@ -64,51 +64,51 @@ TEST_BEGIN(test_malloc_strtoumax) {"++3", "++3", 0, ERR(EINVAL), UINTMAX_MAX}, {"-", "-", 0, ERR(EINVAL), UINTMAX_MAX}, - {"42", "", 0, ERR(0), UMAX(42)}, - {"+42", "", 0, ERR(0), UMAX(42)}, - {"-42", "", 0, ERR(0), UMAX(-42)}, - {"042", "", 0, ERR(0), UMAX(042)}, - {"+042", "", 0, ERR(0), UMAX(042)}, - {"-042", "", 0, ERR(0), UMAX(-042)}, - {"0x42", "", 0, ERR(0), UMAX(0x42)}, - {"+0x42", "", 0, ERR(0), UMAX(0x42)}, - {"-0x42", "", 0, ERR(0), UMAX(-0x42)}, + {"42", "", 0, ERR(0), KUMAX(42)}, + {"+42", "", 0, ERR(0), KUMAX(42)}, + {"-42", "", 0, ERR(0), KUMAX(-42)}, + {"042", "", 0, ERR(0), KUMAX(042)}, + {"+042", "", 0, ERR(0), KUMAX(042)}, + {"-042", "", 0, ERR(0), KUMAX(-042)}, + {"0x42", "", 0, ERR(0), KUMAX(0x42)}, + {"+0x42", "", 0, ERR(0), KUMAX(0x42)}, + {"-0x42", "", 0, ERR(0), KUMAX(-0x42)}, - {"0", "", 0, ERR(0), UMAX(0)}, - {"1", "", 0, ERR(0), UMAX(1)}, + {"0", "", 0, ERR(0), KUMAX(0)}, + {"1", "", 0, ERR(0), KUMAX(1)}, - {"42", "", 0, ERR(0), UMAX(42)}, - {" 42", "", 0, ERR(0), UMAX(42)}, - {"42 ", " ", 0, ERR(0), UMAX(42)}, - {"0x", "x", 0, ERR(0), UMAX(0)}, - {"42x", "x", 0, ERR(0), UMAX(42)}, + {"42", "", 0, ERR(0), KUMAX(42)}, + {" 42", "", 0, ERR(0), KUMAX(42)}, + {"42 ", " ", 0, ERR(0), KUMAX(42)}, + {"0x", "x", 0, ERR(0), KUMAX(0)}, + {"42x", "x", 0, ERR(0), KUMAX(42)}, - {"07", "", 0, ERR(0), UMAX(7)}, - {"010", "", 0, ERR(0), UMAX(8)}, - {"08", "8", 0, ERR(0), UMAX(0)}, - {"0_", "_", 0, ERR(0), UMAX(0)}, + {"07", "", 0, ERR(0), KUMAX(7)}, + {"010", "", 0, ERR(0), KUMAX(8)}, + {"08", "8", 0, ERR(0), KUMAX(0)}, + {"0_", "_", 0, ERR(0), KUMAX(0)}, - {"0x", "x", 0, ERR(0), UMAX(0)}, - {"0X", "X", 0, ERR(0), UMAX(0)}, - {"0xg", "xg", 0, ERR(0), UMAX(0)}, - {"0XA", "", 0, ERR(0), UMAX(10)}, + {"0x", "x", 0, ERR(0), KUMAX(0)}, + {"0X", "X", 0, ERR(0), KUMAX(0)}, + {"0xg", "xg", 0, ERR(0), KUMAX(0)}, + {"0XA", "", 0, ERR(0), KUMAX(10)}, - {"010", "", 10, ERR(0), UMAX(10)}, - {"0x3", "x3", 10, ERR(0), UMAX(0)}, + {"010", "", 10, ERR(0), KUMAX(10)}, + {"0x3", "x3", 10, ERR(0), KUMAX(0)}, - {"12", "2", 2, ERR(0), UMAX(1)}, - {"78", "8", 8, ERR(0), UMAX(7)}, - {"9a", "a", 10, ERR(0), UMAX(9)}, - {"9A", "A", 10, ERR(0), UMAX(9)}, - {"fg", "g", 16, ERR(0), UMAX(15)}, - {"FG", "G", 16, ERR(0), UMAX(15)}, - {"0xfg", "g", 16, ERR(0), UMAX(15)}, - {"0XFG", "G", 16, ERR(0), UMAX(15)}, - {"z_", "_", 36, ERR(0), UMAX(35)}, - {"Z_", "_", 36, ERR(0), UMAX(35)} + {"12", "2", 2, ERR(0), KUMAX(1)}, + {"78", "8", 8, ERR(0), KUMAX(7)}, + {"9a", "a", 10, ERR(0), KUMAX(9)}, + {"9A", "A", 10, ERR(0), KUMAX(9)}, + {"fg", "g", 16, ERR(0), KUMAX(15)}, + {"FG", "G", 16, ERR(0), KUMAX(15)}, + {"0xfg", "g", 16, ERR(0), KUMAX(15)}, + {"0XFG", "G", 16, ERR(0), KUMAX(15)}, + {"z_", "_", 36, ERR(0), KUMAX(35)}, + {"Z_", "_", 36, ERR(0), KUMAX(35)} }; #undef ERR -#undef UMAX +#undef KUMAX unsigned i; for (i = 0; i < sizeof(tests)/sizeof(struct test_s); i++) { @@ -141,8 +141,8 @@ TEST_BEGIN(test_malloc_snprintf_truncated) char buf[BUFLEN]; int result; size_t len; -#define TEST(expected_str_untruncated, fmt...) do { \ - result = malloc_snprintf(buf, len, fmt); \ +#define TEST(expected_str_untruncated, ...) do { \ + result = malloc_snprintf(buf, len, __VA_ARGS__); \ assert_d_eq(strncmp(buf, expected_str_untruncated, len-1), 0, \ "Unexpected string inequality (\"%s\" vs \"%s\")", \ buf, expected_str_untruncated); \ @@ -173,8 +173,8 @@ TEST_BEGIN(test_malloc_snprintf) #define BUFLEN 128 char buf[BUFLEN]; int result; -#define TEST(expected_str, fmt...) do { \ - result = malloc_snprintf(buf, sizeof(buf), fmt); \ +#define TEST(expected_str, ...) do { \ + result = malloc_snprintf(buf, sizeof(buf), __VA_ARGS__); \ assert_str_eq(buf, expected_str, "Unexpected output"); \ assert_d_eq(result, strlen(expected_str), "Unexpected result"); \ } while (0) diff --git a/memory/jemalloc/update.sh b/memory/jemalloc/update.sh index 1691ce80a1a3..385f436289a6 100755 --- a/memory/jemalloc/update.sh +++ b/memory/jemalloc/update.sh @@ -12,17 +12,9 @@ cd src git checkout "$UPSTREAM_COMMIT" autoconf git describe --long --abbrev=40 > VERSION -rm -rf .git .gitignore autom4te.cache +rm -rf .git .gitignore .gitattributes autom4te.cache .autom4te.cfg -patch -p1 < ../0001-Use-a-configure-test-to-detect-whether-to-use-a-cons.patch -patch -p1 < ../0002-Use-ULL-prefix-instead-of-LLU-for-unsigned-long-long.patch -patch -p1 < ../0003-Don-t-use-msvc_compat-s-C99-headers-with-MSVC-versio.patch -patch -p1 < ../0004-Try-to-use-__builtin_ffsl-if-ffsl-is-unavailable.patch -patch -p1 < ../0005-Check-for-__builtin_ffsl-before-ffsl.patch -patch -p1 < ../0006-Fix-clang-warnings.patch -patch -p1 < ../0007-Ensure-the-default-purgeable-zone-is-after-the-defau.patch -patch -p1 < ../0008-Allow-to-build-with-clang-cl.patch -patch -p1 < ../0009-Remove-srcroot-from-cfghdrs_in-cfgoutputs_in-and-cfg.patch +patch -p1 < ../0001-Dont-overwrite-VERSION-on-a-git-repository.patch cd .. hg addremove -q src diff --git a/memory/jemalloc/upstream.info b/memory/jemalloc/upstream.info index 1ca68d9117fa..dd32cf98c912 100644 --- a/memory/jemalloc/upstream.info +++ b/memory/jemalloc/upstream.info @@ -1,2 +1,2 @@ UPSTREAM_REPO=https://github.com/jemalloc/jemalloc -UPSTREAM_COMMIT=3.6.0 +UPSTREAM_COMMIT=b4acf7300a4ca3423ca36fe227e9bc2e23f25b9f From 8eb3f5f4986c196fd5ca0eca13350b98710a4c00 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Tue, 9 Dec 2014 14:59:11 -0800 Subject: [PATCH 106/130] Bug 1103957 - prevent phase nesting, r=terrence --- js/src/gc/Statistics.cpp | 68 ++++++++++++++++++++++++++-------------- js/src/gc/Statistics.h | 14 ++++++--- js/src/shell/js.cpp | 5 ++- 3 files changed, 58 insertions(+), 29 deletions(-) diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp index da56309c4e40..aeb61835fcd2 100644 --- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -283,6 +283,13 @@ struct PhaseInfo static const Phase PHASE_NO_PARENT = PHASE_LIMIT; +/* + * Note that PHASE_MUTATOR, PHASE_GC_BEGIN, and PHASE_GC_END never have any + * child phases. If beginPhase is called while one of these is active, they + * will automatically be suspended and resumed when the phase stack is next + * empty. Timings for these phases are thus exclusive of any other phase. + */ + static const PhaseInfo phases[] = { { PHASE_MUTATOR, "Mutator Running", PHASE_NO_PARENT }, { PHASE_GC_BEGIN, "Begin Callback", PHASE_NO_PARENT }, @@ -639,11 +646,11 @@ Statistics::Statistics(JSRuntime *rt) fullFormat(false), gcDepth(0), nonincrementalReason(nullptr), - timingMutator(false), timedGCStart(0), preBytes(0), maxPauseInInterval(0), phaseNestingDepth(0), + suspendedPhaseNestingDepth(0), sliceCallback(nullptr) { PodArrayZero(phaseTotals); @@ -833,12 +840,10 @@ Statistics::endSlice() void Statistics::startTimingMutator() { - MOZ_ASSERT(!timingMutator); - // Should only be called from outside of GC MOZ_ASSERT(phaseNestingDepth == 0); + MOZ_ASSERT(suspendedPhaseNestingDepth == 0); - timingMutator = true; timedGCTime = 0; phaseStartTimes[PHASE_MUTATOR] = 0; phaseTimes[PHASE_MUTATOR] = 0; @@ -847,38 +852,42 @@ Statistics::startTimingMutator() beginPhase(PHASE_MUTATOR); } -void +bool Statistics::stopTimingMutator(double &mutator_ms, double &gc_ms) { - MOZ_ASSERT(timingMutator); - - // Should only be called from outside of GC - MOZ_ASSERT(phaseNestingDepth == 1 && phaseNesting[0] == PHASE_MUTATOR); + // This should only be called from outside of GC, while timing the mutator. + if (phaseNestingDepth != 1 || phaseNesting[0] != PHASE_MUTATOR) + return false; endPhase(PHASE_MUTATOR); mutator_ms = t(phaseTimes[PHASE_MUTATOR]); gc_ms = t(timedGCTime); - timingMutator = false; + + return true; } void Statistics::beginPhase(Phase phase) { - /* Guard against re-entry */ - MOZ_ASSERT(!phaseStartTimes[phase]); + Phase parent = phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : PHASE_NO_PARENT; - if (timingMutator) { - if (phaseNestingDepth == 1 && phaseNesting[0] == PHASE_MUTATOR) { - endPhase(PHASE_MUTATOR); - timedGCStart = PRMJ_Now(); - } + // Re-entry is allowed during callbacks. Do not account nested GC time + // against the callbacks. + // + // Reuse this mechanism for managing PHASE_MUTATOR. + if (parent == PHASE_GC_BEGIN || parent == PHASE_GC_END || parent == PHASE_MUTATOR) { + suspendedPhases[suspendedPhaseNestingDepth++] = parent; + MOZ_ASSERT(suspendedPhaseNestingDepth <= mozilla::ArrayLength(suspendedPhases)); + endPhase(parent); + parent = phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : PHASE_NO_PARENT; } + // Guard against any other re-entry. + MOZ_ASSERT(!phaseStartTimes[phase]); + #ifdef DEBUG MOZ_ASSERT(phases[phase].index == phase); - Phase parent = phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : PHASE_NO_PARENT; MOZ_ASSERT(phaseNestingDepth < MAX_NESTING); - // Major and minor GCs can nest inside PHASE_GC_BEGIN/PHASE_GC_END. MOZ_ASSERT_IF(gcDepth == 1 && phase != PHASE_MINOR_GC, phases[phase].parent == parent); #endif @@ -891,20 +900,31 @@ Statistics::beginPhase(Phase phase) void Statistics::endPhase(Phase phase) { + int64_t now = PRMJ_Now(); + + if (phase == PHASE_MUTATOR) + timedGCStart = now; + phaseNestingDepth--; - int64_t now = PRMJ_Now(); int64_t t = now - phaseStartTimes[phase]; if (!slices.empty()) slices.back().phaseTimes[phase] += t; phaseTimes[phase] += t; phaseStartTimes[phase] = 0; - if (timingMutator) { - if (phaseNestingDepth == 0 && phase != PHASE_MUTATOR) { + // When emptying the stack, we may need to resume a callback phase + // (PHASE_GC_BEGIN/END) or if not, return to timing the mutator + // (PHASE_MUTATOR). + // + // However, if the phase we're ending is PHASE_MUTATOR, that means + // beginPhase is calling endPhase(PHASE_MUTATOR) because some other phase + // is starting. So don't resume any earlier phase. + if (phaseNestingDepth == 0 && suspendedPhaseNestingDepth > 0 && phase != PHASE_MUTATOR) { + Phase resumePhase = suspendedPhases[--suspendedPhaseNestingDepth]; + if (resumePhase == PHASE_MUTATOR) timedGCTime += now - timedGCStart; - beginPhase(PHASE_MUTATOR); - } + beginPhase(resumePhase); } } diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h index 100c477c9ac8..a9c447d80533 100644 --- a/js/src/gc/Statistics.h +++ b/js/src/gc/Statistics.h @@ -125,7 +125,7 @@ struct Statistics void endSlice(); void startTimingMutator(); - void stopTimingMutator(double &mutator_ms, double &gc_ms); + bool stopTimingMutator(double &mutator_ms, double &gc_ms); void reset(const char *reason) { slices.back().resetReason = reason; } void nonincremental(const char *reason) { nonincrementalReason = reason; } @@ -188,9 +188,6 @@ struct Statistics /* Most recent time when the given phase started. */ int64_t phaseStartTimes[PHASE_LIMIT]; - /* Are we currently timing mutator vs GC time? */ - bool timingMutator; - /* Bookkeeping for GC timings when timingMutator is true */ int64_t timedGCStart; int64_t timedGCTime; @@ -215,6 +212,15 @@ struct Statistics Phase phaseNesting[MAX_NESTING]; size_t phaseNestingDepth; + /* + * To avoid recursive nesting, we discontinue a callback phase when any + * other phases are started. Remember what phase to resume when the inner + * phases are complete. (And because GCs can nest within the callbacks any + * number of times, we need a whole stack of of phases to resume.) + */ + Phase suspendedPhases[MAX_NESTING]; + size_t suspendedPhaseNestingDepth; + /* Sweep times for SCCs of compartments. */ Vector sccTimes; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index a7c889ac5e90..8d4f045c4411 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1680,7 +1680,10 @@ StopTimingMutator(JSContext *cx, unsigned argc, jsval *vp) } double mutator_ms, gc_ms; - cx->runtime()->gc.stats.stopTimingMutator(mutator_ms, gc_ms); + if (!cx->runtime()->gc.stats.stopTimingMutator(mutator_ms, gc_ms)) { + JS_ReportError(cx, "stopTimingMutator called when not timing the mutator"); + return false; + } double total_ms = mutator_ms + gc_ms; if (total_ms > 0) { fprintf(gOutFile, "Mutator: %.3fms (%.1f%%), GC: %.3fms (%.1f%%)\n", From e22dd20905683fab9edd4bff4e3a1f91e6ae677d Mon Sep 17 00:00:00 2001 From: Jared Wein Date: Tue, 16 Dec 2014 13:23:16 -0500 Subject: [PATCH 107/130] Bug 1100595 - Add UI for indicating if renaming a room failed. r=NiKo` --HG-- extra : rebase_source : a03dfe3f46d5ec8881ec7e34f9ec605467f01b8c --- .../components/loop/content/js/roomViews.js | 26 ++++++++++++- .../components/loop/content/js/roomViews.jsx | 26 ++++++++++++- .../loop/content/shared/css/conversation.css | 38 ++++++++++++++----- .../loop/content/shared/js/actions.js | 8 ++++ .../loop/content/shared/js/roomStore.js | 13 +++++-- .../loop/test/shared/roomStore_test.js | 18 ++++++++- 6 files changed, 112 insertions(+), 17 deletions(-) diff --git a/browser/components/loop/content/js/roomViews.js b/browser/components/loop/content/js/roomViews.js index 65cf5f137237..eaa0caba9af6 100644 --- a/browser/components/loop/content/js/roomViews.js +++ b/browser/components/loop/content/js/roomViews.js @@ -67,10 +67,20 @@ loop.roomViews = (function(mozL10n) { getInitialState: function() { return { copiedUrl: false, - newRoomName: "" + newRoomName: "", + error: null, }; }, + componentWillMount: function() { + this.listenTo(this.props.roomStore, "change:error", + this.onRoomError); + }, + + componentWillUnmount: function() { + this.stopListening(this.props.roomStore); + }, + handleFormSubmit: function(event) { event.preventDefault(); @@ -101,9 +111,23 @@ loop.roomViews = (function(mozL10n) { this.setState({copiedUrl: true}); }, + onRoomError: function() { + // Only update the state if we're mounted, to avoid the problem where + // stopListening doesn't nuke the active listeners during a event + // processing. + if (this.isMounted()) { + this.setState({error: this.props.roomStore.getStoreState("error")}); + } + }, + render: function() { + var cx = React.addons.classSet; return ( React.DOM.div({className: "room-invitation-overlay"}, + React.DOM.p({className: cx({"error": !!this.state.error, + "error-display-area": true})}, + mozL10n.get("rooms_name_change_failed_label") + ), React.DOM.form({onSubmit: this.handleFormSubmit}, React.DOM.input({type: "text", className: "input-room-name", valueLink: this.linkState("newRoomName"), diff --git a/browser/components/loop/content/js/roomViews.jsx b/browser/components/loop/content/js/roomViews.jsx index f306a408459b..60debab1ab0c 100644 --- a/browser/components/loop/content/js/roomViews.jsx +++ b/browser/components/loop/content/js/roomViews.jsx @@ -67,10 +67,20 @@ loop.roomViews = (function(mozL10n) { getInitialState: function() { return { copiedUrl: false, - newRoomName: "" + newRoomName: "", + error: null, }; }, + componentWillMount: function() { + this.listenTo(this.props.roomStore, "change:error", + this.onRoomError); + }, + + componentWillUnmount: function() { + this.stopListening(this.props.roomStore); + }, + handleFormSubmit: function(event) { event.preventDefault(); @@ -101,9 +111,23 @@ loop.roomViews = (function(mozL10n) { this.setState({copiedUrl: true}); }, + onRoomError: function() { + // Only update the state if we're mounted, to avoid the problem where + // stopListening doesn't nuke the active listeners during a event + // processing. + if (this.isMounted()) { + this.setState({error: this.props.roomStore.getStoreState("error")}); + } + }, + render: function() { + var cx = React.addons.classSet; return (
+

+ {mozL10n.get("rooms_name_change_failed_label")} +

Date: Tue, 16 Dec 2014 15:34:41 -0500 Subject: [PATCH 108/130] Backed out changeset 779342bb7001 (bug 1068349) for mochitest-e10s orange. --- dom/ipc/ContentParent.cpp | 44 +++++---------------------------------- 1 file changed, 5 insertions(+), 39 deletions(-) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index aa77f89bd4cd..aacf4b449445 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -213,10 +213,6 @@ static const char* sClipboardTextFlavors[] = { kUnicodeMime }; using base::ChildPrivileges; using base::KillProcess; - -#ifdef MOZ_CRASHREPORTER -using namespace CrashReporter; -#endif using namespace mozilla::dom::bluetooth; using namespace mozilla::dom::cellbroadcast; using namespace mozilla::dom::devicestorage; @@ -1778,16 +1774,7 @@ ContentParent::ActorDestroy(ActorDestroyReason why) NS_ConvertUTF16toUTF8(mAppManifestURL)); } - if (mCalledKillHard) { - // We killed the child with KillHard, so two minidumps should already - // exist - one for the content process, and one for the browser process. - // The "main" minidump of this crash report is the content processes, - // and we use GenerateChildData to annotate our crash report with - // information about the child process. - crashReporter->GenerateChildData(nullptr); - } else { - crashReporter->GenerateCrashReport(this, nullptr); - } + crashReporter->GenerateCrashReport(this, nullptr); nsAutoString dumpID(crashReporter->ChildDumpID()); props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID); @@ -3062,31 +3049,10 @@ ContentParent::KillHard() } mCalledKillHard = true; mForceKillTask = nullptr; - -#ifdef MOZ_CRASHREPORTER - if (ManagedPCrashReporterParent().Length() > 0) { - CrashReporterParent* crashReporter = - static_cast(ManagedPCrashReporterParent()[0]); - - // We're about to kill the child process associated with this - // ContentParent. Something has gone wrong to get us here, - // so we generate a minidump to be potentially submitted in - // a crash report. ContentParent::ActorDestroy is where the - // actual report gets generated, once the child process has - // finally died. - if (crashReporter->GeneratePairedMinidump(this)) { - // GeneratePairedMinidump created two minidumps for us - the main - // one is for the content process we're about to kill, and the other - // one is for the main browser process. That second one is the extra - // minidump tagging along, so we have to tell the crash reporter that - // it exists and is being appended. - nsAutoCString additionalDumps("browser"); - crashReporter->AnnotateCrashReport( - NS_LITERAL_CSTRING("additional_minidumps"), - additionalDumps); - } - } -#endif + // This ensures the process is eventually killed, but doesn't + // immediately KILLITWITHFIRE because we want to get a minidump if + // possible. After a timeout though, the process is forceably + // killed. if (!KillProcess(OtherProcess(), 1, false)) { NS_WARNING("failed to kill subprocess!"); } From 6cf86471cadcb51f6e6c4b68fc9ee8681f64a4ba Mon Sep 17 00:00:00 2001 From: abdelrhman Date: Tue, 16 Dec 2014 21:38:33 +0100 Subject: [PATCH 109/130] Bug 1110109 - Use Services.focus instead of Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager). r=dao --- browser/base/content/browser-fullScreen.js | 2 +- browser/base/content/browser-fxaccounts.js | 2 +- browser/base/content/browser-tabPreviews.js | 4 +--- browser/base/content/tabbrowser.xml | 2 +- browser/base/content/test/general/browser_bug565667.js | 2 +- .../base/content/test/general/browser_locationBarCommand.js | 3 +-- .../content/test/general/browser_locationBarExternalLoad.js | 2 +- browser/base/content/test/general/browser_tabfocus.js | 4 ++-- 8 files changed, 9 insertions(+), 12 deletions(-) diff --git a/browser/base/content/browser-fullScreen.js b/browser/base/content/browser-fullScreen.js index 8c765ab31de5..d764655a42c8 100644 --- a/browser/base/content/browser-fullScreen.js +++ b/browser/base/content/browser-fullScreen.js @@ -143,7 +143,7 @@ var FullScreen = { return; } - let focusManager = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); + let focusManager = Services.focus; if (focusManager.activeWindow != window) { // The top-level window has lost focus since the request to enter // full-screen was made. Cancel full-screen. diff --git a/browser/base/content/browser-fxaccounts.js b/browser/base/content/browser-fxaccounts.js index 28b544fa4aba..5dcdbcb12c38 100644 --- a/browser/base/content/browser-fxaccounts.js +++ b/browser/base/content/browser-fxaccounts.js @@ -67,7 +67,7 @@ let gFxAccounts = { }, get isActiveWindow() { - let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); + let fm = Services.focus; return fm.activeWindow == window; }, diff --git a/browser/base/content/browser-tabPreviews.js b/browser/base/content/browser-tabPreviews.js index 7bd853941b37..7bcd6be65eb1 100644 --- a/browser/base/content/browser-tabPreviews.js +++ b/browser/base/content/browser-tabPreviews.js @@ -133,9 +133,7 @@ var tabPreviewPanelHelper = { host.suspendGUI(); if (host._prevFocus) { - Cc["@mozilla.org/focus-manager;1"] - .getService(Ci.nsIFocusManager) - .setFocus(host._prevFocus, Ci.nsIFocusManager.FLAG_NOSCROLL); + Services.focus.setFocus(host._prevFocus, Ci.nsIFocusManager.FLAG_NOSCROLL); host._prevFocus = null; } else gBrowser.selectedBrowser.focus(); diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index db66d0fdfc34..d28441b1e273 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -1262,7 +1262,7 @@ return; } - let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); + let fm = Services.focus; let focusFlags = fm.FLAG_NOSCROLL; if (!gMultiProcessBrowser) { diff --git a/browser/base/content/test/general/browser_bug565667.js b/browser/base/content/test/general/browser_bug565667.js index 6fac026c8481..f08654f7dbea 100644 --- a/browser/base/content/test/general/browser_bug565667.js +++ b/browser/base/content/test/general/browser_bug565667.js @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); +let fm = Services.focus; function test() { waitForExplicitFinish(); diff --git a/browser/base/content/test/general/browser_locationBarCommand.js b/browser/base/content/test/general/browser_locationBarCommand.js index 876eb12d2a48..5ae579e7060d 100644 --- a/browser/base/content/test/general/browser_locationBarCommand.js +++ b/browser/base/content/test/general/browser_locationBarCommand.js @@ -4,8 +4,7 @@ const TEST_VALUE = "example.com"; const START_VALUE = "example.org"; -let gFocusManager = Cc["@mozilla.org/focus-manager;1"]. - getService(Ci.nsIFocusManager); +let gFocusManager = Services.focus; function test() { waitForExplicitFinish(); diff --git a/browser/base/content/test/general/browser_locationBarExternalLoad.js b/browser/base/content/test/general/browser_locationBarExternalLoad.js index be573d01fa97..8394790eca54 100644 --- a/browser/base/content/test/general/browser_locationBarExternalLoad.js +++ b/browser/base/content/test/general/browser_locationBarExternalLoad.js @@ -45,7 +45,7 @@ function testURL(url, loadFunc, endFunc) { loadFunc(url); addPageShowListener(function () { - let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); + let fm = Services.focus; is(fm.focusedElement, null, "should be no focused element"); is(fm.focusedWindow, gBrowser.contentWindow, "content window should be focused"); diff --git a/browser/base/content/test/general/browser_tabfocus.js b/browser/base/content/test/general/browser_tabfocus.js index 289c83c8979e..74e7ab1d9bfb 100644 --- a/browser/base/content/test/general/browser_tabfocus.js +++ b/browser/base/content/test/general/browser_tabfocus.js @@ -39,7 +39,7 @@ function test() { window.addEventListener("blur", _browser_tabfocus_test_eventOccured, true); // make sure that the focus initially starts out blank - var fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); + var fm = Services.focus; var focusedWindow = {}; is(fm.getFocusedElementForWindow(browser1.contentWindow, false, focusedWindow), null, "initial focus in tab 1"); is(focusedWindow.value, browser1.contentWindow, "initial frame focus in tab 1"); @@ -259,7 +259,7 @@ function expectFocusShift(callback, expectedWindow, expectedElement, focusChange is(_browser_tabfocus_test_events, expectedEvents, testid + " events"); _browser_tabfocus_test_events = ""; - var fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); + var fm = Services.focus; var focusedElement = fm.focusedElement; is(focusedElement ? getId(focusedElement) : "none", From 5fd0a1f23047878a96e2d37eefb9c1799feb697d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A3o=20Gottwald?= Date: Tue, 16 Dec 2014 21:41:07 +0100 Subject: [PATCH 110/130] Bug 1107342 - Ctrl-Tab should prevent a few more thumbnails from expiring than are displayed in the UI. r=jimm --- browser/base/content/browser-tabPreviews.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/browser/base/content/browser-tabPreviews.js b/browser/base/content/browser-tabPreviews.js index 7bcd6be65eb1..4d4d14866abf 100644 --- a/browser/base/content/browser-tabPreviews.js +++ b/browser/base/content/browser-tabPreviews.js @@ -501,9 +501,14 @@ var ctrlTab = { }, filterForThumbnailExpiration: function (aCallback) { + // Save a few more thumbnails than we actually display, so that when tabs + // are closed, the previews we add instead still get thumbnails. + const extraThumbnails = 3; + const thumbnailCount = Math.min(this.tabPreviewCount + extraThumbnails, + this.tabCount); + let urls = []; - let previewCount = this.tabPreviewCount; - for (let i = 0; i < previewCount; i++) + for (let i = 0; i < thumbnailCount; i++) urls.push(this.tabList[i].linkedBrowser.currentURI.spec); aCallback(urls); From 84755446f8aa82cb4ac09051e8aa24b6a09813a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A3o=20Gottwald?= Date: Tue, 16 Dec 2014 21:42:43 +0100 Subject: [PATCH 111/130] Bug 1107354 - Rename browser-tabPreviews.js to browser-ctrlTab.js. r=jimm --HG-- rename : browser/base/content/browser-tabPreviews.js => browser/base/content/browser-ctrlTab.js --- .../content/{browser-tabPreviews.js => browser-ctrlTab.js} | 0 browser/base/content/browser.js | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename browser/base/content/{browser-tabPreviews.js => browser-ctrlTab.js} (100%) diff --git a/browser/base/content/browser-tabPreviews.js b/browser/base/content/browser-ctrlTab.js similarity index 100% rename from browser/base/content/browser-tabPreviews.js rename to browser/base/content/browser-ctrlTab.js diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index d06eed3cad4f..a65fe1477632 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -205,20 +205,20 @@ let gInitialPages = [ ]; #include browser-addons.js +#include browser-ctrlTab.js #include browser-customization.js #include browser-devedition.js #include browser-feeds.js #include browser-fullScreen.js #include browser-fullZoom.js +#include browser-gestureSupport.js #include browser-loop.js #include browser-places.js #include browser-plugins.js #include browser-safebrowsing.js #include browser-social.js -#include browser-tabPreviews.js #include browser-tabview.js #include browser-thumbnails.js -#include browser-gestureSupport.js #ifdef MOZ_DATA_REPORTING #include browser-data-submission-info-bar.js From 38e1f446e84226b4bcdbba822f72f730d36a54c0 Mon Sep 17 00:00:00 2001 From: Dan Mosedale Date: Tue, 16 Dec 2014 12:44:20 -0800 Subject: [PATCH 112/130] Bug 1109950-speed up loop run-all-browser-tests by ~20 seconds, r=Standard8 --- browser/components/loop/run-all-loop-tests.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/browser/components/loop/run-all-loop-tests.sh b/browser/components/loop/run-all-loop-tests.sh index 4479922f81ab..7c2aef8d53d8 100755 --- a/browser/components/loop/run-all-loop-tests.sh +++ b/browser/components/loop/run-all-loop-tests.sh @@ -8,9 +8,13 @@ set -e ./mach marionette-test browser/components/loop/manifest.ini # The browser_parsable_css.js can fail if we add some css that isn't parsable. -./mach mochitest browser/components/loop/test/mochitest browser/base/content/test/general/browser_parsable_css.js - +# # The check to make sure that the media devices can be used in Loop without # prompting is in browser_devices_get_user_media_about_urls.js. It's possible # to mess this up with CSP handling, and probably other changes, too. -./mach mochitest browser/base/content/test/general/browser_devices_get_user_media_about_urls.js + +./mach mochitest \ + browser/components/loop/test/mochitest \ + browser/base/content/test/general/browser_parsable_css.js \ + browser/base/content/test/general/browser_devices_get_user_media_about_urls.js + From aad3f3e2f3cd8c2eb751d56f773fa6349dd12ec4 Mon Sep 17 00:00:00 2001 From: Mike de Boer Date: Tue, 16 Dec 2014 16:59:05 +0100 Subject: [PATCH 113/130] Bug 1102432: refresh the list of rooms upon account switch or logout. r=Niko --- browser/components/loop/LoopRooms.jsm | 26 ++++++++++++ browser/components/loop/MozLoopService.jsm | 3 +- .../loop/content/shared/js/roomStore.js | 12 ++++++ .../loop/test/shared/roomStore_test.js | 8 ++++ .../loop/test/xpcshell/test_looprooms.js | 42 +++++++++++++++++++ 5 files changed, 90 insertions(+), 1 deletion(-) diff --git a/browser/components/loop/LoopRooms.jsm b/browser/components/loop/LoopRooms.jsm index 10aaf81765cc..13afd7eb3d59 100644 --- a/browser/components/loop/LoopRooms.jsm +++ b/browser/components/loop/LoopRooms.jsm @@ -34,6 +34,8 @@ const roomsPushNotification = function(version, channelID) { // of date. The Push server may notify us of this event, which will set the global // 'dirty' flag to TRUE. let gDirty = true; +// Global variable that keeps track of the currently used account. +let gCurrentUser = null; /** * Extend a `target` object with the properties defined in `source`. @@ -479,6 +481,26 @@ let LoopRoomsInternal = { gDirty = true; this.getAll(version, () => {}); }, + + /** + * When a user logs in or out, this method should be invoked to check whether + * the rooms cache needs to be refreshed. + * + * @param {String|null} user The FxA userID or NULL + */ + maybeRefresh: function(user = null) { + if (gCurrentUser == user) { + return; + } + + gCurrentUser = user; + if (!gDirty) { + gDirty = true; + this.rooms.clear(); + eventEmitter.emit("refresh"); + this.getAll(null, () => {}); + } + } }; Object.freeze(LoopRoomsInternal); @@ -544,6 +566,10 @@ this.LoopRooms = { return LoopRoomsInternal.getGuestCreatedRoom(); }, + maybeRefresh: function(user) { + return LoopRoomsInternal.maybeRefresh(user); + }, + promise: function(method, ...params) { return new Promise((resolve, reject) => { this[method](...params, (error, result) => { diff --git a/browser/components/loop/MozLoopService.jsm b/browser/components/loop/MozLoopService.jsm index 51feb3fa1ab1..a543c40d231b 100644 --- a/browser/components/loop/MozLoopService.jsm +++ b/browser/components/loop/MozLoopService.jsm @@ -243,7 +243,8 @@ let MozLoopServiceInternal = { notifyStatusChanged: function(aReason = null) { log.debug("notifyStatusChanged with reason:", aReason); let profile = MozLoopService.userProfile; - LoopStorage.switchDatabase(profile ? profile.uid : null); + LoopStorage.switchDatabase(profile && profile.uid); + LoopRooms.maybeRefresh(profile && profile.uid); Services.obs.notifyObservers(null, "loop-status-changed", aReason); }, diff --git a/browser/components/loop/content/shared/js/roomStore.js b/browser/components/loop/content/shared/js/roomStore.js index 90ce391492a2..903225ee503a 100644 --- a/browser/components/loop/content/shared/js/roomStore.js +++ b/browser/components/loop/content/shared/js/roomStore.js @@ -133,6 +133,7 @@ loop.store = loop.store || {}; this._mozLoop.rooms.on("add", this._onRoomAdded.bind(this)); this._mozLoop.rooms.on("update", this._onRoomUpdated.bind(this)); this._mozLoop.rooms.on("delete", this._onRoomRemoved.bind(this)); + this._mozLoop.rooms.on("refresh", this._onRoomsRefresh.bind(this)); }, /** @@ -185,6 +186,17 @@ loop.store = loop.store || {}; })); }, + /** + * Executed when the user switches accounts. + * + * @param {String} eventName The event name (unused). + */ + _onRoomsRefresh: function(eventName) { + this.dispatchAction(new sharedActions.UpdateRoomList({ + roomList: [] + })); + }, + /** * Maps and sorts the raw room list received from the mozLoop API. * diff --git a/browser/components/loop/test/shared/roomStore_test.js b/browser/components/loop/test/shared/roomStore_test.js index e2ba79c9e68e..741aef06aead 100644 --- a/browser/components/loop/test/shared/roomStore_test.js +++ b/browser/components/loop/test/shared/roomStore_test.js @@ -145,6 +145,14 @@ describe("loop.store.RoomStore", function () { })).eql(false); }); }); + + describe("refresh", function() { + it ("should clear the list of rooms", function() { + fakeMozLoop.rooms.trigger("refresh", "refresh"); + + expect(store.getStoreState().rooms).to.have.length.of(0); + }); + }) }); describe("#findNextAvailableRoomNumber", function() { diff --git a/browser/components/loop/test/xpcshell/test_looprooms.js b/browser/components/loop/test/xpcshell/test_looprooms.js index d751efa4311a..83839d6194b1 100644 --- a/browser/components/loop/test/xpcshell/test_looprooms.js +++ b/browser/components/loop/test/xpcshell/test_looprooms.js @@ -5,6 +5,7 @@ Cu.import("resource://services-common/utils.js"); Cu.import("resource:///modules/loop/LoopRooms.jsm"); Cu.import("resource:///modules/Chat.jsm"); +Cu.import("resource://gre/modules/Promise.jsm"); let openChatOrig = Chat.open; @@ -127,6 +128,7 @@ let gExpectedUpdates = []; let gExpectedDeletes = []; let gExpectedJoins = {}; let gExpectedLeaves = {}; +let gExpectedRefresh = false; const onRoomAdded = function(e, room) { let expectedIds = gExpectedAdds.map(room => room.roomToken); @@ -171,6 +173,11 @@ const onRoomLeft = function(e, room, participant) { } }; +const onRefresh = function(e) { + Assert.ok(gExpectedRefresh, "A refresh event should've been expected"); + gExpectedRefresh = false; +}; + const parseQueryString = function(qs) { let map = {}; let parts = qs.split("="); @@ -312,6 +319,34 @@ add_task(function* test_openRoom() { Assert.equal(windowData.roomToken, "fakeToken", "window data should have the roomToken"); }); +// Test if the rooms cache is refreshed after FxA signin or signout. +add_task(function* test_refresh() { + gExpectedAdds.push(...kRooms.values()); + gExpectedRefresh = true; + // Make the switch. + MozLoopServiceInternal.fxAOAuthTokenData = { token_type: "bearer" }; + MozLoopServiceInternal.fxAOAuthProfile = { + email: "fake@invalid.com", + uid: "fake" + }; + + yield waitForCondition(() => !gExpectedRefresh); + yield waitForCondition(() => gExpectedAdds.length === 0); + + gExpectedAdds.push(...kRooms.values()); + gExpectedRefresh = true; + // Simulate a logout. + MozLoopServiceInternal.fxAOAuthTokenData = null; + MozLoopServiceInternal.fxAOAuthProfile = null; + + yield waitForCondition(() => !gExpectedRefresh); + yield waitForCondition(() => gExpectedAdds.length === 0); + + // Simulating a logout again shouldn't yield a refresh event. + MozLoopServiceInternal.fxAOAuthTokenData = null; + MozLoopServiceInternal.fxAOAuthProfile = null; +}); + // Test if push updates function as expected. add_task(function* test_roomUpdates() { gExpectedUpdates.push("_nxD4V4FflQ"); @@ -433,6 +468,11 @@ add_task(function* () { Assert.strictEqual(gExpectedAdds.length, 0, "No room additions should be expected anymore"); Assert.strictEqual(gExpectedUpdates.length, 0, "No room updates should be expected anymore"); Assert.strictEqual(gExpectedDeletes.length, 0, "No room deletes should be expected anymore"); + Assert.strictEqual(Object.getOwnPropertyNames(gExpectedJoins).length, 0, + "No room joins should be expected anymore"); + Assert.strictEqual(Object.getOwnPropertyNames(gExpectedLeaves).length, 0, + "No room leaves should be expected anymore"); + Assert.ok(!gExpectedRefresh, "No refreshes should be expected anymore"); }); function run_test() { @@ -443,6 +483,7 @@ function run_test() { LoopRooms.on("delete", onRoomDeleted); LoopRooms.on("joined", onRoomJoined); LoopRooms.on("left", onRoomLeft); + LoopRooms.on("refresh", onRefresh); do_register_cleanup(function () { // Revert original Chat.open implementation @@ -456,6 +497,7 @@ function run_test() { LoopRooms.off("delete", onRoomDeleted); LoopRooms.off("joined", onRoomJoined); LoopRooms.off("left", onRoomLeft); + LoopRooms.off("refresh", onRefresh); }); run_next_test(); From 9cb7db4564e9d507f57fa1edf83bd2c5d8747ad4 Mon Sep 17 00:00:00 2001 From: Patrick Brosset Date: Tue, 16 Dec 2014 22:34:13 +0100 Subject: [PATCH 114/130] Bug 1104908 - 2 - Remove the timeout in styleinspector's waitforsuccess test helper function; r=harth --- browser/devtools/styleinspector/test/head.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/browser/devtools/styleinspector/test/head.js b/browser/devtools/styleinspector/test/head.js index 1d3250690ade..c030cf5770ab 100644 --- a/browser/devtools/styleinspector/test/head.js +++ b/browser/devtools/styleinspector/test/head.js @@ -506,25 +506,19 @@ function fireCopyEvent(element) { * polling timeouts after several tries and the promise rejects. * @param {String} name Optional name of the test. This is used to generate * the success and failure messages. - * @param {Number} timeout Optional timeout for the validator function, in - * milliseconds. Default is 5000. * @return a promise that resolves when the function returned true or rejects * if the timeout is reached */ -function waitForSuccess(validatorFn, name="untitled", timeout=5000) { +function waitForSuccess(validatorFn, name="untitled") { let def = promise.defer(); let start = Date.now(); function wait(validatorFn) { - if ((Date.now() - start) > timeout) { - ok(false, "Validator function " + name + " timed out"); - return def.reject(); - } if (validatorFn()) { ok(true, "Validator function " + name + " returned true"); def.resolve(); } else { - setTimeout(() => wait(validatorFn), 100); + setTimeout(() => wait(validatorFn), 200); } } wait(validatorFn); From 9c625888b6f965f7c5f1791fdf95c0750296789a Mon Sep 17 00:00:00 2001 From: Patrick Brosset Date: Tue, 16 Dec 2014 22:34:17 +0100 Subject: [PATCH 115/130] Bug 1104908 - 3 - Re-enable most of the styleinspector tests on e10s; r=me --- browser/devtools/styleinspector/test/browser.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/browser/devtools/styleinspector/test/browser.ini b/browser/devtools/styleinspector/test/browser.ini index eea9417c2c52..d551f35c4913 100644 --- a/browser/devtools/styleinspector/test/browser.ini +++ b/browser/devtools/styleinspector/test/browser.ini @@ -1,5 +1,4 @@ [DEFAULT] -skip-if = e10s && os == 'linux' # bug 1104908 subsuite = devtools support-files = doc_content_stylesheet.html @@ -115,10 +114,12 @@ skip-if = e10s # bug 1040670 Cannot open inline styles in viewSourceUtils [browser_styleinspector_refresh_when_active.js] [browser_styleinspector_tooltip-background-image.js] [browser_styleinspector_tooltip-closes-on-new-selection.js] +skip-if = e10s # Bug 1111546 [browser_styleinspector_tooltip-longhand-fontfamily.js] [browser_styleinspector_tooltip-multiple-background-images.js] [browser_styleinspector_tooltip-shorthand-fontfamily.js] [browser_styleinspector_tooltip-size.js] +skip-if = e10s # Bug 1111546 [browser_styleinspector_transform-highlighter-01.js] [browser_styleinspector_transform-highlighter-02.js] [browser_styleinspector_transform-highlighter-03.js] From 19f3ec65dde8452a8ee9656c6cb460628a72406a Mon Sep 17 00:00:00 2001 From: Marcus Saad Date: Tue, 16 Dec 2014 20:12:45 -0200 Subject: [PATCH 116/130] Bug 1102398 - The question mark button under about:preferences#search should point to the proper support article. r=felipe --- browser/components/preferences/in-content/preferences.xul | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/components/preferences/in-content/preferences.xul b/browser/components/preferences/in-content/preferences.xul index ac67c61c35b8..07adfa4155e2 100644 --- a/browser/components/preferences/in-content/preferences.xul +++ b/browser/components/preferences/in-content/preferences.xul @@ -102,7 +102,7 @@ From 2f1f0f7dde8bf215d14178aa826f1eacdea8b3d8 Mon Sep 17 00:00:00 2001 From: Felipe Gomes Date: Tue, 16 Dec 2014 20:36:43 -0200 Subject: [PATCH 117/130] Bug 1094947 - The trusted identity block is not displayed for the about:downloads page. r=jaws This patch was co-developed by members of the Mozilla Brasil community during a development workshop in our first ever community meetup. Thanks to Mauricio Araldi, Marcus Saad, Sergio Campos, Matheus Figueiredo, Gustavo Sillero, Antonio Ladeia, Caio Oliveira, Eduardo Barros, and Guillermo Movia for attending and contributing. --- browser/base/content/browser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index a65fe1477632..5cb871f368ff 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -6999,7 +6999,7 @@ var gIdentityHandler = { // Chrome URIs however get special treatment. Some chrome URIs are // whitelisted to provide a positive security signal to the user. - let whitelist = /^about:(accounts|addons|app-manager|config|crashes|customizing|healthreport|home|license|newaddon|permissions|preferences|privatebrowsing|rights|sessionrestore|support|welcomeback)/i; + let whitelist = /^about:(accounts|addons|app-manager|config|crashes|customizing|downloads|healthreport|home|license|newaddon|permissions|preferences|privatebrowsing|rights|sessionrestore|support|welcomeback)/i; let isChromeUI = uri.schemeIs("about") && whitelist.test(uri.spec); if (isChromeUI) { this.setMode(this.IDENTITY_MODE_CHROMEUI); From de5e9c40f792d004118a74ac31f092db7750f8b5 Mon Sep 17 00:00:00 2001 From: Margaret Leibovic Date: Wed, 10 Dec 2014 16:44:53 -0800 Subject: [PATCH 118/130] Bug 793920 - (Part 1) Move majority of Android reader mode code to a shared place in /toolkit. r=Mossop,bnicholson --HG-- rename : mobile/android/chrome/content/JSDOMParser.js => toolkit/components/reader/content/JSDOMParser.js rename : mobile/android/chrome/content/Readability.js => toolkit/components/reader/content/Readability.js rename : mobile/android/chrome/content/aboutReader.html => toolkit/components/reader/content/aboutReader.html rename : mobile/android/chrome/content/aboutReader.js => toolkit/components/reader/content/aboutReader.js rename : mobile/android/chrome/content/readerWorker.js => toolkit/components/reader/content/readerWorker.js rename : mobile/android/locales/en-US/chrome/aboutReader.properties => toolkit/locales/en-US/chrome/global/aboutReader.properties extra : rebase_source : f0b900c46bb5dc894303ddf3701be7b019b61ae0 extra : histedit_source : 7417d0e4032ed3a3b1ab83af8f7e8a92951fdead --- mobile/android/chrome/content/Reader.js | 2 +- mobile/android/chrome/content/browser.js | 2 +- mobile/android/chrome/jar.mn | 5 ----- mobile/android/components/AboutRedirector.js | 2 +- mobile/android/locales/jar.mn | 1 - mobile/android/themes/core/jar.mn | 1 + toolkit/components/moz.build | 1 + .../components/reader}/content/JSDOMParser.js | 0 .../components/reader}/content/Readability.js | 0 .../components/reader}/content/aboutReader.html | 2 +- .../components/reader}/content/aboutReader.js | 2 +- .../components/reader}/content/readerWorker.js | 0 toolkit/components/reader/jar.mn | 10 ++++++++++ toolkit/components/reader/moz.build | 7 +++++++ .../en-US/chrome/global}/aboutReader.properties | 0 toolkit/locales/jar.mn | 1 + toolkit/themes/osx/global/jar.mn | 1 + toolkit/themes/windows/global/aboutReader.css | 3 +++ toolkit/themes/windows/global/jar.mn | 2 ++ 19 files changed, 31 insertions(+), 11 deletions(-) rename {mobile/android/chrome => toolkit/components/reader}/content/JSDOMParser.js (100%) rename {mobile/android/chrome => toolkit/components/reader}/content/Readability.js (100%) rename {mobile/android/chrome => toolkit/components/reader}/content/aboutReader.html (92%) rename {mobile/android/chrome => toolkit/components/reader}/content/aboutReader.js (99%) rename {mobile/android/chrome => toolkit/components/reader}/content/readerWorker.js (100%) create mode 100644 toolkit/components/reader/jar.mn create mode 100644 toolkit/components/reader/moz.build rename {mobile/android/locales/en-US/chrome => toolkit/locales/en-US/chrome/global}/aboutReader.properties (100%) create mode 100644 toolkit/themes/windows/global/aboutReader.css diff --git a/mobile/android/chrome/content/Reader.js b/mobile/android/chrome/content/Reader.js index 09021e9dc624..0683b319659e 100644 --- a/mobile/android/chrome/content/Reader.js +++ b/mobile/android/chrome/content/Reader.js @@ -277,7 +277,7 @@ let Reader = { return; } - let worker = new ChromeWorker("readerWorker.js"); + let worker = new ChromeWorker("chrome://global/content/reader/readerWorker.js"); worker.onmessage = evt => { let article = evt.data; diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index fb2e15894d87..94c8da2a039f 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -113,7 +113,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Notifications", [ ["SelectHelper", "chrome://browser/content/SelectHelper.js"], ["InputWidgetHelper", "chrome://browser/content/InputWidgetHelper.js"], - ["AboutReader", "chrome://browser/content/aboutReader.js"], + ["AboutReader", "chrome://global/content/reader/aboutReader.js"], ["MasterPassword", "chrome://browser/content/MasterPassword.js"], ["PluginHelper", "chrome://browser/content/PluginHelper.js"], ["OfflineApps", "chrome://browser/content/OfflineApps.js"], diff --git a/mobile/android/chrome/jar.mn b/mobile/android/chrome/jar.mn index 1560a2dc6b76..f87d6c6384e9 100644 --- a/mobile/android/chrome/jar.mn +++ b/mobile/android/chrome/jar.mn @@ -19,12 +19,7 @@ chrome.jar: content/aboutFeedback.js (content/aboutFeedback.js) content/aboutPrivateBrowsing.xhtml (content/aboutPrivateBrowsing.xhtml) content/aboutPrivateBrowsing.js (content/aboutPrivateBrowsing.js) - content/aboutReader.html (content/aboutReader.html) - content/aboutReader.js (content/aboutReader.js) - content/Readability.js (content/Readability.js) content/Reader.js (content/Reader.js) - content/JSDOMParser.js (content/JSDOMParser.js) - content/readerWorker.js (content/readerWorker.js) content/aboutHome.xhtml (content/aboutHome.xhtml) content/aboutRights.xhtml (content/aboutRights.xhtml) * content/aboutApps.xhtml (content/aboutApps.xhtml) diff --git a/mobile/android/components/AboutRedirector.js b/mobile/android/components/AboutRedirector.js index 137acd07ca18..e197f474e454 100644 --- a/mobile/android/components/AboutRedirector.js +++ b/mobile/android/components/AboutRedirector.js @@ -60,7 +60,7 @@ let modules = { privileged: true }, reader: { - uri: "chrome://browser/content/aboutReader.html", + uri: "chrome://global/content/reader/aboutReader.html", privileged: false, hide: true }, diff --git a/mobile/android/locales/jar.mn b/mobile/android/locales/jar.mn index 34b5569b1959..1632455d8258 100644 --- a/mobile/android/locales/jar.mn +++ b/mobile/android/locales/jar.mn @@ -20,7 +20,6 @@ locale/@AB_CD@/browser/aboutHome.dtd (%chrome/aboutHome.dtd) locale/@AB_CD@/browser/aboutHome.properties (%chrome/aboutHome.properties) locale/@AB_CD@/browser/aboutPrivateBrowsing.dtd (%chrome/aboutPrivateBrowsing.dtd) - locale/@AB_CD@/browser/aboutReader.properties (%chrome/aboutReader.properties) #ifdef MOZ_SERVICES_HEALTHREPORT locale/@AB_CD@/browser/aboutHealthReport.dtd (%chrome/aboutHealthReport.dtd) #endif diff --git a/mobile/android/themes/core/jar.mn b/mobile/android/themes/core/jar.mn index 8472579a149f..2df29526258d 100644 --- a/mobile/android/themes/core/jar.mn +++ b/mobile/android/themes/core/jar.mn @@ -30,6 +30,7 @@ chrome.jar: skin/netError.css (netError.css) % override chrome://global/skin/about.css chrome://browser/skin/about.css % override chrome://global/skin/aboutMemory.css chrome://browser/skin/aboutMemory.css +% override chrome://global/skin/aboutReader.css chrome://browser/skin/aboutReader.css % override chrome://global/skin/aboutSupport.css chrome://browser/skin/aboutSupport.css % override chrome://global/skin/media/videocontrols.css chrome://browser/skin/touchcontrols.css % override chrome://global/skin/netError.css chrome://browser/skin/netError.css diff --git a/toolkit/components/moz.build b/toolkit/components/moz.build index f54634b2fc58..f5e3bdc3b36f 100644 --- a/toolkit/components/moz.build +++ b/toolkit/components/moz.build @@ -40,6 +40,7 @@ DIRS += [ 'promiseworker', 'prompts', 'protobuf', + 'reader', 'reflect', 'sqlite', 'startup', diff --git a/mobile/android/chrome/content/JSDOMParser.js b/toolkit/components/reader/content/JSDOMParser.js similarity index 100% rename from mobile/android/chrome/content/JSDOMParser.js rename to toolkit/components/reader/content/JSDOMParser.js diff --git a/mobile/android/chrome/content/Readability.js b/toolkit/components/reader/content/Readability.js similarity index 100% rename from mobile/android/chrome/content/Readability.js rename to toolkit/components/reader/content/Readability.js diff --git a/mobile/android/chrome/content/aboutReader.html b/toolkit/components/reader/content/aboutReader.html similarity index 92% rename from mobile/android/chrome/content/aboutReader.html rename to toolkit/components/reader/content/aboutReader.html index 731ba3739985..22ef846ef9ac 100644 --- a/mobile/android/chrome/content/aboutReader.html +++ b/toolkit/components/reader/content/aboutReader.html @@ -5,7 +5,7 @@ - + diff --git a/mobile/android/chrome/content/aboutReader.js b/toolkit/components/reader/content/aboutReader.js similarity index 99% rename from mobile/android/chrome/content/aboutReader.js rename to toolkit/components/reader/content/aboutReader.js index 8ea53c0c014a..d380cb9cf66d 100644 --- a/mobile/android/chrome/content/aboutReader.js +++ b/toolkit/components/reader/content/aboutReader.js @@ -24,7 +24,7 @@ function dump(s) { Services.console.logStringMessage("AboutReader: " + s); } -let gStrings = Services.strings.createBundle("chrome://browser/locale/aboutReader.properties"); +let gStrings = Services.strings.createBundle("chrome://global/locale/aboutReader.properties"); let AboutReader = function(doc, win) { dump("Init()"); diff --git a/mobile/android/chrome/content/readerWorker.js b/toolkit/components/reader/content/readerWorker.js similarity index 100% rename from mobile/android/chrome/content/readerWorker.js rename to toolkit/components/reader/content/readerWorker.js diff --git a/toolkit/components/reader/jar.mn b/toolkit/components/reader/jar.mn new file mode 100644 index 000000000000..a8c21fc582d4 --- /dev/null +++ b/toolkit/components/reader/jar.mn @@ -0,0 +1,10 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +toolkit.jar: + content/global/reader/aboutReader.html (content/aboutReader.html) + content/global/reader/aboutReader.js (content/aboutReader.js) + content/global/reader/Readability.js (content/Readability.js) + content/global/reader/JSDOMParser.js (content/JSDOMParser.js) + content/global/reader/readerWorker.js (content/readerWorker.js) diff --git a/toolkit/components/reader/moz.build b/toolkit/components/reader/moz.build new file mode 100644 index 000000000000..3bbe6729759c --- /dev/null +++ b/toolkit/components/reader/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ['jar.mn'] diff --git a/mobile/android/locales/en-US/chrome/aboutReader.properties b/toolkit/locales/en-US/chrome/global/aboutReader.properties similarity index 100% rename from mobile/android/locales/en-US/chrome/aboutReader.properties rename to toolkit/locales/en-US/chrome/global/aboutReader.properties diff --git a/toolkit/locales/jar.mn b/toolkit/locales/jar.mn index d03a6fafd661..cea951d0f0cc 100644 --- a/toolkit/locales/jar.mn +++ b/toolkit/locales/jar.mn @@ -8,6 +8,7 @@ % locale global @AB_CD@ %locale/@AB_CD@/global/ locale/@AB_CD@/global/about.dtd (%chrome/global/about.dtd) locale/@AB_CD@/global/aboutAbout.dtd (%chrome/global/aboutAbout.dtd) + locale/@AB_CD@/global/aboutReader.properties (%chrome/global/aboutReader.properties) locale/@AB_CD@/global/aboutRights.dtd (%chrome/global/aboutRights.dtd) locale/@AB_CD@/global/aboutNetworking.dtd (%chrome/global/aboutNetworking.dtd) locale/@AB_CD@/global/aboutSupport.dtd (%chrome/global/aboutSupport.dtd) diff --git a/toolkit/themes/osx/global/jar.mn b/toolkit/themes/osx/global/jar.mn index f5e9320b53c5..13e7d8c8eb2f 100644 --- a/toolkit/themes/osx/global/jar.mn +++ b/toolkit/themes/osx/global/jar.mn @@ -10,6 +10,7 @@ toolkit.jar: skin/classic/global/aboutCache.css (../../windows/global/aboutCache.css) skin/classic/global/aboutCacheEntry.css (../../windows/global/aboutCacheEntry.css) skin/classic/global/aboutMemory.css (../../windows/global/aboutMemory.css) + skin/classic/global/aboutReader.css (../../windows/global/aboutReader.css) skin/classic/global/aboutSupport.css (../../windows/global/aboutSupport.css) skin/classic/global/appPicker.css (../../windows/global/appPicker.css) skin/classic/global/arrow.css diff --git a/toolkit/themes/windows/global/aboutReader.css b/toolkit/themes/windows/global/aboutReader.css new file mode 100644 index 000000000000..630b26ab6aa4 --- /dev/null +++ b/toolkit/themes/windows/global/aboutReader.css @@ -0,0 +1,3 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ diff --git a/toolkit/themes/windows/global/jar.mn b/toolkit/themes/windows/global/jar.mn index 2df14192165a..c05b76ca7bdf 100644 --- a/toolkit/themes/windows/global/jar.mn +++ b/toolkit/themes/windows/global/jar.mn @@ -11,6 +11,7 @@ toolkit.jar: skin/classic/global/aboutCache.css skin/classic/global/aboutCacheEntry.css skin/classic/global/aboutMemory.css + skin/classic/global/aboutReader.css skin/classic/global/aboutSupport.css skin/classic/global/appPicker.css skin/classic/global/arrow.css @@ -206,6 +207,7 @@ toolkit.jar: skin/classic/aero/global/aboutCache.css skin/classic/aero/global/aboutCacheEntry.css skin/classic/aero/global/aboutMemory.css + skin/classic/aero/global/aboutReader.css skin/classic/aero/global/aboutSupport.css skin/classic/aero/global/appPicker.css skin/classic/aero/global/arrow.css From 3dbb00ba332b9fb30b59d43bc820dd6fe4af1a46 Mon Sep 17 00:00:00 2001 From: Margaret Leibovic Date: Fri, 12 Dec 2014 13:47:07 -0800 Subject: [PATCH 119/130] Bug 793920 - (Part 2) Split up Reader.js to create shared ReaderMode.jsm in /toolkit. r=bnicholson --HG-- rename : mobile/android/chrome/content/Reader.js => toolkit/components/reader/ReaderMode.jsm extra : rebase_source : 5f66c449c50135d53644ebc507357ab560938bc7 extra : histedit_source : 53ad05bc9a30977399627c13f07971d7f7250814 --- .../base/tests/testReadingListCache.js | 13 +- mobile/android/chrome/content/Reader.js | 222 +--------------- mobile/android/chrome/content/browser.js | 5 +- toolkit/components/reader/ReaderMode.jsm | 236 ++++++++++++++++++ .../components/reader/content/ReaderMode.jsm | 0 toolkit/components/reader/moz.build | 4 + 6 files changed, 256 insertions(+), 224 deletions(-) create mode 100644 toolkit/components/reader/ReaderMode.jsm create mode 100644 toolkit/components/reader/content/ReaderMode.jsm diff --git a/mobile/android/base/tests/testReadingListCache.js b/mobile/android/base/tests/testReadingListCache.js index be7c3a28e51a..8de822dcf591 100644 --- a/mobile/android/base/tests/testReadingListCache.js +++ b/mobile/android/base/tests/testReadingListCache.js @@ -5,6 +5,7 @@ const { utils: Cu } = Components; +Cu.import("resource://gre/modules/ReaderMode.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Task.jsm"); @@ -39,13 +40,13 @@ let TEST_PAGES = [ add_task(function* test_article_not_found() { let uri = Services.io.newURI(TEST_PAGES[0].url, null, null); - let article = yield Reader.getArticleFromCache(uri); + let article = yield ReaderMode.getArticleFromCache(uri); do_check_eq(article, null); }); add_task(function* test_store_article() { // Create an article object to store in the cache. - yield Reader.storeArticleInCache({ + yield ReaderMode.storeArticleInCache({ url: TEST_PAGES[0].url, content: "Lorem ipsum", title: TEST_PAGES[0].expected.title, @@ -55,14 +56,14 @@ add_task(function* test_store_article() { }); let uri = Services.io.newURI(TEST_PAGES[0].url, null, null); - let article = yield Reader.getArticleFromCache(uri); + let article = yield ReaderMode.getArticleFromCache(uri); checkArticle(article, TEST_PAGES[0]); }); add_task(function* test_remove_article() { let uri = Services.io.newURI(TEST_PAGES[0].url, null, null); - yield Reader.removeArticleFromCache(uri); - let article = yield Reader.getArticleFromCache(uri); + yield ReaderMode.removeArticleFromCache(uri); + let article = yield ReaderMode.getArticleFromCache(uri); do_check_eq(article, null); }); @@ -110,7 +111,7 @@ add_task(function* test_migrate_cache() { // Check to make sure the article made it into the new cache. let uri = Services.io.newURI(TEST_PAGES[0].url, null, null); - let article = yield Reader.getArticleFromCache(uri); + let article = yield ReaderMode.getArticleFromCache(uri); checkArticle(article, TEST_PAGES[0]); }); diff --git a/mobile/android/chrome/content/Reader.js b/mobile/android/chrome/content/Reader.js index 0683b319659e..6fcca2e64391 100644 --- a/mobile/android/chrome/content/Reader.js +++ b/mobile/android/chrome/content/Reader.js @@ -4,21 +4,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils", - "resource://services-common/utils.js"); - let Reader = { - // Version of the cache schema. - CACHE_VERSION: 1, - - DEBUG: 0, - - // Don't try to parse the page if it has too many elements (for memory and - // performance reasons) - MAX_ELEMS_TO_PARSE: 3000, - - _requests: {}, - get isEnabledForParseOnLoad() { delete this.isEnabledForParseOnLoad; @@ -84,14 +70,7 @@ let Reader = { switch(aTopic) { case "Reader:Removed": { let uri = Services.io.newURI(aData, null, null); - this.removeArticleFromCache(uri).catch(e => Cu.reportError("Error removing article from cache: " + e)); - break; - } - - case "nsPref:changed": { - if (aData.startsWith("reader.parse-on-load.")) { - this.isEnabledForParseOnLoad = this._getStateForParseOnLoad(); - } + ReaderMode.removeArticleFromCache(uri).catch(e => Cu.reportError("Error removing article from cache: " + e)); break; } } @@ -133,7 +112,7 @@ let Reader = { excerpt: article.excerpt || "", }); - this.storeArticleInCache(article).catch(e => Cu.reportError("Error storing article in cache: " + e)); + ReaderMode.storeArticleInCache(article).catch(e => Cu.reportError("Error storing article in cache: " + e)); }, _getStateForParseOnLoad: function () { @@ -159,16 +138,14 @@ let Reader = { if (tab) { let article = tab.savedArticle; if (article && article.url == url) { - this.log("Saved article found in tab"); return article; } } // Next, try to find a parsed article in the cache. let uri = Services.io.newURI(url, null, null); - let article = yield this.getArticleFromCache(uri); + let article = yield ReaderMode.getArticleFromCache(uri); if (article) { - this.log("Saved article found in cache"); return article; } @@ -177,146 +154,6 @@ let Reader = { return yield this._downloadAndParseDocument(url); }), - /** - * Gets an article from a loaded tab's document. This method will parse the document - * if it does not find the article in the tab data or the cache. - * - * @param tab The loaded tab. - * @return {Promise} - * @resolves JS object representing the article, or null if no article is found. - */ - parseDocumentFromTab: Task.async(function* (tab) { - let uri = tab.browser.currentURI; - if (!this._shouldCheckUri(uri)) { - this.log("Reader mode disabled for URI"); - return null; - } - - // First, try to find a parsed article in the cache. - let article = yield this.getArticleFromCache(uri); - if (article) { - this.log("Page found in cache, return article immediately"); - return article; - } - - let doc = tab.browser.contentWindow.document; - return yield this._readerParse(uri, doc); - }), - - /** - * Retrieves an article from the cache given an article URI. - * - * @param uri The article URI. - * @return {Promise} - * @resolves JS object representing the article, or null if no article is found. - * @rejects OS.File.Error - */ - getArticleFromCache: Task.async(function* (uri) { - let path = this._toHashedPath(uri.specIgnoringRef); - try { - let array = yield OS.File.read(path); - return JSON.parse(new TextDecoder().decode(array)); - } catch (e if e instanceof OS.File.Error && e.becauseNoSuchFile) { - return null; - } - }), - - /** - * Stores an article in the cache. - * - * @param article JS object representing article. - * @return {Promise} - * @resolves When the article is stored. - * @rejects OS.File.Error - */ - storeArticleInCache: Task.async(function* (article) { - let array = new TextEncoder().encode(JSON.stringify(article)); - let path = this._toHashedPath(article.url); - yield this._ensureCacheDir(); - yield OS.File.writeAtomic(path, array, { tmpPath: path + ".tmp" }); - }), - - /** - * Removes an article from the cache given an article URI. - * - * @param uri The article URI. - * @return {Promise} - * @resolves When the article is removed. - * @rejects OS.File.Error - */ - removeArticleFromCache: Task.async(function* (uri) { - let path = this._toHashedPath(uri.specIgnoringRef); - yield OS.File.remove(path); - }), - - log: function(msg) { - if (this.DEBUG) - dump("Reader: " + msg); - }, - - _shouldCheckUri: function (uri) { - if ((uri.prePath + "/") === uri.spec) { - this.log("Not parsing home page: " + uri.spec); - return false; - } - - if (!(uri.schemeIs("http") || uri.schemeIs("https") || uri.schemeIs("file"))) { - this.log("Not parsing URI scheme: " + uri.scheme); - return false; - } - - return true; - }, - - _readerParse: function (uri, doc) { - return new Promise((resolve, reject) => { - let numTags = doc.getElementsByTagName("*").length; - if (numTags > this.MAX_ELEMS_TO_PARSE) { - this.log("Aborting parse for " + uri.spec + "; " + numTags + " elements found"); - resolve(null); - return; - } - - let worker = new ChromeWorker("chrome://global/content/reader/readerWorker.js"); - worker.onmessage = evt => { - let article = evt.data; - - if (!article) { - this.log("Worker did not return an article"); - resolve(null); - return; - } - - // Append URL to the article data. specIgnoringRef will ignore any hash - // in the URL. - article.url = uri.specIgnoringRef; - let flags = Ci.nsIDocumentEncoder.OutputSelectionOnly | Ci.nsIDocumentEncoder.OutputAbsoluteLinks; - article.title = Cc["@mozilla.org/parserutils;1"].getService(Ci.nsIParserUtils) - .convertToPlainText(article.title, flags, 0); - resolve(article); - }; - - worker.onerror = evt => { - reject("Error in worker: " + evt.message); - }; - - try { - worker.postMessage({ - uri: { - spec: uri.spec, - host: uri.host, - prePath: uri.prePath, - scheme: uri.scheme, - pathBase: Services.io.newURI(".", null, uri).spec - }, - doc: new XMLSerializer().serializeToString(doc) - }); - } catch (e) { - reject("Reader: could not build Readability arguments: " + e); - } - }); - }, - _downloadDocument: function (url) { return new Promise((resolve, reject) => { // We want to parse those arbitrary pages safely, outside the privileged @@ -344,7 +181,6 @@ let Reader = { return; } - this.log("Done loading: " + doc); if (doc.location.href == "about:blank") { reject("about:blank loaded; aborting"); @@ -362,65 +198,17 @@ let Reader = { }, _downloadAndParseDocument: Task.async(function* (url) { - this.log("Needs to fetch page, creating request: " + url); let { browser, doc } = yield this._downloadDocument(url); - this.log("Finished loading page: " + doc); try { let uri = Services.io.newURI(url, null, null); - let article = yield this._readerParse(uri, doc); - this.log("Document parsed successfully"); + let article = yield ReaderMode.readerParse(uri, doc); return article; } finally { browser.parentNode.removeChild(browser); } }), - get _cryptoHash() { - delete this._cryptoHash; - return this._cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash); - }, - - get _unicodeConverter() { - delete this._unicodeConverter; - this._unicodeConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] - .createInstance(Ci.nsIScriptableUnicodeConverter); - this._unicodeConverter.charset = "utf8"; - return this._unicodeConverter; - }, - - /** - * Calculate the hashed path for a stripped article URL. - * - * @param url The article URL. This should have referrers removed. - * @return The file path to the cached article. - */ - _toHashedPath: function (url) { - let value = this._unicodeConverter.convertToByteArray(url); - this._cryptoHash.init(this._cryptoHash.MD5); - this._cryptoHash.update(value, value.length); - - let hash = CommonUtils.encodeBase32(this._cryptoHash.finish(false)); - let fileName = hash.substring(0, hash.indexOf("=")) + ".json"; - return OS.Path.join(OS.Constants.Path.profileDir, "readercache", fileName); - }, - - /** - * Ensures the cache directory exists. - * - * @return Promise - * @resolves When the cache directory exists. - * @rejects OS.File.Error - */ - _ensureCacheDir: function () { - let dir = OS.Path.join(OS.Constants.Path.profileDir, "readercache"); - return OS.File.exists(dir).then(exists => { - if (!exists) { - return OS.File.makeDir(dir); - } - }); - }, - /** * Migrates old indexedDB reader mode cache to new JSON cache. */ @@ -458,7 +246,7 @@ let Reader = { }); for (let article of articles) { - yield this.storeArticleInCache(article); + yield ReaderMode.storeArticleInCache(article); } // Delete the database. diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 94c8da2a039f..535adc80b0df 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -109,6 +109,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "SharedPreferences", XPCOMUtils.defineLazyModuleGetter(this, "Notifications", "resource://gre/modules/Notifications.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", + "resource://gre/modules/ReaderMode.jsm"); + // Lazily-loaded browser scripts: [ ["SelectHelper", "chrome://browser/content/SelectHelper.js"], @@ -4282,7 +4285,7 @@ Tab.prototype = { Reader.updatePageAction(this); // Once document is fully loaded, parse it - Reader.parseDocumentFromTab(this).then(article => { + ReaderMode.parseDocumentFromBrowser(this.browser).then(article => { // The loaded page may have changed while we were parsing the document. // Make sure we've got the current one. let currentURL = this.browser.currentURI.specIgnoringRef; diff --git a/toolkit/components/reader/ReaderMode.jsm b/toolkit/components/reader/ReaderMode.jsm new file mode 100644 index 000000000000..555a4ce50cb6 --- /dev/null +++ b/toolkit/components/reader/ReaderMode.jsm @@ -0,0 +1,236 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + +this.EXPORTED_SYMBOLS = ["ReaderMode"]; + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +Cu.importGlobalProperties(["XMLHttpRequest"]); + +XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils", "resource://services-common/utils.js"); +XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); + +let ReaderMode = { + // Version of the cache schema. + CACHE_VERSION: 1, + + DEBUG: 0, + + // Don't try to parse the page if it has too many elements (for memory and + // performance reasons) + MAX_ELEMS_TO_PARSE: 3000, + + observe: function(aMessage, aTopic, aData) { + switch(aTopic) { + case "nsPref:changed": { + if (aData.startsWith("reader.parse-on-load.")) { + this.isEnabledForParseOnLoad = this._getStateForParseOnLoad(); + } + break; + } + } + }, + + /** + * Gets an article from a loaded browser's document. This method will parse the document + * if it does not find the article in the cache. + * + * @param browser A browser with a loaded page. + * @return {Promise} + * @resolves JS object representing the article, or null if no article is found. + */ + parseDocumentFromBrowser: Task.async(function* (browser) { + let uri = browser.currentURI; + if (!this._shouldCheckUri(uri)) { + this.log("Reader mode disabled for URI"); + return null; + } + + // First, try to find a parsed article in the cache. + let article = yield this.getArticleFromCache(uri); + if (article) { + this.log("Page found in cache, return article immediately"); + return article; + } + + let doc = browser.contentWindow.document; + return yield this.readerParse(uri, doc); + }), + + /** + * Retrieves an article from the cache given an article URI. + * + * @param uri The article URI. + * @return {Promise} + * @resolves JS object representing the article, or null if no article is found. + * @rejects OS.File.Error + */ + getArticleFromCache: Task.async(function* (uri) { + let path = this._toHashedPath(uri.specIgnoringRef); + try { + let array = yield OS.File.read(path); + return JSON.parse(new TextDecoder().decode(array)); + } catch (e if e instanceof OS.File.Error && e.becauseNoSuchFile) { + return null; + } + }), + + /** + * Stores an article in the cache. + * + * @param article JS object representing article. + * @return {Promise} + * @resolves When the article is stored. + * @rejects OS.File.Error + */ + storeArticleInCache: Task.async(function* (article) { + let array = new TextEncoder().encode(JSON.stringify(article)); + let path = this._toHashedPath(article.url); + yield this._ensureCacheDir(); + yield OS.File.writeAtomic(path, array, { tmpPath: path + ".tmp" }); + }), + + /** + * Removes an article from the cache given an article URI. + * + * @param uri The article URI. + * @return {Promise} + * @resolves When the article is removed. + * @rejects OS.File.Error + */ + removeArticleFromCache: Task.async(function* (uri) { + let path = this._toHashedPath(uri.specIgnoringRef); + yield OS.File.remove(path); + }), + + log: function(msg) { + if (this.DEBUG) + dump("Reader: " + msg); + }, + + _shouldCheckUri: function (uri) { + if ((uri.prePath + "/") === uri.spec) { + this.log("Not parsing home page: " + uri.spec); + return false; + } + + if (!(uri.schemeIs("http") || uri.schemeIs("https") || uri.schemeIs("file"))) { + this.log("Not parsing URI scheme: " + uri.scheme); + return false; + } + + return true; + }, + + /** + * Attempts to parse a document into an article. Heavy lifting happens + * in readerWorker.js. + * + * @param uri The article URI. + * @param doc The document to parse. + * @return {Promise} + * @resolves JS object representing the article, or null if no article is found. + */ + readerParse: function (uri, doc) { + return new Promise((resolve, reject) => { + let numTags = doc.getElementsByTagName("*").length; + if (numTags > this.MAX_ELEMS_TO_PARSE) { + this.log("Aborting parse for " + uri.spec + "; " + numTags + " elements found"); + resolve(null); + return; + } + + let worker = new ChromeWorker("chrome://global/content/reader/readerWorker.js"); + worker.onmessage = evt => { + let article = evt.data; + + if (!article) { + this.log("Worker did not return an article"); + resolve(null); + return; + } + + // Append URL to the article data. specIgnoringRef will ignore any hash + // in the URL. + article.url = uri.specIgnoringRef; + let flags = Ci.nsIDocumentEncoder.OutputSelectionOnly | Ci.nsIDocumentEncoder.OutputAbsoluteLinks; + article.title = Cc["@mozilla.org/parserutils;1"].getService(Ci.nsIParserUtils) + .convertToPlainText(article.title, flags, 0); + resolve(article); + }; + + worker.onerror = evt => { + reject("Error in worker: " + evt.message); + }; + + try { + let serializer = Cc["@mozilla.org/xmlextras/xmlserializer;1"]. + createInstance(Ci.nsIDOMSerializer); + worker.postMessage({ + uri: { + spec: uri.spec, + host: uri.host, + prePath: uri.prePath, + scheme: uri.scheme, + pathBase: Services.io.newURI(".", null, uri).spec + }, + doc: serializer.serializeToString(doc) + }); + } catch (e) { + reject("Reader: could not build Readability arguments: " + e); + } + }); + }, + + get _cryptoHash() { + delete this._cryptoHash; + return this._cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash); + }, + + get _unicodeConverter() { + delete this._unicodeConverter; + this._unicodeConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] + .createInstance(Ci.nsIScriptableUnicodeConverter); + this._unicodeConverter.charset = "utf8"; + return this._unicodeConverter; + }, + + /** + * Calculate the hashed path for a stripped article URL. + * + * @param url The article URL. This should have referrers removed. + * @return The file path to the cached article. + */ + _toHashedPath: function (url) { + let value = this._unicodeConverter.convertToByteArray(url); + this._cryptoHash.init(this._cryptoHash.MD5); + this._cryptoHash.update(value, value.length); + + let hash = CommonUtils.encodeBase32(this._cryptoHash.finish(false)); + let fileName = hash.substring(0, hash.indexOf("=")) + ".json"; + return OS.Path.join(OS.Constants.Path.profileDir, "readercache", fileName); + }, + + /** + * Ensures the cache directory exists. + * + * @return Promise + * @resolves When the cache directory exists. + * @rejects OS.File.Error + */ + _ensureCacheDir: function () { + let dir = OS.Path.join(OS.Constants.Path.profileDir, "readercache"); + return OS.File.exists(dir).then(exists => { + if (!exists) { + return OS.File.makeDir(dir); + } + }); + } +}; diff --git a/toolkit/components/reader/content/ReaderMode.jsm b/toolkit/components/reader/content/ReaderMode.jsm new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/toolkit/components/reader/moz.build b/toolkit/components/reader/moz.build index 3bbe6729759c..fd4ec038a70b 100644 --- a/toolkit/components/reader/moz.build +++ b/toolkit/components/reader/moz.build @@ -5,3 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. JAR_MANIFESTS += ['jar.mn'] + +EXTRA_JS_MODULES += [ + 'ReaderMode.jsm' +] From 3dcf3953581577e5bb9705ad798239eab2623cd7 Mon Sep 17 00:00:00 2001 From: Jordan Santell Date: Fri, 12 Dec 2014 11:28:24 -0800 Subject: [PATCH 120/130] Bug 1110952 - Add module for managing devtools colors and From 7d463d4891a7a4f57652cb962e3113eb28dea876 Mon Sep 17 00:00:00 2001 themes. r=bgrins --- browser/devtools/shared/moz.build | 1 + browser/devtools/shared/test/browser.ini | 1 + browser/devtools/shared/test/browser_theme.js | 91 +++++++++++++++++++ browser/devtools/shared/theme.js | 90 ++++++++++++++++++ 4 files changed, 183 insertions(+) create mode 100644 browser/devtools/shared/test/browser_theme.js create mode 100644 browser/devtools/shared/theme.js diff --git a/browser/devtools/shared/moz.build b/browser/devtools/shared/moz.build index f2f398311754..00d09cbed485 100644 --- a/browser/devtools/shared/moz.build +++ b/browser/devtools/shared/moz.build @@ -40,6 +40,7 @@ EXTRA_JS_MODULES.devtools.shared += [ 'observable-object.js', 'telemetry.js', 'theme-switching.js', + 'theme.js', 'undo.js', ] diff --git a/browser/devtools/shared/test/browser.ini b/browser/devtools/shared/test/browser.ini index dd4dba0f878e..5d9e49af113f 100644 --- a/browser/devtools/shared/test/browser.ini +++ b/browser/devtools/shared/test/browser.ini @@ -45,6 +45,7 @@ support-files = [browser_prefs.js] [browser_require_basic.js] [browser_spectrum.js] +[browser_theme.js] [browser_tableWidget_basic.js] [browser_tableWidget_keyboard_interaction.js] [browser_tableWidget_mouse_interaction.js] diff --git a/browser/devtools/shared/test/browser_theme.js b/browser/devtools/shared/test/browser_theme.js new file mode 100644 index 000000000000..9fca5fee1bfb --- /dev/null +++ b/browser/devtools/shared/test/browser_theme.js @@ -0,0 +1,91 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that theme utilities work + +let { Cu } = devtools.require("chrome"); +let { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); +let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}); +let { getColor, getTheme, setTheme } = devtools.require("devtools/shared/theme"); + +function test() { + waitForExplicitFinish(); + testGetTheme(); + testSetTheme(); + testGetColor(); + testColorExistence(); + endTests(); +} + +function endTests() { + gDevTools = Services = null; + finish(); +} + +function testGetTheme () { + let originalTheme = getTheme(); + ok(originalTheme, "has some theme to start with."); + Services.prefs.setCharPref("devtools.theme", "light"); + is(getTheme(), "light", "getTheme() correctly returns light theme"); + Services.prefs.setCharPref("devtools.theme", "dark"); + is(getTheme(), "dark", "getTheme() correctly returns dark theme"); + Services.prefs.setCharPref("devtools.theme", "unknown"); + is(getTheme(), "unknown", "getTheme() correctly returns an unknown theme"); + Services.prefs.setCharPref("devtools.theme", originalTheme); +} + +function testSetTheme () { + let originalTheme = getTheme(); + setTheme("dark"); + is(Services.prefs.getCharPref("devtools.theme"), "dark", "setTheme() correctly sets dark theme."); + setTheme("light"); + is(Services.prefs.getCharPref("devtools.theme"), "light", "setTheme() correctly sets light theme."); + setTheme("unknown"); + is(Services.prefs.getCharPref("devtools.theme"), "unknown", "setTheme() correctly sets an unknown theme."); + Services.prefs.setCharPref("devtools.theme", originalTheme); +} + +function testGetColor () { + let BLUE_DARK = "#3689b2"; + let BLUE_LIGHT = "hsl(208,56%,40%)"; + let originalTheme = getTheme(); + + setTheme("dark"); + is(getColor("highlight-blue"), BLUE_DARK, "correctly gets color for enabled theme."); + setTheme("light"); + is(getColor("highlight-blue"), BLUE_LIGHT, "correctly gets color for enabled theme."); + setTheme("metal"); + is(getColor("highlight-blue"), BLUE_LIGHT, "correctly uses light for default theme if enabled theme not found"); + + is(getColor("highlight-blue", "dark"), BLUE_DARK, "if provided and found, uses the provided theme."); + is(getColor("highlight-blue", "metal"), BLUE_LIGHT, "if provided and not found, defaults to light theme."); + is(getColor("somecomponents"), null, "if a type cannot be found, should return null."); + + setTheme(originalTheme); +} + +function testColorExistence () { + var vars = ["body-background", "sidebar-background", "contrast-background", "tab-toolbar-background", + "toolbar-background", "selection-background", "selection-color", + "selection-background-semitransparent", "splitter-color", "comment", "body-color", + "body-color-alt", "content-color1", "content-color2", "content-color3", + "highlight-green", "highlight-blue", "highlight-bluegrey", "highlight-purple", + "highlight-lightorange", "highlight-orange", "highlight-red", "highlight-pink" + ]; + + for (let type of vars) { + ok(getColor(type, "light"), `${type} is a valid color in light theme`); + ok(getColor(type, "dark"), `${type} is a valid color in light theme`); + } +} + +function isColor (s) { + // Regexes from Heather Arthur's `color-string` + // https://github.com/harthur/color-string + // MIT License + return /^#([a-fA-F0-9]{3})$/.test(s) || + /^#([a-fA-F0-9]{6})$/.test(s) || + /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d\.]+)\s*)?\)$/.test(s) || + /^rgba?\(\s*([\d\.]+)\%\s*,\s*([\d\.]+)\%\s*,\s*([\d\.]+)\%\s*(?:,\s*([\d\.]+)\s*)?\)$/.test(s); +} diff --git a/browser/devtools/shared/theme.js b/browser/devtools/shared/theme.js new file mode 100644 index 000000000000..a65b75b6266a --- /dev/null +++ b/browser/devtools/shared/theme.js @@ -0,0 +1,90 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/** + * Colors for themes taken from: + * https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors + */ + +const { Cu } = require("chrome"); +const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {}); +loader.lazyRequireGetter(this, "Services"); +loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm"); + +const themeURIs = { + light: "chrome://browser/skin/devtools/light-theme.css", + dark: "chrome://browser/skin/devtools/dark-theme.css" +} + +const cachedThemes = {}; + +/** + * Returns a string of the file found at URI + */ +function readURI (uri) { + let stream = NetUtil.newChannel(uri, "UTF-8", null).open(); + let count = stream.available(); + let data = NetUtil.readInputStreamToString(stream, count, { charset: "UTF-8" }); + stream.close(); + return data; +} + +/** + * Takes a theme name and either returns it from the cache, + * or fetches the theme CSS file and caches it. + */ +function getThemeFile (name) { + // Use the cached theme, or generate it + let themeFile = cachedThemes[name] || readURI(themeURIs[name]).match(/--theme-.*: .*;/g).join("\n"); + + // Cache if not already cached + if (!cachedThemes[name]) { + cachedThemes[name] = themeFile; + } + + return themeFile; +} + +/** + * Returns the string value of the current theme, + * like "dark" or "light". + */ +const getTheme = exports.getTheme = () => Services.prefs.getCharPref("devtools.theme"); + +/** + * Returns a color indicated by `type` (like "toolbar-background", or "highlight-red"), + * with the ability to specify a theme, or use whatever the current theme is + * if left unset. If theme not found, falls back to "light" theme. Returns null + * if the type cannot be found for the theme given. + */ +const getColor = exports.getColor = (type, theme) => { + let themeName = theme || getTheme(); + + // If there's no theme URIs for this theme, use `light` as default. + if (!themeURIs[themeName]) { + themeName = "light"; + } + + let themeFile = getThemeFile(themeName); + let match; + + // Return the appropriate variable in the theme, or otherwise, null. + return (match = themeFile.match(new RegExp("--theme-" + type + ": (.*);"))) ? match[1] : null; +}; + +/** + * Mimics selecting the theme selector in the toolbox; + * sets the preference and emits an event on gDevTools to trigger + * the themeing. + */ +const setTheme = exports.setTheme = (newTheme) => { + Services.prefs.setCharPref("devtools.theme", newTheme); + gDevTools.emit("pref-changed", { + pref: "devtools.theme", + newValue: newTheme, + oldValue: getTheme() + }); +}; From 47e78f41b75ea75ed3e531ab12d7d0e687ee13ab Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Tue, 16 Dec 2014 18:39:43 -0500 Subject: [PATCH 121/130] Bug 1111258 - Allow dumping textures without MOZ_DUMP_PAINTING. r=mstange --- gfx/layers/composite/ContentHost.cpp | 4 ++-- gfx/layers/composite/ContentHost.h | 5 +---- gfx/layers/composite/TiledContentHost.cpp | 4 ---- gfx/layers/composite/TiledContentHost.h | 2 -- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/gfx/layers/composite/ContentHost.cpp b/gfx/layers/composite/ContentHost.cpp index 2f3da6585fce..37f650c8b4b5 100644 --- a/gfx/layers/composite/ContentHost.cpp +++ b/gfx/layers/composite/ContentHost.cpp @@ -255,12 +255,12 @@ ContentHostTexture::SetCompositor(Compositor* aCompositor) } } -#ifdef MOZ_DUMP_PAINTING void ContentHostTexture::Dump(std::stringstream& aStream, const char* aPrefix, bool aDumpHtml) { +#ifdef MOZ_DUMP_PAINTING if (!aDumpHtml) { return; } @@ -278,8 +278,8 @@ ContentHostTexture::Dump(std::stringstream& aStream, aStream << "> Front buffer on white "; } aStream << ""; -} #endif +} static inline void AddWrappedRegion(const nsIntRegion& aInput, nsIntRegion& aOutput, diff --git a/gfx/layers/composite/ContentHost.h b/gfx/layers/composite/ContentHost.h index 9855823284e8..5e2b1d8c1d7b 100644 --- a/gfx/layers/composite/ContentHost.h +++ b/gfx/layers/composite/ContentHost.h @@ -129,13 +129,10 @@ public: virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE; -#ifdef MOZ_DUMP_PAINTING virtual TemporaryRef GetAsSurface() MOZ_OVERRIDE; virtual void Dump(std::stringstream& aStream, - const char* aPrefix="", - bool aDumpHtml=false) MOZ_OVERRIDE; -#endif + const char* aPrefix="") MOZ_OVERRIDE; virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE; diff --git a/gfx/layers/composite/TiledContentHost.cpp b/gfx/layers/composite/TiledContentHost.cpp index 8ce13402ce99..9b53ef21b576 100644 --- a/gfx/layers/composite/TiledContentHost.cpp +++ b/gfx/layers/composite/TiledContentHost.cpp @@ -629,17 +629,14 @@ TiledContentHost::PrintInfo(std::stringstream& aStream, const char* aPrefix) aStream << aPrefix; aStream << nsPrintfCString("TiledContentHost (0x%p)", this).get(); -#ifdef MOZ_DUMP_PAINTING if (gfxPrefs::LayersDumpTexture() || profiler_feature_active("layersdump")) { nsAutoCString pfx(aPrefix); pfx += " "; Dump(aStream, pfx.get(), false); } -#endif } -#ifdef MOZ_DUMP_PAINTING void TiledContentHost::Dump(std::stringstream& aStream, const char* aPrefix, @@ -678,7 +675,6 @@ TiledContentHost::Dump(std::stringstream& aStream, x += w; } } -#endif } // namespace } // namespace diff --git a/gfx/layers/composite/TiledContentHost.h b/gfx/layers/composite/TiledContentHost.h index 11e70758110f..229d07e355f1 100644 --- a/gfx/layers/composite/TiledContentHost.h +++ b/gfx/layers/composite/TiledContentHost.h @@ -256,11 +256,9 @@ public: virtual void Detach(Layer* aLayer = nullptr, AttachFlags aFlags = NO_FLAGS) MOZ_OVERRIDE; -#ifdef MOZ_DUMP_PAINTING virtual void Dump(std::stringstream& aStream, const char* aPrefix="", bool aDumpHtml=false) MOZ_OVERRIDE; -#endif virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix); From 644f0f81e533be222e4c9cfb2c3d6ef53e16bc35 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Tue, 16 Dec 2014 21:08:32 -0500 Subject: [PATCH 122/130] Bug 1100379: add *.clearslide.com to allowed screensharing domains rs=mreavy --- modules/libpref/init/all.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index adb91db9ccd1..29031f6e4895 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -409,10 +409,10 @@ pref("media.getusermedia.screensharing.enabled", true); #endif #ifdef RELEASE_BUILD -pref("media.getusermedia.screensharing.allowed_domains", "webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,example.com"); +pref("media.getusermedia.screensharing.allowed_domains", "webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,*.clearslide.com,example.com"); #else // temporary value, not intended for release - bug 1049087 -pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io,webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,example.com"); +pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io,webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,*.clearslide.com,example.com"); #endif // OS/X 10.6 and XP have screen/window sharing off by default due to various issues - Caveat emptor pref("media.getusermedia.screensharing.allow_on_old_platforms", false); From 9df23f9a1ee6f9e2ce313aa3c6fbc439f34cf84d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Dec 2014 18:18:21 -0800 Subject: [PATCH 123/130] Bug 1111948 - Fix --disable-startupcache, and re-disable the startup cache on B2G in the process. r=mshal. --HG-- extra : rebase_source : 59d14319e67eaf349df0ecc2aa80be94865aed70 --- configure.in | 5 +++-- startupcache/StartupCache.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/configure.in b/configure.in index 1d0eb48c14b2..015cc00eaedd 100644 --- a/configure.in +++ b/configure.in @@ -7475,7 +7475,6 @@ fi dnl ======================================================== dnl = Offer a way to disable the startup cache dnl ======================================================== -MOZ_DISABLE_STARTUPCACHE= MOZ_ARG_DISABLE_BOOL(startupcache, [ --disable-startupcache Disable startup cache ], @@ -7486,7 +7485,9 @@ dnl bug 988880: disable startup cache on b2g if test -n "$MOZ_B2G"; then MOZ_DISABLE_STARTUPCACHE=1 fi - +if test -n "$MOZ_DISABLE_STARTUPCACHE"; then + AC_DEFINE(MOZ_DISABLE_STARTUPCACHE) +fi AC_SUBST(MOZ_DISABLE_STARTUPCACHE) dnl ======================================================== diff --git a/startupcache/StartupCache.cpp b/startupcache/StartupCache.cpp index 2ea4cebbcde9..a473ecaaf724 100644 --- a/startupcache/StartupCache.cpp +++ b/startupcache/StartupCache.cpp @@ -93,7 +93,7 @@ StartupCache::GetSingleton() if (XRE_GetProcessType() != GeckoProcessType_Default) { return nullptr; } -#ifdef MOZ_DISABLE_STARTUP_CACHE +#ifdef MOZ_DISABLE_STARTUPCACHE return nullptr; #endif From 11da062e2ad007d6f2815f0ac8f56b13c272b602 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Tue, 16 Dec 2014 21:32:58 -0500 Subject: [PATCH 124/130] Bug 1111258 - Bustage fix. r=mstange --- gfx/layers/composite/CompositableHost.cpp | 2 -- gfx/layers/composite/CompositableHost.h | 2 -- gfx/layers/composite/ContentHost.cpp | 3 --- gfx/layers/composite/ContentHost.h | 3 ++- gfx/layers/composite/ImageHost.cpp | 4 ---- gfx/layers/composite/ImageHost.h | 2 -- 6 files changed, 2 insertions(+), 14 deletions(-) diff --git a/gfx/layers/composite/CompositableHost.cpp b/gfx/layers/composite/CompositableHost.cpp index 84ea3aa5218b..aaecbec64f1a 100644 --- a/gfx/layers/composite/CompositableHost.cpp +++ b/gfx/layers/composite/CompositableHost.cpp @@ -207,7 +207,6 @@ CompositableHost::Create(const TextureInfo& aTextureInfo) return result; } -#ifdef MOZ_DUMP_PAINTING void CompositableHost::DumpTextureHost(std::stringstream& aStream, TextureHost* aTexture) { @@ -220,7 +219,6 @@ CompositableHost::DumpTextureHost(std::stringstream& aStream, TextureHost* aText } aStream << gfxUtils::GetAsLZ4Base64Str(dSurf).get(); } -#endif namespace CompositableMap { diff --git a/gfx/layers/composite/CompositableHost.h b/gfx/layers/composite/CompositableHost.h index d7a5710f1ab6..2b10860ee611 100644 --- a/gfx/layers/composite/CompositableHost.h +++ b/gfx/layers/composite/CompositableHost.h @@ -216,14 +216,12 @@ public: } bool IsAttached() { return mAttached; } -#ifdef MOZ_DUMP_PAINTING virtual void Dump(std::stringstream& aStream, const char* aPrefix="", bool aDumpHtml=false) { } static void DumpTextureHost(std::stringstream& aStream, TextureHost* aTexture); virtual TemporaryRef GetAsSurface() { return nullptr; } -#endif virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) = 0; diff --git a/gfx/layers/composite/ContentHost.cpp b/gfx/layers/composite/ContentHost.cpp index 37f650c8b4b5..4b1ba212bcb2 100644 --- a/gfx/layers/composite/ContentHost.cpp +++ b/gfx/layers/composite/ContentHost.cpp @@ -878,7 +878,6 @@ ContentHostIncremental::GenEffect(const gfx::Filter& aFilter) return CreateTexturedEffect(mSource, mSourceOnWhite, aFilter, true); } -#ifdef MOZ_DUMP_PAINTING TemporaryRef ContentHostTexture::GetAsSurface() { @@ -889,8 +888,6 @@ ContentHostTexture::GetAsSurface() return mTextureHost->GetAsSurface(); } -#endif - } // namespace } // namespace diff --git a/gfx/layers/composite/ContentHost.h b/gfx/layers/composite/ContentHost.h index 5e2b1d8c1d7b..ebffd0aedba3 100644 --- a/gfx/layers/composite/ContentHost.h +++ b/gfx/layers/composite/ContentHost.h @@ -132,7 +132,8 @@ public: virtual TemporaryRef GetAsSurface() MOZ_OVERRIDE; virtual void Dump(std::stringstream& aStream, - const char* aPrefix="") MOZ_OVERRIDE; + const char* aPrefix="", + bool aDumpHtml=false) MOZ_OVERRIDE; virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE; diff --git a/gfx/layers/composite/ImageHost.cpp b/gfx/layers/composite/ImageHost.cpp index c16ac50d69f8..c9a267553c42 100644 --- a/gfx/layers/composite/ImageHost.cpp +++ b/gfx/layers/composite/ImageHost.cpp @@ -217,7 +217,6 @@ ImageHost::PrintInfo(std::stringstream& aStream, const char* aPrefix) } } -#ifdef MOZ_DUMP_PAINTING void ImageHost::Dump(std::stringstream& aStream, const char* aPrefix, @@ -231,7 +230,6 @@ ImageHost::Dump(std::stringstream& aStream, aStream << (aDumpHtml ? " " : " "); } } -#endif LayerRenderState ImageHost::GetRenderState() @@ -242,13 +240,11 @@ ImageHost::GetRenderState() return LayerRenderState(); } -#ifdef MOZ_DUMP_PAINTING TemporaryRef ImageHost::GetAsSurface() { return mFrontBuffer->GetAsSurface(); } -#endif bool ImageHost::Lock() diff --git a/gfx/layers/composite/ImageHost.h b/gfx/layers/composite/ImageHost.h index 038da25320df..44e54f0d0e99 100644 --- a/gfx/layers/composite/ImageHost.h +++ b/gfx/layers/composite/ImageHost.h @@ -72,13 +72,11 @@ public: virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix); -#ifdef MOZ_DUMP_PAINTING virtual void Dump(std::stringstream& aStream, const char* aPrefix = "", bool aDumpHtml = false) MOZ_OVERRIDE; virtual TemporaryRef GetAsSurface() MOZ_OVERRIDE; -#endif virtual bool Lock() MOZ_OVERRIDE; From c244b776e2a066ec6ef189c278ba0493e84997c6 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Mon, 15 Dec 2014 14:37:15 +1100 Subject: [PATCH 125/130] Bug 1052123 - Autohide ruby annotations which are identical to their ruby bases. r=dbaron --HG-- extra : transplant_source : %B5w%BF%89%879%D6F2%DD%BD%F3%BAG%0D%5E%A4%255%EE --- layout/generic/nsFrameState.cpp | 1 + layout/generic/nsFrameStateBits.h | 9 +++++ layout/generic/nsRubyBaseContainerFrame.cpp | 32 +++++++++++++++-- layout/generic/nsRubyTextFrame.cpp | 34 ++++++++++++++++++ layout/generic/nsRubyTextFrame.h | 9 +++++ .../reftests/css-ruby/autohiding-1-ref.html | 14 ++++++++ layout/reftests/css-ruby/autohiding-1.html | 14 ++++++++ .../reftests/css-ruby/autohiding-2-ref.html | 26 ++++++++++++++ layout/reftests/css-ruby/autohiding-2.html | 36 +++++++++++++++++++ .../reftests/css-ruby/autohiding-3-ref.html | 17 +++++++++ layout/reftests/css-ruby/autohiding-3.html | 17 +++++++++ .../reftests/css-ruby/float-handling-ref.html | 8 ++--- layout/reftests/css-ruby/float-handling.html | 8 ++--- layout/reftests/css-ruby/reftest.list | 3 ++ 14 files changed, 217 insertions(+), 11 deletions(-) create mode 100644 layout/reftests/css-ruby/autohiding-1-ref.html create mode 100644 layout/reftests/css-ruby/autohiding-1.html create mode 100644 layout/reftests/css-ruby/autohiding-2-ref.html create mode 100644 layout/reftests/css-ruby/autohiding-2.html create mode 100644 layout/reftests/css-ruby/autohiding-3-ref.html create mode 100644 layout/reftests/css-ruby/autohiding-3.html diff --git a/layout/generic/nsFrameState.cpp b/layout/generic/nsFrameState.cpp index 61ee67d442bf..6a58ac2e5853 100644 --- a/layout/generic/nsFrameState.cpp +++ b/layout/generic/nsFrameState.cpp @@ -17,6 +17,7 @@ #include "nsImageFrame.h" #include "nsInlineFrame.h" #include "nsPlaceholderFrame.h" +#include "nsRubyTextFrame.h" #include "nsSVGContainerFrame.h" #include "nsTableCellFrame.h" #include "nsTableRowFrame.h" diff --git a/layout/generic/nsFrameStateBits.h b/layout/generic/nsFrameStateBits.h index e2c647c833e7..ebe65fb40fed 100644 --- a/layout/generic/nsFrameStateBits.h +++ b/layout/generic/nsFrameStateBits.h @@ -512,6 +512,15 @@ FRAME_STATE_GROUP(Inline, nsInlineFrame) FRAME_STATE_BIT(Inline, 21, NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) FRAME_STATE_BIT(Inline, 22, NS_INLINE_FRAME_BIDI_VISUAL_IS_FIRST) FRAME_STATE_BIT(Inline, 23, NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST) +// nsRubyTextFrame inherits from nsInlineFrame + + +// == Frame state bits that apply to ruby text frames ========================= + +FRAME_STATE_GROUP(RubyText, nsRubyTextFrame) + +// inherits from nsInlineFrame +FRAME_STATE_BIT(RubyText, 24, NS_RUBY_TEXT_FRAME_AUTOHIDE) // == Frame state bits that apply to placeholder frames ======================= diff --git a/layout/generic/nsRubyBaseContainerFrame.cpp b/layout/generic/nsRubyBaseContainerFrame.cpp index 01e3b623e8ed..123a4cc82efb 100644 --- a/layout/generic/nsRubyBaseContainerFrame.cpp +++ b/layout/generic/nsRubyBaseContainerFrame.cpp @@ -7,6 +7,7 @@ /* rendering object for CSS "display: ruby-base-container" */ #include "nsRubyBaseContainerFrame.h" +#include "nsContentUtils.h" #include "nsLineLayout.h" #include "nsPresContext.h" #include "nsStyleContext.h" @@ -523,15 +524,40 @@ nsRubyBaseContainerFrame::ReflowOnePair(nsPresContext* aPresContext, nscoord istart = aReflowState.mLineLayout->GetCurrentICoord(); nscoord pairISize = 0; + nsAutoString baseText; + if (aBaseFrame) { + if (!nsContentUtils::GetNodeTextContent(aBaseFrame->GetContent(), + true, baseText)) { + NS_RUNTIMEABORT("OOM"); + } + } + // Reflow text frames for (uint32_t i = 0; i < rtcCount; i++) { - if (aTextFrames[i]) { - MOZ_ASSERT(aTextFrames[i]->GetType() == nsGkAtoms::rubyTextFrame); + nsIFrame* textFrame = aTextFrames[i]; + if (textFrame) { + MOZ_ASSERT(textFrame->GetType() == nsGkAtoms::rubyTextFrame); + nsAutoString annotationText; + if (!nsContentUtils::GetNodeTextContent(textFrame->GetContent(), + true, annotationText)) { + NS_RUNTIMEABORT("OOM"); + } + // Per CSS Ruby spec, the content comparison for auto-hiding + // takes place prior to white spaces collapsing (white-space) + // and text transformation (text-transform), and ignores elements + // (considers only the textContent of the boxes). Which means + // using the content tree text comparison is correct. + if (annotationText.Equals(baseText)) { + textFrame->AddStateBits(NS_RUBY_TEXT_FRAME_AUTOHIDE); + } else { + textFrame->RemoveStateBits(NS_RUBY_TEXT_FRAME_AUTOHIDE); + } + nsReflowStatus reflowStatus; nsHTMLReflowMetrics metrics(*aReflowStates[i]); bool pushedFrame; - aReflowStates[i]->mLineLayout->ReflowFrame(aTextFrames[i], reflowStatus, + aReflowStates[i]->mLineLayout->ReflowFrame(textFrame, reflowStatus, &metrics, pushedFrame); if (NS_INLINE_IS_BREAK(reflowStatus)) { // If any breaking occurs when reflowing a ruby text frame, diff --git a/layout/generic/nsRubyTextFrame.cpp b/layout/generic/nsRubyTextFrame.cpp index c71686241f87..707a9c01ab51 100644 --- a/layout/generic/nsRubyTextFrame.cpp +++ b/layout/generic/nsRubyTextFrame.cpp @@ -60,3 +60,37 @@ nsRubyTextFrame::IsFrameOfType(uint32_t aFlags) const } return nsRubyTextFrameSuper::IsFrameOfType(aFlags); } + + +/* virtual */ void +nsRubyTextFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) +{ + if (GetStateBits() & NS_RUBY_TEXT_FRAME_AUTOHIDE) { + return; + } + + nsRubyTextFrameSuper::BuildDisplayList(aBuilder, aDirtyRect, aLists); +} + +/* virtual */ void +nsRubyTextFrame::Reflow(nsPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + // Even if we want to hide this frame, we have to reflow it first. + // If we leave it dirty, changes to its content will never be + // propagated to the ancestors, then it won't be displayed even if + // the content is no longer the same, until next reflow triggered by + // some other change. In general, we always reflow all the frames we + // created. There might be other problems if we don't do that. + nsRubyTextFrameSuper::Reflow(aPresContext, aDesiredSize, + aReflowState, aStatus); + + if (GetStateBits() & NS_RUBY_TEXT_FRAME_AUTOHIDE) { + aDesiredSize.ClearSize(); + aDesiredSize.SetOverflowAreasToDesiredBounds(); + } +} diff --git a/layout/generic/nsRubyTextFrame.h b/layout/generic/nsRubyTextFrame.h index f08a05db18b9..287f970b6b65 100644 --- a/layout/generic/nsRubyTextFrame.h +++ b/layout/generic/nsRubyTextFrame.h @@ -35,6 +35,15 @@ public: virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; #endif + virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) MOZ_OVERRIDE; + + virtual void Reflow(nsPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) MOZ_OVERRIDE; + protected: friend nsContainerFrame* NS_NewRubyTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); diff --git a/layout/reftests/css-ruby/autohiding-1-ref.html b/layout/reftests/css-ruby/autohiding-1-ref.html new file mode 100644 index 000000000000..12f15a2e879b --- /dev/null +++ b/layout/reftests/css-ruby/autohiding-1-ref.html @@ -0,0 +1,14 @@ + + + + + Bug 1052123 - Autohide ruby annotations which are identical to their bases + + + + + + + + + diff --git a/layout/reftests/css-ruby/autohiding-1.html b/layout/reftests/css-ruby/autohiding-1.html new file mode 100644 index 000000000000..9c6ecfaaa34c --- /dev/null +++ b/layout/reftests/css-ruby/autohiding-1.html @@ -0,0 +1,14 @@ + + + + + Bug 1052123 - Autohide ruby annotations which are identical to their bases + + + + + + + + + diff --git a/layout/reftests/css-ruby/autohiding-2-ref.html b/layout/reftests/css-ruby/autohiding-2-ref.html new file mode 100644 index 000000000000..e389154bb661 --- /dev/null +++ b/layout/reftests/css-ruby/autohiding-2-ref.html @@ -0,0 +1,26 @@ + + + + + Bug 1052123 - Autohide ruby annotations which are identical to their bases + + + +

+ + ri +

+

+ ri + +

+

+ + +

+

+ + +

+ + diff --git a/layout/reftests/css-ruby/autohiding-2.html b/layout/reftests/css-ruby/autohiding-2.html new file mode 100644 index 000000000000..b05a87f658ec --- /dev/null +++ b/layout/reftests/css-ruby/autohiding-2.html @@ -0,0 +1,36 @@ + + + + + Bug 1052123 - Autohide ruby annotations which are identical to their bases + + + + +

+ + +

+

+ + +

+

+ + ri +

+

+ ri + +

+ + diff --git a/layout/reftests/css-ruby/autohiding-3-ref.html b/layout/reftests/css-ruby/autohiding-3-ref.html new file mode 100644 index 000000000000..70549f0477bb --- /dev/null +++ b/layout/reftests/css-ruby/autohiding-3-ref.html @@ -0,0 +1,17 @@ + + + + + Bug 1052123 - Autohide ruby annotations which are identical to their bases + + + + + + + + + + diff --git a/layout/reftests/css-ruby/autohiding-3.html b/layout/reftests/css-ruby/autohiding-3.html new file mode 100644 index 000000000000..1a39171877b7 --- /dev/null +++ b/layout/reftests/css-ruby/autohiding-3.html @@ -0,0 +1,17 @@ + + + + + Bug 1052123 - Autohide ruby annotations which are identical to their bases + + + + + + + + + + diff --git a/layout/reftests/css-ruby/float-handling-ref.html b/layout/reftests/css-ruby/float-handling-ref.html index 82da681135bb..ed9ba7977b28 100644 --- a/layout/reftests/css-ruby/float-handling-ref.html +++ b/layout/reftests/css-ruby/float-handling-ref.html @@ -14,9 +14,9 @@ -
hello world
hello world
-
hello world
hello world
-
hello world
hello world
-
hello world
hello world
+
HELLO WORLD
hello world
+
HELLO WORLD
hello world
+
HELLO WORLD
hello world
+
HELLO WORLD
hello world
diff --git a/layout/reftests/css-ruby/float-handling.html b/layout/reftests/css-ruby/float-handling.html index de564c97b8e7..a93d94972d01 100644 --- a/layout/reftests/css-ruby/float-handling.html +++ b/layout/reftests/css-ruby/float-handling.html @@ -14,9 +14,9 @@ -
hello world
hello world
-
hello worldhello
world
-
hello world
hello world
-
hello worldhello
world
+
HELLO WORLD
hello world
+
HELLO WORLDhello
world
+
HELLO WORLD
hello world
+
HELLO WORLDhello
world
diff --git a/layout/reftests/css-ruby/reftest.list b/layout/reftests/css-ruby/reftest.list index bb2ee6087571..b260f64c65d5 100644 --- a/layout/reftests/css-ruby/reftest.list +++ b/layout/reftests/css-ruby/reftest.list @@ -1,5 +1,8 @@ default-preferences pref(layout.css.ruby.enabled,true) +== autohiding-1.html autohiding-1-ref.html +== autohiding-2.html autohiding-2-ref.html +== autohiding-3.html autohiding-3-ref.html == box-generation-1.html box-generation-1-ref.html == box-generation-2.html box-generation-2-ref.html == box-generation-3.html box-generation-3-ref.html From 8bacfeb968aeda8579419ce4a73f4cc6c2892082 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 16 Dec 2014 16:30:39 -0800 Subject: [PATCH 126/130] Bug 1054671 - Constify static callback arrays r=ehsan --- dom/base/Console.cpp | 2 +- dom/base/MessagePort.cpp | 2 +- dom/base/nsGlobalWindow.cpp | 2 +- dom/base/nsJSEnvironment.cpp | 4 ++-- dom/indexedDB/IDBObjectStore.cpp | 4 ++-- dom/ipc/StructuredCloneUtils.cpp | 2 +- dom/promise/Promise.cpp | 6 +++--- dom/promise/PromiseWorkerProxy.h | 4 ++-- dom/system/gonk/NetworkUtils.cpp | 30 +++++++++++++-------------- dom/system/gonk/NetworkUtils.h | 34 +++++++++++++++---------------- dom/workers/ChromeWorkerScope.cpp | 2 +- dom/workers/Navigator.cpp | 2 +- dom/workers/RuntimeService.cpp | 4 ++-- dom/workers/WorkerPrivate.cpp | 16 +++++++-------- dom/workers/WorkerPrivate.h | 4 ++-- dom/workers/XMLHttpRequest.cpp | 10 ++++----- js/src/ctypes/CTypes.cpp | 9 ++++---- js/src/ctypes/CTypes.h | 4 ++-- js/src/ctypes/Library.cpp | 2 +- js/src/ctypes/Library.h | 2 +- js/src/jsapi.cpp | 4 ++-- js/src/jsapi.h | 6 +++--- js/src/vm/Runtime.h | 2 +- js/xpconnect/src/XPCLocale.cpp | 10 ++++----- 24 files changed, 84 insertions(+), 83 deletions(-) diff --git a/dom/base/Console.cpp b/dom/base/Console.cpp index 5123d69140d0..5ef2259bf8b3 100644 --- a/dom/base/Console.cpp +++ b/dom/base/Console.cpp @@ -131,7 +131,7 @@ ConsoleStructuredCloneCallbacksError(JSContext* /* aCx */, NS_WARNING("Failed to clone data for the Console API in workers."); } -JSStructuredCloneCallbacks gConsoleCallbacks = { +static const JSStructuredCloneCallbacks gConsoleCallbacks = { ConsoleStructuredCloneCallbacksRead, ConsoleStructuredCloneCallbacksWrite, ConsoleStructuredCloneCallbacksError diff --git a/dom/base/MessagePort.cpp b/dom/base/MessagePort.cpp index ebccfb50907d..e0bc4ab991dd 100644 --- a/dom/base/MessagePort.cpp +++ b/dom/base/MessagePort.cpp @@ -287,7 +287,7 @@ PostMessageFreeTransferStructuredClone(uint32_t aTag, JS::TransferableOwnership } } -JSStructuredCloneCallbacks kPostMessageCallbacks = { +const JSStructuredCloneCallbacks kPostMessageCallbacks = { PostMessageReadStructuredClone, PostMessageWriteStructuredClone, nullptr, diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index f1a729c6702b..897315d22067 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -8054,7 +8054,7 @@ PostMessageFreeTransferStructuredClone(uint32_t aTag, JS::TransferableOwnership } } -JSStructuredCloneCallbacks kPostMessageCallbacks = { +const JSStructuredCloneCallbacks kPostMessageCallbacks = { PostMessageReadStructuredClone, PostMessageWriteStructuredClone, nullptr, diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index e427654b22c6..fdd5a37ba253 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2748,7 +2748,7 @@ nsJSContext::EnsureStatics() sPrevGCSliceCallback = JS::SetGCSliceCallback(sRuntime, DOMGCSliceCallback); // Set up the structured clone callbacks. - static JSStructuredCloneCallbacks cloneCallbacks = { + static const JSStructuredCloneCallbacks cloneCallbacks = { NS_DOMReadStructuredClone, NS_DOMWriteStructuredClone, NS_DOMStructuredCloneError, @@ -2759,7 +2759,7 @@ nsJSContext::EnsureStatics() JS_SetStructuredCloneCallbacks(sRuntime, &cloneCallbacks); // Set up the asm.js cache callbacks - static JS::AsmJSCacheOps asmJSCacheOps = { + static const JS::AsmJSCacheOps asmJSCacheOps = { AsmJSCacheOpenEntryForRead, asmjscache::CloseEntryForRead, AsmJSCacheOpenEntryForWrite, diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index f8e35c101009..f9c36c4873a8 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -1001,7 +1001,7 @@ IDBObjectStore::DeserializeValue(JSContext* aCx, JSAutoRequest ar(aCx); - static JSStructuredCloneCallbacks callbacks = { + static const JSStructuredCloneCallbacks callbacks = { CommonStructuredCloneReadCallback, nullptr, nullptr, @@ -1042,7 +1042,7 @@ IDBObjectStore::DeserializeIndexValue(JSContext* aCx, JSAutoRequest ar(aCx); - static JSStructuredCloneCallbacks callbacks = { + static const JSStructuredCloneCallbacks callbacks = { CommonStructuredCloneReadCallback, nullptr, nullptr diff --git a/dom/ipc/StructuredCloneUtils.cpp b/dom/ipc/StructuredCloneUtils.cpp index 8f3b10492cc6..349e3ea95c2f 100644 --- a/dom/ipc/StructuredCloneUtils.cpp +++ b/dom/ipc/StructuredCloneUtils.cpp @@ -101,7 +101,7 @@ Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr); } -JSStructuredCloneCallbacks gCallbacks = { +const JSStructuredCloneCallbacks gCallbacks = { Read, Write, Error, diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index eb9f05f2c47c..6c50e03278aa 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -1246,7 +1246,7 @@ class PromiseWorkerProxyRunnable : public workers::WorkerRunnable { public: PromiseWorkerProxyRunnable(PromiseWorkerProxy* aPromiseWorkerProxy, - JSStructuredCloneCallbacks* aCallbacks, + const JSStructuredCloneCallbacks* aCallbacks, JSAutoStructuredCloneBuffer&& aBuffer, PromiseWorkerProxy::RunCallbackFunc aFunc) : WorkerRunnable(aPromiseWorkerProxy->GetWorkerPrivate(), @@ -1292,7 +1292,7 @@ protected: private: nsRefPtr mPromiseWorkerProxy; - JSStructuredCloneCallbacks* mCallbacks; + const JSStructuredCloneCallbacks* mCallbacks; JSAutoStructuredCloneBuffer mBuffer; // Function pointer for calling Promise::{ResolveInternal,RejectInternal}. @@ -1301,7 +1301,7 @@ private: PromiseWorkerProxy::PromiseWorkerProxy(WorkerPrivate* aWorkerPrivate, Promise* aWorkerPromise, - JSStructuredCloneCallbacks* aCallbacks) + const JSStructuredCloneCallbacks* aCallbacks) : mWorkerPrivate(aWorkerPrivate) , mWorkerPromise(aWorkerPromise) , mCleanedUp(false) diff --git a/dom/promise/PromiseWorkerProxy.h b/dom/promise/PromiseWorkerProxy.h index 3b83e2fbf0ac..09249e9eba12 100644 --- a/dom/promise/PromiseWorkerProxy.h +++ b/dom/promise/PromiseWorkerProxy.h @@ -67,7 +67,7 @@ class PromiseWorkerProxy : public PromiseNativeHandler, public: PromiseWorkerProxy(workers::WorkerPrivate* aWorkerPrivate, Promise* aWorkerPromise, - JSStructuredCloneCallbacks* aCallbacks = nullptr); + const JSStructuredCloneCallbacks* aCallbacks = nullptr); workers::WorkerPrivate* GetWorkerPrivate() const; @@ -104,7 +104,7 @@ private: bool mCleanedUp; // To specify if the cleanUp() has been done. - JSStructuredCloneCallbacks* mCallbacks; + const JSStructuredCloneCallbacks* mCallbacks; // Aimed to keep objects alive when doing the structured-clone read/write, // which can be added by calling StoreISupports() on the main thread. diff --git a/dom/system/gonk/NetworkUtils.cpp b/dom/system/gonk/NetworkUtils.cpp index 2ac7cb3df6e2..20e2e1c3fc66 100644 --- a/dom/system/gonk/NetworkUtils.cpp +++ b/dom/system/gonk/NetworkUtils.cpp @@ -123,7 +123,7 @@ static nsTArray gReason; static NetworkParams *gWifiTetheringParms = 0; -CommandFunc NetworkUtils::sWifiEnableChain[] = { +const CommandFunc NetworkUtils::sWifiEnableChain[] = { NetworkUtils::clearWifiTetherParms, NetworkUtils::wifiFirmwareReload, NetworkUtils::startAccessPointDriver, @@ -139,7 +139,7 @@ CommandFunc NetworkUtils::sWifiEnableChain[] = { NetworkUtils::wifiTetheringSuccess }; -CommandFunc NetworkUtils::sWifiDisableChain[] = { +const CommandFunc NetworkUtils::sWifiDisableChain[] = { NetworkUtils::clearWifiTetherParms, NetworkUtils::stopSoftAP, NetworkUtils::stopAccessPointDriver, @@ -153,14 +153,14 @@ CommandFunc NetworkUtils::sWifiDisableChain[] = { NetworkUtils::wifiTetheringSuccess }; -CommandFunc NetworkUtils::sWifiFailChain[] = { +const CommandFunc NetworkUtils::sWifiFailChain[] = { NetworkUtils::clearWifiTetherParms, NetworkUtils::stopSoftAP, NetworkUtils::setIpForwardingEnabled, NetworkUtils::stopTethering }; -CommandFunc NetworkUtils::sWifiRetryChain[] = { +const CommandFunc NetworkUtils::sWifiRetryChain[] = { NetworkUtils::clearWifiTetherParms, NetworkUtils::stopSoftAP, NetworkUtils::stopTethering, @@ -180,12 +180,12 @@ CommandFunc NetworkUtils::sWifiRetryChain[] = { NetworkUtils::wifiTetheringSuccess }; -CommandFunc NetworkUtils::sWifiOperationModeChain[] = { +const CommandFunc NetworkUtils::sWifiOperationModeChain[] = { NetworkUtils::wifiFirmwareReload, NetworkUtils::wifiOperationModeSuccess }; -CommandFunc NetworkUtils::sUSBEnableChain[] = { +const CommandFunc NetworkUtils::sUSBEnableChain[] = { NetworkUtils::setInterfaceUp, NetworkUtils::enableNat, NetworkUtils::setIpForwardingEnabled, @@ -196,7 +196,7 @@ CommandFunc NetworkUtils::sUSBEnableChain[] = { NetworkUtils::usbTetheringSuccess }; -CommandFunc NetworkUtils::sUSBDisableChain[] = { +const CommandFunc NetworkUtils::sUSBDisableChain[] = { NetworkUtils::untetherInterface, NetworkUtils::preTetherInterfaceList, NetworkUtils::postTetherInterfaceList, @@ -206,48 +206,48 @@ CommandFunc NetworkUtils::sUSBDisableChain[] = { NetworkUtils::usbTetheringSuccess }; -CommandFunc NetworkUtils::sUSBFailChain[] = { +const CommandFunc NetworkUtils::sUSBFailChain[] = { NetworkUtils::stopSoftAP, NetworkUtils::setIpForwardingEnabled, NetworkUtils::stopTethering }; -CommandFunc NetworkUtils::sUpdateUpStreamChain[] = { +const CommandFunc NetworkUtils::sUpdateUpStreamChain[] = { NetworkUtils::cleanUpStream, NetworkUtils::createUpStream, NetworkUtils::updateUpStreamSuccess }; -CommandFunc NetworkUtils::sStartDhcpServerChain[] = { +const CommandFunc NetworkUtils::sStartDhcpServerChain[] = { NetworkUtils::setInterfaceUp, NetworkUtils::startTethering, NetworkUtils::setDhcpServerSuccess }; -CommandFunc NetworkUtils::sStopDhcpServerChain[] = { +const CommandFunc NetworkUtils::sStopDhcpServerChain[] = { NetworkUtils::stopTethering, NetworkUtils::setDhcpServerSuccess }; -CommandFunc NetworkUtils::sNetworkInterfaceEnableAlarmChain[] = { +const CommandFunc NetworkUtils::sNetworkInterfaceEnableAlarmChain[] = { NetworkUtils::enableAlarm, NetworkUtils::setQuota, NetworkUtils::setAlarm, NetworkUtils::networkInterfaceAlarmSuccess }; -CommandFunc NetworkUtils::sNetworkInterfaceDisableAlarmChain[] = { +const CommandFunc NetworkUtils::sNetworkInterfaceDisableAlarmChain[] = { NetworkUtils::removeQuota, NetworkUtils::disableAlarm, NetworkUtils::networkInterfaceAlarmSuccess }; -CommandFunc NetworkUtils::sNetworkInterfaceSetAlarmChain[] = { +const CommandFunc NetworkUtils::sNetworkInterfaceSetAlarmChain[] = { NetworkUtils::setAlarm, NetworkUtils::networkInterfaceAlarmSuccess }; -CommandFunc NetworkUtils::sSetDnsChain[] = { +const CommandFunc NetworkUtils::sSetDnsChain[] = { NetworkUtils::setDefaultInterface, NetworkUtils::setInterfaceDns }; diff --git a/dom/system/gonk/NetworkUtils.h b/dom/system/gonk/NetworkUtils.h index f352c9343ba8..fcf9763b1c0b 100644 --- a/dom/system/gonk/NetworkUtils.h +++ b/dom/system/gonk/NetworkUtils.h @@ -164,7 +164,7 @@ class CommandChain MOZ_FINAL { public: CommandChain(const NetworkParams& aParams, - CommandFunc aCmds[], + const CommandFunc aCmds[], uint32_t aLength, ErrorCallback aError) : mIndex(-1) @@ -196,7 +196,7 @@ public: private: uint32_t mIndex; NetworkParams mParams; - CommandFunc* mCommands; + const CommandFunc* mCommands; uint32_t mLength; ErrorCallback mError; }; @@ -263,21 +263,21 @@ private: * function pointer array holds all netd commands should be executed * in sequence to accomplish a given command by other module. */ - static CommandFunc sWifiEnableChain[]; - static CommandFunc sWifiDisableChain[]; - static CommandFunc sWifiFailChain[]; - static CommandFunc sWifiRetryChain[]; - static CommandFunc sWifiOperationModeChain[]; - static CommandFunc sUSBEnableChain[]; - static CommandFunc sUSBDisableChain[]; - static CommandFunc sUSBFailChain[]; - static CommandFunc sUpdateUpStreamChain[]; - static CommandFunc sStartDhcpServerChain[]; - static CommandFunc sStopDhcpServerChain[]; - static CommandFunc sNetworkInterfaceEnableAlarmChain[]; - static CommandFunc sNetworkInterfaceDisableAlarmChain[]; - static CommandFunc sNetworkInterfaceSetAlarmChain[]; - static CommandFunc sSetDnsChain[]; + static const CommandFunc sWifiEnableChain[]; + static const CommandFunc sWifiDisableChain[]; + static const CommandFunc sWifiFailChain[]; + static const CommandFunc sWifiRetryChain[]; + static const CommandFunc sWifiOperationModeChain[]; + static const CommandFunc sUSBEnableChain[]; + static const CommandFunc sUSBDisableChain[]; + static const CommandFunc sUSBFailChain[]; + static const CommandFunc sUpdateUpStreamChain[]; + static const CommandFunc sStartDhcpServerChain[]; + static const CommandFunc sStopDhcpServerChain[]; + static const CommandFunc sNetworkInterfaceEnableAlarmChain[]; + static const CommandFunc sNetworkInterfaceDisableAlarmChain[]; + static const CommandFunc sNetworkInterfaceSetAlarmChain[]; + static const CommandFunc sSetDnsChain[]; /** * Individual netd command stored in command chain. diff --git a/dom/workers/ChromeWorkerScope.cpp b/dom/workers/ChromeWorkerScope.cpp index 3b576985e062..9cb25652e5ef 100644 --- a/dom/workers/ChromeWorkerScope.cpp +++ b/dom/workers/ChromeWorkerScope.cpp @@ -59,7 +59,7 @@ DefineChromeWorkerFunctions(JSContext* aCx, JS::Handle aGlobal) return false; } - static JSCTypesCallbacks callbacks = { + static const JSCTypesCallbacks callbacks = { UnicodeToNative }; diff --git a/dom/workers/Navigator.cpp b/dom/workers/Navigator.cpp index 025289df0938..5f26d5794f57 100644 --- a/dom/workers/Navigator.cpp +++ b/dom/workers/Navigator.cpp @@ -194,7 +194,7 @@ GetDataStoresStructuredCloneCallbacksWrite(JSContext* aCx, return true; } -static JSStructuredCloneCallbacks kGetDataStoresStructuredCloneCallbacks = { +static const JSStructuredCloneCallbacks kGetDataStoresStructuredCloneCallbacks = { GetDataStoresStructuredCloneCallbacksRead, GetDataStoresStructuredCloneCallbacksWrite, nullptr diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 0f3537dabfcc..49bbd61031c5 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -775,13 +775,13 @@ CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate, JSRuntime* aRuntime) JS_SetNativeStackQuota(aRuntime, WORKER_CONTEXT_NATIVE_STACK_LIMIT); // Security policy: - static JSSecurityCallbacks securityCallbacks = { + static const JSSecurityCallbacks securityCallbacks = { ContentSecurityPolicyAllows }; JS_SetSecurityCallbacks(aRuntime, &securityCallbacks); // Set up the asm.js cache callbacks - static JS::AsmJSCacheOps asmJSCacheOps = { + static const JS::AsmJSCacheOps asmJSCacheOps = { AsmJSCacheOpenEntryForRead, asmjscache::CloseEntryForRead, AsmJSCacheOpenEntryForWrite, diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 9493b887248b..8b50eed819bb 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -386,7 +386,7 @@ struct WorkerStructuredCloneCallbacks } }; -JSStructuredCloneCallbacks gWorkerStructuredCloneCallbacks = { +const JSStructuredCloneCallbacks gWorkerStructuredCloneCallbacks = { WorkerStructuredCloneCallbacks::Read, WorkerStructuredCloneCallbacks::Write, WorkerStructuredCloneCallbacks::Error, @@ -483,7 +483,7 @@ struct MainThreadWorkerStructuredCloneCallbacks } }; -JSStructuredCloneCallbacks gMainThreadWorkerStructuredCloneCallbacks = { +const JSStructuredCloneCallbacks gMainThreadWorkerStructuredCloneCallbacks = { MainThreadWorkerStructuredCloneCallbacks::Read, MainThreadWorkerStructuredCloneCallbacks::Write, MainThreadWorkerStructuredCloneCallbacks::Error, @@ -516,7 +516,7 @@ struct ChromeWorkerStructuredCloneCallbacks } }; -JSStructuredCloneCallbacks gChromeWorkerStructuredCloneCallbacks = { +const JSStructuredCloneCallbacks gChromeWorkerStructuredCloneCallbacks = { ChromeWorkerStructuredCloneCallbacks::Read, ChromeWorkerStructuredCloneCallbacks::Write, ChromeWorkerStructuredCloneCallbacks::Error, @@ -577,7 +577,7 @@ struct MainThreadChromeWorkerStructuredCloneCallbacks } }; -JSStructuredCloneCallbacks gMainThreadChromeWorkerStructuredCloneCallbacks = { +const JSStructuredCloneCallbacks gMainThreadChromeWorkerStructuredCloneCallbacks = { MainThreadChromeWorkerStructuredCloneCallbacks::Read, MainThreadChromeWorkerStructuredCloneCallbacks::Write, MainThreadChromeWorkerStructuredCloneCallbacks::Error, @@ -2663,7 +2663,7 @@ WorkerPrivateParent::PostMessageInternal( } } - JSStructuredCloneCallbacks* callbacks; + const JSStructuredCloneCallbacks* callbacks; if (GetParent()) { if (IsChromeWorker()) { callbacks = &gChromeWorkerStructuredCloneCallbacks; @@ -5161,7 +5161,7 @@ WorkerPrivate::PostMessageToParentInternal( transferable.setObject(*array); } - JSStructuredCloneCallbacks* callbacks = + const JSStructuredCloneCallbacks* callbacks = IsChromeWorker() ? &gChromeWorkerStructuredCloneCallbacks : &gWorkerStructuredCloneCallbacks; @@ -6184,7 +6184,7 @@ GetWorkerCrossThreadDispatcher(JSContext* aCx, JS::Value aWorker) return w->GetCrossThreadDispatcher(); } -JSStructuredCloneCallbacks* +const JSStructuredCloneCallbacks* WorkerStructuredCloneCallbacks(bool aMainRuntime) { return aMainRuntime ? @@ -6192,7 +6192,7 @@ WorkerStructuredCloneCallbacks(bool aMainRuntime) &gWorkerStructuredCloneCallbacks; } -JSStructuredCloneCallbacks* +const JSStructuredCloneCallbacks* ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime) { return aMainRuntime ? diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 17c79cfd00db..449141a6595b 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -1296,10 +1296,10 @@ enum WorkerStructuredDataType DOMWORKER_SCTAG_END }; -JSStructuredCloneCallbacks* +const JSStructuredCloneCallbacks* WorkerStructuredCloneCallbacks(bool aMainRuntime); -JSStructuredCloneCallbacks* +const JSStructuredCloneCallbacks* ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime); class AutoSyncLoopHolder diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index b176e4992461..e213aa3425a1 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -1219,7 +1219,7 @@ EventRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) if (doClone) { // Anything subject to GC must be cloned. - JSStructuredCloneCallbacks* callbacks = + const JSStructuredCloneCallbacks* callbacks = aWorkerPrivate->IsChromeWorker() ? workers::ChromeWorkerStructuredCloneCallbacks(true) : workers::WorkerStructuredCloneCallbacks(true); @@ -1331,7 +1331,7 @@ EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) JSAutoStructuredCloneBuffer responseBuffer(Move(mResponseBuffer)); - JSStructuredCloneCallbacks* callbacks = + const JSStructuredCloneCallbacks* callbacks = aWorkerPrivate->IsChromeWorker() ? workers::ChromeWorkerStructuredCloneCallbacks(false) : workers::WorkerStructuredCloneCallbacks(false); @@ -1515,7 +1515,7 @@ SendRunnable::MainThreadRun() nsresult rv = NS_OK; - JSStructuredCloneCallbacks* callbacks = + const JSStructuredCloneCallbacks* callbacks = mWorkerPrivate->IsChromeWorker() ? workers::ChromeWorkerStructuredCloneCallbacks(true) : workers::WorkerStructuredCloneCallbacks(true); @@ -2139,7 +2139,7 @@ XMLHttpRequest::Send(JS::Handle aBody, ErrorResult& aRv) valToClone.setString(bodyStr); } - JSStructuredCloneCallbacks* callbacks = + const JSStructuredCloneCallbacks* callbacks = mWorkerPrivate->IsChromeWorker() ? ChromeWorkerStructuredCloneCallbacks(false) : WorkerStructuredCloneCallbacks(false); @@ -2177,7 +2177,7 @@ XMLHttpRequest::Send(File& aBody, ErrorResult& aRv) return; } - JSStructuredCloneCallbacks* callbacks = + const JSStructuredCloneCallbacks* callbacks = mWorkerPrivate->IsChromeWorker() ? ChromeWorkerStructuredCloneCallbacks(false) : WorkerStructuredCloneCallbacks(false); diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 79da39fc80d9..10e0b1670d82 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -1320,7 +1320,7 @@ IsCTypesGlobal(HandleValue v) } // Get the JSCTypesCallbacks struct from the 'ctypes' object 'obj'. -JSCTypesCallbacks* +const JSCTypesCallbacks* GetCallbacks(JSObject* obj) { MOZ_ASSERT(IsCTypesGlobal(obj)); @@ -1329,7 +1329,7 @@ GetCallbacks(JSObject* obj) if (result.isUndefined()) return nullptr; - return static_cast(result.toPrivate()); + return static_cast(result.toPrivate()); } // Utility function to access a property of an object as an object @@ -1406,13 +1406,14 @@ JS_InitCTypesClass(JSContext* cx, HandleObject global) } JS_PUBLIC_API(void) -JS_SetCTypesCallbacks(JSObject *ctypesObj, JSCTypesCallbacks* callbacks) +JS_SetCTypesCallbacks(JSObject *ctypesObj, const JSCTypesCallbacks* callbacks) { MOZ_ASSERT(callbacks); MOZ_ASSERT(IsCTypesGlobal(ctypesObj)); // Set the callbacks on a reserved slot. - JS_SetReservedSlot(ctypesObj, SLOT_CALLBACKS, PRIVATE_TO_JSVAL(callbacks)); + JS_SetReservedSlot(ctypesObj, SLOT_CALLBACKS, + PRIVATE_TO_JSVAL(const_cast(callbacks))); } namespace js { diff --git a/js/src/ctypes/CTypes.h b/js/src/ctypes/CTypes.h index 7e971661675b..bb118f2cc217 100644 --- a/js/src/ctypes/CTypes.h +++ b/js/src/ctypes/CTypes.h @@ -344,7 +344,7 @@ struct ClosureInfo bool IsCTypesGlobal(HandleValue v); bool IsCTypesGlobal(JSObject* obj); -JSCTypesCallbacks* GetCallbacks(JSObject* obj); +const JSCTypesCallbacks* GetCallbacks(JSObject* obj); /******************************************************************************* ** JSClass reserved slot definitions @@ -461,7 +461,7 @@ namespace CType { JSString* GetName(JSContext* cx, HandleObject obj); JSObject* GetProtoFromCtor(JSObject* obj, CTypeProtoSlot slot); JSObject* GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot); - JSCTypesCallbacks* GetCallbacksFromType(JSObject* obj); + const JSCTypesCallbacks* GetCallbacksFromType(JSObject* obj); } namespace PointerType { diff --git a/js/src/ctypes/Library.cpp b/js/src/ctypes/Library.cpp index a880fd4688cb..c084a1e1a591 100644 --- a/js/src/ctypes/Library.cpp +++ b/js/src/ctypes/Library.cpp @@ -80,7 +80,7 @@ Library::Name(JSContext* cx, unsigned argc, jsval *vp) } JSObject* -Library::Create(JSContext* cx, jsval path_, JSCTypesCallbacks* callbacks) +Library::Create(JSContext* cx, jsval path_, const JSCTypesCallbacks* callbacks) { RootedValue path(cx, path_); RootedObject libraryObj(cx, diff --git a/js/src/ctypes/Library.h b/js/src/ctypes/Library.h index e37ea0f95116..2413afd6e537 100644 --- a/js/src/ctypes/Library.h +++ b/js/src/ctypes/Library.h @@ -23,7 +23,7 @@ namespace Library { bool Name(JSContext* cx, unsigned argc, JS::Value *vp); - JSObject* Create(JSContext* cx, JS::Value path, JSCTypesCallbacks* callbacks); + JSObject* Create(JSContext* cx, JS::Value path, const JSCTypesCallbacks* callbacks); bool IsLibrary(JSObject* obj); PRLibrary* GetLibrary(JSObject* obj); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index ab25e80f4b29..648342129d5a 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5542,13 +5542,13 @@ JS_ResetDefaultLocale(JSRuntime *rt) } JS_PUBLIC_API(void) -JS_SetLocaleCallbacks(JSRuntime *rt, JSLocaleCallbacks *callbacks) +JS_SetLocaleCallbacks(JSRuntime *rt, const JSLocaleCallbacks *callbacks) { AssertHeapIsIdle(rt); rt->localeCallbacks = callbacks; } -JS_PUBLIC_API(JSLocaleCallbacks *) +JS_PUBLIC_API(const JSLocaleCallbacks *) JS_GetLocaleCallbacks(JSRuntime *rt) { /* This function can be called by a finalizer. */ diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 2743e463289a..89a06cd06ada 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1928,7 +1928,7 @@ typedef struct JSCTypesCallbacks JSCTypesCallbacks; * to call this function again. */ extern JS_PUBLIC_API(void) -JS_SetCTypesCallbacks(JSObject *ctypesObj, JSCTypesCallbacks *callbacks); +JS_SetCTypesCallbacks(JSObject *ctypesObj, const JSCTypesCallbacks *callbacks); #endif typedef bool @@ -4679,13 +4679,13 @@ struct JSLocaleCallbacks { * JSRuntime. Passing nullptr restores the default behaviour. */ extern JS_PUBLIC_API(void) -JS_SetLocaleCallbacks(JSRuntime *rt, JSLocaleCallbacks *callbacks); +JS_SetLocaleCallbacks(JSRuntime *rt, const JSLocaleCallbacks *callbacks); /* * Return the address of the current locale callbacks struct, which may * be nullptr. */ -extern JS_PUBLIC_API(JSLocaleCallbacks *) +extern JS_PUBLIC_API(const JSLocaleCallbacks *) JS_GetLocaleCallbacks(JSRuntime *rt); /************************************************************************/ diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index c36e4c89553d..5e07400d1ed9 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -808,7 +808,7 @@ struct JSRuntime : public JS::shadow::Runtime, size_t numCompartments; /* Locale-specific callbacks for string conversion. */ - JSLocaleCallbacks *localeCallbacks; + const JSLocaleCallbacks *localeCallbacks; /* Default locale for Internationalization API */ char *defaultLocale; diff --git a/js/xpconnect/src/XPCLocale.cpp b/js/xpconnect/src/XPCLocale.cpp index ca48629f547f..f7fe2c6c6fa7 100644 --- a/js/xpconnect/src/XPCLocale.cpp +++ b/js/xpconnect/src/XPCLocale.cpp @@ -60,16 +60,16 @@ struct XPCLocaleCallbacks : public JSLocaleCallbacks { // Locale information for |rt| was associated using xpc_LocalizeRuntime; // assert and double-check this. - JSLocaleCallbacks* lc = JS_GetLocaleCallbacks(rt); + const JSLocaleCallbacks* lc = JS_GetLocaleCallbacks(rt); MOZ_ASSERT(lc); MOZ_ASSERT(lc->localeToUpperCase == LocaleToUpperCase); MOZ_ASSERT(lc->localeToLowerCase == LocaleToLowerCase); MOZ_ASSERT(lc->localeCompare == LocaleCompare); MOZ_ASSERT(lc->localeToUnicode == LocaleToUnicode); - XPCLocaleCallbacks* ths = static_cast(lc); + const XPCLocaleCallbacks* ths = static_cast(lc); ths->AssertThreadSafety(); - return ths; + return const_cast(ths); } static bool @@ -233,7 +233,7 @@ private: return false; } - void AssertThreadSafety() + void AssertThreadSafety() const { MOZ_ASSERT(mThread == PR_GetCurrentThread(), "XPCLocaleCallbacks used unsafely!"); @@ -273,7 +273,7 @@ xpc_LocalizeRuntime(JSRuntime *rt) void xpc_DelocalizeRuntime(JSRuntime *rt) { - XPCLocaleCallbacks* lc = XPCLocaleCallbacks::This(rt); + const XPCLocaleCallbacks* lc = XPCLocaleCallbacks::This(rt); JS_SetLocaleCallbacks(rt, nullptr); delete lc; } From f5d5822f69514b83f0aa0b6750f9d1de8e4642c5 Mon Sep 17 00:00:00 2001 From: Brian Grinstead Date: Tue, 16 Dec 2014 17:18:19 -0800 Subject: [PATCH 127/130] Bug 1088861 - Refactor console tests to prepare for async js evaluation requests;r=past --- .../commandline/test/browser_cmd_commands.js | 3 +- .../test/browser_console_dead_objects.js | 24 ++-- .../test/browser_console_variables_view.js | 8 +- ...nt_sort_non_sortable_classes_properties.js | 2 +- ...wser_console_variables_view_highlighter.js | 2 +- ..._console_variables_view_while_debugging.js | 4 +- ...les_view_while_debugging_and_inspecting.js | 4 +- .../browser_eval_in_debugger_stackframe.js | 12 +- ...-properties-with-non-alphanumeric-names.js | 2 +- ...webconsole_bug_585991_autocomplete_keys.js | 8 +- ...rowser_webconsole_bug_586388_select_all.js | 10 +- ..._webconsole_bug_594477_clickable_output.js | 2 +- .../browser_webconsole_bug_601352_scroll.js | 4 +- ...ser_webconsole_bug_614793_jsterm_scroll.js | 2 +- ...ser_webconsole_bug_664131_console_group.js | 12 +- .../browser_webconsole_cached_autocomplete.js | 8 +- .../test/browser_webconsole_cd_iframe.js | 28 ++-- .../test/browser_webconsole_completion.js | 2 +- .../test/browser_webconsole_history.js | 2 +- .../test/browser_webconsole_jsterm.js | 128 +++++++----------- browser/devtools/webconsole/webconsole.js | 14 +- 21 files changed, 122 insertions(+), 159 deletions(-) diff --git a/browser/devtools/commandline/test/browser_cmd_commands.js b/browser/devtools/commandline/test/browser_cmd_commands.js index 8e97d8b656fd..78dc0a4886f3 100644 --- a/browser/devtools/commandline/test/browser_cmd_commands.js +++ b/browser/devtools/commandline/test/browser_cmd_commands.js @@ -28,8 +28,7 @@ function spawnTest() { let hud = HUDService.getHudReferenceById(subject.data); ok(hud, "console open"); - let jstermExecute = helpers.promiseify(hud.jsterm.execute, hud.jsterm); - let msg = yield jstermExecute("pprint(window)"); + let msg = yield hud.jsterm.execute("pprint(window)"); ok(msg, "output for pprint(window)"); diff --git a/browser/devtools/webconsole/test/browser_console_dead_objects.js b/browser/devtools/webconsole/test/browser_console_dead_objects.js index f5186c697241..574573064abf 100644 --- a/browser/devtools/webconsole/test/browser_console_dead_objects.js +++ b/browser/devtools/webconsole/test/browser_console_dead_objects.js @@ -35,10 +35,12 @@ function test() hud = yield HUDService.toggleBrowserConsole(); ok(hud, "browser console opened"); - hud.jsterm.clearOutput(); + let jsterm = hud.jsterm; + + jsterm.clearOutput(); // Add the reference to the content document. - yield execute("Cu = Components.utils;" + + yield jsterm.execute("Cu = Components.utils;" + "Cu.import('resource://gre/modules/Services.jsm');" + "chromeWindow = Services.wm.getMostRecentWindow('navigator:browser');" + "foobarzTezt = chromeWindow.content.document;" + @@ -46,18 +48,18 @@ function test() gBrowser.removeCurrentTab(); - let msg = yield execute("foobarzTezt"); + let msg = yield jsterm.execute("foobarzTezt"); isnot(hud.outputNode.textContent.indexOf("[object DeadObject]"), -1, "dead object found"); - hud.jsterm.setInputValue("foobarzTezt"); + jsterm.setInputValue("foobarzTezt"); for (let c of ".hello") { EventUtils.synthesizeKey(c, {}, hud.iframeWindow); } - yield execute(); + yield jsterm.execute(); isnot(hud.outputNode.textContent.indexOf("can't access dead object"), -1, "'cannot access dead object' message found"); @@ -74,19 +76,11 @@ function test() EventUtils.synthesizeMouseAtCenter(clickable, {}, hud.iframeWindow); }); - yield hud.jsterm.once("variablesview-fetched"); + yield jsterm.once("variablesview-fetched"); ok(true, "variables view fetched"); - msg = yield execute("delete window.foobarzTezt; 2013-26"); + msg = yield jsterm.execute("delete window.foobarzTezt; 2013-26"); isnot(msg.textContent.indexOf("1987"), -1, "result message found"); } - - function execute(str) { - let deferred = promise.defer(); - hud.jsterm.execute(str, (msg) => { - deferred.resolve(msg); - }); - return deferred.promise; - } } diff --git a/browser/devtools/webconsole/test/browser_console_variables_view.js b/browser/devtools/webconsole/test/browser_console_variables_view.js index 071e7c2c7c4f..bfd5a128a194 100644 --- a/browser/devtools/webconsole/test/browser_console_variables_view.js +++ b/browser/devtools/webconsole/test/browser_console_variables_view.js @@ -18,7 +18,7 @@ let test = asyncTest(function* () { gWebConsole = hud; gJSTerm = hud.jsterm; - let msg = yield execute(hud, "fooObj"); + let msg = yield gJSTerm.execute("fooObj"); ok(msg, "output message found"); ok(msg.textContent.contains('{ testProp: "testValue" }'), "message text check"); @@ -187,9 +187,3 @@ function testPropDelete(aProp) validator: () => !("testUpdatedProp" in content.wrappedJSObject.fooObj) }); } - -function execute(hud, str) { - let deferred = promise.defer(); - hud.jsterm.execute(str, deferred.resolve); - return deferred.promise; -} diff --git a/browser/devtools/webconsole/test/browser_console_variables_view_dont_sort_non_sortable_classes_properties.js b/browser/devtools/webconsole/test/browser_console_variables_view_dont_sort_non_sortable_classes_properties.js index ed80e16d7680..60d82f99e649 100644 --- a/browser/devtools/webconsole/test/browser_console_variables_view_dont_sort_non_sortable_classes_properties.js +++ b/browser/devtools/webconsole/test/browser_console_variables_view_dont_sort_non_sortable_classes_properties.js @@ -57,7 +57,7 @@ function test() { // Create an ArrayBuffer of 80 bytes to test TypedArrays. 80 bytes is // enough to get 10 items in all different TypedArrays. - jsterm.execute("let buf = new ArrayBuffer(80);"); + yield jsterm.execute("let buf = new ArrayBuffer(80);"); // Array yield testNotSorted("Array(0,1,2,3,4,5,6,7,8,9,10)"); diff --git a/browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js b/browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js index 2e65f1bab58e..6c7087a94b15 100644 --- a/browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js +++ b/browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js @@ -24,7 +24,7 @@ function consoleOpened(hud) gWebConsole = hud; gJSTerm = hud.jsterm; gToolbox = gDevTools.getToolbox(hud.target); - gJSTerm.execute("document.querySelectorAll('p')", onQSAexecuted); + gJSTerm.execute("document.querySelectorAll('p')").then(onQSAexecuted); } function onQSAexecuted(msg) diff --git a/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging.js b/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging.js index 46e3118939f2..0c6f56973a19 100644 --- a/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging.js +++ b/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging.js @@ -51,7 +51,7 @@ function onFramesAdded() executeSoon(() => openConsole().then(() => - gJSTerm.execute("fooObj", onExecuteFooObj) + gJSTerm.execute("fooObj").then(onExecuteFooObj) ) ); } @@ -114,7 +114,7 @@ function onUpdatedTestPropFound(aResults) ok(prop, "matched the updated |testProp2| property value"); // Check that testProp2 was updated. - executeSoon(() => gJSTerm.execute("fooObj.testProp2", onExecuteFooObjTestProp2)); + executeSoon(() => gJSTerm.execute("fooObj.testProp2").then(onExecuteFooObjTestProp2)); } function onExecuteFooObjTestProp2() diff --git a/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging_and_inspecting.js b/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging_and_inspecting.js index 75b8cbf1000a..55890c3f7994 100644 --- a/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging_and_inspecting.js +++ b/browser/devtools/webconsole/test/browser_console_variables_view_while_debugging_and_inspecting.js @@ -51,7 +51,7 @@ function onFramesAdded() { info("onFramesAdded"); - openConsole().then(() => gJSTerm.execute("fooObj", onExecuteFooObj)); + openConsole().then(() => gJSTerm.execute("fooObj").then(onExecuteFooObj)); } function onExecuteFooObj(msg) @@ -111,7 +111,7 @@ function onUpdatedTestPropFound(aResults) ok(prop, "matched the updated |testProp2| property value"); // Check that testProp2 was updated. - gJSTerm.execute("fooObj.testProp2", onExecuteFooObjTestProp2); + gJSTerm.execute("fooObj.testProp2").then(onExecuteFooObjTestProp2); } function onExecuteFooObjTestProp2() diff --git a/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe.js b/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe.js index 79086afaeed3..beed0255266a 100644 --- a/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe.js +++ b/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe.js @@ -21,7 +21,7 @@ function consoleOpened(hud) { gWebConsole = hud; gJSTerm = hud.jsterm; - gJSTerm.execute("foo", onExecuteFoo); + gJSTerm.execute("foo").then(onExecuteFoo); } function onExecuteFoo() @@ -33,7 +33,7 @@ function onExecuteFoo() // Test for Bug 690529 - Web Console and Scratchpad should evaluate // expressions in the scope of the content window, not in a sandbox. - executeSoon(() => gJSTerm.execute("foo2 = 'newFoo'; window.foo2", onNewFoo2)); + executeSoon(() => gJSTerm.execute("foo2 = 'newFoo'; window.foo2").then(onNewFoo2)); } function onNewFoo2(msg) @@ -62,7 +62,7 @@ function debuggerOpened(aResult) info("openConsole"); executeSoon(() => openConsole().then(() => - gJSTerm.execute("foo + foo2", onExecuteFooAndFoo2) + gJSTerm.execute("foo + foo2").then(onExecuteFooAndFoo2) ) ); } @@ -91,7 +91,7 @@ function onFramesAdded() info("onFramesAdded, openConsole() now"); executeSoon(() => openConsole().then(() => - gJSTerm.execute("foo + foo2", onExecuteFooAndFoo2InSecondCall) + gJSTerm.execute("foo + foo2").then(onExecuteFooAndFoo2InSecondCall) ) ); } @@ -113,7 +113,7 @@ function onExecuteFooAndFoo2InSecondCall() info("openConsole"); executeSoon(() => openConsole().then(() => - gJSTerm.execute("foo + foo2 + foo3", onExecuteFoo23InFirstCall) + gJSTerm.execute("foo + foo2 + foo3").then(onExecuteFoo23InFirstCall) ) ); }); @@ -127,7 +127,7 @@ function onExecuteFoo23InFirstCall() "|foo + foo2 + foo3| from |firstCall()|"); executeSoon(() => - gJSTerm.execute("foo = 'abba'; foo3 = 'bug783499'; foo + foo3", + gJSTerm.execute("foo = 'abba'; foo3 = 'bug783499'; foo + foo3").then( onExecuteFooAndFoo3ChangesInFirstCall)); } diff --git a/browser/devtools/webconsole/test/browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js b/browser/devtools/webconsole/test/browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js index 907941ba9911..0577b8cc2b36 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js +++ b/browser/devtools/webconsole/test/browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js @@ -28,7 +28,7 @@ let test = asyncTest(function*() { let { jsterm } = yield openConsole(); let popup = jsterm.autocompletePopup; - jsterm.execute("let testObject = {$$aaab: '', $$aaac: ''}"); + yield jsterm.execute("let testObject = {$$aaab: '', $$aaac: ''}"); // Should work with bug 967468. yield autocomplete("Object.__d"); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js index c63ca41b48dd..7704bd627599 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js @@ -22,20 +22,20 @@ let test = asyncTest(function*() { HUD = popup = jsterm = inputNode = completeNode = null; }); -function consoleOpened(aHud) { +let consoleOpened = Task.async(function*(aHud) { let deferred = promise.defer(); HUD = aHud; info("web console opened"); jsterm = HUD.jsterm; - jsterm.execute("window.foobarBug585991={" + + yield jsterm.execute("window.foobarBug585991={" + "'item0': 'value0'," + "'item1': 'value1'," + "'item2': 'value2'," + "'item3': 'value3'" + "}"); - jsterm.execute("window.testBug873250a = 'hello world';" + yield jsterm.execute("window.testBug873250a = 'hello world';" + "window.testBug873250b = 'hello world 2';"); popup = jsterm.autocompletePopup; completeNode = jsterm.completeNode; @@ -133,7 +133,7 @@ function consoleOpened(aHud) { EventUtils.synthesizeKey(".", {}); return deferred.promise; -} +}); function popupHideAfterTab() { diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js b/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js index 112cd582379f..5512201cf5f7 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js @@ -20,15 +20,15 @@ let test = asyncTest(function* () { performTestsAfterOutput(hud); }) -function testSelectionWhenMovingBetweenBoxes(aHud) { +let testSelectionWhenMovingBetweenBoxes = Task.async(function *(aHud) { let hud = aHud; let jsterm = hud.jsterm; // Fill the console with some output. jsterm.clearOutput(); - jsterm.execute("1 + 2"); - jsterm.execute("3 + 4"); - jsterm.execute("5 + 6"); + yield jsterm.execute("1 + 2"); + yield jsterm.execute("3 + 4"); + yield jsterm.execute("5 + 6"); return waitForMessages({ webconsole: hud, @@ -45,7 +45,7 @@ function testSelectionWhenMovingBetweenBoxes(aHud) { category: CATEGORY_OUTPUT, }], }); -} +}); function performTestsAfterOutput(aHud) { let hud = aHud; diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js b/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js index 3a31b650eb88..c6a983d6b2d9 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js @@ -114,7 +114,7 @@ function networkPanelHidden() { // Done with the network output. Now test the jsterm output and the property // panel. - HUD.jsterm.execute("document", (msg) => { + HUD.jsterm.execute("document").then((msg) => { info("jsterm execute 'document' callback"); HUD.jsterm.once("variablesview-open", deferred.resolve); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_601352_scroll.js b/browser/devtools/webconsole/test/browser_webconsole_bug_601352_scroll.js index 3e3d8461879f..2ff267896251 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_601352_scroll.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_601352_scroll.js @@ -43,9 +43,7 @@ function test() { }], }); - let nodeDeferred = promise.defer(); - hud.jsterm.execute("1+1", (node) => { nodeDeferred.resolve(node); }); - let node = yield nodeDeferred.promise; + let node = yield hud.jsterm.execute("1+1"); let scrollNode = hud.outputNode.parentNode; let rectNode = node.getBoundingClientRect(); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_614793_jsterm_scroll.js b/browser/devtools/webconsole/test/browser_webconsole_bug_614793_jsterm_scroll.js index 20decb266db5..05dcb76faeb0 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_614793_jsterm_scroll.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_614793_jsterm_scroll.js @@ -43,7 +43,7 @@ function consoleOpened(hud) { oldScrollTop = scrollNode.scrollTop; isnot(oldScrollTop, 0, "scroll location is not at the top"); - hud.jsterm.execute("'hello world'", onExecute); + hud.jsterm.execute("'hello world'").then(onExecute); }); function onExecute(msg) diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_664131_console_group.js b/browser/devtools/webconsole/test/browser_webconsole_bug_664131_console_group.js index 792490245117..ff719877c8ea 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_664131_console_group.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_664131_console_group.js @@ -16,7 +16,7 @@ let test = asyncTest(function* () { hud.jsterm.clearOutput(); - jsterm.execute("console.group('bug664131a')") + yield jsterm.execute("console.group('bug664131a')") yield waitForMessages({ webconsole: hud, @@ -26,7 +26,7 @@ let test = asyncTest(function* () { }], }); - jsterm.execute("console.log('bug664131a-inside')") + yield jsterm.execute("console.log('bug664131a-inside')") yield waitForMessages({ webconsole: hud, @@ -38,8 +38,8 @@ let test = asyncTest(function* () { }], }); - jsterm.execute('console.groupEnd("bug664131a")'); - jsterm.execute('console.log("bug664131-outside")'); + yield jsterm.execute('console.groupEnd("bug664131a")'); + yield jsterm.execute('console.log("bug664131-outside")'); yield waitForMessages({ webconsole: hud, @@ -51,7 +51,7 @@ let test = asyncTest(function* () { }], }); - jsterm.execute('console.groupCollapsed("bug664131b")'); + yield jsterm.execute('console.groupCollapsed("bug664131b")'); yield waitForMessages({ webconsole: hud, @@ -63,7 +63,7 @@ let test = asyncTest(function* () { // Test that clearing the console removes the indentation. hud.jsterm.clearOutput(); - jsterm.execute('console.log("bug664131-cleared")'); + yield jsterm.execute('console.log("bug664131-cleared")'); yield waitForMessages({ webconsole: hud, diff --git a/browser/devtools/webconsole/test/browser_webconsole_cached_autocomplete.js b/browser/devtools/webconsole/test/browser_webconsole_cached_autocomplete.js index d38e0b866a7d..1c780a3fcfd4 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_cached_autocomplete.js +++ b/browser/devtools/webconsole/test/browser_webconsole_cached_autocomplete.js @@ -34,7 +34,7 @@ let test = asyncTest(function* () { ok(popup.getItems().length > 0, "'window.' gave a list of suggestions") - jsterm.execute("window.docfoobar = true"); + yield jsterm.execute("window.docfoobar = true"); // Test typing 'window.doc'. input.value = "window.doc"; @@ -56,7 +56,7 @@ let test = asyncTest(function* () { return item.label != "docfoobar"; }), "autocomplete cached results do not contain docfoobar. list has not been updated"); - jsterm.execute("delete window.docfoobar"); + yield jsterm.execute("delete window.docfoobar"); // Test if 'window.getC' gives 'getComputedStyle' input.value = "window." @@ -84,7 +84,7 @@ let test = asyncTest(function* () { input.setSelectionRange(12, 12); yield complete(jsterm.COMPLETE_HINT_ONLY); - jsterm.execute("window.docfoobar = true"); + yield jsterm.execute("window.docfoobar = true"); // Make sure 'dump(window.doc)' does not contain 'docfoobar'. input.value = "dump(window.doc)"; @@ -96,7 +96,7 @@ let test = asyncTest(function* () { return item.label != "docfoobar"; }), "autocomplete cached results do not contain docfoobar. list has not been updated"); - jsterm.execute("delete window.docfoobar"); + yield jsterm.execute("delete window.docfoobar"); jsterm = null; }); diff --git a/browser/devtools/webconsole/test/browser_webconsole_cd_iframe.js b/browser/devtools/webconsole/test/browser_webconsole_cd_iframe.js index 82c667145f41..bc919a258fbf 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_cd_iframe.js +++ b/browser/devtools/webconsole/test/browser_webconsole_cd_iframe.js @@ -42,27 +42,27 @@ function test() { const {tab} = yield loadTab(TEST_URI); hud = yield openConsole(tab); - executeWindowTest(); + yield executeWindowTest(); yield waitForMessages({ webconsole: hud, messages: parentMessages }); info("cd() into the iframe using a selector"); hud.jsterm.clearOutput(); - hud.jsterm.execute("cd('iframe')"); - executeWindowTest(); + yield hud.jsterm.execute("cd('iframe')"); + yield executeWindowTest(); yield waitForMessages({ webconsole: hud, messages: childMessages }); info("cd() out of the iframe, reset to default window"); hud.jsterm.clearOutput(); - hud.jsterm.execute("cd()"); - executeWindowTest(); + yield hud.jsterm.execute("cd()"); + yield executeWindowTest(); yield waitForMessages({ webconsole: hud, messages: parentMessages }); info("call cd() with unexpected arguments"); hud.jsterm.clearOutput(); - hud.jsterm.execute("cd(document)"); + yield hud.jsterm.execute("cd(document)"); yield waitForMessages({ webconsole: hud, @@ -74,7 +74,7 @@ function test() { }); hud.jsterm.clearOutput(); - hud.jsterm.execute("cd('p')"); + yield hud.jsterm.execute("cd('p')"); yield waitForMessages({ webconsole: hud, @@ -87,15 +87,15 @@ function test() { info("cd() into the iframe using an iframe DOM element"); hud.jsterm.clearOutput(); - hud.jsterm.execute("cd($('iframe'))"); - executeWindowTest(); + yield hud.jsterm.execute("cd($('iframe'))"); + yield executeWindowTest(); yield waitForMessages({ webconsole: hud, messages: childMessages }); info("cd(window.parent)"); hud.jsterm.clearOutput(); - hud.jsterm.execute("cd(window.parent)"); - executeWindowTest(); + yield hud.jsterm.execute("cd(window.parent)"); + yield executeWindowTest(); yield waitForMessages({ webconsole: hud, messages: parentMessages }); @@ -103,8 +103,8 @@ function test() { } function executeWindowTest() { - hud.jsterm.execute("document.title"); - hud.jsterm.execute("'p: ' + document.querySelector('p').textContent"); - hud.jsterm.execute("'obj: ' + window.foobarBug609872"); + yield hud.jsterm.execute("document.title"); + yield hud.jsterm.execute("'p: ' + document.querySelector('p').textContent"); + yield hud.jsterm.execute("'obj: ' + window.foobarBug609872"); } } diff --git a/browser/devtools/webconsole/test/browser_webconsole_completion.js b/browser/devtools/webconsole/test/browser_webconsole_completion.js index 7e384b346698..d68ae0ac3557 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_completion.js +++ b/browser/devtools/webconsole/test/browser_webconsole_completion.js @@ -69,7 +69,7 @@ let test = asyncTest(function* () { yield complete(jsterm.COMPLETE_HINT_ONLY); is(jsterm.completeNode.value, " ment", "'docu' completion"); - jsterm.execute(); + yield jsterm.execute(); is(jsterm.completeNode.value, "", "clear completion on execute()"); // Test multi-line completion works diff --git a/browser/devtools/webconsole/test/browser_webconsole_history.js b/browser/devtools/webconsole/test/browser_webconsole_history.js index 0da0b1d6ee3d..42d957afbb26 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_history.js +++ b/browser/devtools/webconsole/test/browser_webconsole_history.js @@ -25,7 +25,7 @@ let test = asyncTest(function*() { for each (var item in executeList) { input.value = item; - jsterm.execute(); + yield jsterm.execute(); } for (var i = executeList.length - 1; i != -1; i--) { diff --git a/browser/devtools/webconsole/test/browser_webconsole_jsterm.js b/browser/devtools/webconsole/test/browser_webconsole_jsterm.js index e4118a577cee..8b9100d0ebea 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_jsterm.js +++ b/browser/devtools/webconsole/test/browser_webconsole_jsterm.js @@ -5,22 +5,18 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; -let jsterm, testDriver; +let jsterm; -function test() { - loadTab(TEST_URI).then(() => { - openConsole().then((hud) => { - testDriver = testJSTerm(hud); - testDriver.next(); - }) - }); -} - -function nextTest() { - testDriver.next(); -} +let test = asyncTest(function* () { + yield loadTab(TEST_URI); + let hud = yield openConsole(); + jsterm = hud.jsterm; + yield testJSTerm(hud); + jsterm = null; +}); function checkResult(msg, desc) { + let def = promise.defer(); waitForMessages({ webconsole: jsterm.hud.owner, messages: [{ @@ -37,57 +33,49 @@ function checkResult(msg, desc) { ok(msg(node), "correct message shown for " + desc); } - nextTest(); + def.resolve(); }); + return def.promise; } function testJSTerm(hud) { - jsterm = hud.jsterm; const HELP_URL = "https://developer.mozilla.org/docs/Tools/Web_Console/Helpers"; jsterm.clearOutput(); - jsterm.execute("$('#header').getAttribute('id')"); - checkResult('"header"', "$() worked"); - yield undefined; + yield jsterm.execute("$('#header').getAttribute('id')"); + yield checkResult('"header"', "$() worked"); jsterm.clearOutput(); - jsterm.execute("$$('h1').length"); - checkResult("1", "$$() worked"); - yield undefined; + yield jsterm.execute("$$('h1').length"); + yield checkResult("1", "$$() worked"); jsterm.clearOutput(); - jsterm.execute("$x('.//*', document.body)[0] == $$('h1')[0]"); - checkResult("true", "$x() worked"); - yield undefined; + yield jsterm.execute("$x('.//*', document.body)[0] == $$('h1')[0]"); + yield checkResult("true", "$x() worked"); // no jsterm.clearOutput() here as we clear the output using the clear() fn. - jsterm.execute("clear()"); + yield jsterm.execute("clear()"); - waitForSuccess({ + yield waitForSuccess({ name: "clear() worked", validator: function() { return jsterm.outputNode.childNodes.length == 0; } - }).then(nextTest); - - yield undefined; + }); jsterm.clearOutput(); - jsterm.execute("keys({b:1})[0] == 'b'"); - checkResult("true", "keys() worked", 1); - yield undefined; + yield jsterm.execute("keys({b:1})[0] == 'b'"); + yield checkResult("true", "keys() worked", 1); jsterm.clearOutput(); - jsterm.execute("values({b:1})[0] == 1"); - checkResult("true", "values() worked", 1); - yield undefined; + yield jsterm.execute("values({b:1})[0] == 1"); + yield checkResult("true", "values() worked", 1); jsterm.clearOutput(); let openedLinks = 0; - let onExecuteCalls = 0; let oldOpenLink = hud.openLink; hud.openLink = (url) => { if (url == HELP_URL) { @@ -95,17 +83,9 @@ function testJSTerm(hud) } }; - function onExecute() { - onExecuteCalls++; - if (onExecuteCalls == 3) { - nextTest(); - } - } - - jsterm.execute("help()", onExecute); - jsterm.execute("help", onExecute); - jsterm.execute("?", onExecute); - yield undefined; + yield jsterm.execute("help()"); + yield jsterm.execute("help"); + yield jsterm.execute("?"); let output = jsterm.outputNode.querySelector(".message[category='output']"); ok(!output, "no output for help() calls"); @@ -113,66 +93,52 @@ function testJSTerm(hud) hud.openLink = oldOpenLink; jsterm.clearOutput(); - jsterm.execute("pprint({b:2, a:1})"); - checkResult("\" b: 2\n a: 1\"", "pprint()"); - yield undefined; + yield jsterm.execute("pprint({b:2, a:1})"); + yield checkResult("\" b: 2\n a: 1\"", "pprint()"); // check instanceof correctness, bug 599940 jsterm.clearOutput(); - jsterm.execute("[] instanceof Array"); - checkResult("true", "[] instanceof Array == true"); - yield undefined; + yield jsterm.execute("[] instanceof Array"); + yield checkResult("true", "[] instanceof Array == true"); jsterm.clearOutput(); - jsterm.execute("({}) instanceof Object"); - checkResult("true", "({}) instanceof Object == true"); - yield undefined; + yield jsterm.execute("({}) instanceof Object"); + yield checkResult("true", "({}) instanceof Object == true"); // check for occurrences of Object XRayWrapper, bug 604430 jsterm.clearOutput(); - jsterm.execute("document"); - checkResult(function(node) { + yield jsterm.execute("document"); + yield checkResult(function(node) { return node.textContent.search(/\[object xraywrapper/i) == -1; }, "document - no XrayWrapper"); - yield undefined; // check that pprint(window) and keys(window) don't throw, bug 608358 jsterm.clearOutput(); - jsterm.execute("pprint(window)"); - checkResult(null, "pprint(window)"); - yield undefined; + yield jsterm.execute("pprint(window)"); + yield checkResult(null, "pprint(window)"); jsterm.clearOutput(); - jsterm.execute("keys(window)"); - checkResult(null, "keys(window)"); - yield undefined; + yield jsterm.execute("keys(window)"); + yield checkResult(null, "keys(window)"); // bug 614561 jsterm.clearOutput(); - jsterm.execute("pprint('hi')"); - checkResult("\" 0: \"h\"\n 1: \"i\"\"", "pprint('hi')"); - yield undefined; + yield jsterm.execute("pprint('hi')"); + yield checkResult("\" 0: \"h\"\n 1: \"i\"\"", "pprint('hi')"); // check that pprint(function) shows function source, bug 618344 jsterm.clearOutput(); - jsterm.execute("pprint(function() { var someCanaryValue = 42; })"); - checkResult(function(node) { + yield jsterm.execute("pprint(function() { var someCanaryValue = 42; })"); + yield checkResult(function(node) { return node.textContent.indexOf("someCanaryValue") > -1; }, "pprint(function) shows source"); - yield undefined; // check that an evaluated null produces "null", bug 650780 jsterm.clearOutput(); - jsterm.execute("null"); - checkResult("null", "null is null"); - yield undefined; + yield jsterm.execute("null"); + yield checkResult("null", "null is null"); jsterm.clearOutput(); - jsterm.execute("undefined"); - checkResult("undefined", "undefined is printed"); - yield undefined; - - jsterm = testDriver = null; - executeSoon(finishTest); - yield undefined; + yield jsterm.execute("undefined"); + yield checkResult("undefined", "undefined is printed"); } diff --git a/browser/devtools/webconsole/webconsole.js b/browser/devtools/webconsole/webconsole.js index 55cfde3c55b6..3e4303b1a0b3 100644 --- a/browser/devtools/webconsole/webconsole.js +++ b/browser/devtools/webconsole/webconsole.js @@ -3318,9 +3318,20 @@ JSTerm.prototype = { * user input is used - taken from |this.inputNode.value|. * @param function [aCallback] * Optional function to invoke when the result is displayed. + * This is deprecated - please use the promise return value instead. + * @returns Promise + * Resolves with the message once the result is displayed. */ execute: function JST_execute(aExecuteString, aCallback) { + let deferred = promise.defer(); + let callback = function(msg) { + deferred.resolve(msg); + if (aCallback) { + aCallback(msg); + } + } + // attempt to execute the content of the inputNode aExecuteString = aExecuteString || this.inputNode.value; if (!aExecuteString) { @@ -3338,7 +3349,7 @@ JSTerm.prototype = { severity: "log", }); this.hud.output.addMessage(message); - let onResult = this._executeResultCallback.bind(this, message, aCallback); + let onResult = this._executeResultCallback.bind(this, message, callback); let options = { frame: this.SELECTED_FRAME, @@ -3355,6 +3366,7 @@ JSTerm.prototype = { WebConsoleUtils.usageCount++; this.setInputValue(""); this.clearCompletion(); + return deferred.promise; }, /** From 7f02b8f09863d659085313bb4202ec893e60f905 Mon Sep 17 00:00:00 2001 From: Brian Grinstead Date: Tue, 16 Dec 2014 17:18:26 -0800 Subject: [PATCH 128/130] Bug 1088861 - Add evaluateJSAsync method on the web console actor;r=past --- browser/devtools/scratchpad/scratchpad.js | 2 +- browser/devtools/webconsole/test/browser.ini | 1 + .../browser_eval_in_debugger_stackframe2.js | 63 +++++++++++++++++++ browser/devtools/webconsole/webconsole.js | 2 +- toolkit/devtools/client/dbg-client.jsm | 3 +- toolkit/devtools/server/actors/webconsole.js | 34 ++++++++++ toolkit/devtools/webconsole/client.js | 48 ++++++++++++++ .../devtools/webconsole/test/test_jsterm.html | 32 +++++++--- 8 files changed, 175 insertions(+), 10 deletions(-) create mode 100644 browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe2.js diff --git a/browser/devtools/scratchpad/scratchpad.js b/browser/devtools/scratchpad/scratchpad.js index 00a7abb918b4..94813a0cfd4a 100644 --- a/browser/devtools/scratchpad/scratchpad.js +++ b/browser/devtools/scratchpad/scratchpad.js @@ -468,7 +468,7 @@ var Scratchpad = { return connection.then(({ debuggerClient, webConsoleClient }) => { let deferred = promise.defer(); - webConsoleClient.evaluateJS(aString, aResponse => { + webConsoleClient.evaluateJSAsync(aString, aResponse => { this.debuggerClient = debuggerClient; this.webConsoleClient = webConsoleClient; if (aResponse.error) { diff --git a/browser/devtools/webconsole/test/browser.ini b/browser/devtools/webconsole/test/browser.ini index 60d179a3c425..cabc635f6352 100644 --- a/browser/devtools/webconsole/test/browser.ini +++ b/browser/devtools/webconsole/test/browser.ini @@ -172,6 +172,7 @@ skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s [browser_eval_in_debugger_stackframe.js] skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s +[browser_eval_in_debugger_stackframe2.js] [browser_jsterm_inspect.js] [browser_longstring_hang.js] [browser_netpanel_longstring_expand.js] diff --git a/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe2.js b/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe2.js new file mode 100644 index 000000000000..e9437518198e --- /dev/null +++ b/browser/devtools/webconsole/test/browser_eval_in_debugger_stackframe2.js @@ -0,0 +1,63 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Test to make sure that web console commands can fire while paused at a breakpoint +// that was triggered from a JS call. Relies on asynchronous js evaluation over the +// protocol - see Bug 1088861. + +"use strict"; + +const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-eval-in-stackframe.html"; +let test = asyncTest(function*() { + yield loadTab(TEST_URI); + + info("open the web console"); + let hud = yield openConsole(); + let {jsterm} = hud; + + info("open the debugger"); + let {panel,panelWin} = yield openDebugger(); + let {DebuggerController} = panelWin; + let {activeThread,StackFrames} = DebuggerController; + + let firstCall = promise.defer(); + let frameAdded = promise.defer(); + executeSoon(() => { + info ("Executing firstCall"); + activeThread.addOneTimeListener("framesadded", () => { + executeSoon(frameAdded.resolve); + }); + jsterm.execute("firstCall()").then(firstCall.resolve); + }); + + info ("Waiting for a frame to be added"); + yield frameAdded.promise; + + info ("Executing basic command while paused"); + yield executeAndConfirm(jsterm, "1 + 2", "3"); + + info ("Executing command using scoped variables while paused"); + yield executeAndConfirm(jsterm, "foo + foo2", '"globalFooBug783499foo2SecondCall"'); + + info ("Resuming the thread"); + activeThread.resume(); + + info ("Checking the first command (which is the last to resolve since it paused"); + let node = yield firstCall.promise; + is (node.querySelector(".message-body").textContent, + "undefined", + "firstCall() returned correct value"); +}); + +function* executeAndConfirm(jsterm, input, output) { + info ("Executing command `"+input+"`"); + + let node = yield jsterm.execute(input); + + is (node.querySelector(".message-body").textContent, + output, + "Expected result from call to " + input); +} + diff --git a/browser/devtools/webconsole/webconsole.js b/browser/devtools/webconsole/webconsole.js index 3e4303b1a0b3..e84c83406953 100644 --- a/browser/devtools/webconsole/webconsole.js +++ b/browser/devtools/webconsole/webconsole.js @@ -3417,7 +3417,7 @@ JSTerm.prototype = { selectedNodeActor: aOptions.selectedNodeActor, }; - this.webConsoleClient.evaluateJS(aString, onResult, evalOptions); + this.webConsoleClient.evaluateJSAsync(aString, onResult, evalOptions); return deferred.promise; }, diff --git a/toolkit/devtools/client/dbg-client.jsm b/toolkit/devtools/client/dbg-client.jsm index a7f559a1beb8..92d1afc41761 100644 --- a/toolkit/devtools/client/dbg-client.jsm +++ b/toolkit/devtools/client/dbg-client.jsm @@ -234,7 +234,8 @@ const UnsolicitedNotifications = { "appOpen": "appOpen", "appClose": "appClose", "appInstall": "appInstall", - "appUninstall": "appUninstall" + "appUninstall": "appUninstall", + "evaluationResult": "evaluationResult", }; /** diff --git a/toolkit/devtools/server/actors/webconsole.js b/toolkit/devtools/server/actors/webconsole.js index 6a499e35494e..b52f6acb5159 100644 --- a/toolkit/devtools/server/actors/webconsole.js +++ b/toolkit/devtools/server/actors/webconsole.js @@ -728,6 +728,39 @@ WebConsoleActor.prototype = }; }, + /** + * Handler for the "evaluateJSAsync" request. This method evaluates the given + * JavaScript string and sends back a packet with a unique ID. + * The result will be returned later as an unsolicited `evaluationResult`, + * that can be associated back to this request via the `resultID` field. + * + * @param object aRequest + * The JSON request object received from the Web Console client. + * @return object + * The response packet to send to with the unique id in the + * `resultID` field. + */ + onEvaluateJSAsync: function WCA_onEvaluateJSAsync(aRequest) + { + // We want to be able to run console commands without waiting + // for the first to return (see Bug 1088861). + + // First, send a response packet with the id only. + let resultID = Date.now(); + this.conn.send({ + from: this.actorID, + resultID: resultID + }); + + // Then, execute the script that may pause. + let response = this.onEvaluateJS(aRequest); + response.resultID = resultID; + + // Finally, send an unsolicited evaluationResult packet with + // the normal return value + this.conn.sendActorEvent(this.actorID, "evaluationResult", response); + }, + /** * Handler for the "evaluateJS" request. This method evaluates the given * JavaScript string and sends back the result. @@ -1471,6 +1504,7 @@ WebConsoleActor.prototype.requestTypes = stopListeners: WebConsoleActor.prototype.onStopListeners, getCachedMessages: WebConsoleActor.prototype.onGetCachedMessages, evaluateJS: WebConsoleActor.prototype.onEvaluateJS, + evaluateJSAsync: WebConsoleActor.prototype.onEvaluateJSAsync, autocomplete: WebConsoleActor.prototype.onAutocomplete, clearMessagesCache: WebConsoleActor.prototype.onClearMessagesCache, getPreferences: WebConsoleActor.prototype.onGetPreferences, diff --git a/toolkit/devtools/webconsole/client.js b/toolkit/devtools/webconsole/client.js index f1eb08980adf..e50577e833c5 100644 --- a/toolkit/devtools/webconsole/client.js +++ b/toolkit/devtools/webconsole/client.js @@ -7,6 +7,7 @@ "use strict"; const {Cc, Ci, Cu} = require("chrome"); +const DevToolsUtils = require("devtools/toolkit/DevToolsUtils"); loader.lazyImporter(this, "LongStringClient", "resource://gre/modules/devtools/dbg-client.jsm"); @@ -27,7 +28,13 @@ function WebConsoleClient(aDebuggerClient, aResponse) this._longStrings = {}; this.traits = aResponse.traits || {}; this.events = []; + + this.pendingEvaluationResults = new Map(); + this.onEvaluationResult = this.onEvaluationResult.bind(this); + + this._client.addListener("evaluationResult", this.onEvaluationResult); } + exports.WebConsoleClient = WebConsoleClient; WebConsoleClient.prototype = { @@ -124,6 +131,44 @@ WebConsoleClient.prototype = { this._client.request(packet, aOnResponse); }, + /** + * Evaluate a JavaScript expression asynchronously. + * See evaluateJS for parameter and response information. + */ + evaluateJSAsync: function(aString, aOnResponse, aOptions = {}) + { + let packet = { + to: this._actor, + type: "evaluateJSAsync", + text: aString, + bindObjectActor: aOptions.bindObjectActor, + frameActor: aOptions.frameActor, + url: aOptions.url, + selectedNodeActor: aOptions.selectedNodeActor, + }; + + this._client.request(packet, response => { + this.pendingEvaluationResults.set(response.resultID, aOnResponse); + }); + }, + + /** + * Handler for the actors's unsolicited evaluationResult packet. + */ + onEvaluationResult: function(aNotification, aPacket) { + // Find the associated callback based on this ID, and fire it. + // In a sync evaluation, this would have already been called in + // direct response to the client.request function. + let onResponse = this.pendingEvaluationResults.get(aPacket.resultID); + if (onResponse) { + onResponse(aPacket); + this.pendingEvaluationResults.delete(aPacket.resultID); + } else { + DevToolsUtils.reportException("onEvaluationResult", + "No response handler for an evaluateJSAsync result (resultID: " + aPacket.resultID + ")"); + } + }, + /** * Autocomplete a JavaScript expression. * @@ -400,8 +445,11 @@ WebConsoleClient.prototype = { */ detach: function WCC_detach(aOnResponse) { + this._client.removeListener("evaluationResult", this.onEvaluationResult); this.stopListeners(null, aOnResponse); this._longStrings = null; this._client = null; + this.pendingEvaluationResults.clear(); + this.pendingEvaluationResults = null; }, }; diff --git a/toolkit/devtools/webconsole/test/test_jsterm.html b/toolkit/devtools/webconsole/test/test_jsterm.html index 19784c1091e9..a7022fd2622a 100644 --- a/toolkit/devtools/webconsole/test/test_jsterm.html +++ b/toolkit/devtools/webconsole/test/test_jsterm.html @@ -19,6 +19,17 @@ let gState; let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); let {MAX_AUTOCOMPLETE_ATTEMPTS,MAX_AUTOCOMPLETIONS} = devtools.require("devtools/toolkit/webconsole/utils"); +// This test runs all of its assertions twice - once with +// evaluateJS and once with evaluateJSAsync. +let evaluatingSync = true; +function evaluateJS(input, callback) { + if (evaluatingSync) { + gState.client.evaluateJS(input, callback); + } else { + gState.client.evaluateJSAsync(input, callback); + } +} + function startTest() { removeEventListener("load", startTest); @@ -162,7 +173,7 @@ function onAutocompleteLarge2(aResponse) function doSimpleEval() { info("test eval '2+2'"); - gState.client.evaluateJS("2+2", onSimpleEval); + evaluateJS("2+2", onSimpleEval); } function onSimpleEval(aResponse) @@ -182,7 +193,7 @@ function onSimpleEval(aResponse) function doWindowEval() { info("test eval 'document'"); - gState.client.evaluateJS("document", onWindowEval); + evaluateJS("document", onWindowEval); } function onWindowEval(aResponse) @@ -206,7 +217,7 @@ function onWindowEval(aResponse) function doEvalWithException() { info("test eval with exception"); - gState.client.evaluateJS("window.doTheImpossible()", onEvalWithException); + evaluateJS("window.doTheImpossible()", onEvalWithException); } function onEvalWithException(aResponse) @@ -229,7 +240,7 @@ function onEvalWithException(aResponse) function doEvalWithHelper() { info("test eval with helper"); - gState.client.evaluateJS("clear()", onEvalWithHelper); + evaluateJS("clear()", onEvalWithHelper); } function onEvalWithHelper(aResponse) @@ -250,7 +261,7 @@ function onEvalWithHelper(aResponse) function doEvalString() { - gState.client.evaluateJS("window.foobarObject.strfoo", onEvalString); + evaluateJS("window.foobarObject.strfoo", onEvalString); } function onEvalString(aResponse) @@ -266,7 +277,7 @@ function onEvalString(aResponse) function doEvalLongString() { - gState.client.evaluateJS("window.foobarObject.omgstr", onEvalLongString); + evaluateJS("window.foobarObject.omgstr", onEvalLongString); } function onEvalLongString(aResponse) @@ -289,9 +300,16 @@ function onEvalLongString(aResponse) function testEnd() { + // If this is the first run, reload the page and do it again. + // Otherwise, end the test. closeDebugger(gState, function() { gState = null; - SimpleTest.finish(); + if (evaluatingSync) { + evaluatingSync = false; + startTest(); + } else { + SimpleTest.finish(); + } }); } From ae1fb259fad12c4ed2772f6cceb9a42e3ec47746 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 16 Dec 2014 21:12:52 -0500 Subject: [PATCH 129/130] Bug 1112426 - stop generating unused PremultiplyTables.h in gfx/layers/; r=jrmuizel --- gfx/layers/Makefile.in | 9 --------- gfx/layers/genTables.py | 12 ------------ gfx/layers/moz.build | 4 ---- 3 files changed, 25 deletions(-) delete mode 100644 gfx/layers/Makefile.in delete mode 100644 gfx/layers/genTables.py diff --git a/gfx/layers/Makefile.in b/gfx/layers/Makefile.in deleted file mode 100644 index 7e24cb090076..000000000000 --- a/gfx/layers/Makefile.in +++ /dev/null @@ -1,9 +0,0 @@ -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -include $(topsrcdir)/config/rules.mk - -PremultiplyTables.h: $(srcdir)/genTables.py - $(PYTHON) $(srcdir)/genTables.py diff --git a/gfx/layers/genTables.py b/gfx/layers/genTables.py deleted file mode 100644 index 369ec10d47e0..000000000000 --- a/gfx/layers/genTables.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/python - -def table_generator(f): - return ",\n".join([", ".join(["0x%2.2x" % h for h in [f(i) for i in range(r,r+16)]]) for r in range(0, 65536, 16)]) - -with open("PremultiplyTables.h", "w") as f: - f.write("const uint8_t PremultiplyTable[256*256] = {\n"); - f.write(table_generator(lambda i: ((i / 256) * (i % 256) + 254) / 255) + "\n") - f.write("};\n"); - f.write("const uint8_t UnpremultiplyTable[256*256] = {\n"); - f.write(table_generator(lambda i: (i % 256) * 255 / ((i / 256) if (i / 256) > 0 else 255) % 256) + "\n") - f.write("};\n"); diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index de9556981f01..8aeebe452513 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -378,10 +378,6 @@ if CONFIG['MOZ_DEBUG']: if CONFIG['MOZ_ENABLE_D3D10_LAYER']: DEFINES['MOZ_ENABLE_D3D10_LAYER'] = True -GENERATED_FILES = [ - 'PremultiplyTables.h', -] - CXXFLAGS += [ '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ 'frameworks/base/include/media/stagefright', From d926d6b5929e6cfda4ff3a76ea32e2c6bdf00f3b Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Wed, 17 Dec 2014 13:12:58 +0900 Subject: [PATCH 130/130] Bug 958949 - Save return value for generator function into local variable before running finally-block. r=jandem --- js/src/asmjs/AsmJSValidate.cpp | 16 +- js/src/frontend/BytecodeEmitter.cpp | 51 ++++- js/src/frontend/FoldConstants.cpp | 7 +- js/src/frontend/FullParseHandler.h | 4 +- js/src/frontend/ParseNode.h | 3 +- js/src/frontend/Parser.cpp | 32 +++- js/src/frontend/SharedContext.h | 4 + js/src/frontend/SyntaxParseHandler.h | 2 +- .../tests/generators/yield-in-finally.js | 178 ++++++++++++++++++ js/src/jsreflect.cpp | 19 +- js/src/vm/CommonPropertyNames.h | 1 + js/src/vm/Xdr.h | 2 +- 12 files changed, 283 insertions(+), 36 deletions(-) create mode 100644 js/src/jit-test/tests/generators/yield-in-finally.js diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index b2bc333a15cc..c074d819e865 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -85,13 +85,6 @@ UnaryKid(ParseNode *pn) return pn->pn_kid; } -static inline ParseNode * -ReturnExpr(ParseNode *pn) -{ - MOZ_ASSERT(pn->isKind(PNK_RETURN)); - return UnaryKid(pn); -} - static inline ParseNode * BinaryRight(ParseNode *pn) { @@ -106,6 +99,13 @@ BinaryLeft(ParseNode *pn) return pn->pn_left; } +static inline ParseNode * +ReturnExpr(ParseNode *pn) +{ + MOZ_ASSERT(pn->isKind(PNK_RETURN)); + return BinaryLeft(pn); +} + static inline ParseNode * TernaryKid1(ParseNode *pn) { @@ -4165,7 +4165,7 @@ static bool CheckFinalReturn(FunctionCompiler &f, ParseNode *stmt, RetType *retType) { if (stmt && stmt->isKind(PNK_RETURN)) { - if (ParseNode *coercionNode = UnaryKid(stmt)) { + if (ParseNode *coercionNode = BinaryLeft(stmt)) { AsmJSNumLit lit; if (IsLiteralOrConst(f, coercionNode, &lit)) { switch (lit.which()) { diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 281aec8b8f05..3985c1dc8f46 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1074,9 +1074,9 @@ EmitAtomOp(ExclusiveContext *cx, JSAtom *atom, JSOp op, BytecodeEmitter *bce) { MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ATOM); - // .generator lookups should be emitted as JSOP_GETALIASEDVAR instead of - // JSOP_GETNAME etc, to bypass |with| objects on the scope chain. - MOZ_ASSERT_IF(op == JSOP_GETNAME || op == JSOP_GETGNAME, atom != cx->names().dotGenerator); + // .generator and .genrval lookups should be emitted as JSOP_GETALIASEDVAR + // instead of JSOP_GETNAME etc, to bypass |with| objects on the scope chain. + MOZ_ASSERT_IF(op == JSOP_GETNAME || op == JSOP_GETGNAME, !bce->sc->isDotVariable(atom)); if (op == JSOP_GETPROP && atom == cx->names().length) { /* Specialize length accesses for the interpreter. */ @@ -5588,6 +5588,16 @@ EmitContinue(ExclusiveContext *cx, BytecodeEmitter *bce, PropertyName *label) return EmitGoto(cx, bce, stmt, &stmt->continues, SRC_CONTINUE) >= 0; } +static bool +InTryBlockWithFinally(BytecodeEmitter *bce) +{ + for (StmtInfoBCE *stmt = bce->topStmt; stmt; stmt = stmt->down) { + if (stmt->type == STMT_FINALLY) + return true; + } + return false; +} + static bool EmitReturn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) { @@ -5600,7 +5610,7 @@ EmitReturn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) } /* Push a return value */ - if (ParseNode *pn2 = pn->pn_kid) { + if (ParseNode *pn2 = pn->pn_left) { if (!EmitTree(cx, bce, pn2)) return false; } else { @@ -5628,8 +5638,25 @@ EmitReturn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) ptrdiff_t top = bce->offset(); bool isGenerator = bce->sc->isFunctionBox() && bce->sc->asFunctionBox()->isGenerator(); - if (Emit1(cx, bce, isGenerator ? JSOP_SETRVAL : JSOP_RETURN) < 0) - return false; + bool useGenRVal = false; + if (isGenerator) { + if (bce->sc->asFunctionBox()->isStarGenerator() && InTryBlockWithFinally(bce)) { + // Emit JSOP_SETALIASEDVAR .genrval to store the return value on the + // scope chain, so it's not lost when we yield in a finally block. + useGenRVal = true; + MOZ_ASSERT(pn->pn_right); + if (!EmitTree(cx, bce, pn->pn_right)) + return false; + if (Emit1(cx, bce, JSOP_POP) < 0) + return false; + } else { + if (Emit1(cx, bce, JSOP_SETRVAL) < 0) + return false; + } + } else { + if (Emit1(cx, bce, JSOP_RETURN) < 0) + return false; + } NonLocalExitScope nle(cx, bce); @@ -5638,9 +5665,17 @@ EmitReturn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) if (isGenerator) { ScopeCoordinate sc; - // We know that .generator is on the top scope chain node, as we just - // exited nested scopes. + // We know that .generator and .genrval are on the top scope chain node, + // as we just exited nested scopes. sc.setHops(0); + if (useGenRVal) { + MOZ_ALWAYS_TRUE(LookupAliasedNameSlot(bce, bce->script, cx->names().dotGenRVal, &sc)); + if (!EmitAliasedVarOp(cx, JSOP_GETALIASEDVAR, sc, DontCheckLexical, bce)) + return false; + if (Emit1(cx, bce, JSOP_SETRVAL) < 0) + return false; + } + MOZ_ALWAYS_TRUE(LookupAliasedNameSlot(bce, bce->script, cx->names().dotGenerator, &sc)); if (!EmitAliasedVarOp(cx, JSOP_GETALIASEDVAR, sc, DontCheckLexical, bce)) return false; diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index cbf4366196e1..747da5093906 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -363,8 +363,11 @@ Fold(ExclusiveContext *cx, ParseNode **pnp, if (!Fold(cx, &pn->pn_left, handler, options, inGenexpLambda, condIf(pn, PNK_WHILE))) return false; } - if (!Fold(cx, &pn->pn_right, handler, options, inGenexpLambda, condIf(pn, PNK_DOWHILE))) - return false; + /* Second kid may be null (for return in non-generator). */ + if (pn->pn_right) { + if (!Fold(cx, &pn->pn_right, handler, options, inGenexpLambda, condIf(pn, PNK_DOWHILE))) + return false; + } } pn1 = pn->pn_left; pn2 = pn->pn_right; diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 12977276bada..ab8c87e77bc4 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -478,9 +478,9 @@ class FullParseHandler return new_(label, pos); } - ParseNode *newReturnStatement(ParseNode *expr, const TokenPos &pos) { + ParseNode *newReturnStatement(ParseNode *expr, ParseNode *genrval, const TokenPos &pos) { MOZ_ASSERT_IF(expr, pos.encloses(expr->pn_pos)); - return new_(PNK_RETURN, JSOP_RETURN, pos, expr); + return new_(PNK_RETURN, JSOP_RETURN, pos, expr, genrval); } ParseNode *newWithStatement(uint32_t begin, ParseNode *expr, ParseNode *body, diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index ed264c420432..9a9c8dcb1af8 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -311,7 +311,8 @@ enum ParseNodeKind * pn_left: PNK_NAME with pn_used true and * pn_lexdef (NOT pn_expr) set * pn_right: initializer - * PNK_RETURN unary pn_kid: return expr or null + * PNK_RETURN binary pn_left: return expr or null + * pn_right: .genrval name or null * PNK_SEMI unary pn_kid: expr or null statement * pn_prologue: true if Directive Prologue member * in original source, not introduced via diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index a16b7b7b4674..2473b45856d0 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1047,7 +1047,7 @@ Parser::functionBody(FunctionSyntaxKind kind, FunctionBodyType typ if (!kid) return null(); - pn = handler.newReturnStatement(kid, handler.getPosition(kid)); + pn = handler.newReturnStatement(kid, null(), handler.getPosition(kid)); if (!pn) return null(); } @@ -1087,6 +1087,14 @@ Parser::functionBody(FunctionSyntaxKind kind, FunctionBodyType typ if (!pc->define(tokenStream, context->names().dotGenerator, generator, Definition::VAR)) return null(); + if (pc->isStarGenerator()) { + Node genrval = newName(context->names().dotGenRVal); + if (!genrval) + return null(); + if (!pc->define(tokenStream, context->names().dotGenRVal, genrval, Definition::VAR)) + return null(); + } + generator = newName(context->names().dotGenerator); if (!generator) return null(); @@ -3111,7 +3119,7 @@ LexicalLookup(ContextT *ct, HandleAtom atom, int *slotp, typename ContextT::Stmt * can potentially override any static bindings introduced by statements * further up the stack, we have to abort the search. */ - if (stmt->type == STMT_WITH && atom != ct->sc->context->names().dotGenerator) + if (stmt->type == STMT_WITH && !ct->sc->isDotVariable(atom)) break; // Skip statements that do not introduce a new scope @@ -5288,7 +5296,18 @@ Parser::returnStatement() if (!MatchOrInsertSemicolon(tokenStream)) return null(); - Node pn = handler.newReturnStatement(exprNode, TokenPos(begin, pos().end)); + Node genrval = null(); + if (pc->isStarGenerator()) { + genrval = newName(context->names().dotGenRVal); + if (!genrval) + return null(); + if (!noteNameUse(context->names().dotGenRVal, genrval)) + return null(); + if (!checkAndMarkAsAssignmentLhs(genrval, PlainAssignment)) + return null(); + } + + Node pn = handler.newReturnStatement(exprNode, genrval, TokenPos(begin, pos().end)); if (!pn) return null(); @@ -5486,7 +5505,7 @@ Parser::withStatement() for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) { DefinitionNode defn = r.front().value().get(); DefinitionNode lexdep = handler.resolve(defn); - if (lexdep->name() != context->names().dotGenerator) + if (!pc->sc->isDotVariable(lexdep->name())) handler.deoptimizeUsesWithin(lexdep, TokenPos(begin, pos().begin)); } @@ -6556,10 +6575,9 @@ LegacyCompExprTransplanter::transplant(ParseNode *pn) MOZ_ASSERT(!stmt || stmt != pc->topStmt); #endif if (isGenexp && !dn->isOp(JSOP_CALLEE)) { - MOZ_ASSERT_IF(atom != parser->context->names().dotGenerator, - !pc->decls().lookupFirst(atom)); + MOZ_ASSERT_IF(!pc->sc->isDotVariable(atom), !pc->decls().lookupFirst(atom)); - if (atom == parser->context->names().dotGenerator) { + if (pc->sc->isDotVariable(atom)) { if (dn->dn_uses == pn) { if (!BumpStaticLevel(parser->tokenStream, dn, pc)) return false; diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index f3657e96fb1c..8016b68e396d 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -206,6 +206,10 @@ class SharedContext bool needStrictChecks() { return strict || extraWarnings; } + + bool isDotVariable(JSAtom *atom) const { + return atom == context->names().dotGenerator || atom == context->names().dotGenRVal; + } }; class GlobalSharedContext : public SharedContext diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 595462455f4b..5b13ac6297c6 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -156,7 +156,7 @@ class SyntaxParseHandler Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; } Node newContinueStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; } Node newBreakStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; } - Node newReturnStatement(Node expr, const TokenPos &pos) { return NodeGeneric; } + Node newReturnStatement(Node expr, Node genrval, const TokenPos &pos) { return NodeGeneric; } Node newLabeledStatement(PropertyName *label, Node stmt, uint32_t begin) { return NodeGeneric; diff --git a/js/src/jit-test/tests/generators/yield-in-finally.js b/js/src/jit-test/tests/generators/yield-in-finally.js new file mode 100644 index 000000000000..a99e5a61a957 --- /dev/null +++ b/js/src/jit-test/tests/generators/yield-in-finally.js @@ -0,0 +1,178 @@ +// return value in try block should not be overridden by yield in finally block. + +load(libdir + "asserts.js"); + +// simple +function* g1() { + try { + return 42; + } finally { + yield 43; + } +} +var o = g1(); +var v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 43); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, 42); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); + +// without return value +function* g2() { + try { + return; + } finally { + yield 43; + } +} +o = g2(); +v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 43); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); + +// nested try-finally +function* g3() { + try { + try { + return 42; + } finally { + try { + return 43; + } finally { + yield 44; + } + } + } finally { + yield 45; + } +} +o = g3(); +v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 44); +v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 45); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, 43); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); + +// yield* +function* g4() { + try { + return 42; + } finally { + try { + return 43; + } finally { + yield* g5(); + } + } +} +function* g5() { + yield 44; + return 45; +} +o = g4(); +v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 44); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, 43); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); + +// return in block scope +function* g6() { + let a = 10; + { + let a = 20; + try { + let a = 30; + { + let a = 40; + return 42; + } + } finally { + yield 43; + } + } +} +o = g6(); +v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 43); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, 42); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); + +// no finally +function* g7() { + try { + return 42; + } catch (e) { + yield 1; + } +} +o = g7(); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, 42); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); + +// legacy iterator have no return value +function g8() { + try { + return; + } finally { + yield 43; + } +} +o = g8(); +v = o.next(); +assertEq(v, 43); +assertThrowsInstanceOf(() => o.next(), StopIteration); + +// in "with" statement +options("strict"); +eval(` +function* g9() { + with ({ ".genrval": { value: 44, done: false } }) { + try { + return 42; + } finally { + yield 43; + } + } +} +o = g9(); +v = o.next(); +assertEq(v.done, false); +assertEq(v.value, 43); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, 42); +v = o.next(); +assertEq(v.done, true); +assertEq(v.value, undefined); +`); diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index 72654797b9ec..912e364af626 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -2522,16 +2522,23 @@ ASTSerializer::statement(ParseNode *pn, MutableHandleValue dst) } case PNK_THROW: - case PNK_RETURN: { MOZ_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos)); RootedValue arg(cx); return optExpression(pn->pn_kid, &arg) && - (pn->isKind(PNK_THROW) - ? builder.throwStatement(arg, &pn->pn_pos, dst) - : builder.returnStatement(arg, &pn->pn_pos, dst)); + builder.throwStatement(arg, &pn->pn_pos, dst); + } + + case PNK_RETURN: + { + MOZ_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos)); + + RootedValue arg(cx); + + return optExpression(pn->pn_left, &arg) && + builder.returnStatement(arg, &pn->pn_pos, dst); } case PNK_DEBUGGER: @@ -3295,7 +3302,7 @@ ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, NodeVector & switch (pnbody->getKind()) { case PNK_RETURN: /* expression closure, no destructured args */ return functionArgs(pn, pnargs, nullptr, pnbody, args, defaults, rest) && - expression(pnbody->pn_kid, body); + expression(pnbody->pn_left, body); case PNK_SEQ: /* expression closure with destructured args */ { @@ -3303,7 +3310,7 @@ ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, NodeVector & LOCAL_ASSERT(pnstart && pnstart->isKind(PNK_RETURN)); return functionArgs(pn, pnargs, pndestruct, pnbody, args, defaults, rest) && - expression(pnstart->pn_kid, body); + expression(pnstart->pn_left, body); } case PNK_STATEMENTLIST: /* statement closure */ diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index e187144ab833..c75d2a932fcf 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -61,6 +61,7 @@ macro(displayURL, displayURL, "displayURL") \ macro(done, done, "done") \ macro(dotGenerator, dotGenerator, ".generator") \ + macro(dotGenRVal, dotGenRVal, ".genrval") \ macro(each, each, "each") \ macro(elementType, elementType, "elementType") \ macro(empty, empty, "") \ diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index ecfb6634bc5d..08145f972a07 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -35,7 +35,7 @@ namespace js { * Nightly) and without (all others). FIXME: Bug 1066322 - Enable ES6 symbols * in all builds. */ -static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 222; +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 224; static_assert(XDR_BYTECODE_VERSION_SUBTRAHEND % 2 == 0, "see the comment above"); static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - (XDR_BYTECODE_VERSION_SUBTRAHEND