diff --git a/core/includes/ajax.inc b/core/includes/ajax.inc
index 7ab2059..9d482cc 100644
--- a/core/includes/ajax.inc
+++ b/core/includes/ajax.inc
@@ -387,7 +387,7 @@ function ajax_pre_render_element($element) {
       // uniquely, in which case a match on value is also needed.
       // @see _form_button_was_clicked()
       if (!empty($element['#is_button']) && empty($element['#has_garbage_value'])) {
-        $settings['submit']['_triggering_element_value'] = $element['#value'];
+        $settings['submit']['_triggering_element_value'] = (string) $element['#value'];
       }
     }
 
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 3d41fcb..592cda2 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -16,6 +16,7 @@
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Utility\Title;
 use Drupal\Core\Utility\Error;
 use Symfony\Component\ClassLoader\ApcClassLoader;
@@ -1180,6 +1181,9 @@ function watchdog($type, $message, array $variables = array(), $severity = WATCH
  */
 function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE) {
   if ($message) {
+    if ($message instanceof SafeMarkup) {
+      $message = chr(0) . $message;
+    }
     if (!isset($_SESSION['messages'][$type])) {
       $_SESSION['messages'][$type] = array();
     }
@@ -1223,6 +1227,13 @@ function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE)
  */
 function drupal_get_messages($type = NULL, $clear_queue = TRUE) {
   if ($messages = drupal_set_message()) {
+    foreach ($messages as $message_type => $messages_typed) {
+      foreach ($messages_typed as $key => $message) {
+        if (!$message instanceof SafeMarkup && $message[0] == chr(0)) {
+          $messages[$message_type][$key] = SafeMarkup::create(substr($message, 1));
+        }
+      }
+    }
     if ($type) {
       if ($clear_queue) {
         unset($_SESSION['messages'][$type]);
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 5572e54..bb4d6a7 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -29,6 +29,7 @@
 use Drupal\Core\EventSubscriber\HtmlViewSubscriber;
 use Drupal\Core\Routing\GeneratorNotInitializedException;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Session\AnonymousUserSession;
 
@@ -886,8 +887,7 @@ function l($text, $path, array $options = array()) {
 
   // Sanitize the link text if necessary.
   $text = $variables['options']['html'] ? $variables['text'] : String::checkPlain($variables['text']);
-
-  return '<a href="' . $url . '"' . $attributes . '>' . $text . '</a>';
+  return SafeMarkup::create('<a href="' . $url . '"' . $attributes . '>' . $text . '</a>');
 }
 
 /**
@@ -1440,6 +1440,9 @@ function drupal_html_class($class) {
   // static instead of drupal_static().
   static $classes = array();
 
+  // @todo Needs safe markup preservation or should be cast to string before
+  // arg is passed to this function?
+  $class = (string) $class;
   if (!isset($classes[$class])) {
     $classes[$class] = drupal_clean_css_identifier(drupal_strtolower($class));
   }
@@ -2829,6 +2832,7 @@ function drupal_pre_render_conditional_comments($elements) {
  *     - meta: To provide meta information, such as a page refresh.
  *     - link: To refer to stylesheets and other contextual information.
  *     - script: To load JavaScript.
+ *     This is not HTML escaped, do not pass in user input.
  *   - #attributes: (optional) An array of HTML attributes to apply to the
  *     tag.
  *   - #value: (optional) A string containing tag content, such as inline
@@ -2841,7 +2845,9 @@ function drupal_pre_render_conditional_comments($elements) {
 function drupal_pre_render_html_tag($element) {
   $attributes = isset($element['#attributes']) ? new Attribute($element['#attributes']) : '';
   if (!isset($element['#value'])) {
-    $markup = '<' . $element['#tag'] . $attributes . " />\n";
+    // Attributes are safe and we are assuming people don't use this function
+    // and second they don't pass unsafe variables to #tag.
+    $markup = SafeMarkup::create('<' . $element['#tag'] . $attributes . " />\n");
   }
   else {
     $markup = '<' . $element['#tag'] . $attributes . '>';
@@ -2853,6 +2859,8 @@ function drupal_pre_render_html_tag($element) {
       $markup .= $element['#value_suffix'];
     }
     $markup .= '</' . $element['#tag'] . ">\n";
+    // @TODO Creating safe markup, avoid if possible!
+    $markup = SafeMarkup::create($markup);
   }
   if (!empty($element['#noscript'])) {
     $element['#markup'] = '<noscript>' . $markup . '</noscript>';
@@ -3261,7 +3269,7 @@ function drupal_render_page($page) {
  * @param bool $is_recursive_call
  *   Whether this is a recursive call or not, for internal use.
  *
- * @return string
+ * @return \Drupal\Core\Template\SafeMarkup|string
  *   The rendered HTML.
  *
  * @see element_info()
@@ -3286,6 +3294,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
     $cached_element = drupal_render_cache_get($elements);
     if ($cached_element !== FALSE) {
       $elements = $cached_element;
+      $elements['#markup'] = SafeMarkup::create($elements['#markup']);
       // Only when we're not in a recursive drupal_render() call,
       // #post_render_cache callbacks must be executed, to prevent breaking the
       // render cache in case of nested elements with #cache set.
@@ -3336,6 +3345,33 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
     $elements['#children'] = '';
   }
 
+  // Assume still safe unless the element or it's __toString return value aren't
+  // instances of Twig_Markup.
+  $get_string = function ($element)  {
+    if (is_object($element) && method_exists($element, '__toString')) {
+      $markup = $element->__toString();
+    }
+    else {
+      $markup = $element;
+    }
+    // This is necessary because $element can be a RenderWrapper.
+    if ($markup && !$element instanceof SafeMarkup && !$markup instanceof SafeMarkup) {
+      $markup = String::checkPlain($markup);
+    }
+    return $markup;
+  };
+
+  // @TODO: remove wrapping of #markup.
+  if (isset($elements['#markup'])) {
+    if (is_object($elements['#markup']) && method_exists($elements['#markup'], '__toString')) {
+      $markup = $elements['#markup']->__toString();
+    }
+    else {
+      $markup = $elements['#markup'];
+    }
+    $elements['#markup'] = SafeMarkup::create($markup);
+  }
+
   // Assume that if #theme is set it represents an implemented hook.
   $theme_is_implemented = isset($elements['#theme']);
 
@@ -3357,8 +3393,9 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
   // process as drupal_render_children() but is inlined for speed.
   if ((!$theme_is_implemented || isset($elements['#render_children'])) && empty($elements['#children'])) {
     foreach ($children as $key) {
-      $elements['#children'] .= drupal_render($elements[$key], TRUE);
+      $elements['#children'] .= $get_string(drupal_render($elements[$key], TRUE));
     }
+    $elements['#children'] = SafeMarkup::create($elements['#children']);
   }
 
   // If #theme is not implemented and the element has raw #markup as a
@@ -3369,7 +3406,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
   // required. Eventually #theme_wrappers will expect both #markup and
   // #children to be a single string as #children.
   if (!$theme_is_implemented && isset($elements['#markup'])) {
-    $elements['#children'] = $elements['#markup'] . $elements['#children'];
+    $elements['#children'] = SafeMarkup::create($get_string($elements['#markup']) . $get_string($elements['#children']));
   }
 
   // Let the theme functions in #theme_wrappers add markup around the rendered
@@ -3453,6 +3490,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
   }
 
   $elements['#printed'] = TRUE;
+  $elements['#markup'] = SafeMarkup::create($elements['#markup']);
   return $elements['#markup'];
 }
 
@@ -3466,7 +3504,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
  *   can be passed in to save another run of
  *   \Drupal\Core\Render\Element::children().
  *
- * @return string
+ * @return \Drupal\Core\Template\SafeMarkup|string
  *   The rendered HTML of all children of the element.
 
  * @see drupal_render()
@@ -3475,13 +3513,13 @@ function drupal_render_children(&$element, $children_keys = NULL) {
   if ($children_keys === NULL) {
     $children_keys = Element::children($element);
   }
-  $output = '';
+  $markups = array();
   foreach ($children_keys as $key) {
     if (!empty($element[$key])) {
-      $output .= drupal_render($element[$key]);
+      $markups[] = drupal_render($element[$key]);
     }
   }
-  return $output;
+  return SafeMarkup::implode('', $markups);
 }
 
 /**
diff --git a/core/includes/form.inc b/core/includes/form.inc
index 42206a4..50367e0 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -15,6 +15,7 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Utility\Color;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
@@ -983,7 +984,7 @@ function form_select_options($element, $choices = NULL) {
       $options .= form_select_options($element, $choice);
       $options .= '</optgroup>';
     }
-    elseif (is_object($choice)) {
+    elseif (is_object($choice) && isset($choice->option)) {
       $options .= form_select_options($element, $choice->option);
     }
     else {
@@ -998,7 +999,7 @@ function form_select_options($element, $choices = NULL) {
       $options .= '<option value="' . String::checkPlain($key) . '"' . $selected . '>' . String::checkPlain($choice) . '</option>';
     }
   }
-  return $options;
+  return SafeMarkup::create($options);
 }
 
 /**
@@ -1659,7 +1660,7 @@ function theme_tableselect($variables) {
       foreach ($element['#header'] as $fieldname => $title) {
         // A row cell can span over multiple headers, which means less row cells
         // than headers could be present.
-        if (isset($element['#options'][$key][$fieldname])) {
+        if (isset($element['#options'][$key][$fieldname]) && is_array($element['#options'][$key][$fieldname])) {
           // A header can span over multiple cells and in this case the cells
           // are passed in an array. The order of this array determines the
           // order in which they are added.
@@ -1976,7 +1977,7 @@ function form_process_machine_name($element, &$form_state) {
   $element['#machine_name'] += array(
     'source' => array('label'),
     'target' => '#' . $element['#id'],
-    'label' => t('Machine name'),
+    'label' => (string) t('Machine name'),
     'replace_pattern' => '[^a-z0-9_]+',
     'replace' => '_',
     'standalone' => FALSE,
@@ -2009,13 +2010,13 @@ function form_process_machine_name($element, &$form_state) {
   $element['#machine_name']['suffix'] = '#' . $suffix_id;
 
   if ($element['#machine_name']['standalone']) {
-    $element['#suffix'] .= ' <small id="' . $suffix_id . '">&nbsp;</small>';
+    $element['#suffix'] = SafeMarkup::concat($element['#suffix'], SafeMarkup::create(' <small id="' . $suffix_id . '">&nbsp;</small>'));
   }
   else {
     // Append a field suffix to the source form element, which will contain
     // the live preview of the machine name.
     $source += array('#field_suffix' => '');
-    $source['#field_suffix'] .= ' <small id="' . $suffix_id . '">&nbsp;</small>';
+    $source['#field_suffix'] = SafeMarkup::concat($source['#field_suffix'], SafeMarkup::create(' <small id="' . $suffix_id . '">&nbsp;</small>'));
 
     $parents = array_merge($element['#machine_name']['source'], array('#field_suffix'));
     NestedArray::setValue($form_state['complete_form'], $parents, $source['#field_suffix']);
@@ -2348,6 +2349,9 @@ function template_preprocess_input(&$variables) {
 function theme_input($variables) {
   $element = $variables['element'];
   $attributes = $variables['attributes'];
+  if (!$attributes instanceof Attribute) {
+    throw new \LogicException('Attributes are expected to be an instance of attributes');
+  }
   return '<input' . $attributes . ' />' . drupal_render_children($element);
 }
 
@@ -2976,8 +2980,6 @@ function theme_form_element_label($variables) {
     return '';
   }
 
-  $title = Xss::filterAdmin($element['#title']);
-
   $attributes = array();
   // Style the label as class option to display inline with the element.
   if ($element['#title_display'] == 'after') {
@@ -3008,6 +3010,8 @@ function theme_form_element_label($variables) {
     $attributes['class'][] = 'form-required';
   }
 
+  $title = Xss::filterAdmin($element['#title']);
+
   return '<label' . new Attribute($attributes) . '>' . $title . '</label>';
 }
 
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index b00d23b..1a4e38f 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -14,6 +14,7 @@
 use Drupal\Core\Page\DefaultHtmlPageRenderer;
 use Drupal\Core\Site\Settings;
 use Drupal\Core\StringTranslation\Translator\FileTranslation;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\Reference;
@@ -1707,11 +1708,11 @@ function install_finished(&$install_state) {
 
   // @todo Temporary hack to satisfy PIFR.
   // @see https://drupal.org/node/1317548
-  $pifr_assertion = '<span style="display: none;">Drupal installation complete</span>';
+  $pifr_assertion = SafeMarkup::create('<span style="display: none;">Drupal installation complete</span>');
 
-  drupal_set_message(t('Congratulations, you installed @drupal!', array(
+  drupal_set_message(SafeMarkup::concat(t('Congratulations, you installed @drupal!', array(
     '@drupal' => drupal_install_profile_distribution_name(),
-  )) . $pifr_assertion);
+  )) , $pifr_assertion));
 }
 
 /**
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 2b06429..f577e3f 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -21,6 +21,7 @@
 use Drupal\Core\Page\MetaElement;
 use Drupal\Core\Template\Attribute;
 use Drupal\Core\Template\RenderWrapper;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Theme\ThemeSettings;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Render\Element;
@@ -579,7 +580,7 @@ function _theme($hook, $variables = array()) {
   $output = '';
   if (isset($info['function'])) {
     if (function_exists($info['function'])) {
-      $output = $info['function']($variables);
+      $output = SafeMarkup::create($info['function']($variables));
     }
   }
   else {
@@ -650,7 +651,7 @@ function _theme($hook, $variables = array()) {
 
   // restore path_to_theme()
   $theme_path = $temp;
-  return (string) $output;
+  return $output;
 }
 
 /**
@@ -1712,7 +1713,9 @@ function theme_mark($variables) {
  * @see http://drupal.org/node/1842756
  */
 function template_preprocess_item_list(&$variables) {
-  $variables['title'] = (string) $variables['title'];
+  if (!$variables['title'] instanceof SafeMarkup) {
+    $variables['title'] = (string) $variables['title'];
+  }
 
   foreach ($variables['items'] as &$item) {
     $attributes = array();
@@ -2053,7 +2056,10 @@ function template_preprocess_html(&$variables) {
 
   // Wrap function calls in an object so they can be called when printed.
   $variables['head'] = new RenderWrapper(function() use ($page) {
-    return implode("\n", $page->getMetaElements()) . implode("\n", $page->getLinkElements());
+    // HeadElement itself is safe and MetaElement and LinkElement both extend
+    // it so each element are safe. The result of concatenating a lot of them
+    // together is also safe.
+    return SafeMarkup::create(implode("\n", $page->getMetaElements()) . implode("\n", $page->getLinkElements()));
   });
   $variables['styles'] = new RenderWrapper('drupal_get_css');
   $variables['scripts'] = new RenderWrapper('drupal_get_js');
diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc
index 8a19a49..09957df 100644
--- a/core/includes/theme.maintenance.inc
+++ b/core/includes/theme.maintenance.inc
@@ -7,6 +7,7 @@
 
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Sets up the theming system for maintenance page.
@@ -110,6 +111,8 @@ function _drupal_maintenance_theme() {
  * @param $variables
  *   An associative array containing:
  *   - items: An associative array of maintenance tasks.
+ *     It's the caller's responsibility to ensure this array's items contains no
+ *     XSS holes.
  *   - active: The key for the currently active maintenance task.
  *
  * @ingroup themeable
@@ -178,6 +181,7 @@ function theme_authorize_report($variables) {
     }
     $output .= '</div>';
   }
+
   return $output;
 }
 
@@ -187,6 +191,8 @@ function theme_authorize_report($variables) {
  * @param $variables
  *   An associative array containing:
  *   - message: The log message.
+ *     It's the caller's responsibility to ensure this string contains no
+ *     XSS holes.
  *   - success: A boolean indicating failure or success.
  *
  * @ingroup themeable
diff --git a/core/lib/Drupal/Component/Utility/String.php b/core/lib/Drupal/Component/Utility/String.php
index 9796a5f..109f691 100644
--- a/core/lib/Drupal/Component/Utility/String.php
+++ b/core/lib/Drupal/Component/Utility/String.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Component\Utility;
 
+use Drupal\Core\Template\SafeMarkup;
+
 /**
  * Provides helpers to operate on strings.
  *
@@ -22,16 +24,16 @@ class String {
    * @param string $text
    *   The text to be checked or processed.
    *
-   * @return string
-   *   An HTML safe version of $text, or an empty string if $text is not
-   *   valid UTF-8.
+   * @return \Drupal\Core\Template\SafeMarkup|string
+   *   A SafeMarkup object containing the HTML safe version of $text, or an
+   *   empty string if $text is an empty string or not valid UTF-8.
    *
    * @ingroup sanitization
    *
    * @see drupal_validate_utf8()
    */
   public static function checkPlain($text) {
-    return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
+    return SafeMarkup::create(htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8'));
   }
 
   /**
@@ -65,7 +67,8 @@ public static function decodeEntities($text) {
    * addition to formatting it.
    *
    * @param $string
-   *   A string containing placeholders.
+   *   A string containing placeholders. The string itself is not escaped, any
+   *   unsafe content must be in $args and inserted via placeholders.
    * @param $args
    *   An associative array of replacements to make. Occurrences in $string of
    *   any key in $args are replaced with the corresponding value, after
@@ -108,7 +111,7 @@ public static function format($string, array $args = array()) {
           // Pass-through.
       }
     }
-    return strtr($string, $args);
+    return SafeMarkup::create(strtr($string, $args));
   }
 
   /**
@@ -123,7 +126,8 @@ public static function format($string, array $args = array()) {
    *   The formatted text (html).
    */
   public static function placeholder($text) {
-    return '<em class="placeholder">' . static::checkPlain($text) . '</em>';
+    return SafeMarkup::create('<em class="placeholder">' . static::checkPlain($text) . '</em>');
   }
 
+
 }
diff --git a/core/lib/Drupal/Component/Utility/Xss.php b/core/lib/Drupal/Component/Utility/Xss.php
index dc49913..af67803 100644
--- a/core/lib/Drupal/Component/Utility/Xss.php
+++ b/core/lib/Drupal/Component/Utility/Xss.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Component\Utility;
 
+use Drupal\Core\Template\SafeMarkup;
+
 /**
  * Provides helper to filter for cross-site scripting.
  *
@@ -90,7 +92,7 @@ public static function filter($string, $html_tags = array('a', 'em', 'strong', '
     $splitter = function ($matches) use ($html_tags, $mode) {
       return static::split($matches[1], $html_tags, $mode);
     };
-    return preg_replace_callback('%
+    return SafeMarkup::create(preg_replace_callback('%
       (
       <(?=[^a-zA-Z!/])  # a lone <
       |                 # or
@@ -99,7 +101,7 @@ public static function filter($string, $html_tags = array('a', 'em', 'strong', '
       <[^>]*(>|$)       # a string that starts with a <, up until the > or the end of the string
       |                 # or
       >                 # just a >
-      )%x', $splitter, $string);
+      )%x', $splitter, $string));
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Ajax/AjaxResponseRenderer.php b/core/lib/Drupal/Core/Ajax/AjaxResponseRenderer.php
index eac0b62..b2f87df 100644
--- a/core/lib/Drupal/Core/Ajax/AjaxResponseRenderer.php
+++ b/core/lib/Drupal/Core/Ajax/AjaxResponseRenderer.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Ajax;
 
 use Drupal\Core\Page\HtmlFragment;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\HttpFoundation\Response;
 
 /**
@@ -36,9 +37,9 @@ public function render($content) {
       $content = $content->getContent();
     }
     // Most controllers return a render array, but some return a string.
-    if (!is_array($content)) {
+    if (is_string($content) || $content instanceof SafeMarkup) {
       $content = array(
-        '#markup' => $content,
+        '#markup' => (string) $content,
       );
     }
 
@@ -74,11 +75,9 @@ public function render($content) {
 
   /**
    * Wraps drupal_render().
-   *
-   * @todo: Remove as part of https://drupal.org/node/2182149
    */
   protected function drupalRender(&$elements, $is_recursive_call = FALSE) {
-    return drupal_render($elements, $is_recursive_call);
+    return (string) drupal_render($elements, $is_recursive_call);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Ajax/InsertCommand.php b/core/lib/Drupal/Core/Ajax/InsertCommand.php
index 9871ef2..e46eac0 100644
--- a/core/lib/Drupal/Core/Ajax/InsertCommand.php
+++ b/core/lib/Drupal/Core/Ajax/InsertCommand.php
@@ -57,7 +57,7 @@ class InsertCommand implements CommandInterface {
    */
   public function __construct($selector, $html, array $settings = NULL) {
     $this->selector = $selector;
-    $this->html = $html;
+    $this->html = (string) $html;
     $this->settings = $settings;
   }
 
diff --git a/core/lib/Drupal/Core/Config/StorableConfigBase.php b/core/lib/Drupal/Core/Config/StorableConfigBase.php
index 4a5fd1d..3f5fa38 100644
--- a/core/lib/Drupal/Core/Config/StorableConfigBase.php
+++ b/core/lib/Drupal/Core/Config/StorableConfigBase.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Config\Schema\Ignore;
 use Drupal\Core\Config\Schema\SchemaIncompleteException;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\TypedData\PrimitiveInterface;
 use Drupal\Core\TypedData\Type\FloatInterface;
 use Drupal\Core\TypedData\Type\IntegerInterface;
@@ -140,6 +141,9 @@ protected function getSchemaWrapper() {
    *   If there is any invalid value.
    */
   protected function validateValue($key, $value) {
+    if ($value instanceof SafeMarkup) {
+      $value = (string) $value;
+    }
     // Minimal validation. Should not try to serialize resources or non-arrays.
     if (is_array($value)) {
       foreach ($value as $nested_value_key => $nested_value) {
@@ -169,6 +173,10 @@ protected function validateValue($key, $value) {
    *   Exception on unsupported/undefined data type deducted.
    */
   protected function castValue($key, $value) {
+    if ($value instanceof SafeMarkup) {
+      $value = (string) $value;
+    }
+
     $element = FALSE;
     try {
       $element = $this->getSchemaWrapper()->get($key);
diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php
index fe23fb6..99784f7 100644
--- a/core/lib/Drupal/Core/CoreServiceProvider.php
+++ b/core/lib/Drupal/Core/CoreServiceProvider.php
@@ -101,7 +101,7 @@ public static function registerTwig(ContainerBuilder $container) {
         'cache' => drupal_installation_attempted() ? FALSE : Settings::get('twig_cache', TRUE),
         // @todo Remove in followup issue
         // @see http://drupal.org/node/1712444.
-        'autoescape' => FALSE,
+        'autoescape' => TRUE,
         'debug' => Settings::get('twig_debug', FALSE),
         'auto_reload' => Settings::get('twig_auto_reload', NULL),
       ))
diff --git a/core/lib/Drupal/Core/Database/Install/Tasks.php b/core/lib/Drupal/Core/Database/Install/Tasks.php
index c4d88d2..6d0dfe7 100644
--- a/core/lib/Drupal/Core/Database/Install/Tasks.php
+++ b/core/lib/Drupal/Core/Database/Install/Tasks.php
@@ -92,14 +92,14 @@ protected function hasPdoDriver() {
    * Assert test as failed.
    */
   protected function fail($message) {
-    $this->results[$message] = FALSE;
+    $this->results[(string) $message] = FALSE;
   }
 
   /**
    * Assert test as a pass.
    */
   protected function pass($message) {
-    $this->results[$message] = TRUE;
+    $this->results[(string) $message] = TRUE;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 93e9fcf..34fd1fd 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -703,7 +703,7 @@ public function getEntityTypeLabels($group = FALSE) {
 
     foreach ($definitions as $entity_type_id => $definition) {
       if ($group) {
-        $options[$definition->getGroupLabel()][$entity_type_id] = $definition->getLabel();
+        $options[(string) $definition->getGroupLabel()][$entity_type_id] = $definition->getLabel();
       }
       else {
         $options[$entity_type_id] = $definition->getLabel();
@@ -717,7 +717,7 @@ public function getEntityTypeLabels($group = FALSE) {
       }
 
       // Make sure that the 'Content' group is situated at the top.
-      $content = $this->t('Content', array(), array('context' => 'Entity type group'));
+      $content = (string) $this->t('Content', array(), array('context' => 'Entity type group'));
       $options = array($content => $options[$content]) + $options;
     }
 
diff --git a/core/lib/Drupal/Core/Extension/ThemeHandler.php b/core/lib/Drupal/Core/Extension/ThemeHandler.php
index dbe2c78..8354bea 100644
--- a/core/lib/Drupal/Core/Extension/ThemeHandler.php
+++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php
@@ -626,6 +626,8 @@ public function getName($theme) {
     if (!isset($themes[$theme])) {
       throw new \InvalidArgumentException(String::format('Requested the name of a non-existing theme @theme', array('@theme' => $theme)));
     }
+    // @todo For testing please remove before commit.
+    return \Drupal::config('system.site')->get('name');
     return String::checkPlain($themes[$theme]->info['name']);
   }
 
diff --git a/core/lib/Drupal/Core/Form/OptGroup.php b/core/lib/Drupal/Core/Form/OptGroup.php
index f94d62d..21e9855 100644
--- a/core/lib/Drupal/Core/Form/OptGroup.php
+++ b/core/lib/Drupal/Core/Form/OptGroup.php
@@ -43,7 +43,7 @@ public static function flattenOptions(array $array) {
    */
   protected static function doFlattenOptions(array $array, array &$options) {
     foreach ($array as $key => $value) {
-      if (is_object($value)) {
+      if (is_object($value) && isset($value->option)) {
         static::doFlattenOptions($value->option, $options);
       }
       elseif (is_array($value)) {
diff --git a/core/lib/Drupal/Core/Page/HeadElement.php b/core/lib/Drupal/Core/Page/HeadElement.php
index 85055ad..70cf2b7 100644
--- a/core/lib/Drupal/Core/Page/HeadElement.php
+++ b/core/lib/Drupal/Core/Page/HeadElement.php
@@ -8,11 +8,12 @@
 namespace Drupal\Core\Page;
 
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * This class represents an HTML element that appears in the HEAD tag.
  */
-class HeadElement {
+class HeadElement extends SafeMarkup {
 
   /**
    * An array of attributes for this element.
diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
index bd1b3b3..20e1911 100644
--- a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
+++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\StringTranslation\Translator\TranslatorInterface;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Defines a chained translation implementation combining multiple translators.
@@ -140,7 +141,7 @@ public function translate($string, array $args = array(), array $options = array
     $string = $translation === FALSE ? $string : $translation;
 
     if (empty($args)) {
-      return $string;
+      return SafeMarkup::create($string);
     }
     else {
       return String::format($string, $args);
@@ -160,7 +161,7 @@ public function formatPlural($count, $singular, $plural, array $args = array(),
     $translated_array = explode(LOCALE_PLURAL_DELIMITER, $translated_strings);
 
     if ($count == 1) {
-      return $translated_array[0];
+      return SafeMarkup::create($translated_array[0]);
     }
 
     // Get the plural index through the gettext formula.
@@ -168,20 +169,21 @@ public function formatPlural($count, $singular, $plural, array $args = array(),
     $index = (function_exists('locale_get_plural')) ? locale_get_plural($count, isset($options['langcode']) ? $options['langcode'] : NULL) : -1;
     if ($index == 0) {
       // Singular form.
-      return $translated_array[0];
+      $return = $translated_array[0];
     }
     else {
       if (isset($translated_array[$index])) {
         // N-th plural form.
-        return $translated_array[$index];
+        $return = $translated_array[$index];
       }
       else {
         // If the index cannot be computed or there's no translation, use
         // the second plural form as a fallback (which allows for most flexiblity
         // with the replaceable @count value).
-        return $translated_array[1];
+        $return = $translated_array[1];
       }
     }
+    return SafeMarkup::create($return);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Template/Attribute.php b/core/lib/Drupal/Core/Template/Attribute.php
index ead5d05..7432b6d 100644
--- a/core/lib/Drupal/Core/Template/Attribute.php
+++ b/core/lib/Drupal/Core/Template/Attribute.php
@@ -31,7 +31,7 @@
  *  // Produces <cat class="cat black-cat white-cat black-white-cat" id="socks">
  * @endcode
  */
-class Attribute implements \ArrayAccess, \IteratorAggregate {
+class Attribute extends \Twig_Markup implements \ArrayAccess, \IteratorAggregate {
 
   /**
    * Stores the attribute data.
@@ -86,9 +86,12 @@ protected function createAttributeValue($name, $value) {
     elseif (is_bool($value)) {
       $value = new AttributeBoolean($name, $value);
     }
-    elseif (!is_object($value)) {
+    elseif (!is_object($value) || $value instanceof SafeMarkup) {
       $value = new AttributeString($name, $value);
     }
+    elseif (!method_exists($value, 'render')) {
+      throw new \Exception('boo!');
+    }
     return $value;
   }
 
diff --git a/core/lib/Drupal/Core/Template/AttributeArray.php b/core/lib/Drupal/Core/Template/AttributeArray.php
index 95e0ef3..4d8145f 100644
--- a/core/lib/Drupal/Core/Template/AttributeArray.php
+++ b/core/lib/Drupal/Core/Template/AttributeArray.php
@@ -66,7 +66,7 @@ public function offsetExists($offset) {
    * Implements the magic __toString() method.
    */
   public function __toString() {
-    return String::checkPlain(implode(' ', $this->value));
+    return (string) String::checkPlain(implode(' ', $this->value));
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Template/AttributeBoolean.php b/core/lib/Drupal/Core/Template/AttributeBoolean.php
index 4e9ea67..b5a0957 100644
--- a/core/lib/Drupal/Core/Template/AttributeBoolean.php
+++ b/core/lib/Drupal/Core/Template/AttributeBoolean.php
@@ -42,7 +42,7 @@ public function render() {
    * Implements the magic __toString() method.
    */
   public function __toString() {
-    return $this->value === FALSE ? '' : String::checkPlain($this->name);
+    return $this->value === FALSE ? '' : (string) String::checkPlain($this->name);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Template/AttributeString.php b/core/lib/Drupal/Core/Template/AttributeString.php
index 07211be..e1c69dc 100644
--- a/core/lib/Drupal/Core/Template/AttributeString.php
+++ b/core/lib/Drupal/Core/Template/AttributeString.php
@@ -30,7 +30,7 @@ class AttributeString extends AttributeValueBase {
    * Implements the magic __toString() method.
    */
   public function __toString() {
-    return String::checkPlain($this->value);
+    return (string) String::checkPlain($this->value);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Template/SafeMarkup.php b/core/lib/Drupal/Core/Template/SafeMarkup.php
new file mode 100644
index 0000000..5407dc3
--- /dev/null
+++ b/core/lib/Drupal/Core/Template/SafeMarkup.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Template\SafeMarkup.
+ */
+
+namespace Drupal\Core\Template;
+use Drupal\Component\Utility\String;
+
+/**
+ * A class marking strings as already escaped for XSS purposes.
+ */
+class SafeMarkup extends \Twig_Markup implements \JsonSerializable {
+
+  /**
+   * Wraps non-empty strings in SafeMarkup. Empty strings are returned as is.
+   *
+   * @param string $content
+   *   The content to be wrapped.
+   * @return \Drupal\Core\Template\SafeMarkup|string
+   */
+  public static function create($content) {
+    return $content !== '' ? new static($content, 'utf-8') : '';
+  }
+
+  /**
+   * Concatenates strings in a safe manner.
+   *
+   * @return \Drupal\Core\Template\SafeMarkup|string
+   */
+  public static function concat() {
+    return SafeMarkup::implode('', func_get_args());
+  }
+
+  /**
+   * Implodes strings in a safe manner.
+   *
+   * @return \Drupal\Core\Template\SafeMarkup|string
+   */
+  public static function implode($delimiter, array $array) {
+    foreach ($array as $key => $string) {
+      if (!$string instanceof SafeMarkup) {
+        $array[$key] = String::checkPlain($string);
+      }
+    }
+    return SafeMarkup::create(implode($delimiter, $array));
+  }
+
+  public static function strReplace($search, $replace, $subject, &$count = NULL) {
+    $safe = $subject instanceof SafeMarkup;
+    $replacement = str_replace($search, $replace, $subject, $count);
+    return $safe ? SafeMarkup::create($replacement) : $replacement;
+  }
+
+  /**
+   * Renders the markup.
+   *
+   * @return string
+   *   The results of the callback function.
+   */
+  public function render() {
+    return $this->__toString();
+  }
+
+  /**
+   * {inheritdoc}
+   */
+  public function jsonSerialize() {
+    return $this->__toString();
+  }
+}
diff --git a/core/lib/Drupal/Core/Utility/LinkGenerator.php b/core/lib/Drupal/Core/Utility/LinkGenerator.php
index b547d95..96029f7 100644
--- a/core/lib/Drupal/Core/Utility/LinkGenerator.php
+++ b/core/lib/Drupal/Core/Utility/LinkGenerator.php
@@ -11,8 +11,9 @@
 use Drupal\Component\Utility\String;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Path\AliasManagerInterface;
-use Drupal\Core\Template\Attribute;
 use Drupal\Core\Routing\UrlGeneratorInterface;
+use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Url;
 
 /**
@@ -122,8 +123,7 @@ public function generateFromUrl($text, Url $url) {
 
     // Sanitize the link text if necessary.
     $text = $variables['options']['html'] ? $variables['text'] : String::checkPlain($variables['text']);
-
-    return '<a href="' . $url . '"' . $attributes . '>' . $text . '</a>';
+    return SafeMarkup::create('<a href="' . $url . '"' . $attributes . '>' . $text . '</a>');
   }
 
   /**
diff --git a/core/modules/action/action.views_execution.inc b/core/modules/action/action.views_execution.inc
index 32bc883..66d18bf 100644
--- a/core/modules/action/action.views_execution.inc
+++ b/core/modules/action/action.views_execution.inc
@@ -19,6 +19,6 @@ function action_views_form_substitutions() {
     '#attributes' => array('class' => array('action-table-select-all')),
   );
   return array(
-    $select_all_placeholder => drupal_render($select_all),
+    (string) $select_all_placeholder => drupal_render($select_all),
   );
 }
diff --git a/core/modules/block/custom_block/src/Tests/CustomBlockListTest.php b/core/modules/block/custom_block/src/Tests/CustomBlockListTest.php
index 8bded49..2fbd583 100644
--- a/core/modules/block/custom_block/src/Tests/CustomBlockListTest.php
+++ b/core/modules/block/custom_block/src/Tests/CustomBlockListTest.php
@@ -52,7 +52,7 @@ public function testListing() {
     // Test the contents of each th cell.
     $expected_items = array(t('Block description'), t('Operations'));
     foreach ($elements as $key => $element) {
-      $this->assertIdentical((string) $element[0], $expected_items[$key]);
+      $this->assertIdentical((string) $element[0], (string) $expected_items[$key]);
     }
 
     $label = 'Antelope';
diff --git a/core/modules/block/src/Tests/BlockInterfaceTest.php b/core/modules/block/src/Tests/BlockInterfaceTest.php
index 0b71146..67f0faa 100644
--- a/core/modules/block/src/Tests/BlockInterfaceTest.php
+++ b/core/modules/block/src/Tests/BlockInterfaceTest.php
@@ -7,6 +7,9 @@
 
 namespace Drupal\block\Tests;
 
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Render\Element;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\simpletest\DrupalUnitTestBase;
 use Drupal\block\BlockInterface;
 
@@ -82,14 +85,14 @@ public function testBlockInterface() {
       ),
       'label' => array(
         '#type' => 'textfield',
-        '#title' => 'Title',
+        '#title' => t('Title'),
         '#maxlength' => 255,
         '#default_value' => 'Custom Display Message',
         '#required' => TRUE,
       ),
       'label_display' => array(
         '#type' => 'checkbox',
-        '#title' => 'Display title',
+        '#title' => t('Display title'),
         '#default_value' => TRUE,
         '#return_value' => 'visible',
       ),
@@ -124,7 +127,7 @@ public function testBlockInterface() {
     );
     $form_state = array();
     // Ensure there are no form elements that do not belong to the plugin.
-    $this->assertIdentical($display_block->buildConfigurationForm(array(), $form_state), $expected_form, 'Only the expected form elements were present.');
+    $this->assertIdenticalArray($display_block->buildConfigurationForm(array(), $form_state), $expected_form, 'Only the expected form elements were present.');
 
     $expected_build = array(
       '#children' => 'My custom display message.',
@@ -136,4 +139,5 @@ public function testBlockInterface() {
     // testing BlockBase's implementation, not the interface itself.
     $this->assertIdentical($display_block->getMachineNameSuggestion(), 'displaymessage', 'The plugin returned the expected machine name suggestion.');
   }
+
 }
diff --git a/core/modules/block/src/Tests/BlockViewBuilderTest.php b/core/modules/block/src/Tests/BlockViewBuilderTest.php
index a6571cb..78a53eb 100644
--- a/core/modules/block/src/Tests/BlockViewBuilderTest.php
+++ b/core/modules/block/src/Tests/BlockViewBuilderTest.php
@@ -100,7 +100,7 @@ public function testBasicRendering() {
     $expected[] = '</div>';
     $expected[] = '';
     $expected_output = implode("\n", $expected);
-    $this->assertEqual(drupal_render($output), $expected_output);
+    $this->assertEqual((string) drupal_render($output), $expected_output);
 
     // Reset the HTML IDs so that the next render is not affected.
     drupal_static_reset('drupal_html_id');
@@ -128,7 +128,7 @@ public function testBasicRendering() {
     $expected[] = '</div>';
     $expected[] = '';
     $expected_output = implode("\n", $expected);
-    $this->assertEqual(drupal_render($output), $expected_output);
+    $this->assertEqual((string) drupal_render($output), $expected_output);
   }
 
   /**
@@ -198,7 +198,7 @@ protected function verifyRenderCacheHandling() {
   public function testBlockViewBuilderAlter() {
     // Establish baseline.
     $build = $this->getBlockRenderArray();
-    $this->assertIdentical(drupal_render($build), 'Llamas &gt; unicorns!');
+    $this->assertIdentical((string) drupal_render($build), 'Llamas &gt; unicorns!');
 
     // Enable the block view alter hook that adds a suffix, for basic testing.
     \Drupal::state()->set('block_test_view_alter_suffix', TRUE);
@@ -206,13 +206,13 @@ public function testBlockViewBuilderAlter() {
     // Basic: non-empty block.
     $build = $this->getBlockRenderArray();
     $this->assertTrue(isset($build['#suffix']) && $build['#suffix'] === '<br>Goodbye!', 'A block with content is altered.');
-    $this->assertIdentical(drupal_render($build), 'Llamas &gt; unicorns!<br>Goodbye!');
+    $this->assertIdentical((string) drupal_render($build), 'Llamas &gt; unicorns!<br>Goodbye!');
 
     // Basic: empty block.
     \Drupal::state()->set('block_test.content', NULL);
     $build = $this->getBlockRenderArray();
     $this->assertTrue(isset($build['#suffix']) && $build['#suffix'] === '<br>Goodbye!', 'A block without content is altered.');
-    $this->assertIdentical(drupal_render($build), '<br>Goodbye!');
+    $this->assertIdentical((string) drupal_render($build), '<br>Goodbye!');
 
     // Disable the block view alter hook that adds a suffix, for basic testing.
     \Drupal::state()->set('block_test_view_alter_suffix', FALSE);
@@ -234,7 +234,7 @@ public function testBlockViewBuilderAlter() {
     $build = $this->getBlockRenderArray();
     $this->assertIdentical($expected_keys, $build['#cache']['keys'], 'An altered cacheable block has the expected cache keys.');
     $cid = drupal_render_cid_create(array('#cache' => array('keys' => $expected_keys)));
-    $this->assertIdentical(drupal_render($build), '');
+    $this->assertIdentical((string) drupal_render($build), '');
     $cache_entry = $this->container->get('cache.render')->get($cid);
     $this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
     $expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'theme:stark', 'block_plugin:test_cache');
@@ -248,7 +248,7 @@ public function testBlockViewBuilderAlter() {
     $build = $this->getBlockRenderArray();
     $this->assertIdentical($expected_tags, $build['#cache']['tags'], 'An altered cacheable block has the expected cache tags.');
     $cid = drupal_render_cid_create(array('#cache' => array('keys' => $expected_keys)));
-    $this->assertIdentical(drupal_render($build), '');
+    $this->assertIdentical((string) drupal_render($build), '');
     $cache_entry = $this->container->get('cache.render')->get($cid);
     $this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
     $expected_flattened_tags = array('content:1', 'block_view:1', 'block:test_block', 'theme:stark', 'block_plugin:test_cache', $alter_add_tag . ':1');
@@ -260,7 +260,7 @@ public function testBlockViewBuilderAlter() {
     \Drupal::state()->set('block_test_view_alter_append_pre_render_prefix', TRUE);
     $build = $this->getBlockRenderArray();
     $this->assertFalse(isset($build['#prefix']), 'The appended #pre_render callback has not yet run before calling drupal_render().');
-    $this->assertIdentical(drupal_render($build), 'Hiya!<br>');
+    $this->assertIdentical((string) drupal_render($build), 'Hiya!<br>');
     $this->assertTrue(isset($build['#prefix']) && $build['#prefix'] === 'Hiya!<br>', 'A cached block without content is altered.');
 
     // Restore the previous request method.
diff --git a/core/modules/block/tests/src/CategoryAutocompleteTest.php b/core/modules/block/tests/src/CategoryAutocompleteTest.php
index 26bd6b9..d443d90 100644
--- a/core/modules/block/tests/src/CategoryAutocompleteTest.php
+++ b/core/modules/block/tests/src/CategoryAutocompleteTest.php
@@ -59,7 +59,7 @@ public function setUp() {
    */
   public function testAutocompleteSuggestions($string, $suggestions) {
     $suggestions = array_map(function ($suggestion) {
-      return array('value' => $suggestion, 'label' => String::checkPlain($suggestion));
+      return array('value' => $suggestion, 'label' => (string) String::checkPlain($suggestion));
     }, $suggestions);
     $result = $this->autocompleteController->autocomplete(new Request(array('q' => $string)));
     $this->assertSame($suggestions, json_decode($result->getContent(), TRUE));
diff --git a/core/modules/book/book.admin.inc b/core/modules/book/book.admin.inc
index 4379582..09bb7b8 100644
--- a/core/modules/book/book.admin.inc
+++ b/core/modules/book/book.admin.inc
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Render\Element;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Returns HTML for a book administration form.
@@ -36,9 +37,9 @@ function theme_book_admin_table($variables) {
 
     $indentation = array('#theme' => 'indentation', '#size' => $form[$key]['depth']['#value'] - 2);
     $data = array(
-      drupal_render($indentation) . drupal_render($form[$key]['title']),
+      SafeMarkup::concat(drupal_render($indentation) , drupal_render($form[$key]['title'])),
       drupal_render($form[$key]['weight']),
-      drupal_render($form[$key]['pid']) . drupal_render($form[$key]['nid']),
+      SafeMarkup::concat(drupal_render($form[$key]['pid']) , drupal_render($form[$key]['nid'])),
     );
     $links = array();
     $links['view'] = array(
diff --git a/core/modules/book/src/BookExport.php b/core/modules/book/src/BookExport.php
index f28f855..9376985 100644
--- a/core/modules/book/src/BookExport.php
+++ b/core/modules/book/src/BookExport.php
@@ -8,6 +8,7 @@
 namespace Drupal\book;
 
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\node\NodeInterface;
 
 /**
@@ -105,18 +106,16 @@ protected function exportTraverse(array $tree, $callable) {
     // If there is no valid callable, use the default callback.
     $callable = !empty($callable) ? $callable : array($this, 'bookNodeExport');
 
-    $output = '';
+    $build = array();
     foreach ($tree as $data) {
       // Note- access checking is already performed when building the tree.
       if ($node = $this->nodeStorage->load($data['link']['nid'])) {
         $children = $data['below'] ? $this->exportTraverse($data['below'], $callable) : '';
-
-        $callable_output = call_user_func($callable, $node, $children);
-        $output .= drupal_render($callable_output);
+        $build[] = call_user_func($callable, $node, $children);
       }
     }
 
-    return $output;
+    return drupal_render($build);
   }
 
   /**
diff --git a/core/modules/ckeditor/ckeditor.admin.inc b/core/modules/ckeditor/ckeditor.admin.inc
index 373ebd2..e2cf656 100644
--- a/core/modules/ckeditor/ckeditor.admin.inc
+++ b/core/modules/ckeditor/ckeditor.admin.inc
@@ -115,7 +115,8 @@ function template_preprocess_ckeditor_settings_toolbar(&$variables) {
   $variables['active_buttons'] = array();
   foreach ($active_buttons as $row_number => $button_row) {
     foreach ($button_groups[$row_number] as $group_name) {
-      $variables['active_buttons'][$row_number][$group_name] = array(
+      $group_name_string = (string) $group_name;
+      $variables['active_buttons'][$row_number][$group_name_string] = array(
         'group_name_class' => drupal_html_class($group_name),
         'buttons' => array(),
       );
@@ -123,7 +124,7 @@ function template_preprocess_ckeditor_settings_toolbar(&$variables) {
         return $button['group'] === $group_name;
       });
       foreach ($buttons as $button) {
-        $variables['active_buttons'][$row_number][$group_name]['buttons'][] = $build_button_item($button, $rtl);
+        $variables['active_buttons'][$row_number][$group_name_string]['buttons'][] = $build_button_item($button, $rtl);
       }
     }
   }
diff --git a/core/modules/ckeditor/src/Tests/CKEditorAdminTest.php b/core/modules/ckeditor/src/Tests/CKEditorAdminTest.php
index 0d2d5b2..1d8bd99 100644
--- a/core/modules/ckeditor/src/Tests/CKEditorAdminTest.php
+++ b/core/modules/ckeditor/src/Tests/CKEditorAdminTest.php
@@ -109,7 +109,7 @@ function testExistingFormat() {
       ),
       'plugins' => array(),
     );
-    $this->assertIdentical($ckeditor->getDefaultSettings(), $expected_default_settings);
+    $this->assertIdenticalArray($ckeditor->getDefaultSettings(), $expected_default_settings);
 
     // Keep the "CKEditor" editor selected and click the "Configure" button.
     $this->drupalPostAjaxForm(NULL, $edit, 'editor_configure');
@@ -134,7 +134,7 @@ function testExistingFormat() {
     $expected_settings['plugins']['stylescombo']['styles'] = '';
     $editor = entity_load('editor', 'filtered_html');
     $this->assertTrue($editor instanceof Editor, 'An Editor config entity exists now.');
-    $this->assertIdentical($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
+    $this->assertIdenticalArray($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
 
     // Configure the Styles plugin, and ensure the updated settings are saved.
     $this->drupalGet('admin/config/content/formats/manage/filtered_html');
@@ -145,7 +145,7 @@ function testExistingFormat() {
     $expected_settings['plugins']['stylescombo']['styles'] = "h1.title|Title\np.callout|Callout\n\n";
     $editor = entity_load('editor', 'filtered_html');
     $this->assertTrue($editor instanceof Editor, 'An Editor config entity exists.');
-    $this->assertIdentical($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
+    $this->assertIdenticalArray($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
 
     // Change the buttons that appear on the toolbar (in JavaScript, this is
     // done via drag and drop, but here we can only emulate the end result of
@@ -162,7 +162,7 @@ function testExistingFormat() {
     $this->drupalPostForm(NULL, $edit, t('Save configuration'));
     $editor = entity_load('editor', 'filtered_html');
     $this->assertTrue($editor instanceof Editor, 'An Editor config entity exists.');
-    $this->assertIdentical($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
+    $this->assertIdenticalArray($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
 
     // Now enable the ckeditor_test module, which provides one configurable
     // CKEditor plugin — this should not affect the Editor config entity.
@@ -174,7 +174,7 @@ function testExistingFormat() {
     $this->assertTrue(count($ultra_llama_mode_checkbox) === 1, 'The "Ultra llama mode" checkbox exists and is not checked.');
     $editor = entity_load('editor', 'filtered_html');
     $this->assertTrue($editor instanceof Editor, 'An Editor config entity exists.');
-    $this->assertIdentical($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
+    $this->assertIdenticalArray($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
 
     // Finally, check the "Ultra llama mode" checkbox.
     $this->drupalGet('admin/config/content/formats/manage/filtered_html');
@@ -188,7 +188,7 @@ function testExistingFormat() {
     $expected_settings['plugins']['llama_contextual_and_button']['ultra_llama_mode'] = 1;
     $editor = entity_load('editor', 'filtered_html');
     $this->assertTrue($editor instanceof Editor, 'An Editor config entity exists.');
-    $this->assertIdentical($expected_settings, $editor->getSettings());
+    $this->assertIdenticalArray($expected_settings, $editor->getSettings());
   }
 
   /**
@@ -250,7 +250,7 @@ function testNewFormat() {
     $expected_settings['plugins']['stylescombo']['styles'] = '';
     $editor = entity_load('editor', 'amazing_format');
     $this->assertTrue($editor instanceof Editor, 'An Editor config entity exists now.');
-    $this->assertIdentical($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
+    $this->assertIdenticalArray($expected_settings, $editor->getSettings(), 'The Editor config entity has the correct settings.');
   }
 
 }
diff --git a/core/modules/ckeditor/src/Tests/CKEditorLoadingTest.php b/core/modules/ckeditor/src/Tests/CKEditorLoadingTest.php
index e4231a3..13100bd 100644
--- a/core/modules/ckeditor/src/Tests/CKEditorLoadingTest.php
+++ b/core/modules/ckeditor/src/Tests/CKEditorLoadingTest.php
@@ -107,7 +107,7 @@ function testLoading() {
       'isXssSafe' => FALSE,
     )));
     $this->assertTrue($editor_settings_present, "Text Editor module's JavaScript settings are on the page.");
-    $this->assertIdentical($expected, $settings['editor'], "Text Editor module's JavaScript settings on the page are correct.");
+    $this->assertIdenticalArray($expected, $settings['editor'], "Text Editor module's JavaScript settings on the page are correct.");
     $this->assertTrue($editor_js_present, 'Text Editor JavaScript is present.');
     $this->assertTrue(count($body) === 1, 'A body field exists.');
     $this->assertTrue(count($format_selector) === 1, 'A single text format selector exists on the page.');
@@ -137,7 +137,7 @@ function testLoading() {
       'isXssSafe' => FALSE,
     )));
     $this->assertTrue($editor_settings_present, "Text Editor module's JavaScript settings are on the page.");
-    $this->assertIdentical($expected, $settings['editor'], "Text Editor module's JavaScript settings on the page are correct.");
+    $this->assertIdenticalArray($expected, $settings['editor'], "Text Editor module's JavaScript settings on the page are correct.");
     $this->assertTrue($editor_js_present, 'Text Editor JavaScript is present.');
     $this->assertTrue(isset($settings['ajaxPageState']['js']['core/modules/ckeditor/js/ckeditor.js']), 'CKEditor glue JS is present.');
     $this->assertTrue(isset($settings['ajaxPageState']['js']['core/assets/vendor/ckeditor/ckeditor.js']), 'CKEditor lib JS is present.');
diff --git a/core/modules/ckeditor/src/Tests/CKEditorTest.php b/core/modules/ckeditor/src/Tests/CKEditorTest.php
index be08da2..850c7f7 100644
--- a/core/modules/ckeditor/src/Tests/CKEditorTest.php
+++ b/core/modules/ckeditor/src/Tests/CKEditorTest.php
@@ -85,10 +85,10 @@ function testGetJSSettings() {
 
     // Default toolbar.
     $expected_config = $this->getDefaultInternalConfig() + array(
-      'drupalImage_dialogTitleAdd' => 'Insert Image',
-      'drupalImage_dialogTitleEdit' => 'Edit Image',
-      'drupalLink_dialogTitleAdd' => 'Add Link',
-      'drupalLink_dialogTitleEdit' => 'Edit Link',
+      'drupalImage_dialogTitleAdd' => t('Insert Image'),
+      'drupalImage_dialogTitleEdit' => t('Edit Image'),
+      'drupalLink_dialogTitleAdd' => t('Add Link'),
+      'drupalLink_dialogTitleEdit' => t('Edit Link'),
       'allowedContent' => $this->getDefaultAllowedContentConfig(),
       'disallowedContent' => $this->getDefaultDisallowedContentConfig(),
       'toolbar' => $this->getDefaultToolbarConfig(),
@@ -102,7 +102,7 @@ function testGetJSSettings() {
       ),
     );
     ksort($expected_config);
-    $this->assertIdentical($expected_config, $this->ckeditor->getJSSettings($editor), 'Generated JS settings are correct for default configuration.');
+    $this->assertIdenticalArray($expected_config, $this->ckeditor->getJSSettings($editor), 'Generated JS settings are correct for default configuration.');
 
     // Customize the configuration: add button, have two contextually enabled
     // buttons, and configure a CKEditor plugin setting.
@@ -123,7 +123,7 @@ function testGetJSSettings() {
     $expected_config['drupalExternalPlugins']['llama_contextual_and_button'] = file_create_url('core/modules/ckeditor/tests/modules/js/llama_contextual_and_button.js');
     $expected_config['contentsCss'][] = file_create_url('core/modules/ckeditor/tests/modules/ckeditor_test.css');
     ksort($expected_config);
-    $this->assertIdentical($expected_config, $this->ckeditor->getJSSettings($editor), 'Generated JS settings are correct for customized configuration.');
+    $this->assertIdenticalArray($expected_config, $this->ckeditor->getJSSettings($editor), 'Generated JS settings are correct for customized configuration.');
 
     // Change the allowed HTML tags; the "allowedContent" and "format_tags"
     // settings for CKEditor should automatically be updated as well.
@@ -134,7 +134,7 @@ function testGetJSSettings() {
     $expected_config['allowedContent']['pre'] = array('attributes' => TRUE, 'styles' => FALSE, 'classes' => TRUE);
     $expected_config['allowedContent']['h3'] = array('attributes' => TRUE, 'styles' => FALSE, 'classes' => TRUE);
     $expected_config['format_tags'] = 'p;h3;h4;h5;h6;pre';
-    $this->assertIdentical($expected_config, $this->ckeditor->getJSSettings($editor), 'Generated JS settings are correct for customized configuration.');
+    $this->assertIdenticalArray($expected_config, $this->ckeditor->getJSSettings($editor), 'Generated JS settings are correct for customized configuration.');
 
     // Disable the filter_html filter: allow *all *tags.
     $format->setFilterConfig('filter_html', array('status' => 0));
@@ -143,7 +143,7 @@ function testGetJSSettings() {
     $expected_config['allowedContent'] = TRUE;
     $expected_config['disallowedContent'] = FALSE;
     $expected_config['format_tags'] = 'p;h1;h2;h3;h4;h5;h6;pre';
-    $this->assertIdentical($expected_config, $this->ckeditor->getJSSettings($editor), 'Generated JS settings are correct for customized configuration.');
+    $this->assertIdenticalArray($expected_config, $this->ckeditor->getJSSettings($editor), 'Generated JS settings are correct for customized configuration.');
 
     // Enable the filter_test_restrict_tags_and_attributes filter.
     $format->setFilterConfig('filter_test_restrict_tags_and_attributes', array(
@@ -212,7 +212,7 @@ function testGetJSSettings() {
     );
     $expected_config['format_tags'] = 'p';
     ksort($expected_config);
-    $this->assertIdentical($expected_config, $this->ckeditor->getJSSettings($editor), 'Generated JS settings are correct for customized configuration.');
+    $this->assertIdenticalArray($expected_config, $this->ckeditor->getJSSettings($editor), 'Generated JS settings are correct for customized configuration.');
   }
 
   /**
@@ -223,7 +223,7 @@ function testBuildToolbarJSSetting() {
 
     // Default toolbar.
     $expected = $this->getDefaultToolbarConfig();
-    $this->assertIdentical($expected, $this->ckeditor->buildToolbarJSSetting($editor), '"toolbar" configuration part of JS settings built correctly for default toolbar.');
+    $this->assertIdenticalArray($expected, $this->ckeditor->buildToolbarJSSetting($editor), '"toolbar" configuration part of JS settings built correctly for default toolbar.');
 
     // Customize the configuration.
     $settings = $editor->getSettings();
@@ -231,7 +231,7 @@ function testBuildToolbarJSSetting() {
     $editor->setSettings($settings);
     $editor->save();
     $expected[0]['items'][] = 'Strike';
-    $this->assertIdentical($expected, $this->ckeditor->buildToolbarJSSetting($editor), '"toolbar" configuration part of JS settings built correctly for customized toolbar.');
+    $this->assertIdenticalArray($expected, $this->ckeditor->buildToolbarJSSetting($editor), '"toolbar" configuration part of JS settings built correctly for customized toolbar.');
 
     // Enable the editor_test module, customize further.
     $this->enableModules(array('ckeditor_test'));
@@ -243,7 +243,7 @@ function testBuildToolbarJSSetting() {
     $editor->save();
     $expected[0]['name'] = 'JunkScience';
     $expected[0]['items'][] = 'Llama';
-    $this->assertIdentical($expected, $this->ckeditor->buildToolbarJSSetting($editor), '"toolbar" configuration part of JS settings built correctly for customized toolbar with contrib module-provided CKEditor plugin.');
+    $this->assertIdenticalArray($expected, $this->ckeditor->buildToolbarJSSetting($editor), '"toolbar" configuration part of JS settings built correctly for customized toolbar with contrib module-provided CKEditor plugin.');
   }
 
   /**
diff --git a/core/modules/color/color.module b/core/modules/color/color.module
index 335e0ad..6ce779f 100644
--- a/core/modules/color/color.module
+++ b/core/modules/color/color.module
@@ -8,6 +8,7 @@
 use Drupal\Component\Utility\Bytes;
 use Drupal\Component\Utility\Environment;
 use Drupal\Component\Utility\String;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -275,7 +276,7 @@ function template_preprocess_color_scheme_form(&$variables) {
 
   // Attempt to load preview HTML if the theme provides it.
   $preview_html_path = DRUPAL_ROOT . '/' . (isset($info['preview_html']) ? drupal_get_path('theme', $theme) . '/' . $info['preview_html'] : drupal_get_path('module', 'color') . '/preview.html');
-  $variables['html_preview'] = file_get_contents($preview_html_path);
+  $variables['html_preview'] = SafeMarkup::create(file_get_contents($preview_html_path));
 }
 
 /**
diff --git a/core/modules/config/src/Tests/ConfigEntityListTest.php b/core/modules/config/src/Tests/ConfigEntityListTest.php
index 71b7a4d..36e7b2c 100644
--- a/core/modules/config/src/Tests/ConfigEntityListTest.php
+++ b/core/modules/config/src/Tests/ConfigEntityListTest.php
@@ -68,28 +68,28 @@ function testList() {
     $actual_operations = $controller->getOperations($entity);
     // Sort the operations to normalize link order.
     uasort($actual_operations, array('Drupal\Component\Utility\SortArray', 'sortByWeightElement'));
-    $this->assertIdentical($expected_operations, $actual_operations, 'The operations are identical.');
+    $this->assertIdenticalArray($expected_operations, $actual_operations, 'The operations are identical.');
 
     // Test buildHeader() method.
     $expected_items = array(
-      'label' => 'Label',
-      'id' => 'Machine name',
-      'operations' => 'Operations',
+      'label' => t('Label'),
+      'id' => t('Machine name'),
+      'operations' => t('Operations'),
     );
     $actual_items = $controller->buildHeader();
-    $this->assertIdentical($expected_items, $actual_items, 'Return value from buildHeader matches expected.');
+    $this->assertIdenticalArray($expected_items, $actual_items, 'Return value from buildHeader matches expected.');
 
     // Test buildRow() method.
     $build_operations = $controller->buildOperations($entity);
     $expected_items = array(
-      'label' => 'Default',
+      'label' => t('Default'),
       'id' => 'dotted.default',
       'operations' => array(
         'data' => $build_operations,
       ),
     );
     $actual_items = $controller->buildRow($entity);
-    $this->assertIdentical($expected_items, $actual_items, 'Return value from buildRow matches expected.');
+    $this->assertIdenticalArray($expected_items, $actual_items, 'Return value from buildRow matches expected.');
     // Test sorting.
     $storage = $controller->getStorage();
     $entity = $storage->create(array(
@@ -136,7 +136,7 @@ function testList() {
     $actual_operations = $controller->getOperations($entity);
     // Sort the operations to normalize link order.
     uasort($actual_operations, array('Drupal\Component\Utility\SortArray', 'sortByWeightElement'));
-    $this->assertIdentical($expected_operations, $actual_operations, 'The operations are identical.');
+    $this->assertIdenticalArray($expected_operations, $actual_operations, 'The operations are identical.');
   }
 
   /**
diff --git a/core/modules/config/src/Tests/ConfigImportRenameValidationTest.php b/core/modules/config/src/Tests/ConfigImportRenameValidationTest.php
index 7e8024a..238e1d8 100644
--- a/core/modules/config/src/Tests/ConfigImportRenameValidationTest.php
+++ b/core/modules/config/src/Tests/ConfigImportRenameValidationTest.php
@@ -119,7 +119,7 @@ public function testRenameValidation() {
       $expected = array(
         String::format('Entity type mismatch on rename. !old_type not equal to !new_type for existing configuration !old_name and staged configuration !new_name.', array('old_type' => 'node_type', 'new_type' => 'config_test', 'old_name' => 'node.type.' . $content_type->id(), 'new_name' => 'config_test.dynamic.' . $test_entity_id))
       );
-      $this->assertIdentical($expected, $this->configImporter->getErrors());
+      $this->assertIdenticalArray($expected, $this->configImporter->getErrors());
     }
   }
 
@@ -162,7 +162,7 @@ public function testRenameSimpleConfigValidation() {
       $expected = array(
         String::format('Rename operation for simple configuration. Existing configuration !old_name and staged configuration !new_name.', array('old_name' => 'config_test.old', 'new_name' => 'config_test.new'))
       );
-      $this->assertIdentical($expected, $this->configImporter->getErrors());
+      $this->assertIdenticalArray($expected, $this->configImporter->getErrors());
     }
   }
 
diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
index b01feb8..52bd30a 100644
--- a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
+++ b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
@@ -517,7 +517,7 @@ public function testViewsTranslationUI() {
     $response = $this->renderContextualLinks($ids, 'node');
     $this->assertResponse(200);
     $json = Json::decode($response);
-    $this->assertTrue(strpos($json[$ids[0]], t('Translate view')), 'Translate view contextual link added.');
+    $this->assertTrue(strpos($json[$ids[0]], (string) t('Translate view')), 'Translate view contextual link added.');
 
     $description = 'All content promoted to the front page.';
     $human_readable_name = 'Frontpage';
diff --git a/core/modules/config_translation/tests/src/ConfigEntityMapperTest.php b/core/modules/config_translation/tests/src/ConfigEntityMapperTest.php
index bdc04f8..314a9fb 100644
--- a/core/modules/config_translation/tests/src/ConfigEntityMapperTest.php
+++ b/core/modules/config_translation/tests/src/ConfigEntityMapperTest.php
@@ -199,6 +199,8 @@ public function testGetOperations() {
         'href' => 'admin/config/regional/config-translation/language_entity',
       )
     );
+    $this->assertFalse(is_string($result['list']['title']));
+    $result['list']['title'] = (string) $result['list']['title'];
 
     $this->assertSame($expected, $result);
   }
diff --git a/core/modules/config_translation/tests/src/ConfigNamesMapperTest.php b/core/modules/config_translation/tests/src/ConfigNamesMapperTest.php
index 41a6b1a..e065f4a 100644
--- a/core/modules/config_translation/tests/src/ConfigNamesMapperTest.php
+++ b/core/modules/config_translation/tests/src/ConfigNamesMapperTest.php
@@ -118,7 +118,8 @@ public function setUp() {
    */
   public function testGetTitle() {
     $result = $this->configNamesMapper->getTitle();
-    $this->assertSame($this->pluginDefinition['title'], $result);
+    $this->assertFalse(is_string($result));
+    $this->assertSame($this->pluginDefinition['title'], (string) $result);
   }
 
   /**
@@ -366,7 +367,8 @@ public function testPopulateFromRequest() {
    */
   public function testGetTypeLabel() {
     $result = $this->configNamesMapper->getTypeLabel();
-    $this->assertSame($this->pluginDefinition['title'], $result);
+    $this->assertFalse(is_string($result));
+    $this->assertSame($this->pluginDefinition['title'], (string) $result);
   }
 
   /**
@@ -597,7 +599,8 @@ public function providerTestHasTranslation() {
    */
   public function testGetTypeName() {
     $result = $this->configNamesMapper->getTypeName();
-    $this->assertSame('Settings', $result);
+    $this->assertFalse(is_string($result));
+    $this->assertSame('Settings', (string) $result);
   }
 
   /**
diff --git a/core/modules/contact/src/Tests/ContactPersonalTest.php b/core/modules/contact/src/Tests/ContactPersonalTest.php
index f1df078..a2d793d 100644
--- a/core/modules/contact/src/Tests/ContactPersonalTest.php
+++ b/core/modules/contact/src/Tests/ContactPersonalTest.php
@@ -83,7 +83,7 @@ function testSendPersonalContactMessage() {
       '!recipient-name' => $this->contact_user->getUsername(),
     );
     $this->assertEqual($mail['subject'], t('[!site-name] !subject', $variables), 'Subject is in sent message.');
-    $this->assertTrue(strpos($mail['body'], t('Hello !recipient-name,', $variables)) !== FALSE, 'Recipient name is in sent message.');
+    $this->assertTrue(strpos($mail['body'], (string) t('Hello !recipient-name,', $variables)) !== FALSE, 'Recipient name is in sent message.');
     $this->assertTrue(strpos($mail['body'], $this->web_user->getUsername()) !== FALSE, 'Sender name is in sent message.');
     $this->assertTrue(strpos($mail['body'], $message['message']) !== FALSE, 'Message body is in sent message.');
 
diff --git a/core/modules/editor/src/Tests/EditorManagerTest.php b/core/modules/editor/src/Tests/EditorManagerTest.php
index 997d861..e7f685f 100644
--- a/core/modules/editor/src/Tests/EditorManagerTest.php
+++ b/core/modules/editor/src/Tests/EditorManagerTest.php
@@ -82,7 +82,7 @@ public function testManager() {
     $this->editorManager->clearCachedDefinitions();
 
     // Case 2: a text editor available.
-    $this->assertIdentical(array('unicorn' => 'Unicorn Editor'), $this->editorManager->listOptions(), 'When some text editor is enabled, the manager works correctly.');
+    $this->assertIdenticalArray(array('unicorn' => t('Unicorn Editor')), $this->editorManager->listOptions(), 'When some text editor is enabled, the manager works correctly.');
 
     // Case 3: a text editor available & associated (but associated only with
     // the 'Full HTML' text format).
diff --git a/core/modules/editor/tests/src/EditorXssFilter/StandardTest.php b/core/modules/editor/tests/src/EditorXssFilter/StandardTest.php
index 7927eef..cc3a884 100644
--- a/core/modules/editor/tests/src/EditorXssFilter/StandardTest.php
+++ b/core/modules/editor/tests/src/EditorXssFilter/StandardTest.php
@@ -551,7 +551,7 @@ public function providerTestFilterXss() {
    */
   public function testFilterXss($input, $expected_output) {
     $output = call_user_func($this->editorXssFilterClass . '::filterXss', $input, $this->format);
-    $this->assertSame($expected_output, $output);
+    $this->assertSame($expected_output, (string) $output);
   }
 
 }
diff --git a/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php b/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php
index e5ad209..9a5b732 100644
--- a/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php
+++ b/core/modules/entity_reference/src/ConfigurableEntityReferenceItem.php
@@ -90,7 +90,7 @@ public function getSettableOptions(AccountInterface $account = NULL) {
     $return = array();
     foreach ($options as $bundle => $entity_ids) {
       $bundle_label = String::checkPlain($bundles[$bundle]['label']);
-      $return[$bundle_label] = $entity_ids;
+      $return[(string) $bundle_label] = $entity_ids;
     }
 
     return count($return) == 1 ? reset($return) : $return;
diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceAutocompleteTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceAutocompleteTest.php
index ff59b8b..ca19d6d 100644
--- a/core/modules/entity_reference/src/Tests/EntityReferenceAutocompleteTest.php
+++ b/core/modules/entity_reference/src/Tests/EntityReferenceAutocompleteTest.php
@@ -82,8 +82,8 @@ function testEntityReferenceAutocompletion() {
     // We should get both entities in a JSON encoded string.
     $input = '10/';
     $data = $this->getAutocompleteResult('single', $input);
-    $this->assertIdentical($data[0]['label'], String::checkPlain($entity_1->name->value), 'Autocomplete returned the first matching entity');
-    $this->assertIdentical($data[1]['label'], String::checkPlain($entity_2->name->value), 'Autocomplete returned the second matching entity');
+    $this->assertIdentical($data[0]['label'], (string) String::checkPlain($entity_1->name->value), 'Autocomplete returned the first matching entity');
+    $this->assertIdentical($data[1]['label'], (string) String::checkPlain($entity_2->name->value), 'Autocomplete returned the second matching entity');
 
     // Try to autocomplete a entity label that matches the first entity.
     // We should only get the first entity in a JSON encoded string.
@@ -91,7 +91,7 @@ function testEntityReferenceAutocompletion() {
     $data = $this->getAutocompleteResult('single', $input);
     $target = array(
       'value' => $entity_1->name->value . ' (1)',
-      'label' => String::checkPlain($entity_1->name->value),
+      'label' => (string) String::checkPlain($entity_1->name->value),
     );
     $this->assertIdentical(reset($data), $target, 'Autocomplete returns only the expected matching entity.');
 
@@ -99,7 +99,7 @@ function testEntityReferenceAutocompletion() {
     // the first entity  is already typed in the autocomplete (tags) widget.
     $input = $entity_1->name->value . ' (1), 10/17';
     $data = $this->getAutocompleteResult('tags', $input);
-    $this->assertIdentical($data[0]['label'], String::checkPlain($entity_2->name->value), 'Autocomplete returned the second matching entity');
+    $this->assertIdentical($data[0]['label'], (string) String::checkPlain($entity_2->name->value), 'Autocomplete returned the second matching entity');
 
     // Try to autocomplete a entity label with both a comma and a slash.
     $input = '"label with, and / t';
@@ -109,7 +109,7 @@ function testEntityReferenceAutocompletion() {
     $n = Tags::encode($n);
     $target = array(
       'value' => $n,
-      'label' => String::checkPlain($entity_3->name->value),
+      'label' => (string) String::checkPlain($entity_3->name->value),
     );
     $this->assertIdentical(reset($data), $target, 'Autocomplete returns an entity label containing a comma and a slash.');
   }
@@ -152,8 +152,8 @@ public function testBaseField() {
     $result = $entity_reference_controller->handleAutocomplete($request, 'single', 'user_id', 'entity_test', 'entity_test', 'NULL')->getContent();
 
     $data = Json::decode($result);
-    $this->assertIdentical($data[0]['label'], String::checkPlain($user_1->getUsername()), 'Autocomplete returned the first matching entity');
-    $this->assertIdentical($data[1]['label'], String::checkPlain($user_2->getUsername()), 'Autocomplete returned the second matching entity');
+    $this->assertIdentical($data[0]['label'], (string) String::checkPlain($user_1->getUsername()), 'Autocomplete returned the first matching entity');
+    $this->assertIdentical($data[1]['label'], (string) String::checkPlain($user_2->getUsername()), 'Autocomplete returned the second matching entity');
 
     // Checks that exception thrown for unknown field.
     try {
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 4e0157d..7b0ac51 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -9,6 +9,7 @@
 use Drupal\Core\Config\ConfigImporter;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Extension\Extension;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\HttpFoundation\Request;
 
 /*
@@ -266,7 +267,7 @@ function field_entity_bundle_delete($entity_type, $bundle) {
  *   UTF-8.
  */
 function field_filter_xss($string) {
-  return Html::normalize(Xss::filter($string, _field_filter_xss_allowed_tags()));
+  return SafeMarkup::create(Html::normalize(Xss::filter($string, _field_filter_xss_allowed_tags())));
 }
 
 /**
diff --git a/core/modules/field/src/Plugin/views/field/Field.php b/core/modules/field/src/Plugin/views/field/Field.php
index ec794fd..4a949f5 100644
--- a/core/modules/field/src/Plugin/views/field/Field.php
+++ b/core/modules/field/src/Plugin/views/field/Field.php
@@ -7,12 +7,14 @@
 
 namespace Drupal\field\Plugin\views\field;
 
+use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Field\FieldDefinition;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Entity\ContentEntityDatabaseStorage;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FormatterPluginManager;
@@ -685,11 +687,11 @@ public function submitGroupByForm(&$form, &$form_state) {
   protected function renderItems($items) {
     if (!empty($items)) {
       if (!$this->options['group_rows']) {
-        return implode('', $items);
+        return SafeMarkup::implode('', $items);
       }
 
       if ($this->options['multi_type'] == 'separator') {
-        return implode(Xss::filterAdmin($this->options['separator']), $items);
+        return SafeMarkup::create(implode(Xss::filterAdmin($this->options['separator']), $items));
       }
       else {
         $item_list = array(
diff --git a/core/modules/field_ui/src/DisplayOverviewBase.php b/core/modules/field_ui/src/DisplayOverviewBase.php
index 2a6f46f..29ea754 100644
--- a/core/modules/field_ui/src/DisplayOverviewBase.php
+++ b/core/modules/field_ui/src/DisplayOverviewBase.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -398,7 +399,7 @@ protected function buildFieldRow(FieldDefinitionInterface $field_definition, Ent
 
         if (!empty($summary)) {
           $field_row['settings_summary'] = array(
-            '#markup' => '<div class="field-plugin-summary">' . implode('<br />', $summary) . '</div>',
+            '#markup' => '<div class="field-plugin-summary">' . SafeMarkup::implode('<br />', $summary) . '</div>',
             '#cell_attributes' => array('class' => array('field-plugin-summary-cell')),
           );
         }
diff --git a/core/modules/field_ui/src/FieldConfigListBuilder.php b/core/modules/field_ui/src/FieldConfigListBuilder.php
index 0da1bf9..91f8d45 100644
--- a/core/modules/field_ui/src/FieldConfigListBuilder.php
+++ b/core/modules/field_ui/src/FieldConfigListBuilder.php
@@ -7,11 +7,13 @@
 
 namespace Drupal\field_ui;
 
+use Drupal\Component\Utility\String;
 use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -117,7 +119,7 @@ public function buildRow(EntityInterface $field) {
         $usage[] = $this->bundles[$field->entity_type][$bundle]['label'];
       }
     }
-    $row['data']['usage'] = implode(', ', $usage);
+    $row['data']['usage'] = SafeMarkup::implode(', ', $usage);
     return $row;
   }
 
diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc
index f9aa9f9..f3b3fb2 100644
--- a/core/modules/file/file.field.inc
+++ b/core/modules/file/file.field.inc
@@ -8,6 +8,7 @@
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Returns HTML for an individual file upload widget.
@@ -125,7 +126,7 @@ function theme_file_widget_multiple($variables) {
       $row[] = $display;
     }
     $row[] = $weight;
-    $row[] = $operations;
+    $row[] = SafeMarkup::create($operations);
     $rows[] = array(
       'data' => $row,
       'class' => isset($widget['#attributes']['class']) ? array_merge($widget['#attributes']['class'], array('draggable')) : array('draggable'),
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index 47b72ef..4c41b78 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -7,6 +7,7 @@
 
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\file\Entity\File;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\Unicode;
@@ -943,10 +944,10 @@ function file_save_upload($form_field_name, $validators = array(), $destination
           '#theme' => 'item_list',
           '#items' => $errors,
         );
-        $message .= drupal_render($item_list);
+        $message = SafeMarkup::concat($message, drupal_render($item_list));
       }
       else {
-        $message .= ' ' . array_pop($errors);
+        $message = SafeMarkup::concat($message, ' ', array_pop($errors));
       }
       drupal_set_message($message, 'error');
       $files[$i] = FALSE;
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index f25fe79..b01ad2b 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -13,6 +13,7 @@
 use Drupal\Core\Render\Element;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\filter\FilterFormatInterface;
 use Drupal\filter\Plugin\FilterInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -414,7 +415,7 @@ function check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE,
     \Drupal::cache('filter')->set($cache_id, $text, Cache::PERMANENT, array('filter_format' => $format->id()));
   }
 
-  return $text;
+  return SafeMarkup::create($text);
 }
 
 /**
diff --git a/core/modules/filter/src/Plugin/Filter/FilterCaption.php b/core/modules/filter/src/Plugin/Filter/FilterCaption.php
index 08ad4c8..9fb40fe 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterCaption.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterCaption.php
@@ -11,6 +11,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\filter\Plugin\FilterBase;
 
 /**
@@ -76,7 +77,7 @@ public function process($text, $langcode, $cache, $cache_id) {
         // caption.
         $filter_caption = array(
           '#theme' => 'filter_caption',
-          '#node' => $node->C14N(),
+          '#node' => SafeMarkup::create($node->C14N()),
           '#tag' => $node->tagName,
           '#caption' => $caption,
           '#align' => $align,
diff --git a/core/modules/filter/src/Tests/FilterAPITest.php b/core/modules/filter/src/Tests/FilterAPITest.php
index 1c33d74..7468a92 100644
--- a/core/modules/filter/src/Tests/FilterAPITest.php
+++ b/core/modules/filter/src/Tests/FilterAPITest.php
@@ -94,7 +94,7 @@ function testCheckMarkupFilterOrder() {
     $text = "<p>Llamas are <not> awesome!</p>";
     $expected_filtered_text = "&lt;p&gt;Llamas are  awesome!&lt;/p&gt;";
 
-    $this->assertIdentical(check_markup($text, 'crazy'), $expected_filtered_text, 'Filters applied in correct order.');
+    $this->assertIdentical((string) check_markup($text, 'crazy'), $expected_filtered_text, 'Filters applied in correct order.');
   }
 
   /**
@@ -106,12 +106,12 @@ function testCheckMarkupFilterSubset() {
     $expected_filter_text_without_html_generators = "Text with evil content and a URL: http://drupal.org!";
 
     $this->assertIdentical(
-      check_markup($text, 'filtered_html', '', FALSE, array()),
+      (string) check_markup($text, 'filtered_html', '', FALSE, array()),
       $expected_filtered_text,
       'Expected filter result.'
     );
     $this->assertIdentical(
-      check_markup($text, 'filtered_html', '', FALSE, array(FilterInterface::TYPE_MARKUP_LANGUAGE)),
+      (string) check_markup($text, 'filtered_html', '', FALSE, array(FilterInterface::TYPE_MARKUP_LANGUAGE)),
       $expected_filter_text_without_html_generators,
       'Expected filter result when skipping FilterInterface::TYPE_MARKUP_LANGUAGE filters.'
     );
@@ -120,7 +120,7 @@ function testCheckMarkupFilterSubset() {
     // Drupal core only ships with these two types of filters, so this is the
     // most extensive test possible.
     $this->assertIdentical(
-      check_markup($text, 'filtered_html', '', FALSE, array(FilterInterface::TYPE_HTML_RESTRICTOR, FilterInterface::TYPE_MARKUP_LANGUAGE)),
+      (string) check_markup($text, 'filtered_html', '', FALSE, array(FilterInterface::TYPE_HTML_RESTRICTOR, FilterInterface::TYPE_MARKUP_LANGUAGE)),
       $expected_filter_text_without_html_generators,
       'Expected filter result when skipping FilterInterface::TYPE_MARKUP_LANGUAGE filters, even when trying to disable filters of the FilterInterface::TYPE_HTML_RESTRICTOR type.'
     );
diff --git a/core/modules/filter/templates/filter-guidelines.html.twig b/core/modules/filter/templates/filter-guidelines.html.twig
index 88a3b47..ecf9b94 100644
--- a/core/modules/filter/templates/filter-guidelines.html.twig
+++ b/core/modules/filter/templates/filter-guidelines.html.twig
@@ -20,6 +20,6 @@
  */
 #}
 <div{{ attributes }}>
-  <h4 class="label">{{ format.name|escape }}</h4>
+  <h4 class="label">{{ format.name }}</h4>
   {{ tips }}
 </div>
diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc
index e87ec99..52d6bf9 100644
--- a/core/modules/image/image.admin.inc
+++ b/core/modules/image/image.admin.inc
@@ -4,8 +4,11 @@
  * @file
  * Administration pages for image settings.
  */
+
 use Drupal\Component\Utility\String;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Template\SafeMarkup;
+
 /**
  * Returns HTML for a listing of the effects within a specific image style.
  *
@@ -30,7 +33,8 @@ function theme_image_style_effects($variables) {
     }
     else {
       // Add the row for adding a new image effect.
-      $row[] = '<div class="image-style-new">' . drupal_render($form['new']['new']) . drupal_render($form['new']['add']) . '</div>';
+      $cell = '<div class="image-style-new">' . drupal_render($form['new']['new']) . drupal_render($form['new']['add']) . '</div>';
+      $row[] = SafeMarkup::create($cell);
       $row[] = drupal_render($form['new']['weight']);
       $row[] = '';
     }
diff --git a/core/modules/locale/templates/locale-translation-update-info.html.twig b/core/modules/locale/templates/locale-translation-update-info.html.twig
index 809028a..2af4c57 100644
--- a/core/modules/locale/templates/locale-translation-update-info.html.twig
+++ b/core/modules/locale/templates/locale-translation-update-info.html.twig
@@ -21,7 +21,7 @@
 <div class="inner" tabindex="0" role="button">
   <span class="update-description-prefix visually-hidden">Show description</span>
   {% if modules %}
-    {% set module_list = modules|join(', ') %}
+    {% set module_list = modules|join(', ')|raw %}
     <span class="text">{% trans %}Updates for: {{ module_list }}{% endtrans %}</span>
   {% elseif missing_updates_status %}
     <span class="text">{{ missing_updates_status }}</span>
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index d0d6d1c..b7c73fd 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -7,6 +7,7 @@
 
 use Drupal\Component\Uuid\Uuid;
 use Drupal\Core\Language\Language;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Implements hook_requirements().
@@ -29,7 +30,9 @@ function node_requirements($phase) {
     $requirements['node_access'] = array(
       'title' => t('Node Access Permissions'),
       'value' => $value,
-      'description' => $description . ' ' . l(t('Rebuild permissions'), 'admin/reports/status/rebuild'),
+      // The results of t() is safe and so is the results of l(). Preserving
+      // safe object.
+      'description' => SafeMarkup::create($description . ' ' . l(t('Rebuild permissions'), 'admin/reports/status/rebuild')),
     );
   }
   return $requirements;
diff --git a/core/modules/node/src/NodeViewBuilder.php b/core/modules/node/src/NodeViewBuilder.php
index 606ef36..138e1bd 100644
--- a/core/modules/node/src/NodeViewBuilder.php
+++ b/core/modules/node/src/NodeViewBuilder.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityViewBuilder;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Render controller for nodes.
@@ -124,7 +125,7 @@ public static function renderLinks(array $element, array $context) {
       \Drupal::moduleHandler()->alter('node_links', $links, $entity, $hook_context);
     }
     $markup = drupal_render($links);
-    $element['#markup'] = str_replace($placeholder, $markup, $element['#markup']);
+    $element['#markup'] = SafeMarkup::strReplace($placeholder, $markup, $element['#markup']);
 
     return $element;
   }
diff --git a/core/modules/options/src/Tests/OptionsFormattersTest.php b/core/modules/options/src/Tests/OptionsFormattersTest.php
index 34cda3a..be7b63f 100644
--- a/core/modules/options/src/Tests/OptionsFormattersTest.php
+++ b/core/modules/options/src/Tests/OptionsFormattersTest.php
@@ -45,7 +45,7 @@ public function testFormatter() {
 
     $build = $items->view(array('type' => 'list_key'));
     $this->assertEqual($build['#formatter'], 'list_key', 'The chosen formatter is used.');
-    $this->assertEqual($build[0]['#markup'], 1);
+    $this->assertEqual($build[0]['#markup'], "1");
   }
 
 }
diff --git a/core/modules/responsive_image/responsive_image.module b/core/modules/responsive_image/responsive_image.module
index 53c182c..b1cbac0 100644
--- a/core/modules/responsive_image/responsive_image.module
+++ b/core/modules/responsive_image/responsive_image.module
@@ -7,6 +7,7 @@
 
 use Drupal\breakpoint\Entity\Breakpoint;
 use \Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -190,7 +191,6 @@ function theme_responsive_image($variables) {
   }
 
   $sources = array();
-  $output = array();
 
   // Fallback image, output as source with media query.
   $sources[] = array(
@@ -234,6 +234,7 @@ function theme_responsive_image($variables) {
   }
 
   if (!empty($sources)) {
+    $output = array();
     $output[] = '<picture>';
 
     // Add source tags to the output.
@@ -253,7 +254,7 @@ function theme_responsive_image($variables) {
     }
 
     $output[] = '</picture>';
-    return implode("\n", $output);
+    return SafeMarkup::create(implode("\n", $output));
   }
 }
 
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index bec96c4..dd03660 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -526,7 +526,7 @@ function simpletest_test_get_all($module = NULL) {
             }
           }
 
-          $groups[$info['group']][$class] = $info;
+          $groups[(string) $info['group']][$class] = $info;
         }
       }
 
diff --git a/core/modules/simpletest/src/Form/SimpletestResultsForm.php b/core/modules/simpletest/src/Form/SimpletestResultsForm.php
index 299f305..e9251ca 100644
--- a/core/modules/simpletest/src/Form/SimpletestResultsForm.php
+++ b/core/modules/simpletest/src/Form/SimpletestResultsForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
@@ -155,7 +156,8 @@ public function buildForm(array $form, array &$form_state, $test_id = NULL) {
       $rows = array();
       foreach ($assertions as $assertion) {
         $row = array();
-        $row[] = $assertion->message;
+        // @todo Need to preserve safe markup, not create it.
+        $row[] = SafeMarkup::create($assertion->message);
         $row[] = $assertion->message_group;
         $row[] = drupal_basename($assertion->file);
         $row[] = $assertion->line;
diff --git a/core/modules/simpletest/src/Form/SimpletestTestForm.php b/core/modules/simpletest/src/Form/SimpletestTestForm.php
index e3876a5..466ea67 100644
--- a/core/modules/simpletest/src/Form/SimpletestTestForm.php
+++ b/core/modules/simpletest/src/Form/SimpletestTestForm.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\SortArray;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Form\FormBase;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * List tests arranged in groups that can be selected and run.
@@ -87,8 +88,8 @@ public function buildForm(array $form, array &$form_state) {
       'data' => array(
         'simpleTest' => array(
           'images' => array(
-            drupal_render($image_collapsed),
-            drupal_render($image_extended),
+            (string) drupal_render($image_collapsed),
+            (string) drupal_render($image_extended),
           ),
         ),
       ),
diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php
index 023cf8e..977b65f 100644
--- a/core/modules/simpletest/src/TestBase.php
+++ b/core/modules/simpletest/src/TestBase.php
@@ -277,7 +277,7 @@ protected function assert($status, $message = '', $group = 'Other', array $calle
       'test_id' => $this->testId,
       'test_class' => get_class($this),
       'status' => $status,
-      'message' => $message,
+      'message' => (string) $message,
       'message_group' => $group,
       'function' => $caller['function'],
       'line' => $caller['line'],
@@ -641,11 +641,46 @@ protected function assertIdenticalObject($object1, $object2, $message = '', $gro
     ));
     $identical = TRUE;
     foreach ($object1 as $key => $value) {
-      $identical = $identical && isset($object2->$key) && $object2->$key === $value;
+      $identical = $identical && property_exists($object2, $key) && $object2->$key === $value;
     }
     return $this->assertTrue($identical, $message, $group);
   }
 
+ /**
+   * Asserts two array are identical.
+   *
+   * Use this helper if the arrays contain objects.
+   *
+   * @param array $array1
+   *   The first array to check.
+   * @param array $array2
+   *   The second array to check.
+   * @param $message
+   *   (optional) A message to display with the assertion. Do not translate
+   *   messages: use \Drupal\Component\Utility\String::format() to embed
+   *   variables in the message text, not t(). If left blank, a default message
+   *   will be displayed.
+   * @param $group
+   *   (optional) The group this message is in, which is displayed in a column
+   *   in test output. Use 'Debug' to indicate this is debugging output. Do not
+   *   translate this string. Defaults to 'Other'; most tests do not override
+   *   this default.
+   */
+  protected function assertIdenticalArray(array $array1, array $array2, $message = '', $group = 'Other') {
+    $this->assertEqual(count($array1), count($array2));
+    foreach (array_keys($array1) as $key) {
+      if (is_array($array1[$key])) {
+        $this->assertIdenticalArray($array1[$key], $array2[$key]);
+      }
+      elseif (is_object($array1[$key])) {
+        $this->assertIdenticalObject($array1[$key], $array2[$key]);
+      }
+      else {
+        $this->assertIdentical($array1[$key], $array2[$key]);
+      }
+    }
+  }
+
   /**
    * Asserts that no errors have been logged to the PHP error.log thus far.
    *
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index ec50d4d..f2a229a 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -23,6 +23,7 @@
 use Drupal\Core\StreamWrapper\PublicStream;
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\block\Entity\Block;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\CssSelector\CssSelector;
 
@@ -1629,6 +1630,9 @@ protected function drupalGetAJAX($path, array $options = array(), array $headers
    */
   protected function drupalPostForm($path, $edit, $submit, array $options = array(), array $headers = array(), $form_html_id = NULL, $extra_post = NULL) {
     $submit_matches = FALSE;
+    if ($submit instanceof SafeMarkup) {
+      $submit = (string) $submit;
+    }
     $ajax = is_array($submit);
     if (isset($path)) {
       $this->drupalGet($path, $options);
@@ -2285,7 +2289,7 @@ protected function buildXPathQuery($xpath, array $args = array()) {
       // XPath 1.0 doesn't support a way to escape single or double quotes in a
       // string literal. We split double quotes out of the string, and encode
       // them separately.
-      if (is_string($value)) {
+      if (is_string($value) || $value instanceof SafeMarkup) {
         // Explode the text at the quote characters.
         $parts = explode('"', $value);
 
@@ -2776,7 +2780,7 @@ protected function assertRaw($raw, $message = '', $group = 'Other') {
     if (!$message) {
       $message = String::format('Raw "@raw" found', array('@raw' => $raw));
     }
-    return $this->assert(strpos($this->drupalGetContent(), $raw) !== FALSE, $message, $group);
+    return $this->assert(strpos($this->drupalGetContent(), (string) $raw) !== FALSE, $message, $group);
   }
 
   /**
@@ -2803,7 +2807,7 @@ protected function assertNoRaw($raw, $message = '', $group = 'Other') {
     if (!$message) {
       $message = String::format('Raw "@raw" not found', array('@raw' => $raw));
     }
-    return $this->assert(strpos($this->drupalGetContent(), $raw) === FALSE, $message, $group);
+    return $this->assert(strpos($this->drupalGetContent(), (string) $raw) === FALSE, $message, $group);
   }
 
   /**
@@ -2887,7 +2891,7 @@ protected function assertTextHelper($text, $message = '', $group, $not_exists) {
     if (!$message) {
       $message = !$not_exists ? String::format('"@text" found', array('@text' => $text)) : String::format('"@text" not found', array('@text' => $text));
     }
-    return $this->assert($not_exists == (strpos($this->plainTextContent, $text) === FALSE), $message, $group);
+    return $this->assert($not_exists == (strpos($this->plainTextContent, (string) $text) === FALSE), $message, $group);
   }
 
   /**
@@ -3701,6 +3705,7 @@ protected function assertMail($name, $value = '', $message = '', $group = 'E-mai
   protected function assertMailString($field_name, $string, $email_depth, $message = '', $group = 'Other') {
     $mails = $this->drupalGetMails();
     $string_found = FALSE;
+    $string = (string) $string;
     for ($i = count($mails) -1; $i >= count($mails) - $email_depth && $i >= 0; $i--) {
       $mail = $mails[$i];
       // Normalize whitespace, as we don't know what the mail system might have
diff --git a/core/modules/system/src/Form/ModulesListForm.php b/core/modules/system/src/Form/ModulesListForm.php
index d061495..a0a0ee9 100644
--- a/core/modules/system/src/Form/ModulesListForm.php
+++ b/core/modules/system/src/Form/ModulesListForm.php
@@ -17,6 +17,7 @@
 use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Access\AccessManager;
 
@@ -162,7 +163,7 @@ public function buildForm(array $form, array &$form_state) {
         '#open' => TRUE,
         '#theme' => 'system_modules_details',
         '#header' => array(
-          array('data' => '<span class="visually-hidden">' . $this->t('Installed') . '</span>', 'class' => array('checkbox')),
+          array('data' => SafeMarkup::create('<span class="visually-hidden">' . $this->t('Installed') . '</span>'), 'class' => array('checkbox')),
           array('data' => $this->t('Name'), 'class' => array('name')),
           array('data' => $this->t('Description'), 'class' => array('description', RESPONSIVE_PRIORITY_LOW)),
         ),
diff --git a/core/modules/system/src/Form/ModulesUninstallForm.php b/core/modules/system/src/Form/ModulesUninstallForm.php
index 7438e48..b272148 100644
--- a/core/modules/system/src/Form/ModulesUninstallForm.php
+++ b/core/modules/system/src/Form/ModulesUninstallForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
diff --git a/core/modules/system/src/Tests/Common/FormatDateTest.php b/core/modules/system/src/Tests/Common/FormatDateTest.php
index 171b915..624b8e7 100644
--- a/core/modules/system/src/Tests/Common/FormatDateTest.php
+++ b/core/modules/system/src/Tests/Common/FormatDateTest.php
@@ -85,9 +85,9 @@ function testAdminDefinedFormatDate() {
     $this->assertText(t('Custom date format added.'));
 
     $timestamp = strtotime('2007-03-10T00:00:00+00:00');
-    $this->assertIdentical(format_date($timestamp, 'example_style', '', 'America/Los_Angeles'), '9 Mar 07', 'Test format_date() using an admin-defined date type.');
-    $this->assertIdentical(format_date($timestamp, 'example_style_uppercase', '', 'America/Los_Angeles'), '9 Mar 2007', 'Test format_date() using an admin-defined date type with different case.');
-    $this->assertIdentical(format_date($timestamp, 'undefined_style'), format_date($timestamp, 'fallback'), 'Test format_date() defaulting to `fallback` when $type not found.');
+    $this->assertIdentical((string) format_date($timestamp, 'example_style', '', 'America/Los_Angeles'), '9 Mar 07', 'Test format_date() using an admin-defined date type.');
+    $this->assertIdentical((string) format_date($timestamp, 'example_style_uppercase', '', 'America/Los_Angeles'), '9 Mar 2007', 'Test format_date() using an admin-defined date type with different case.');
+    $this->assertIdentical((string) format_date($timestamp, 'undefined_style'), (string) format_date($timestamp, 'fallback'), 'Test format_date() defaulting to `fallback` when $type not found.');
   }
 
   /**
@@ -99,12 +99,12 @@ function testFormatDate() {
     $language_interface = \Drupal::languageManager()->getCurrentLanguage();
 
     $timestamp = strtotime('2007-03-26T00:00:00+00:00');
-    $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', 'en'), 'Sunday, 25-Mar-07 17:00:00 PDT', 'Test all parameters.');
-    $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), 'domingo, 25-Mar-07 17:00:00 PDT', 'Test translated format.');
-    $this->assertIdentical(format_date($timestamp, 'custom', '\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), 'l, 25-Mar-07 17:00:00 PDT', 'Test an escaped format string.');
-    $this->assertIdentical(format_date($timestamp, 'custom', '\\\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), '\\domingo, 25-Mar-07 17:00:00 PDT', 'Test format containing backslash character.');
-    $this->assertIdentical(format_date($timestamp, 'custom', '\\\\\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), '\\l, 25-Mar-07 17:00:00 PDT', 'Test format containing backslash followed by escaped format string.');
-    $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'Europe/London', 'en'), 'Monday, 26-Mar-07 01:00:00 BST', 'Test a different time zone.');
+    $this->assertIdentical((string) format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', 'en'), 'Sunday, 25-Mar-07 17:00:00 PDT', 'Test all parameters.');
+    $this->assertIdentical((string) format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), 'domingo, 25-Mar-07 17:00:00 PDT', 'Test translated format.');
+    $this->assertIdentical((string) format_date($timestamp, 'custom', '\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), 'l, 25-Mar-07 17:00:00 PDT', 'Test an escaped format string.');
+    $this->assertIdentical((string) format_date($timestamp, 'custom', '\\\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), '\\domingo, 25-Mar-07 17:00:00 PDT', 'Test format containing backslash character.');
+    $this->assertIdentical((string) format_date($timestamp, 'custom', '\\\\\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), '\\l, 25-Mar-07 17:00:00 PDT', 'Test format containing backslash followed by escaped format string.');
+    $this->assertIdentical((string) format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'Europe/London', 'en'), 'Monday, 26-Mar-07 01:00:00 BST', 'Test a different time zone.');
 
     // Create an admin user and add Spanish language.
     $admin_user = $this->drupalCreateUser(array('administer languages'));
@@ -137,21 +137,21 @@ function testFormatDate() {
     // Simulate a Drupal bootstrap with the logged-in user.
     date_default_timezone_set(drupal_get_user_timezone());
 
-    $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', 'en'), 'Sunday, 25-Mar-07 17:00:00 PDT', 'Test a different language.');
-    $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'Europe/London'), 'Monday, 26-Mar-07 01:00:00 BST', 'Test a different time zone.');
-    $this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T'), 'domingo, 25-Mar-07 17:00:00 PDT', 'Test custom date format.');
-    $this->assertIdentical(format_date($timestamp, 'long'), 'domingo, 25. marzo 2007 - 17:00', 'Test long date format.');
-    $this->assertIdentical(format_date($timestamp, 'medium'), '25. marzo 2007 - 17:00', 'Test medium date format.');
-    $this->assertIdentical(format_date($timestamp, 'short'), '2007 Mar 25 - 5:00pm', 'Test short date format.');
-    $this->assertIdentical(format_date($timestamp), '25. marzo 2007 - 17:00', 'Test default date format.');
+    $this->assertIdentical((string) format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', 'en'), 'Sunday, 25-Mar-07 17:00:00 PDT', 'Test a different language.');
+    $this->assertIdentical((string) format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'Europe/London'), 'Monday, 26-Mar-07 01:00:00 BST', 'Test a different time zone.');
+    $this->assertIdentical((string) format_date($timestamp, 'custom', 'l, d-M-y H:i:s T'), 'domingo, 25-Mar-07 17:00:00 PDT', 'Test custom date format.');
+    $this->assertIdentical((string) format_date($timestamp, 'long'), 'domingo, 25. marzo 2007 - 17:00', 'Test long date format.');
+    $this->assertIdentical((string) format_date($timestamp, 'medium'), '25. marzo 2007 - 17:00', 'Test medium date format.');
+    $this->assertIdentical((string) format_date($timestamp, 'short'), '2007 Mar 25 - 5:00pm', 'Test short date format.');
+    $this->assertIdentical((string) format_date($timestamp), '25. marzo 2007 - 17:00', 'Test default date format.');
     // Test HTML time element formats.
-    $this->assertIdentical(format_date($timestamp, 'html_datetime'), '2007-03-25T17:00:00-0700', 'Test html_datetime date format.');
-    $this->assertIdentical(format_date($timestamp, 'html_date'), '2007-03-25', 'Test html_date date format.');
-    $this->assertIdentical(format_date($timestamp, 'html_time'), '17:00:00', 'Test html_time date format.');
-    $this->assertIdentical(format_date($timestamp, 'html_yearless_date'), '03-25', 'Test html_yearless_date date format.');
-    $this->assertIdentical(format_date($timestamp, 'html_week'), '2007-W12', 'Test html_week date format.');
-    $this->assertIdentical(format_date($timestamp, 'html_month'), '2007-03', 'Test html_month date format.');
-    $this->assertIdentical(format_date($timestamp, 'html_year'), '2007', 'Test html_year date format.');
+    $this->assertIdentical((string) format_date($timestamp, 'html_datetime'), '2007-03-25T17:00:00-0700', 'Test html_datetime date format.');
+    $this->assertIdentical((string) format_date($timestamp, 'html_date'), '2007-03-25', 'Test html_date date format.');
+    $this->assertIdentical((string) format_date($timestamp, 'html_time'), '17:00:00', 'Test html_time date format.');
+    $this->assertIdentical((string) format_date($timestamp, 'html_yearless_date'), '03-25', 'Test html_yearless_date date format.');
+    $this->assertIdentical((string) format_date($timestamp, 'html_week'), '2007-W12', 'Test html_week date format.');
+    $this->assertIdentical((string) format_date($timestamp, 'html_month'), '2007-03', 'Test html_month date format.');
+    $this->assertIdentical((string) format_date($timestamp, 'html_year'), '2007', 'Test html_year date format.');
 
     // Restore the original user and language, and enable session saving.
     $user = $real_user;
diff --git a/core/modules/system/src/Tests/Common/RenderTest.php b/core/modules/system/src/Tests/Common/RenderTest.php
index 8edbb07..1458a0f 100644
--- a/core/modules/system/src/Tests/Common/RenderTest.php
+++ b/core/modules/system/src/Tests/Common/RenderTest.php
@@ -277,7 +277,8 @@ function testDrupalRenderBasics() {
     );
 
     foreach($types as $type) {
-      $this->assertIdentical(drupal_render($type['value']), $type['expected'], '"' . $type['name'] . '" input rendered correctly by drupal_render().');
+      $value = drupal_render($type['value']);
+      $this->assertIdentical((string) $value, $type['expected'], '"' . $type['name'] . '" input rendered correctly by drupal_render().');
     }
   }
 
@@ -394,14 +395,14 @@ function testDrupalRenderThemeArguments() {
       '#theme' => 'common_test_foo',
     );
     // Test that defaults work.
-    $this->assertEqual(drupal_render($element), 'foobar', 'Defaults work');
+    $this->assertEqual((string) drupal_render($element), 'foobar', 'Defaults work');
     $element = array(
       '#theme' => 'common_test_foo',
       '#foo' => $this->randomName(),
       '#bar' => $this->randomName(),
     );
     // Tests that passing arguments to the theme function works.
-    $this->assertEqual(drupal_render($element), $element['#foo'] . $element['#bar'], 'Passing arguments to theme functions works');
+    $this->assertEqual((string) drupal_render($element), $element['#foo'] . $element['#bar'], 'Passing arguments to theme functions works');
   }
 
   /**
@@ -470,7 +471,7 @@ function testDrupalRenderPostRenderCache() {
     $element = $test_element;
     $element['#markup'] = '<p>#cache disabled</p>';
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.');
@@ -486,7 +487,7 @@ function testDrupalRenderPostRenderCache() {
     $element['#cache'] = array('cid' => 'post_render_cache_test_GET');
     $element['#markup'] = '<p>#cache enabled, GET</p>';
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertTrue(isset($element['#printed']), 'No cache hit');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -509,7 +510,7 @@ function testDrupalRenderPostRenderCache() {
     $element['#cache'] = array('cid' => 'post_render_cache_test_GET');
     $element['#markup'] = '<p>#cache enabled, GET</p>';
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertFalse(isset($element['#printed']), 'Cache hit');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -526,7 +527,7 @@ function testDrupalRenderPostRenderCache() {
     $element['#cache'] = array('cid' => 'post_render_cache_test_POST');
     $element['#markup'] = '<p>#cache enabled, POST</p>';
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertTrue(isset($element['#printed']), 'No cache hit');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -589,7 +590,7 @@ function testDrupalRenderChildrenPostRenderCache() {
     );
     $element = $test_element;
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertTrue(isset($element['#printed']), 'No cache hit');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -635,7 +636,7 @@ function testDrupalRenderChildrenPostRenderCache() {
     drupal_static_reset('_drupal_add_js');
     $element = $test_element;
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertFalse(isset($element['#printed']), 'Cache hit');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.');
@@ -647,7 +648,7 @@ function testDrupalRenderChildrenPostRenderCache() {
     unset($test_element['#cache']);
     $element = $test_element;
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $expected_settings = $context_1 + $context_2 + $context_3;
@@ -667,7 +668,7 @@ function testDrupalRenderChildrenPostRenderCache() {
     $element['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_parent');
     $element['child']['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_child');
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertTrue(isset($element['#printed']), 'No cache hit');
     $this->assertIdentical($element['#markup'], '<p>overridden</p>', '#markup is overridden.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -742,7 +743,7 @@ function testDrupalRenderChildrenPostRenderCache() {
     $element = $test_element;
     $element['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_parent');
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertFalse(isset($element['#printed']), 'Cache hit');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.');
@@ -754,7 +755,7 @@ function testDrupalRenderChildrenPostRenderCache() {
     $element['child']['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_child');
     $element = $element['child'];
     $output = drupal_render($element);
-    $this->assertIdentical($output, '<p>overridden</p>', 'Output is overridden.');
+    $this->assertIdentical((string) $output, '<p>overridden</p>', 'Output is overridden.');
     $this->assertFalse(isset($element['#printed']), 'Cache hit');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $expected_settings = $context_2 + $context_3;
@@ -790,7 +791,7 @@ function testDrupalRenderRenderCachePlaceholder() {
     drupal_static_reset('_drupal_add_js');
     $element = $test_element;
     $output = drupal_render($element);
-    $this->assertIdentical($output, $expected_output, 'Placeholder was replaced in output');
+    $this->assertIdentical((string) $output, $expected_output, 'Placeholder was replaced in output');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $this->assertIdentical($settings['common_test'], $context, '#attached is modified; JavaScript setting is added to page.');
 
@@ -803,7 +804,7 @@ function testDrupalRenderRenderCachePlaceholder() {
     $element = $test_element;
     $element['#cache'] = array('cid' => 'render_cache_placeholder_test_GET');
     $output = drupal_render($element);
-    $this->assertIdentical($output, $expected_output, 'Placeholder was replaced in output');
+    $this->assertIdentical((string) $output, $expected_output, 'Placeholder was replaced in output');
     $this->assertTrue(isset($element['#printed']), 'No cache hit');
     $this->assertIdentical($element['#markup'], $expected_output, 'Placeholder was replaced in #markup.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -840,7 +841,7 @@ function testDrupalRenderRenderCachePlaceholder() {
     $element = $test_element;
     $element['#cache'] = array('cid' => 'render_cache_placeholder_test_GET');
     $output = drupal_render($element);
-    $this->assertIdentical($output, $expected_output, 'Placeholder was replaced in output');
+    $this->assertIdentical((string) $output, $expected_output, 'Placeholder was replaced in output');
     $this->assertFalse(isset($element['#printed']), 'Cache hit');
     $this->assertIdentical($element['#markup'], $expected_output, 'Placeholder was replaced in #markup.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -880,7 +881,7 @@ function testDrupalRenderChildElementRenderCachePlaceholder() {
     drupal_static_reset('_drupal_add_js');
     $element = $container;
     $output = drupal_render($element);
-    $this->assertIdentical($output, $expected_output, 'Placeholder was replaced in output');
+    $this->assertIdentical((string) $output, $expected_output, 'Placeholder was replaced in output');
     $settings = $this->parseDrupalSettings(drupal_get_js());
     $this->assertIdentical($settings['common_test'], $context, '#attached is modified; JavaScript setting is added to page.');
 
@@ -899,7 +900,7 @@ function testDrupalRenderChildElementRenderCachePlaceholder() {
     $element['#children'] = drupal_render($child, TRUE);
     // Eventually, drupal_render() gets called on the root element.
     $output = drupal_render($element);
-    $this->assertIdentical($output, $expected_output, 'Placeholder was replaced in output');
+    $this->assertIdentical((string) $output, $expected_output, 'Placeholder was replaced in output');
     $this->assertTrue(isset($element['#printed']), 'No cache hit');
     $this->assertIdentical($element['#markup'], $expected_output, 'Placeholder was replaced in #markup.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
@@ -996,7 +997,7 @@ function testDrupalRenderChildElementRenderCachePlaceholder() {
     $child = &$element['test_element'];
     $element['#children'] = drupal_render($child, TRUE);
     $output = drupal_render($element);
-    $this->assertIdentical($output, $expected_output, 'Placeholder was replaced in output');
+    $this->assertIdentical((string) $output, $expected_output, 'Placeholder was replaced in output');
     $this->assertFalse(isset($element['#printed']), 'Cache hit');
     $this->assertIdentical($element['#markup'], $expected_output, 'Placeholder was replaced in #markup.');
     $settings = $this->parseDrupalSettings(drupal_get_js());
diff --git a/core/modules/system/src/Tests/Form/FormTest.php b/core/modules/system/src/Tests/Form/FormTest.php
index e45defc..ef001d7 100644
--- a/core/modules/system/src/Tests/Form/FormTest.php
+++ b/core/modules/system/src/Tests/Form/FormTest.php
@@ -143,7 +143,7 @@ function testRequiredFields() {
               // Select elements are going to have validation errors with empty
               // input, since those are illegal choices. Just make sure the
               // error is not "field is required".
-              $this->assertTrue((empty($errors[$element]) || strpos('field is required', $errors[$element]) === FALSE), "Optional '$type' field '$element' is not treated as a required element");
+              $this->assertTrue((empty($errors[$element]) || strpos('field is required', (string) $errors[$element]) === FALSE), "Optional '$type' field '$element' is not treated as a required element");
             }
             else {
               // Make sure there is *no* form error for this element.
diff --git a/core/modules/system/src/Tests/Menu/MenuTestBase.php b/core/modules/system/src/Tests/Menu/MenuTestBase.php
index d205b13..e66dcf9 100644
--- a/core/modules/system/src/Tests/Menu/MenuTestBase.php
+++ b/core/modules/system/src/Tests/Menu/MenuTestBase.php
@@ -65,7 +65,7 @@ protected function assertBreadcrumbParts($trail) {
       foreach ($trail as $path => $title) {
         $url = url($path);
         $part = array_shift($parts);
-        $pass = ($pass && $part['href'] === $url && $part['text'] === check_plain($title));
+        $pass = ($pass && $part['href'] === $url && $part['text'] === (string) check_plain($title));
       }
     }
     // No parts must be left, or an expected "Home" will always pass.
diff --git a/core/modules/system/src/Tests/Plugin/DerivativeTest.php b/core/modules/system/src/Tests/Plugin/DerivativeTest.php
index 8feeff6..b09b869 100644
--- a/core/modules/system/src/Tests/Plugin/DerivativeTest.php
+++ b/core/modules/system/src/Tests/Plugin/DerivativeTest.php
@@ -25,11 +25,11 @@ public static function getInfo() {
    */
   function testDerivativeDecorator() {
     // Ensure that getDefinitions() returns the expected definitions.
-    $this->assertIdentical($this->mockBlockManager->getDefinitions(), $this->mockBlockExpectedDefinitions);
+    $this->assertIdenticalArray($this->mockBlockManager->getDefinitions(), $this->mockBlockExpectedDefinitions);
 
     // Ensure that getDefinition() returns the expected definition.
     foreach ($this->mockBlockExpectedDefinitions as $id => $definition) {
-      $this->assertIdentical($this->mockBlockManager->getDefinition($id), $definition);
+      $this->assertIdenticalArray($this->mockBlockManager->getDefinition($id), $definition);
     }
 
     // Ensure that NULL is returned as the definition of a non-existing base
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 9ba1a1c..691e2ed 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -10,6 +10,7 @@
 use Drupal\Core\Extension\Extension;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Recursively check compatibility.
@@ -231,7 +232,7 @@ function theme_system_modules_details($variables) {
 
     // Add the module label and expand/collapse functionalty.
     $col2 = '<label id="module-' . $key . '" for="' . $module['enable']['#id'] . '" class="module-name table-filter-text-source">' . drupal_render($module['name']) . '</label>';
-    $row[] = array('class' => array('module'), 'data' => $col2);
+    $row[] = array('class' => array('module'), 'data' => SafeMarkup::create($col2));
 
     // Add the description, along with any modules it requires.
     $description = '';
@@ -259,9 +260,9 @@ function theme_system_modules_details($variables) {
     }
     $details = array(
       '#type' => 'details',
-      '#title' => '<span class="text"> ' . drupal_render($module['description']) . '</span>',
+      '#title' => SafeMarkup::create('<span class="text"> ' . drupal_render($module['description']) . '</span>'),
       '#attributes' => array('id' => $module['enable']['#id'] . '-description'),
-      '#description' => $description,
+      '#description' => SafeMarkup::create($description),
     );
     $col4 = drupal_render($details);
     $row[] = array('class' => array('description', 'expand'), 'data' => $col4);
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 6161819..8033348 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -11,6 +11,7 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\Site\Settings;
 use Drupal\Core\StreamWrapper\PublicStream;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Implements hook_requirements().
@@ -57,7 +58,8 @@ function system_requirements($phase) {
   if (function_exists('phpinfo')) {
     $requirements['php'] = array(
       'title' => t('PHP'),
-      'value' => ($phase == 'runtime') ? $phpversion .' ('. l(t('more information'), 'admin/reports/status/php') .')' : $phpversion,
+      // $phpversion is safe and output of l() is safe, so this value is safe.
+      'value' => SafeMarkup::create(($phase == 'runtime') ? $phpversion . ' (' . l(t('more information'), 'admin/reports/status/php') . ')' : $phpversion),
     );
   }
   else {
@@ -319,7 +321,8 @@ function system_requirements($phase) {
       'title' => t('Cron maintenance tasks'),
       'severity' => $severity,
       'value' => $summary,
-      'description' => $description
+      // @todo Needs to preserve safe markup.
+      'description' => SafeMarkup::create($description),
     );
   }
   if ($phase != 'install') {
diff --git a/core/modules/system/templates/block--system-branding-block.html.twig b/core/modules/system/templates/block--system-branding-block.html.twig
index 2a12c7a..4cf0f1a 100644
--- a/core/modules/system/templates/block--system-branding-block.html.twig
+++ b/core/modules/system/templates/block--system-branding-block.html.twig
@@ -23,7 +23,7 @@
   {% endif %}
   {% if site_name %}
     <div class="site-name">
-      <a href="{{ url('<front>') }}" title="{{ 'Home'|t }}" rel="home">{{ site_name|e }}</a>
+      <a href="{{ url('<front>') }}" title="{{ 'Home'|t }}" rel="home">{{ site_name }}</a>
     </div>
   {% endif %}
   {% if site_slogan %}
diff --git a/core/modules/system/templates/datetime.html.twig b/core/modules/system/templates/datetime.html.twig
index 25ef788..183b834 100644
--- a/core/modules/system/templates/datetime.html.twig
+++ b/core/modules/system/templates/datetime.html.twig
@@ -25,5 +25,4 @@
  * @see http://www.w3.org/TR/html5-author/the-time-element.html#attr-time-datetime
  */
 #}
-{# @todo Revisit once http://drupal.org/node/1825952 is resolved. #}
-<time{{ attributes }}>{{ html ? text|raw : text|escape }}</time>
+<time{{ attributes }}>{{ html ? text|raw : text }}</time>
diff --git a/core/modules/system/templates/system-themes-page.html.twig b/core/modules/system/templates/system-themes-page.html.twig
index fa0e748..caf38c2 100644
--- a/core/modules/system/templates/system-themes-page.html.twig
+++ b/core/modules/system/templates/system-themes-page.html.twig
@@ -39,7 +39,7 @@
             <h3>
               {{- theme.name }} {{ theme.version -}}
               {% if theme.notes %}
-                ({{ theme.notes|join(', ') }})
+                ({{ theme.notes|join(', ')|raw }})
               {%- endif -%}
             </h3>
             <div class="theme-description">{{ theme.description }}</div>
diff --git a/core/modules/system/tests/themes/test_theme/templates/theme-test-specific-suggestions--variant--foo.html.twig b/core/modules/system/tests/themes/test_theme/templates/theme-test-specific-suggestions--variant--foo.html.twig
index 7e0b485..6510784 100644
--- a/core/modules/system/tests/themes/test_theme/templates/theme-test-specific-suggestions--variant--foo.html.twig
+++ b/core/modules/system/tests/themes/test_theme/templates/theme-test-specific-suggestions--variant--foo.html.twig
@@ -2,4 +2,4 @@
 Template overridden based on suggestion alter hook determined by the base hook.
 
 <p>Theme hook suggestions:
-{{ theme_hook_suggestions|join("<br />") }}</p>
+{{ theme_hook_suggestions|join("<br />")|raw }}</p>
diff --git a/core/modules/system/tests/themes/test_theme/templates/theme-test-specific-suggestions--variant.html.twig b/core/modules/system/tests/themes/test_theme/templates/theme-test-specific-suggestions--variant.html.twig
index 655db4e..92f70d8 100644
--- a/core/modules/system/tests/themes/test_theme/templates/theme-test-specific-suggestions--variant.html.twig
+++ b/core/modules/system/tests/themes/test_theme/templates/theme-test-specific-suggestions--variant.html.twig
@@ -2,4 +2,4 @@
 Template matching the specific theme call.
 
 <p>Theme hook suggestions:
-{{ theme_hook_suggestions|join("<br />") }}</p>
+{{ theme_hook_suggestions|join("<br />")|raw }}</p>
diff --git a/core/modules/text/src/TextProcessed.php b/core/modules/text/src/TextProcessed.php
index 5d99de3..ef885b9 100644
--- a/core/modules/text/src/TextProcessed.php
+++ b/core/modules/text/src/TextProcessed.php
@@ -8,6 +8,7 @@
 namespace Drupal\text;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\TypedData\DataDefinitionInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\TypedData\TypedData;
@@ -59,7 +60,7 @@ public function getValue($langcode = NULL) {
     else {
       // Escape all HTML and retain newlines.
       // @see \Drupal\Core\Field\Plugin\Field\FieldFormatter\StringFormatter
-      $this->processed = nl2br(String::checkPlain($text));
+      $this->processed = SafeMarkup::create(nl2br(String::checkPlain($text)));
     }
     return $this->processed;
   }
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index eb77313..814128c 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -12,6 +12,7 @@
  */
 
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -536,7 +537,8 @@ function _update_message_text($msg_type, $msg_reason, $report_link = FALSE, $lan
     }
   }
 
-  return $text;
+  // All strings are t() and empty space concatinated so return SafeMarkup.
+  return SafeMarkup::create($text);
 }
 
 /**
diff --git a/core/modules/user/src/Tests/UserCancelTest.php b/core/modules/user/src/Tests/UserCancelTest.php
index edd4ea1..5c15c77 100644
--- a/core/modules/user/src/Tests/UserCancelTest.php
+++ b/core/modules/user/src/Tests/UserCancelTest.php
@@ -452,7 +452,7 @@ function testMassUserCancelByAdmin() {
     $this->drupalPostForm(NULL, NULL, t('Cancel accounts'));
     $status = TRUE;
     foreach ($users as $account) {
-      $status = $status && (strpos($this->content, t('%name has been deleted.', array('%name' => $account->getUsername()))) !== FALSE);
+      $status = $status && (strpos($this->content, (string) t('%name has been deleted.', array('%name' => $account->getUsername()))) !== FALSE);
       $status = $status && !user_load($account->id(), TRUE);
     }
     $this->assertTrue($status, 'Users deleted and not found in the database.');
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 4b28c81..23a85dd 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -6,6 +6,7 @@
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AnonymousUserSession;
 use \Drupal\Core\Entity\Display\EntityViewDisplayInterface;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\Core\Url;
 use Drupal\file\Entity\File;
 use Drupal\user\Entity\Role;
@@ -692,7 +693,7 @@ function theme_username($variables) {
     // We have a link path, so we should generate a link using l().
     // Additional classes may be added as array elements like
     // $variables['link_options']['attributes']['class'][] = 'myclass';
-    $output = l($variables['name'] . $variables['extra'], $variables['link_path'], $variables['link_options']);
+    $output = l(SafeMarkup::create($variables['name'] . $variables['extra']), $variables['link_path'], $variables['link_options']);
   }
   else {
     // Modules may have added important attributes so they must be included
diff --git a/core/modules/views/src/Plugin/views/HandlerBase.php b/core/modules/views/src/Plugin/views/HandlerBase.php
index cbff847..cd6ffa5 100644
--- a/core/modules/views/src/Plugin/views/HandlerBase.php
+++ b/core/modules/views/src/Plugin/views/HandlerBase.php
@@ -236,7 +236,7 @@ public function getField($field = NULL) {
    * @param $type
    *   The type of sanitization needed. If not provided, String::checkPlain() is used.
    *
-   * @return string
+   * @return \Drupal\Core\Template\SafeMarkup|string
    *   Returns the safe value.
    */
   public function sanitizeValue($value, $type = NULL) {
diff --git a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php
index 6f0add5..9af6b70 100644
--- a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php
+++ b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php
@@ -51,13 +51,13 @@ public function tokenForm(&$form, &$form_state) {
     // Get a list of the available fields and arguments for token replacement.
     $options = array();
     foreach ($this->view->display_handler->getHandlers('field') as $field => $handler) {
-      $options[t('Fields')]["[$field]"] = $handler->adminLabel();
+      $options[(string) t('Fields')]["[$field]"] = $handler->adminLabel();
     }
 
     $count = 0; // This lets us prepare the key as we want it printed.
     foreach ($this->view->display_handler->getHandlers('argument') as $handler) {
-      $options[t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->adminLabel()));
-      $options[t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->adminLabel()));
+      $options[(string) t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->adminLabel()));
+      $options[(string) t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->adminLabel()));
     }
 
     if (!empty($options)) {
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
index b960d5b..c40a3c7 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -1732,8 +1732,8 @@ public function buildOptionsForm(&$form, &$form_state) {
         $options = array();
         $count = 0; // This lets us prepare the key as we want it printed.
         foreach ($this->view->display_handler->getHandlers('argument') as $handler) {
-          $options[t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->adminLabel()));
-          $options[t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->adminLabel()));
+          $options[(string) t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->adminLabel()));
+          $options[(string) t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->adminLabel()));
         }
 
         // Default text.
diff --git a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
index 5eb5765..7ac8b6b 100644
--- a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
+++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
@@ -11,6 +11,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\views\Plugin\views\HandlerBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ResultRow;
@@ -850,18 +851,18 @@ public function buildOptionsForm(&$form, &$form_state) {
       // Setup the tokens for fields.
       $previous = $this->getPreviousFieldLabels();
       foreach ($previous as $id => $label) {
-        $options[t('Fields')]["[$id]"] = $label;
+        $options[(string) t('Fields')]["[$id]"] = $label;
       }
       // Add the field to the list of options.
-      $options[t('Fields')]["[{$this->options['id']}]"] = $this->label();
+      $options[(string) t('Fields')]["[{$this->options['id']}]"] = $this->label();
 
       $count = 0; // This lets us prepare the key as we want it printed.
       foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
-        $options[t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->adminLabel()));
-        $options[t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->adminLabel()));
+        $options[(string) t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->adminLabel()));
+        $options[(string) t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->adminLabel()));
       }
 
-      $this->documentSelfTokens($options[t('Fields')]);
+      $this->documentSelfTokens($options[(string) t('Fields')]);
 
       // Default text.
       $output = '<p>' . t('You must add some additional fields to this display before using this field. These fields may be marked as <em>Exclude from display</em> if you prefer. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.') . '</p>';
@@ -890,7 +891,7 @@ public function buildOptionsForm(&$form, &$form_state) {
       $form['alter']['help'] = array(
         '#type' => 'details',
         '#title' => t('Replacement patterns'),
-        '#value' => $output,
+        '#value' => SafeMarkup::create($output),
         '#states' => array(
           'visible' => array(
             array(
@@ -1172,6 +1173,10 @@ public function advancedRender(ResultRow $values) {
         $this->last_render = $this->renderText($alter);
       }
     }
+    // @TODO: this is very dicey!
+    if ($this->last_render && is_string($this->last_render)) {
+      $this->last_render = SafeMarkup::create($this->last_render);
+    }
 
     return $this->last_render;
   }
diff --git a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
index 902b543..42b8d0b 100644
--- a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
+++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
@@ -1159,8 +1159,7 @@ protected function prepareFilterSelectOptions(&$options) {
         $this->prepareFilterSelectOptions($options[$value]);
       }
       // FAPI has some special value to allow hierarchy.
-      // @see _form_options_flatten
-      elseif (is_object($label)) {
+      elseif (is_object($label) && isset($options[$value]->option)) {
         $this->prepareFilterSelectOptions($options[$value]->option);
       }
       else {
diff --git a/core/modules/views/src/Plugin/views/relationship/GroupwiseMax.php b/core/modules/views/src/Plugin/views/relationship/GroupwiseMax.php
index 7a85bbc..673869b 100644
--- a/core/modules/views/src/Plugin/views/relationship/GroupwiseMax.php
+++ b/core/modules/views/src/Plugin/views/relationship/GroupwiseMax.php
@@ -130,10 +130,10 @@ public function buildOptionsForm(&$form, &$form_state) {
         // TODO: check the field is the correct sort?
         // or let users hang themselves at this stage and check later?
         if ($view->type == 'Default') {
-          $views[t('Default Views')][$view->storage->id()] = $view->storage->id();
+          $views[(string) t('Default Views')][$view->storage->id()] = $view->storage->id();
         }
         else {
-          $views[t('Existing Views')][$view->storage->id()] = $view->storage->id();
+          $views[(string) t('Existing Views')][$view->storage->id()] = $view->storage->id();
         }
       }
     }
diff --git a/core/modules/views/src/Tests/ViewsTaxonomyAutocompleteTest.php b/core/modules/views/src/Tests/ViewsTaxonomyAutocompleteTest.php
index 766ae49..5361dec 100644
--- a/core/modules/views/src/Tests/ViewsTaxonomyAutocompleteTest.php
+++ b/core/modules/views/src/Tests/ViewsTaxonomyAutocompleteTest.php
@@ -83,7 +83,7 @@ public function testTaxonomyAutocomplete() {
     $label = $this->term1->getName();
     $expected = array(array(
       'value' => $label,
-      'label' => String::checkPlain($label),
+      'label' => (string) String::checkPlain($label),
     ));
     $this->assertIdentical($expected, $this->drupalGetJSON($base_autocomplete_path, array('query' => array('q' => $label))));
     // Test a term by partial name.
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 216bc93..5a93d2e 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -14,6 +14,7 @@
 use Drupal\Core\Database\Query\AlterableInterface;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\views\Plugin\Derivative\ViewsLocalTask;
 use Drupal\Core\Template\AttributeArray;
 use Drupal\views\ViewExecutable;
@@ -903,7 +904,7 @@ function views_pre_render_views_form_views_form($element) {
   }
 
   // Apply substitutions to the rendered output.
-  $element['output']['#markup'] = str_replace($search, $replace, $element['output']['#markup']);
+  $element['output']['#markup'] = SafeMarkup::strReplace($search, $replace, $element['output']['#markup']);
 
   // Sort, render and add remaining form fields.
   $children = Element::children($element, TRUE);
diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc
index 86e3e85..93493da 100644
--- a/core/modules/views/views.theme.inc
+++ b/core/modules/views/views.theme.inc
@@ -9,6 +9,7 @@
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\views\Form\ViewsForm;
 use Drupal\views\ViewExecutable;
 
@@ -525,6 +526,7 @@ function template_preprocess_views_view_table(&$variables) {
 
     // Render the header labels.
     if ($field == $column && empty($fields[$field]->options['exclude'])) {
+      $safe = TRUE;
       $label = String::checkPlain(!empty($fields[$field]) ? $fields[$field]->label() : '');
       if (empty($options['info'][$field]['sortable']) || !$fields[$field]->clickSortable()) {
         $variables['header'][$field]['content'] = $label;
@@ -542,7 +544,10 @@ function template_preprocess_views_view_table(&$variables) {
             '#theme' => 'tablesort_indicator',
             '#style' => $initial,
           );
-          $label .= drupal_render($tablesort_indicator);
+          $markup = drupal_render($tablesort_indicator);
+          // $label is safe.
+          $safe = $markup instanceof SafeMarkup;
+          $label .= $markup;
         }
 
         $query['order'] = $field;
@@ -552,7 +557,7 @@ function template_preprocess_views_view_table(&$variables) {
           'attributes' => array('title' => $title),
           'query' => $query,
         );
-        $variables['header'][$field]['content'] = l($label, current_path(), $link_options);
+        $variables['header'][$field]['content'] = l($safe ? SafeMarkup::create($label) : $label, current_path(), $link_options);
       }
 
       // Set up the header label class.
@@ -633,7 +638,7 @@ function template_preprocess_views_view_table(&$variables) {
         $field_output = $handler->getField($num, $field);
         $element_type = $fields[$field]->elementType(TRUE, TRUE);
         if ($element_type) {
-          $field_output = '<' . $element_type . '>' . $field_output . '</' . $element_type . '>';
+          $field_output = SafeMarkup::concat(SafeMarkup::create('<' . $element_type . '>'), $field_output, SafeMarkup::create('</' . $element_type . '>'));
         }
 
         // Only bother with separators and stuff if the field shows up.
@@ -641,13 +646,13 @@ function template_preprocess_views_view_table(&$variables) {
           // Place the field into the column, along with an optional separator.
           if (!empty($column_reference['content'])) {
             if (!empty($options['info'][$column]['separator'])) {
-              $column_reference['content'] .= Xss::filterAdmin($options['info'][$column]['separator']);
+              $column_reference['content'] = SafeMarkup::concat($column_reference['content'], Xss::filterAdmin($options['info'][$column]['separator']));
             }
           }
           else {
             $column_reference['content'] = '';
           }
-          $column_reference['content'] .= $field_output;
+          $column_reference['content'] = SafeMarkup::concat($column_reference['content'], $field_output);
         }
       }
       $column_reference['attributes'] = new Attribute($column_reference['attributes']);
diff --git a/core/modules/views_ui/admin.inc b/core/modules/views_ui/admin.inc
index e90ef35..3fe9789 100644
--- a/core/modules/views_ui/admin.inc
+++ b/core/modules/views_ui/admin.inc
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Tags;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Views;
@@ -89,16 +90,18 @@ function views_ui_add_ajax_trigger(&$wrapping_element, $trigger_key, $refresh_pa
   // always give the button a unique #value, rather than playing around with
   // #name.
   $button_title = !empty($triggering_element['#title']) ? $triggering_element['#title'] : $trigger_key;
-  if (empty($seen_buttons[$button_title])) {
-    $wrapping_element[$button_key]['#value'] = t('Update "@title" choice', array(
+  $button_title_string = (string) $button_title;
+  if (empty($seen_buttons[$button_title_string])) {
+    // This code relies on check_plain()'ing the string because of the quotes.
+    $wrapping_element[$button_key]['#value'] = (string) t('Update "@title" choice', array(
       '@title' => $button_title,
     ));
-    $seen_buttons[$button_title] = 1;
+    $seen_buttons[$button_title_string] = 1;
   }
   else {
-    $wrapping_element[$button_key]['#value'] = t('Update "@title" choice (@number)', array(
+    $wrapping_element[$button_key]['#value'] = (string) t('Update "@title" choice (@number)', array(
       '@title' => $button_title,
-      '@number' => ++$seen_buttons[$button_title],
+      '@number' => ++$seen_buttons[$button_title_string],
     ));
   }
 
diff --git a/core/modules/views_ui/src/Controller/ViewsUIController.php b/core/modules/views_ui/src/Controller/ViewsUIController.php
index a09b063..735c95d 100644
--- a/core/modules/views_ui/src/Controller/ViewsUIController.php
+++ b/core/modules/views_ui/src/Controller/ViewsUIController.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Utility\String;
 use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\views\ViewExecutable;
 use Drupal\views\ViewStorageInterface;
 use Drupal\views\Views;
@@ -92,7 +93,7 @@ public function reportFields() {
       foreach ($views as $view) {
         $rows[$field_name]['data'][1][] = $this->l($view, 'views_ui.edit', array('view' => $view));
       }
-      $rows[$field_name]['data'][1] = implode(', ', $rows[$field_name]['data'][1]);
+      $rows[$field_name]['data'][1] = SafeMarkup::implode(', ', $rows[$field_name]['data'][1]);
     }
 
     // Sort rows by field name.
@@ -120,7 +121,7 @@ public function reportPlugins() {
       foreach ($row['views'] as $row_name => $view) {
         $row['views'][$row_name] = $this->l($view, 'views_ui.edit', array('view' => $view));
       }
-      $row['views'] = implode(', ', $row['views']);
+      $row['views'] = SafeMarkup::implode(', ', $row['views']);
     }
 
     // Sort rows by field name.
diff --git a/core/modules/views_ui/src/Tests/HandlerTest.php b/core/modules/views_ui/src/Tests/HandlerTest.php
index 5a00b03..8963c42 100644
--- a/core/modules/views_ui/src/Tests/HandlerTest.php
+++ b/core/modules/views_ui/src/Tests/HandlerTest.php
@@ -159,11 +159,11 @@ public function testBrokenHandlers() {
 
       $text = t('Broken/missing handler (Module: @module) …', array('@module' => 'views'));
 
-      $this->assertIdentical((string) $result[0], $text, 'Ensure the broken handler text was found.');
+      $this->assertIdentical((string) $result[0], (string) $text, 'Ensure the broken handler text was found.');
 
       $this->drupalGet($href);
       $result = $this->xpath('//h1');
-      $this->assertTrue(strpos((string) $result[0], $text) !== FALSE, 'Ensure the broken handler text was found.');
+      $this->assertTrue(strpos((string) $result[0], (string) $text) !== FALSE, 'Ensure the broken handler text was found.');
 
       $description_args = array(
         '@module' => 'views',
@@ -193,11 +193,11 @@ public function testOptionalHandlers() {
 
       $text = t('Optional handler is missing (Module: @module) …', array('@module' => 'views'));
 
-      $this->assertIdentical((string) $result[0], $text, 'Ensure the optional handler link text was found.');
+      $this->assertIdentical((string) $result[0], (string) $text, 'Ensure the optional handler link text was found.');
 
       $this->drupalGet($href);
       $result = $this->xpath('//h1');
-      $this->assertTrue(strpos((string) $result[0], $text) !== FALSE, 'Ensure the optional handler title was found.');
+      $this->assertTrue(strpos((string) $result[0], (string) $text) !== FALSE, 'Ensure the optional handler title was found.');
 
       $description_args = array(
         '@module' => 'views',
diff --git a/core/modules/views_ui/src/ViewListBuilder.php b/core/modules/views_ui/src/ViewListBuilder.php
index 68ad5b0..8cb3fc6 100644
--- a/core/modules/views_ui/src/ViewListBuilder.php
+++ b/core/modules/views_ui/src/ViewListBuilder.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Template\SafeMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -96,7 +97,7 @@ public function buildRow(EntityInterface $view) {
           'class' => array('views-table-filter-text-source'),
         ),
         'tag' => $view->get('tag'),
-        'path' => implode(', ', $this->getDisplayPaths($view)),
+        'path' => SafeMarkup::implode(', ', $this->getDisplayPaths($view)),
         'operations' => $row['operations'],
       ),
       'title' => $this->t('Machine name: @name', array('@name' => $view->id())),
@@ -230,7 +231,7 @@ protected function getDisplaysList(EntityInterface $view) {
     foreach ($view->get('display') as $display) {
       $definition = $this->displayManager->getDefinition($display['display_plugin']);
       if (!empty($definition['admin'])) {
-        $displays[$definition['admin']] = TRUE;
+        $displays[(string) $definition['admin']] = TRUE;
       }
     }
 
diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php
index 52d99b2..5ecce05 100644
--- a/core/modules/views_ui/src/ViewUI.php
+++ b/core/modules/views_ui/src/ViewUI.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Timer;
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Template\SafeMarkup;
 use Drupal\views\Views;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\views\ViewExecutable;
@@ -202,7 +203,7 @@ public function set($property_name, $value, $notify = TRUE) {
   }
 
   public static function getDefaultAJAXMessage() {
-    return '<div class="message">' . t("Click on an item to edit that item's details.") . '</div>';
+    return SafeMarkup::create('<div class="message">' . t("Click on an item to edit that item's details.") . '</div>');
   }
 
   /**
@@ -677,7 +678,10 @@ public function renderPreview($display_id, $args = array()) {
                 }
               }
             }
-            $rows['query'][] = array('<strong>' . t('Query') . '</strong>', '<pre>' . String::checkPlain(strtr($query_string, $quoted)) . '</pre>');
+            $rows['query'][] = array(
+              SafeMarkup::create('<strong>' . t('Query') . '</strong>'),
+              SafeMarkup::create('<pre>' . String::checkPlain(strtr($query_string, $quoted)) . '</pre>'),
+            );
             if (!empty($this->additionalQueries)) {
               $queries = '<strong>' . t('These queries were run during view rendering:') . '</strong>';
               foreach ($this->additionalQueries as $query) {
@@ -688,18 +692,24 @@ public function renderPreview($display_id, $args = array()) {
                 $queries .= t('[@time ms] @query', array('@time' => round($query['time'] * 100000, 1) / 100000.0, '@query' => $query_string));
               }
 
-              $rows['query'][] = array('<strong>' . t('Other queries') . '</strong>', '<pre>' . $queries . '</pre>');
+              $rows['query'][] = array(
+                SafeMarkup::create('<strong>' . t('Other queries') . '</strong>'),
+                SafeMarkup::create('<pre>' . $queries . '</pre>'),
+              );
             }
           }
           if ($show_info) {
-            $rows['query'][] = array('<strong>' . t('Title') . '</strong>', Xss::filterAdmin($this->executable->getTitle()));
+            $rows['query'][] = array(
+              SafeMarkup::create('<strong>' . t('Title') . '</strong>'),
+              Xss::filterAdmin($this->executable->getTitle()),
+            );
             if (isset($path)) {
               $path = l($path, $path);
             }
             else {
               $path = t('This display has no path.');
             }
-            $rows['query'][] = array('<strong>' . t('Path') . '</strong>', $path);
+            $rows['query'][] = array(SafeMarkup::create('<strong>' . t('Path') . '</strong>'), $path);
           }
 
           if ($show_stats) {
@@ -714,10 +724,10 @@ public function renderPreview($display_id, $args = array()) {
           // No query was run. Display that information in place of either the
           // query or the performance statistics, whichever comes first.
           if ($combined || ($show_location === 'above')) {
-            $rows['query'] = array(array('<strong>' . t('Query') . '</strong>', t('No query was run')));
+            $rows['query'] = array(array(SafeMarkup::create('<strong>' . t('Query') . '</strong>'), t('No query was run')));
           }
           else {
-            $rows['statistics'] = array(array('<strong>' . t('Query') . '</strong>', t('No query was run')));
+            $rows['statistics'] = array(array(SafeMarkup::create('<strong>' . t('Query') . '</strong>'), t('No query was run')));
           }
         }
       }
diff --git a/core/modules/views_ui/templates/views-ui-display-tab-setting.html.twig b/core/modules/views_ui/templates/views-ui-display-tab-setting.html.twig
index 1c67469..4659514 100644
--- a/core/modules/views_ui/templates/views-ui-display-tab-setting.html.twig
+++ b/core/modules/views_ui/templates/views-ui-display-tab-setting.html.twig
@@ -20,6 +20,7 @@
     <span class="label">{{ description }}</span>
   {%- endif %}
   {% if settings_links %}
-    {{ settings_links|join('<span class="label">&nbsp;|&nbsp;</span>') }}
+    {# @todo Need to identify a way to figure out how to remove |raw #}
+    {{ settings_links|join('<span class="label">&nbsp;|&nbsp;</span>')|raw }}
   {% endif %}
 </div>
diff --git a/core/modules/views_ui/views_ui.theme.inc b/core/modules/views_ui/views_ui.theme.inc
index 430f14a..4e31357 100644
--- a/core/modules/views_ui/views_ui.theme.inc
+++ b/core/modules/views_ui/views_ui.theme.inc
@@ -7,6 +7,7 @@
 
 use Drupal\Core\Render\Element;
 use Drupal\Core\Template\Attribute;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Prepares variables for Views UI display tab setting templates.
@@ -88,7 +89,7 @@ function template_preprocess_views_ui_display_tab_bucket(&$variables) {
  */
 function template_preprocess_views_ui_view_info(&$variables) {
   $variables['title'] = $variables['view']->label();
-  $variables['displays'] = empty($variables['displays']) ? t('None') : format_plural(count($variables['displays']), 'Display', 'Displays') . ': ' . '<em>' . implode(', ', $variables['displays']) . '</em>';
+  $variables['displays'] = empty($variables['displays']) ? t('None') : SafeMarkup::create(format_plural(count($variables['displays']), 'Display', 'Displays') . ': ' . '<em>' . SafeMarkup::implode(', ', $variables['displays']) . '</em>');
 }
 
 /**
diff --git a/core/themes/bartik/templates/block--system-branding-block.html.twig b/core/themes/bartik/templates/block--system-branding-block.html.twig
index 5917f58..f6147a6 100644
--- a/core/themes/bartik/templates/block--system-branding-block.html.twig
+++ b/core/themes/bartik/templates/block--system-branding-block.html.twig
@@ -23,7 +23,7 @@
     <div class="site-branding-text">
       {% if site_name %}
         <strong class="site-name">
-          <a href="{{ url('<front>') }}" title="{{ 'Home'|t }}" rel="home">{{ site_name|e }}</a>
+          <a href="{{ url('<front>') }}" title="{{ 'Home'|t }}" rel="home">{{ site_name }}</a>
         </strong>
       {% endif %}
       {% if site_slogan %}
diff --git a/core/themes/engines/twig/twig.engine b/core/themes/engines/twig/twig.engine
index 1595bf8..b6e3e02 100644
--- a/core/themes/engines/twig/twig.engine
+++ b/core/themes/engines/twig/twig.engine
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Extension\Extension;
+use Drupal\Core\Template\SafeMarkup;
 
 /**
  * Implements hook_theme().
@@ -45,6 +46,7 @@ function twig_init(Extension $theme) {
  *   The output generated by the template, plus any debug information.
  */
 function twig_render_template($template_file, $variables) {
+  /** @var \Twig_Environment $twig_service */
   $twig_service = \Drupal::service('twig');
   $output = array(
     'debug_prefix'    => '',
@@ -93,7 +95,7 @@ function twig_render_template($template_file, $variables) {
     $output['debug_info']   .= "\n<!-- BEGIN OUTPUT from '{$template_file}' -->\n";
     $output['debug_suffix'] .= "\n<!-- END OUTPUT from '{$template_file}' -->\n\n";
   }
-  return implode('', $output);
+  return SafeMarkup::create(implode('', $output));
 }
 
 /**
diff --git a/core/vendor/twig/twig/lib/Twig/Extension/Core.php b/core/vendor/twig/twig/lib/Twig/Extension/Core.php
index 4e80c67..396a9f3 100644
--- a/core/vendor/twig/twig/lib/Twig/Extension/Core.php
+++ b/core/vendor/twig/twig/lib/Twig/Extension/Core.php
@@ -922,7 +922,12 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html',
 
     if (!is_string($string)) {
         if (is_object($string) && method_exists($string, '__toString')) {
-            $string = (string) $string;
+            // @todo Move to twig engine. This is necessary because of
+            // RenderWrapper.
+            $string = $string->__toString();
+            if ($autoescape && $string instanceof Twig_Markup) {
+              return $string;
+            }
         } else {
             return $string;
         }
