diff --git a/core/includes/common.inc b/core/includes/common.inc
index 7154875..3bd78fc 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2495,7 +2495,7 @@ function drupal_pre_render_scripts($elements) {
  *   FALSE if there were any missing library dependencies; TRUE if all library
  *   dependencies were met.
  *
- * @see drupal_add_library()
+ * @see _drupal_add_library()
  * @see _drupal_add_js()
  * @see _drupal_add_css()
  * @see drupal_render()
@@ -2511,7 +2511,7 @@ function drupal_process_attached($elements, $dependency_check = FALSE) {
   // Add the libraries first.
   $success = TRUE;
   foreach ($elements['#attached']['library'] as $library) {
-    if (drupal_add_library($library[0], $library[1]) === FALSE) {
+    if (_drupal_add_library($library[0], $library[1]) === FALSE) {
       $success = FALSE;
       // Exit if the dependency is missing.
       if ($dependency_check) {
@@ -2713,7 +2713,7 @@ function drupal_process_states(&$elements) {
  * @see hook_library_info()
  * @see hook_library_info_alter()
  */
-function drupal_add_library($module, $name, $every_page = NULL) {
+function _drupal_add_library($module, $name, $every_page = NULL) {
   $added = &drupal_static(__FUNCTION__, array());
 
   // Only process the library if it exists and it was not added already.
@@ -2773,7 +2773,7 @@ function drupal_add_library($module, $name, $every_page = NULL) {
  *   or FALSE if it does not exist. If no $name was passed, an associative array
  *   of libraries registered by $module is returned (which may be empty).
  *
- * @see drupal_add_library()
+ * @see _drupal_add_library()
  * @see hook_library_info()
  * @see hook_library_info_alter()
  *
@@ -3828,6 +3828,12 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
     drupal_process_states($elements);
   }
 
+  // Add additional libraries, CSS, JavaScript an other custom
+  // attached data associated with this element.
+  if (!empty($elements['#attached'])) {
+    drupal_process_attached($elements);
+  }
+
   // Get the children of the element, sorted by weight.
   $children = Element::children($elements, TRUE);
 
@@ -3873,12 +3879,6 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
     $elements['#children'] = $elements['#markup'] . $elements['#children'];
   }
 
-  // Add additional libraries, CSS, JavaScript an other custom
-  // attached data associated with this element.
-  if (!empty($elements['#attached'])) {
-    drupal_process_attached($elements);
-  }
-
   // Let the theme functions in #theme_wrappers add markup around the rendered
   // children.
   // #states and #attached have to be processed before #theme_wrappers, because
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 3d57521..fa20f99 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1481,6 +1481,24 @@ function drupal_pre_render_table(array $element) {
   // Take over $element['#id'] as HTML ID attribute, if not already set.
   element_set_attributes($element, array('id'));
 
+
+  // Add sticky headers, if applicable.
+  if (count($element['#header']) && $element['#sticky']) {
+    $element['#attached']['library'][] = array('system', 'drupal.tableheader');
+    // Add 'sticky-enabled' class to the table to identify it for JS.
+    // This is needed to target tables constructed by this function.
+    $element['#attributes']['class'][] = 'sticky-enabled';
+  }
+  // If the table has headers and it should react responsively to columns hidden
+  // with the classes represented by the constants RESPONSIVE_PRIORITY_MEDIUM
+  // and RESPONSIVE_PRIORITY_LOW, add the tableresponsive behaviors.
+  if (count($element['#header']) && $element['#responsive']) {
+    $element['#attached']['library'][] = array('system', 'drupal.tableresponsive');
+    // Add 'responsive-enabled' class to the table to identify it for JS.
+    // This is needed to target tables constructed by this function.
+    $element['#attributes']['class'][] = 'responsive-enabled';
+  }
+
   // If the custom #tabledrag is set and there is a HTML ID, add the table's
   // HTML ID to the options and attach the behavior.
   if (!empty($element['#tabledrag']) && isset($element['#attributes']['id'])) {
@@ -1588,23 +1606,6 @@ function theme_table($variables) {
   $responsive = $variables['responsive'];
   $empty = $variables['empty'];
 
-  // Add sticky headers, if applicable.
-  if (count($header) && $sticky) {
-    drupal_add_library('system', 'drupal.tableheader');
-    // Add 'sticky-enabled' class to the table to identify it for JS.
-    // This is needed to target tables constructed by this function.
-    $attributes['class'][] = 'sticky-enabled';
-  }
-  // If the table has headers and it should react responsively to columns hidden
-  // with the classes represented by the constants RESPONSIVE_PRIORITY_MEDIUM
-  // and RESPONSIVE_PRIORITY_LOW, add the tableresponsive behaviors.
-  if (count($header) && $responsive) {
-    drupal_add_library('system', 'drupal.tableresponsive');
-    // Add 'responsive-enabled' class to the table to identify it for JS.
-    // This is needed to target tables constructed by this function.
-    $attributes['class'][] = 'responsive-enabled';
-  }
-
   $output = '<table' . new Attribute($attributes) . ">\n";
 
   if (isset($caption)) {
@@ -2037,6 +2038,30 @@ function _template_preprocess_default_variables() {
 }
 
 /**
+ * #pre_render callback for the html element type.
+ *
+ * @param array $element
+ *   A structured array containing the html element type build properties.
+ *
+ * @see system_element_info()
+ */
+function drupal_pre_render_html(array $element) {
+  // Add favicon.
+  if (theme_get_setting('features.favicon')) {
+    $favicon = theme_get_setting('favicon.url');
+    $type = theme_get_setting('favicon.mimetype');
+    $element['#attached']['drupal_add_html_head_link'][][] = array(
+      'rel' => 'shortcut icon',
+      'href' => Url::stripDangerousProtocols($favicon),
+      'type' => $type,
+    );
+  }
+  // HTML5 Shiv
+  $element['#attached']['library'][] = array('system', 'html5shiv');
+
+  return $element;
+}
+/**
  * Prepares variables for HTML document templates.
  *
  * Default template: html.html.twig.
@@ -2085,18 +2110,6 @@ function template_preprocess_html(&$variables) {
   $variables['html_attributes']['lang'] = $language_interface->id;
   $variables['html_attributes']['dir'] = $language_interface->direction ? 'rtl' : 'ltr';
 
-  // Add favicon.
-  if (theme_get_setting('features.favicon')) {
-    $favicon = theme_get_setting('favicon.url');
-    $type = theme_get_setting('favicon.mimetype');
-    $build['#attached']['drupal_add_html_head_link'][][] = array(
-      'rel' => 'shortcut icon',
-      'href' => Url::stripDangerousProtocols($favicon),
-      'type' => $type,
-    );
-    drupal_render($build);
-  }
-
   $site_config = \Drupal::config('system.site');
   // Construct page title.
   if ($page->hasTitle()) {
@@ -2157,8 +2170,6 @@ function template_preprocess_html(&$variables) {
     drupal_add_html_head($element, $name);
   }
 
-  drupal_add_library('system', 'html5shiv', TRUE);
-
   $variables['page_top'][] = array('#markup' => $page->getBodyTop());
   $variables['page_bottom'][] = array('#markup' => $page->getBodyBottom());
 
diff --git a/core/lib/Drupal/Core/Ajax/OpenDialogCommand.php b/core/lib/Drupal/Core/Ajax/OpenDialogCommand.php
index 45115df..ab10436 100644
--- a/core/lib/Drupal/Core/Ajax/OpenDialogCommand.php
+++ b/core/lib/Drupal/Core/Ajax/OpenDialogCommand.php
@@ -124,7 +124,7 @@ public function setDialogTitle($title) {
    */
   public function render() {
     // Add the library for handling the dialog in the response.
-    drupal_add_library('system', 'drupal.dialog.ajax');
+    $this->drupalAttachLibrary('system', 'drupal.dialog.ajax');
 
     // For consistency ensure the modal option is set to TRUE or FALSE.
     $this->dialogOptions['modal'] = isset($this->dialogOptions['modal']) && $this->dialogOptions['modal'];
@@ -136,4 +136,21 @@ public function render() {
       'dialogOptions' => $this->dialogOptions,
     );
   }
+
+  /**
+   * Wraps drupal_render.
+   *
+   * @param string $module
+   *   The name of the module that declares the library.
+   * @param string $name
+   *   The name of the library.
+   *
+   * @todo Remove once drupal_render is converted to autoloadable code.
+   * @see https://drupal.org/node/2171071
+   */
+  protected function drupalAttachLibrary($module, $name) {
+    $attached['#attached']['library'][] = array($module, $name);
+    drupal_render($attached);
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Page/DefaultHtmlPageRenderer.php b/core/lib/Drupal/Core/Page/DefaultHtmlPageRenderer.php
index 63e0d9c..821d42d 100644
--- a/core/lib/Drupal/Core/Page/DefaultHtmlPageRenderer.php
+++ b/core/lib/Drupal/Core/Page/DefaultHtmlPageRenderer.php
@@ -17,7 +17,7 @@ class DefaultHtmlPageRenderer implements HtmlPageRendererInterface {
    */
   public function render(HtmlPage $page) {
     $render = array(
-      '#theme' => 'html',
+      '#type' => 'html',
       '#page_object' => $page,
     );
     return drupal_render($render);
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleExportTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleExportTest.php
index d77fdc2..c0ceb05 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleExportTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleExportTest.php
@@ -121,9 +121,9 @@ function testExportTranslation() {
    * Test exportation of translation template file.
    */
   function testExportTranslationTemplateFile() {
-    // Load an admin page with JavaScript so drupal_add_library() fires at least
-    // once and _locale_parse_js_file() gets to run at least once so that the
-    // locales_source table gets populated with something.
+    // Load an admin page with JavaScript so _drupal_add_library() fires at
+    // least once and _locale_parse_js_file() gets to run at least once so that
+    // the locales_source table gets populated with something.
     $this->drupalGet('admin/config/regional/language');
     // Get the translation template file.
     $this->drupalPostForm('admin/config/regional/translate/export', array(), t('Export'));
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleLibraryInfoAlterTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleLibraryInfoAlterTest.php
index 912d657..4344441 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleLibraryInfoAlterTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleLibraryInfoAlterTest.php
@@ -36,7 +36,8 @@ public static function getInfo() {
      * @see locale_library_info_alter()
      */
   public function testLibraryInfoAlter() {
-    drupal_add_library('system', 'jquery.ui.datepicker');
+    $attached['#attached']['library'][] = array('system', 'jquery.ui.datepicker');
+    drupal_render($attached);
     $scripts = drupal_get_js();
     $this->assertTrue(strpos($scripts, 'locale.datepicker.js'), 'locale.datepicker.js added to scripts.');
   }
diff --git a/core/modules/simpletest/simpletest.theme.inc b/core/modules/simpletest/simpletest.theme.inc
index 1743b74..072ac65 100644
--- a/core/modules/simpletest/simpletest.theme.inc
+++ b/core/modules/simpletest/simpletest.theme.inc
@@ -17,8 +17,6 @@
 function theme_simpletest_test_table($variables) {
   $table = $variables['table'];
 
-  drupal_add_library('simpletest', 'drupal.simpletest');
-
   // Create header for test selection table.
   $header = array(
     array('class' => array('select-all')),
@@ -133,6 +131,7 @@ function theme_simpletest_test_table($variables) {
 
   // Add js array of settings.
   $attached = array();
+  $attached['#attached']['library'][] = array('simpletest', 'drupal.simpletest');
   $attached['#attached']['js'][] = array(
     'data' => array('simpleTest' => $js),
     'type' => 'setting',
diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php
index 565e35e..e94cebf 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php
@@ -47,9 +47,8 @@ function setUp() {
     $config->set('js.preprocess', 0);
     $config->save();
 
-    // Reset _drupal_add_js() and drupal_add_library() statics before each test.
+    // Reset _drupal_add_js() statics before each test.
     drupal_static_reset('_drupal_add_js');
-    drupal_static_reset('drupal_add_library');
   }
 
   function tearDown() {
@@ -71,7 +70,9 @@ function testDefault() {
    * Tests adding a JavaScript file.
    */
   function testAddFile() {
-    $javascript = _drupal_add_js('core/misc/collapse.js');
+    $attached['#attached']['js']['core/misc/collapse.js'] = array();
+    drupal_render($attached);
+    $javascript = _drupal_add_js();
     $this->assertTrue(array_key_exists('core/misc/collapse.js', $javascript), 'JavaScript files are correctly added.');
   }
 
@@ -80,7 +81,8 @@ function testAddFile() {
    */
   function testAddSetting() {
     // Add a file in order to test default settings.
-    drupal_add_library('system', 'drupalSettings');
+    $attached['#attached']['library'][] = array('system', 'drupalSettings');
+    drupal_render($attached);
     $javascript = _drupal_add_js();
     $last_settings = reset($javascript['settings']['data']);
     $this->assertTrue(array_key_exists('currentPath', $last_settings['path']), 'The current path JavaScript setting is set correctly.');
@@ -95,8 +97,9 @@ function testAddSetting() {
    * Tests adding an external JavaScript File.
    */
   function testAddExternal() {
-    $path = 'http://example.com/script.js';
-    $javascript = _drupal_add_js($path, 'external');
+    $attached['#attached']['js']['http://example.com/script.js'] = array('type' => 'external');
+    drupal_render($attached);
+    $javascript = _drupal_add_js();
     $this->assertTrue(array_key_exists('http://example.com/script.js', $javascript), 'Added an external JavaScript file.');
   }
 
@@ -106,12 +109,18 @@ function testAddExternal() {
   function testAttributes() {
     $default_query_string = $this->container->get('state')->get('system.css_js_query_string') ?: '0';
 
-    drupal_add_library('system', 'drupal');
-    _drupal_add_js('http://example.com/script.js', array('attributes' => array('defer' => 'defer')));
-    _drupal_add_js('core/misc/collapse.js', array('attributes' => array('defer' => 'defer')));
+    $attached['#attached']['library'][] = array('system', 'drupal');
+    $attached['#attached']['js']['http://example.com/script.js'] = array(
+      'type' => 'external',
+      'attributes' => array('defer' => 'defer'),
+    );
+    $attached['#attached']['js']['core/misc/collapse.js'] = array(
+      'attributes' => array('defer' => 'defer'),
+    );
+    drupal_render($attached);
     $javascript = drupal_get_js();
 
-    $expected_1 = '<script src="http://example.com/script.js?' . $default_query_string . '" defer="defer"></script>';
+    $expected_1 = '<script src="http://example.com/script.js" defer="defer"></script>';
     $expected_2 = '<script src="' . file_create_url('core/misc/collapse.js') . '?' . $default_query_string . '" defer="defer"></script>';
 
     $this->assertTrue(strpos($javascript, $expected_1) > 0, 'Rendered external JavaScript with correct defer attribute.');
@@ -127,12 +136,18 @@ function testAggregatedAttributes() {
 
     $default_query_string = $this->container->get('state')->get('system.css_js_query_string') ?: '0';
 
-    drupal_add_library('system', 'drupal');
-    _drupal_add_js('http://example.com/script.js', array('attributes' => array('defer' => 'defer')));
-    _drupal_add_js('core/misc/collapse.js', array('attributes' => array('defer' => 'defer')));
+    $attached['#attached']['library'][] = array('system', 'drupal');
+    $attached['#attached']['js']['http://example.com/script.js'] = array(
+      'type' => 'external',
+      'attributes' => array('defer' => 'defer'),
+    );
+    $attached['#attached']['js']['core/misc/collapse.js'] = array(
+      'attributes' => array('defer' => 'defer'),
+    );
+    drupal_render($attached);
     $javascript = drupal_get_js();
 
-    $expected_1 = '<script src="http://example.com/script.js?' . $default_query_string . '" defer="defer"></script>';
+    $expected_1 = '<script src="http://example.com/script.js" defer="defer"></script>';
     $expected_2 = '<script src="' . file_create_url('core/misc/collapse.js') . '?' . $default_query_string . '" defer="defer"></script>';
 
     $this->assertTrue(strpos($javascript, $expected_1) > 0, 'Rendered external JavaScript with correct defer attribute with aggregation enabled.');
@@ -143,7 +158,9 @@ function testAggregatedAttributes() {
    * Tests drupal_get_js() for JavaScript settings.
    */
   function testHeaderSetting() {
-    drupal_add_library('system', 'drupalSettings');
+    $attached = array();
+    $attached['#attached']['library'][] = array('system', 'drupalSettings');
+    drupal_render($attached);
 
     $javascript = drupal_get_js('header');
     $this->assertTrue(strpos($javascript, 'basePath') > 0, 'Rendered JavaScript header returns basePath setting.');
@@ -152,25 +169,57 @@ function testHeaderSetting() {
     $this->assertTrue(strpos($javascript, 'currentPath') > 0, 'Rendered JavaScript header returns currentPath setting.');
 
     // Only the second of these two entries should appear in drupalSettings.
-    _drupal_add_js(array('commonTest' => 'commonTestShouldNotAppear'), 'setting');
-    _drupal_add_js(array('commonTest' => 'commonTestShouldAppear'), 'setting');
+    $attached = array();
+    $attached['#attached']['js'][] = array(
+      'type' => 'setting',
+      'data' => array('commonTest' => 'commonTestShouldNotAppear'),
+    );
+    $attached['#attached']['js'][] = array(
+      'type' => 'setting',
+      'data' => array('commonTest' => 'commonTestShouldAppear'),
+    );
     // Only the second of these entries should appear in drupalSettings.
-    _drupal_add_js(array('commonTestJsArrayLiteral' => array('commonTestJsArrayLiteralOldValue')), 'setting');
-    _drupal_add_js(array('commonTestJsArrayLiteral' => array('commonTestJsArrayLiteralNewValue')), 'setting');
+    $attached['#attached']['js'][] = array(
+      'type' => 'setting',
+      'data' => array('commonTestJsArrayLiteral' => array('commonTestJsArrayLiteralOldValue')),
+    );
+    $attached['#attached']['js'][] = array(
+      'type' => 'setting',
+      'data' => array('commonTestJsArrayLiteral' => array('commonTestJsArrayLiteralNewValue')),
+    );
     // Only the second of these two entries should appear in drupalSettings.
-    _drupal_add_js(array('commonTestJsObjectLiteral' => array('key' => 'commonTestJsObjectLiteralOldValue')), 'setting');
-    _drupal_add_js(array('commonTestJsObjectLiteral' => array('key' => 'commonTestJsObjectLiteralNewValue')), 'setting');
+    $attached['#attached']['js'][] = array(
+      'type' => 'setting',
+      'data' => array('commonTestJsObjectLiteral' => array('key' => 'commonTestJsObjectLiteralOldValue')),
+    );
+    $attached['#attached']['js'][] = array(
+      'type' => 'setting',
+      'data' => array('commonTestJsObjectLiteral' => array('key' => 'commonTestJsObjectLiteralNewValue')),
+    );
     // Real world test case: multiple elements in a render array are adding the
     // same (or nearly the same) JavaScript settings. When merged, they should
     // contain all settings and not duplicate some settings.
     $settings_one = array('moduleName' => array('ui' => array('button A', 'button B'), 'magical flag' => 3.14159265359));
-    _drupal_add_js(array('commonTestRealWorldIdentical' => $settings_one), 'setting');
-    _drupal_add_js(array('commonTestRealWorldIdentical' => $settings_one), 'setting');
+    $attached['#attached']['js'][] = array(
+      'type' => 'setting',
+      'data' => array('commonTestRealWorldIdentical' => $settings_one),
+    );
+    $attached['#attached']['js'][] = array(
+      'type' => 'setting',
+      'data' => array('commonTestRealWorldIdentical' => $settings_one),
+    );
     $settings_two = array('moduleName' => array('ui' => array('button A', 'button B'), 'magical flag' => 3.14159265359, 'thingiesOnPage' => array('id1' => array())));
-    _drupal_add_js(array('commonTestRealWorldAlmostIdentical' => $settings_two), 'setting');
+    $attached['#attached']['js'][] = array(
+      'type' => 'setting',
+      'data' => array('commonTestRealWorldAlmostIdentical' => $settings_two),
+    );
     $settings_two = array('moduleName' => array('ui' => array('button C', 'button D'), 'magical flag' => 3.14, 'thingiesOnPage' => array('id2' => array())));
-    _drupal_add_js(array('commonTestRealWorldAlmostIdentical' => $settings_two), 'setting');
+    $attached['#attached']['js'][] = array(
+      'type' => 'setting',
+      'data' => array('commonTestRealWorldAlmostIdentical' => $settings_two),
+    );
 
+    drupal_render($attached);
     $javascript = drupal_get_js('header');
 
     // Test whether _drupal_add_js can be used to override a previous setting.
@@ -205,8 +254,9 @@ function testHeaderSetting() {
    * Tests to see if resetting the JavaScript empties the cache.
    */
   function testReset() {
-    drupal_add_library('system', 'drupal');
-    _drupal_add_js('core/misc/collapse.js');
+    $attached['#attached']['library'][] = array('system', 'drupal');
+    $attached['#attached']['js']['core/misc/collapse.js'] = array();
+    drupal_render($attached);
     drupal_static_reset('_drupal_add_js');
     $this->assertEqual(array(), _drupal_add_js(), 'Resetting the JavaScript correctly empties the cache.');
   }
@@ -215,9 +265,15 @@ function testReset() {
    * Tests adding inline scripts.
    */
   function testAddInline() {
-    drupal_add_library('system', 'jquery');
     $inline = 'jQuery(function () { });';
-    $javascript = _drupal_add_js($inline, array('type' => 'inline', 'scope' => 'footer'));
+    $attached['#attached']['library'][] = array('system', 'jquery');
+    $attached['#attached']['js'][] = array(
+      'type' => 'inline',
+      'data' => $inline,
+      'attributes' => array('defer' => 'defer'),
+    );
+    drupal_render($attached);
+    $javascript = _drupal_add_js();
     $this->assertTrue(array_key_exists('core/assets/vendor/jquery/jquery.js', $javascript), 'jQuery is added when inline scripts are added.');
     $data = end($javascript);
     $this->assertEqual($inline, $data['data'], 'Inline JavaScript is correctly added to the footer.');
@@ -227,9 +283,14 @@ function testAddInline() {
    * Tests rendering an external JavaScript file.
    */
   function testRenderExternal() {
-    drupal_add_library('system', 'drupal');
     $external = 'http://example.com/example.js';
-    _drupal_add_js($external, 'external');
+    $attached['#attached']['library'][] = array('system', 'drupal');
+    $attached['#attached']['js'][] = array(
+      'type' => 'external',
+      'data' => $external,
+    );
+    drupal_render($attached);
+
     $javascript = drupal_get_js();
     // Local files have a base_path() prefix, external files should not.
     $this->assertTrue(strpos($javascript, 'src="' . $external) > 0, 'Rendering an external JavaScript file.');
@@ -239,9 +300,16 @@ function testRenderExternal() {
    * Tests drupal_get_js() with a footer scope.
    */
   function testFooterHTML() {
-    drupal_add_library('system', 'drupal');
     $inline = 'jQuery(function () { });';
-    _drupal_add_js($inline, array('type' => 'inline', 'scope' => 'footer'));
+    $attached['#attached']['library'][] = array('system', 'drupal');
+    $attached['#attached']['js'][] = array(
+      'type' => 'inline',
+      'data' => $inline,
+      'scope' => 'footer',
+      'attributes' => array('defer' => 'defer'),
+    );
+    drupal_render($attached);
+
     $javascript = drupal_get_js('footer');
     $this->assertTrue(strpos($javascript, $inline) > 0, 'Rendered JavaScript footer returns the inline code.');
   }
@@ -250,8 +318,10 @@ function testFooterHTML() {
    * Tests _drupal_add_js() sets preproccess to FALSE when cache is also FALSE.
    */
   function testNoCache() {
-    drupal_add_library('system', 'drupal');
-    $javascript = _drupal_add_js('core/misc/collapse.js', array('cache' => FALSE));
+    $attached['#attached']['library'][] = array('system', 'drupal');
+    $attached['#attached']['js']['core/misc/collapse.js'] = array('cache' => FALSE);
+    drupal_render($attached);
+    $javascript = _drupal_add_js();
     $this->assertFalse($javascript['core/misc/collapse.js']['preprocess'], 'Setting cache to FALSE sets proprocess to FALSE when adding JavaScript.');
   }
 
@@ -259,8 +329,10 @@ function testNoCache() {
    * Tests adding a JavaScript file with a different group.
    */
   function testDifferentGroup() {
-    drupal_add_library('system', 'drupal');
-    $javascript = _drupal_add_js('core/misc/collapse.js', array('group' => JS_THEME));
+    $attached['#attached']['library'][] = array('system', 'drupal');
+    $attached['#attached']['js']['core/misc/collapse.js'] = array('group' => JS_THEME);
+    drupal_render($attached);
+    $javascript = _drupal_add_js();
     $this->assertEqual($javascript['core/misc/collapse.js']['group'], JS_THEME, 'Adding a JavaScript file with a different group caches the given group.');
   }
 
@@ -268,7 +340,9 @@ function testDifferentGroup() {
    * Tests adding a JavaScript file with a different weight.
    */
   function testDifferentWeight() {
-    $javascript = _drupal_add_js('core/misc/collapse.js', array('weight' => 2));
+    $attached['#attached']['js']['core/misc/collapse.js'] = array('weight' => 2);
+    drupal_render($attached);
+    $javascript = _drupal_add_js();
     $this->assertEqual($javascript['core/misc/collapse.js']['weight'], 2, 'Adding a JavaScript file with a different weight caches the given weight.');
   }
 
@@ -280,9 +354,16 @@ function testDifferentWeight() {
   function testBrowserConditionalComments() {
     $default_query_string = $this->container->get('state')->get('system.css_js_query_string') ?: '0';
 
-    drupal_add_library('system', 'drupal');
-    _drupal_add_js('core/misc/collapse.js', array('browsers' => array('IE' => 'lte IE 8', '!IE' => FALSE)));
-    _drupal_add_js('jQuery(function () { });', array('type' => 'inline', 'browsers' => array('IE' => FALSE)));
+    $attached['#attached']['library'][] = array('system', 'drupal');
+    $attached['#attached']['js']['core/misc/collapse.js'] = array(
+      'browsers' => array('IE' => 'lte IE 8', '!IE' => FALSE),
+    );
+    $attached['#attached']['js'][] = array(
+      'type' => 'inline',
+      'data' => 'jQuery(function () { });',
+      'browsers' => array('IE' => FALSE),
+    );
+    drupal_render($attached);
     $javascript = drupal_get_js();
 
     $expected_1 = "<!--[if lte IE 8]>\n" . '<script src="' . file_create_url('core/misc/collapse.js') . '?' . $default_query_string . '"></script>' . "\n<![endif]-->";
@@ -296,9 +377,10 @@ function testBrowserConditionalComments() {
    * Tests JavaScript versioning.
    */
   function testVersionQueryString() {
-    drupal_add_library('system', 'drupal');
-    _drupal_add_js('core/misc/collapse.js', array('version' => 'foo'));
-    _drupal_add_js('core/misc/ajax.js', array('version' => 'bar'));
+    $attached['#attached']['library'][] = array('system', 'drupal');
+    $attached['#attached']['js']['core/misc/collapse.js'] = array('version' => 'foo');
+    $attached['#attached']['js']['core/misc/ajax.js'] = array('version' => 'bar');
+    drupal_render($attached);
     $javascript = drupal_get_js();
     $this->assertTrue(strpos($javascript, 'core/misc/collapse.js?v=foo') > 0 && strpos($javascript, 'core/misc/ajax.js?v=bar') > 0 , 'JavaScript version identifiers correctly appended to URLs');
   }
@@ -313,11 +395,13 @@ function testAggregation() {
     // ahead of ones without. The order of JavaScript execution must be the
     // same regardless of whether aggregation is enabled, so ensure this
     // expected order, first with aggregation off.
-    drupal_add_library('system', 'drupal');
-    _drupal_add_js('core/misc/ajax.js');
-    _drupal_add_js('core/misc/collapse.js', array('every_page' => TRUE));
-    _drupal_add_js('core/misc/autocomplete.js');
-    _drupal_add_js('core/misc/batch.js', array('every_page' => TRUE));
+    $attached = array();
+    $attached['#attached']['library'][] = array('system', 'drupal');
+    $attached['#attached']['js']['core/misc/ajax.js'] = array();
+    $attached['#attached']['js']['core/misc/collapse.js'] = array('every_page' => TRUE);
+    $attached['#attached']['js']['core/misc/autocomplete.js'] = array();
+    $attached['#attached']['js']['core/misc/batch.js'] = array('every_page' => TRUE);
+    drupal_render($attached);
     $javascript = drupal_get_js();
     $expected = implode("\n", array(
       '<script src="' . file_create_url('core/misc/collapse.js') . '?' . $default_query_string . '"></script>',
@@ -333,11 +417,13 @@ function testAggregation() {
     $config = \Drupal::config('system.performance');
     $config->set('js.preprocess', 1);
     $config->save();
-    drupal_add_library('system', 'drupal');
-    _drupal_add_js('core/misc/ajax.js');
-    _drupal_add_js('core/misc/collapse.js', array('every_page' => TRUE));
-    _drupal_add_js('core/misc/autocomplete.js');
-    _drupal_add_js('core/misc/batch.js', array('every_page' => TRUE));
+    $attached = array();
+    $attached['#attached']['library'][] = array('system', 'drupal');
+    $attached['#attached']['js']['core/misc/ajax.js'] = array();
+    $attached['#attached']['js']['core/misc/collapse.js'] = array('every_page' => TRUE);
+    $attached['#attached']['js']['core/misc/autocomplete.js'] = array();
+    $attached['#attached']['js']['core/misc/batch.js'] = array('every_page' => TRUE);
+    drupal_render($attached);
     $js_items = _drupal_add_js();
     $javascript = drupal_get_js();
     $expected = implode("\n", array(
@@ -356,9 +442,11 @@ function testAggregationOrder() {
     drupal_static_reset('_drupal_add_js');
 
     // Add two JavaScript files to the current request and build the cache.
-    drupal_add_library('system', 'drupal');
-    _drupal_add_js('core/misc/ajax.js');
-    _drupal_add_js('core/misc/autocomplete.js');
+    $attached = array();
+    $attached['#attached']['library'][] = array('system', 'drupal');
+    $attached['#attached']['js']['core/misc/ajax.js'] = array();
+    $attached['#attached']['js']['core/misc/autocomplete.js'] = array();
+    drupal_render($attached);
 
     $js_items = _drupal_add_js();
     $scripts_html = array(
@@ -377,10 +465,12 @@ function testAggregationOrder() {
     // Reset variables and add a file in a different scope first.
     \Drupal::state()->delete('system.js_cache_files');
     drupal_static_reset('_drupal_add_js');
-    drupal_add_library('system', 'drupal');
-    _drupal_add_js('some/custom/javascript_file.js', array('scope' => 'footer'));
-    _drupal_add_js('core/misc/ajax.js');
-    _drupal_add_js('core/misc/autocomplete.js');
+    $attached = array();
+    $attached['#attached']['library'][] = array('system', 'drupal');
+    $attached['#attached']['js']['some/custom/javascript_file.js'] = array('scope' => 'footer');
+    $attached['#attached']['js']['core/misc/ajax.js'] = array();
+    $attached['#attached']['js']['core/misc/autocomplete.js'] = array();
+    drupal_render($attached);
 
     // Rebuild the cache.
     $js_items = _drupal_add_js();
@@ -403,17 +493,50 @@ function testAggregationOrder() {
    * Tests JavaScript ordering.
    */
   function testRenderOrder() {
+    $shared_options = array(
+      'type' => 'inline',
+      'scope' => 'footer',
+    );
     // Add a bunch of JavaScript in strange ordering.
-    _drupal_add_js('(function($){alert("Weight 5 #1");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => 5));
-    _drupal_add_js('(function($){alert("Weight 0 #1");})(jQuery);', array('type' => 'inline', 'scope' => 'footer'));
-    _drupal_add_js('(function($){alert("Weight 0 #2");})(jQuery);', array('type' => 'inline', 'scope' => 'footer'));
-    _drupal_add_js('(function($){alert("Weight -8 #1");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => -8));
-    _drupal_add_js('(function($){alert("Weight -8 #2");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => -8));
-    _drupal_add_js('(function($){alert("Weight -8 #3");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => -8));
-    _drupal_add_js('http://example.com/example.js?Weight -5 #1', array('type' => 'external', 'scope' => 'footer', 'weight' => -5));
-    _drupal_add_js('(function($){alert("Weight -8 #4");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => -8));
-    _drupal_add_js('(function($){alert("Weight 5 #2");})(jQuery);', array('type' => 'inline', 'scope' => 'footer', 'weight' => 5));
-    _drupal_add_js('(function($){alert("Weight 0 #3");})(jQuery);', array('type' => 'inline', 'scope' => 'footer'));
+    $attached['#attached']['js'][] = $shared_options + array(
+      'data' => '(function($){alert("Weight 5 #1");})(jQuery);',
+      'weight' => 5,
+    );
+    $attached['#attached']['js'][] = $shared_options + array(
+      'data' => '(function($){alert("Weight 0 #1");})(jQuery);',
+    );
+    $attached['#attached']['js'][] = $shared_options + array(
+      'data' => '(function($){alert("Weight 0 #2");})(jQuery);',
+    );
+    $attached['#attached']['js'][] = $shared_options + array(
+      'data' => '(function($){alert("Weight -8 #1");})(jQuery);',
+      'weight' => -8,
+    );
+    $attached['#attached']['js'][] = $shared_options + array(
+      'data' => '(function($){alert("Weight -8 #2");})(jQuery);',
+      'weight' => -8,
+    );
+    $attached['#attached']['js'][] = $shared_options + array(
+      'data' => '(function($){alert("Weight -8 #3");})(jQuery);',
+      'weight' => -8,
+    );
+    $attached['#attached']['js']['http://example.com/example.js?Weight -5 #1'] = array(
+      'type' => 'external',
+      'scope' => 'footer',
+      'weight' => -5,
+    );
+    $attached['#attached']['js'][] = $shared_options + array(
+      'data' => '(function($){alert("Weight -8 #4");})(jQuery);',
+      'weight' => -8,
+    );
+    $attached['#attached']['js'][] = $shared_options + array(
+      'data' => '(function($){alert("Weight 5 #2");})(jQuery);',
+      'weight' => 5,
+    );
+    $attached['#attached']['js'][] = $shared_options + array(
+      'data' => '(function($){alert("Weight 0 #3");})(jQuery);',
+    );
+    drupal_render($attached);
 
     // Construct the expected result from the regex.
     $expected = array(
@@ -448,8 +571,13 @@ function testRenderDifferentWeight() {
     // JavaScript files are sorted first by group, then by the 'every_page'
     // flag, then by weight (see drupal_sort_css_js()), so to test the effect of
     // weight, we need the other two options to be the same.
-    drupal_add_library('system', 'jquery');
-    _drupal_add_js('core/misc/collapse.js', array('group' => JS_LIBRARY, 'every_page' => TRUE, 'weight' => -21));
+    $attached['#attached']['library'][] = array('system', 'jquery');
+    $attached['#attached']['js']['core/misc/collapse.js'] = array(
+      'group' => JS_LIBRARY,
+      'every_page' => TRUE,
+      'weight' => -21,
+    );
+    drupal_render($attached);
     $javascript = drupal_get_js();
     $this->assertTrue(strpos($javascript, 'core/misc/collapse.js') < strpos($javascript, 'core/assets/vendor/jquery/jquery.js'), 'Rendering a JavaScript file above jQuery.');
   }
@@ -461,8 +589,9 @@ function testRenderDifferentWeight() {
    */
   function testAlter() {
     // Add both tableselect.js and simpletest.js, with a larger weight on SimpleTest.
-    _drupal_add_js('core/misc/tableselect.js');
-    _drupal_add_js(drupal_get_path('module', 'simpletest') . '/simpletest.js', array('weight' => 9999));
+    $attached['#attached']['js']['core/misc/tableselect.js'] = array();
+    $attached['#attached']['js'][drupal_get_path('module', 'simpletest') . '/simpletest.js'] = array('weight' => 9999);
+    drupal_render($attached);
 
     // Render the JavaScript, testing if simpletest.js was altered to be before
     // tableselect.js. See simpletest_js_alter() to see where this alteration
@@ -475,14 +604,17 @@ function testAlter() {
    * Adds a library to the page and tests for both its JavaScript and its CSS.
    */
   function testLibraryRender() {
-    $result = drupal_add_library('system', 'jquery.farbtastic');
-    $this->assertTrue($result !== FALSE, 'Library was added without errors.');
+    $attached = array();
+    $attached['#attached']['library'][] = array('system', 'jquery.farbtastic');
+    drupal_render($attached);
     $scripts = drupal_get_js();
     $styles = drupal_get_css();
     $this->assertTrue(strpos($scripts, 'core/assets/vendor/farbtastic/farbtastic.js'), 'JavaScript of library was added to the page.');
     $this->assertTrue(strpos($styles, 'core/assets/vendor/farbtastic/farbtastic.css'), 'Stylesheet of library was added to the page.');
 
-    drupal_add_library('common_test', 'shorthand.plugin');
+    $attached = array();
+    $attached['#attached']['library'][] = array('common_test', 'shorthand.plugin');
+    drupal_render($attached);
     $path = drupal_get_path('module', 'common_test') . '/js/shorthand.js?v=0.8.3.37';
     $scripts = drupal_get_js();
     $this->assertTrue(strpos($scripts, $path), 'JavaScript specified in hook_library_info() using shorthand format (without any options) was added to the page.');
@@ -500,7 +632,8 @@ function testLibraryAlter() {
     $this->assertEqual($library['title'], 'Farbtastic: Altered Library', 'Registered libraries were altered.');
 
     // common_test_library_info_alter() also added a dependency on jQuery Form.
-    drupal_add_library('system', 'jquery.farbtastic');
+    $attached['#attached']['library'][] = array('system', 'jquery.farbtastic');
+    drupal_render($attached);
     $scripts = drupal_get_js();
     $this->assertTrue(strpos($scripts, 'core/assets/vendor/jquery-form/jquery.form.js'), 'Altered library dependencies are added to the page.');
   }
@@ -523,8 +656,8 @@ function testLibraryUnknown() {
     $this->assertFalse($result, 'Unknown library returned FALSE.');
     drupal_static_reset('drupal_get_library');
 
-    $result = drupal_add_library('unknown', 'unknown');
-    $this->assertFalse($result, 'Unknown library returned FALSE.');
+    $attached['#attached']['library'][] = array('unknown', 'unknown');
+    drupal_render($attached);
     $scripts = drupal_get_js();
     $this->assertTrue(strpos($scripts, 'unknown') === FALSE, 'Unknown library was not added to the page.');
   }
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 3664623..8be41c4 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -311,7 +311,7 @@ function hook_js_alter(&$javascript) {
  *   An array defining libraries associated with a module.
  *
  * @see system_library_info()
- * @see drupal_add_library()
+ * @see _drupal_add_library()
  * @see drupal_get_library()
  */
 function hook_library_info() {
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index d85a30e..d3bd8f2 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -264,6 +264,10 @@ function system_hook_info() {
  */
 function system_element_info() {
   // Top level elements.
+  $types['html'] = array(
+    '#theme' => 'html',
+    '#pre_render' => array('drupal_pre_render_html'),
+  );
   $types['form'] = array(
     '#method' => 'post',
     '#action' => request_uri(),
@@ -596,6 +600,8 @@ function system_element_info() {
     '#input' => TRUE,
     '#tree' => TRUE,
     '#tableselect' => FALSE,
+    '#sticky' => FALSE,
+    '#responsive' => TRUE,
     '#multiple' => TRUE,
     '#js_select' => TRUE,
     '#value_callback' => 'form_type_table_value',
@@ -1509,6 +1515,7 @@ function system_library_info() {
     'version' => '3.6.2',
     'js' => array(
       'core/assets/vendor/html5shiv/html5.js' => array(
+        'every_page' => TRUE,
         'group' => JS_LIBRARY,
         'weight' => -22,
         'browsers' => array('IE' => 'lte IE 8', '!IE' => FALSE),
@@ -2454,8 +2461,8 @@ function system_user_timezone(&$form, &$form_state) {
   );
   if (!$account->getTimezone() && $account->id() == $user->id() && empty($form_state['input']['timezone'])) {
     $form['timezone']['#description'] = t('Your time zone setting will be automatically detected if possible. Confirm the selection and click save.');
+    $form['timezone']['#attached']['library'][] = array('system', 'drupal.timezone');
     $form['timezone']['timezone']['#attributes'] = array('class' => array('timezone-detect'));
-    drupal_add_library('system', 'drupal.timezone');
   }
 }
 
diff --git a/core/modules/views/lib/Drupal/views/Controller/ViewAjaxController.php b/core/modules/views/lib/Drupal/views/Controller/ViewAjaxController.php
index 307d63f..725a031 100644
--- a/core/modules/views/lib/Drupal/views/Controller/ViewAjaxController.php
+++ b/core/modules/views/lib/Drupal/views/Controller/ViewAjaxController.php
@@ -131,7 +131,7 @@ public function ajaxView(Request $request) {
         $view->dom_id = $dom_id;
 
         $preview = $view->preview($display_id, $args);
-        $response->addCommand(new ReplaceCommand(".view-dom-id-$dom_id", drupal_render($preview)));
+        $response->addCommand(new ReplaceCommand(".view-dom-id-$dom_id", $this->drupalRender($preview)));
         return $response;
       }
       else {
@@ -143,4 +143,20 @@ public function ajaxView(Request $request) {
     }
   }
 
+  /**
+   * Wraps drupal_render.
+   *
+   * @param array $elements
+   *   The structured array describing the data to be rendered.
+   *
+   * @return string
+   *   The rendered HTML.
+   *
+   * @todo Remove once drupal_render is converted to autoloadable code.
+   * @see https://drupal.org/node/2171071
+   */
+  protected function drupalRender(array $elements) {
+    return drupal_render($elements);
+  }
+
 }
diff --git a/core/modules/views/tests/Drupal/views/Tests/Controller/ViewAjaxControllerTest.php b/core/modules/views/tests/Drupal/views/Tests/Controller/ViewAjaxControllerTest.php
index 8cc5d10..da1245b 100644
--- a/core/modules/views/tests/Drupal/views/Tests/Controller/ViewAjaxControllerTest.php
+++ b/core/modules/views/tests/Drupal/views/Tests/Controller/ViewAjaxControllerTest.php
@@ -58,7 +58,7 @@ protected function setUp() {
       ->disableOriginalConstructor()
       ->getMock();
 
-    $this->viewAjaxController = new ViewAjaxController($this->viewStorage, $this->executableFactory);
+    $this->viewAjaxController = new TestViewAjaxController($this->viewStorage, $this->executableFactory);
   }
 
   /**
@@ -280,6 +280,18 @@ protected function assertViewResultCommand(ViewAjaxResponse $response, $position
 
 }
 
+/**
+ * Overrides ViewAjaxController::drupalRender to protect the parent method.
+ */
+class TestViewAjaxController extends ViewAjaxController {
+
+  // @todo Remove once drupal_render is converted to autoloadable code.
+  protected function drupalRender(array $elements) {
+    return isset($elements['#markup']) ? $elements['#markup'] : '';
+  }
+
+}
+
 }
 
 namespace {
@@ -290,11 +302,4 @@ function &drupal_static($key) {
     }
   }
 
-  // @todo Remove once drupal_render is converted to autoloadable code.
-  if (!function_exists('drupal_render')) {
-    function drupal_render($array) {
-      return isset($array['#markup']) ? $array['#markup'] : '';
-    }
-  }
-
 }
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 6cb91a6..a7bda5a 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -377,7 +377,8 @@ function views_preprocess_page(&$variables) {
       unset($class[$key]);
       $attributes['class'] = $class;
       $attributes['data-views-page-contextual-id'] = $variables['title_suffix']['contextual_links']['#id'];
-      drupal_add_library('views', 'views.contextual-links');
+      $attached['#attached']['library'][] = array('views', 'views.contextual-links');
+      drupal_render($attached);
     }
   }
 }
diff --git a/core/tests/Drupal/Tests/Core/Ajax/AjaxCommandsTest.php b/core/tests/Drupal/Tests/Core/Ajax/AjaxCommandsTest.php
index 188c042..adff37a 100644
--- a/core/tests/Drupal/Tests/Core/Ajax/AjaxCommandsTest.php
+++ b/core/tests/Drupal/Tests/Core/Ajax/AjaxCommandsTest.php
@@ -5,7 +5,7 @@
  * Contains \Drupal\Tests\Core\Ajax\AjaxCommandsTest.
  */
 
-namespace Drupal\Tests\Core\Ajax {
+namespace Drupal\Tests\Core\Ajax;
 
 use Drupal\Tests\UnitTestCase;
 use Drupal\Core\Ajax\AddCssCommand;
@@ -308,7 +308,7 @@ public function testSettingsCommand() {
    * Tests that OpenDialogCommand objects can be constructed and rendered.
    */
   public function testOpenDialogCommand() {
-    $command = new OpenDialogCommand('#some-dialog', 'Title', '<p>Text!</p>', array(
+    $command = new TestOpenDialogCommand('#some-dialog', 'Title', '<p>Text!</p>', array(
       'url' => FALSE,
       'width' => 500,
     ));
@@ -332,7 +332,7 @@ public function testOpenDialogCommand() {
    * Tests that OpenModalDialogCommand objects can be constructed and rendered.
    */
   public function testOpenModalDialogCommand() {
-    $command = new OpenModalDialogCommand('Title', '<p>Text!</p>', array(
+    $command = new TestOpenModalDialogCommand('Title', '<p>Text!</p>', array(
       'url' => 'example',
       'width' => 500,
     ));
@@ -425,12 +425,26 @@ public function testRedirectCommand() {
 
 }
 
+/**
+ * Wraps OpenModalDialogCommand::drupalAttachLibrary().
+ *
+ * {@inheritdoc}
+ */
+class TestOpenModalDialogCommand extends OpenModalDialogCommand {
+
+  protected function drupalAttachLibrary($module, $name) {
+  }
+
 }
 
-namespace {
-  if (!function_exists('drupal_add_library')) {
-    function drupal_add_library() {
-      return TRUE;
-    }
+/**
+ * Wraps OpenDialogCommand::drupalAttachLibrary().
+ *
+ * {@inheritdoc}
+ */
+class TestOpenDialogCommand extends OpenDialogCommand {
+
+  protected function drupalAttachLibrary($module, $name) {
   }
+
 }
