diff --git a/src/libslic3r/ExPolygonCollection.hpp b/src/libslic3r/ExPolygonCollection.hpp
index 4c181cd6a..099a6a112 100644
--- a/src/libslic3r/ExPolygonCollection.hpp
+++ b/src/libslic3r/ExPolygonCollection.hpp
@@ -13,12 +13,12 @@ typedef std::vector<ExPolygonCollection> ExPolygonCollections;
 
 class ExPolygonCollection
 {
-    public:
+public:
     ExPolygons expolygons;
     
-    ExPolygonCollection() {};
+    ExPolygonCollection() {}
     ExPolygonCollection(const ExPolygon &expolygon);
-    ExPolygonCollection(const ExPolygons &expolygons) : expolygons(expolygons) {};
+    ExPolygonCollection(const ExPolygons &expolygons) : expolygons(expolygons) {}
     operator Points() const;
     operator Polygons() const;
     operator ExPolygons&();
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index efcf15ad5..65264c9cd 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -117,11 +117,11 @@ Polygons AvoidCrossingPerimeters::collect_contours_all_layers(const PrintObjectP
                      const Layer* layer1 = object->layers()[i * 2];
                      const Layer* layer2 = object->layers()[i * 2 + 1];
                      Polygons polys;
-                     polys.reserve(layer1->slices.expolygons.size() + layer2->slices.expolygons.size());
-                    for (const ExPolygon &expoly : layer1->slices.expolygons)
+                     polys.reserve(layer1->slices.size() + layer2->slices.size());
+                    for (const ExPolygon &expoly : layer1->slices)
                         //FIXME no holes?
                         polys.emplace_back(expoly.contour);
-                    for (const ExPolygon &expoly : layer2->slices.expolygons)
+                    for (const ExPolygon &expoly : layer2->slices)
                         //FIXME no holes?
                         polys.emplace_back(expoly.contour);
                      polygons_per_layer[i] = union_(polys);
@@ -130,8 +130,8 @@ Polygons AvoidCrossingPerimeters::collect_contours_all_layers(const PrintObjectP
          if (object->layers().size() & 1) {
             const Layer *layer = object->layers().back();
             Polygons polys;
-            polys.reserve(layer->slices.expolygons.size());
-            for (const ExPolygon &expoly : layer->slices.expolygons)
+            polys.reserve(layer->slices.size());
+            for (const ExPolygon &expoly : layer->slices)
                 //FIXME no holes?
                 polys.emplace_back(expoly.contour);
              polygons_per_layer.back() = union_(polys);
@@ -1802,11 +1802,8 @@ void GCode::process_layer(
             // - for each island, we extrude perimeters first, unless user set the infill_first
             //   option
             // (Still, we have to keep track of regions because we need to apply their config)
-            size_t n_slices = layer.slices.expolygons.size();
-            std::vector<BoundingBox> layer_surface_bboxes;
-            layer_surface_bboxes.reserve(n_slices);
-            for (const ExPolygon &expoly : layer.slices.expolygons)
-                layer_surface_bboxes.push_back(get_extents(expoly.contour));
+            size_t n_slices = layer.slices.size();
+            const std::vector<BoundingBox> &layer_surface_bboxes = layer.slices_bboxes;
             // Traverse the slices in an increasing order of bounding box size, so that the islands inside another islands are tested first,
             // so we can just test a point inside ExPolygon::contour and we may skip testing the holes.
             std::vector<size_t> slices_test_order;
@@ -1822,7 +1819,7 @@ void GCode::process_layer(
                 const BoundingBox &bbox = layer_surface_bboxes[i];
                 return point(0) >= bbox.min(0) && point(0) < bbox.max(0) &&
                        point(1) >= bbox.min(1) && point(1) < bbox.max(1) &&
-                       layer.slices.expolygons[i].contour.contains(point);
+                       layer.slices[i].contour.contains(point);
             };
 
             for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) {
@@ -2418,7 +2415,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
             static int iRun = 0;
             SVG svg(debug_out_path("GCode_extrude_loop-%d.svg", iRun ++));
             if (m_layer->lower_layer != NULL)
-                svg.draw(m_layer->lower_layer->slices.expolygons);
+                svg.draw(m_layer->lower_layer->slices);
             for (size_t i = 0; i < loop.paths.size(); ++ i)
                 svg.draw(loop.paths[i].as_polyline(), "red");
             Polylines polylines;
diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp
index 94f114a26..74deabf3e 100644
--- a/src/libslic3r/Layer.cpp
+++ b/src/libslic3r/Layer.cpp
@@ -47,8 +47,8 @@ void Layer::make_slices()
         slices = union_ex(slices_p);
     }
     
-    this->slices.expolygons.clear();
-    this->slices.expolygons.reserve(slices.size());
+    this->slices.clear();
+    this->slices.reserve(slices.size());
     
     // prepare ordering points
     Points ordering_points;
@@ -61,7 +61,7 @@ void Layer::make_slices()
     
     // populate slices vector
     for (size_t i : order)
-        this->slices.expolygons.push_back(std::move(slices[i]));
+        this->slices.push_back(std::move(slices[i]));
 }
 
 // Merge typed slices into untyped slices. This method is used to revert the effects of detect_surfaces_type() called for posPrepareInfill.
@@ -70,7 +70,7 @@ void Layer::merge_slices()
     if (m_regions.size() == 1) {
         // Optimization, also more robust. Don't merge classified pieces of layerm->slices,
         // but use the non-split islands of a layer. For a single region print, these shall be equal.
-        m_regions.front()->slices.set(this->slices.expolygons, stInternal);
+        m_regions.front()->slices.set(this->slices, stInternal);
     } else {
         for (LayerRegion *layerm : m_regions)
             // without safety offset, artifacts are generated (GH #2494)
diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp
index 539ae3925..9a4297ce5 100644
--- a/src/libslic3r/Layer.hpp
+++ b/src/libslic3r/Layer.hpp
@@ -110,7 +110,8 @@ public:
     // also known as 'islands' (all regions and surface types are merged here)
     // The slices are chained by the shortest traverse distance and this traversal
     // order will be recovered by the G-code generator.
-    ExPolygonCollection slices;
+    ExPolygons 			slices;
+    std::vector<BoundingBox> slices_bboxes;
 
     size_t                  region_count() const { return m_regions.size(); }
     const LayerRegion*      get_region(int idx) const { return m_regions.at(idx); }
diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp
index d13549bf4..0ff59d35f 100644
--- a/src/libslic3r/LayerRegion.cpp
+++ b/src/libslic3r/LayerRegion.cpp
@@ -140,7 +140,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
         	// Remove voids from fill_boundaries, that are not supported by the layer below.
             if (lower_layer_covered == nullptr) {
             	lower_layer_covered = &lower_layer_covered_tmp;
-            	lower_layer_covered_tmp = to_polygons(lower_layer->slices.expolygons);
+            	lower_layer_covered_tmp = to_polygons(lower_layer->slices);
             }
             if (! lower_layer_covered->empty())
             	voids = diff(voids, *lower_layer_covered);
diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp
index 8cd71e697..c0d9e65a7 100644
--- a/src/libslic3r/PerimeterGenerator.hpp
+++ b/src/libslic3r/PerimeterGenerator.hpp
@@ -3,7 +3,6 @@
 
 #include "libslic3r.h"
 #include <vector>
-#include "ExPolygonCollection.hpp"
 #include "Flow.hpp"
 #include "Polygon.hpp"
 #include "PrintConfig.hpp"
@@ -15,7 +14,7 @@ class PerimeterGenerator {
 public:
     // Inputs:
     const SurfaceCollection     *slices;
-    const ExPolygonCollection   *lower_slices;
+    const ExPolygons            *lower_slices;
     double                       layer_height;
     int                          layer_id;
     Flow                         perimeter_flow;
@@ -45,7 +44,7 @@ public:
         ExtrusionEntityCollection*  gap_fill,
         // Infills without the gap fills
         SurfaceCollection*          fill_surfaces)
-        : slices(slices), lower_slices(NULL), layer_height(layer_height),
+        : slices(slices), lower_slices(nullptr), layer_height(layer_height),
             layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow),
             overhang_flow(flow), solid_infill_flow(flow),
             config(config), object_config(object_config), print_config(print_config),
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index f5601276f..245b79e80 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -328,17 +328,6 @@ unsigned int Print::num_object_instances() const
     return instances;
 }
 
-void Print::_simplify_slices(double distance)
-{
-    for (PrintObject *object : m_objects) {
-        for (Layer *layer : object->m_layers) {
-            layer->slices.simplify(distance);
-            for (LayerRegion *layerm : layer->regions())
-                layerm->slices.simplify(distance);
-        }
-    }
-}
-
 double Print::max_allowed_layer_height() const
 {
     double nozzle_diameter_max = 0.;
@@ -1114,6 +1103,9 @@ std::string Print::validate() const
     if (m_objects.empty())
         return L("All objects are outside of the print volume.");
 
+    if (extruders().empty())
+        return L("The supplied settings will cause an empty print.");
+
     if (m_config.complete_objects) {
         // Check horizontal clearance.
         {
@@ -1271,10 +1263,7 @@ std::string Print::validate() const
     }
     
 	{
-		// find the smallest nozzle diameter
 		std::vector<unsigned int> extruders = this->extruders();
-		if (extruders.empty())
-			return L("The supplied settings will cause an empty print.");
 
 		// Find the smallest used nozzle diameter and the number of unique nozzle diameters.
 		double min_nozzle_diameter = std::numeric_limits<double>::max();
@@ -1593,7 +1582,7 @@ void Print::_make_skirt()
         for (const Layer *layer : object->m_layers) {
             if (layer->print_z > skirt_height_z)
                 break;
-            for (const ExPolygon &expoly : layer->slices.expolygons)
+            for (const ExPolygon &expoly : layer->slices)
                 // Collect the outer contour points only, ignore holes for the calculation of the convex hull.
                 append(object_points, expoly.contour.points);
         }
@@ -1704,7 +1693,7 @@ void Print::_make_brim()
     Polygons    islands;
     for (PrintObject *object : m_objects) {
         Polygons object_islands;
-        for (ExPolygon &expoly : object->m_layers.front()->slices.expolygons)
+        for (ExPolygon &expoly : object->m_layers.front()->slices)
             object_islands.push_back(expoly.contour);
         if (! object->support_layers().empty())
             object->support_layers().front()->support_fills.polygons_covered_by_spacing(object_islands, float(SCALED_EPSILON));
diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp
index 5cb13039c..ce616a150 100644
--- a/src/libslic3r/Print.hpp
+++ b/src/libslic3r/Print.hpp
@@ -180,7 +180,6 @@ private:
     void _slice(const std::vector<coordf_t> &layer_height_profile);
     std::string _fix_slicing_errors();
     void _simplify_slices(double distance);
-    void _make_perimeters();
     bool has_support_material() const;
     void detect_surfaces_type();
     void process_external_surfaces();
@@ -383,7 +382,6 @@ private:
     void                _make_skirt();
     void                _make_brim();
     void                _make_wipe_tower();
-    void                _simplify_slices(double distance);
 
     // Declared here to have access to Model / ModelObject / ModelInstance
     static void         model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_src);
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index 1ce00f269..78dd60a4b 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -2392,6 +2392,7 @@ void PrintConfigDef::init_sla_params()
                       "the threshold in the middle. This behaviour eliminates "
                       "antialiasing without losing holes in polygons.");
     def->min = 0;
+    def->max = 1;
     def->mode = comExpert;
     def->set_default_value(new ConfigOptionFloat(1.0));
 
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index c4f77b6d7..d87e63c27 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -117,6 +117,19 @@ void PrintObject::slice()
     // Simplify slices if required.
     if (m_print->config().resolution)
         this->_simplify_slices(scale_(this->print()->config().resolution));
+    // Update bounding boxes
+    tbb::parallel_for(
+        tbb::blocked_range<size_t>(0, m_layers.size()),
+        [this](const tbb::blocked_range<size_t>& range) {
+            for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
+                m_print->throw_if_canceled();
+                Layer &layer = *m_layers[layer_idx];
+                layer.slices_bboxes.clear();
+                layer.slices_bboxes.reserve(layer.slices.size());
+                for (const ExPolygon &expoly : layer.slices)
+                	layer.slices_bboxes.emplace_back(get_extents(expoly));
+            }
+        });
     if (m_layers.empty())
         throw std::runtime_error("No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n");    
     this->set_done(posSlice);
@@ -865,7 +878,7 @@ void PrintObject::process_external_surfaces()
 		                			// Shrink the holes, let the layer above expand slightly inside the unsupported areas.
 		                			polygons_append(voids, offset(surface.expolygon, unsupported_width));
 		                }
-		                surfaces_covered[layer_idx] = diff(to_polygons(this->m_layers[layer_idx]->slices.expolygons), voids);
+		                surfaces_covered[layer_idx] = diff(to_polygons(this->m_layers[layer_idx]->slices), voids);
 	            	}
 	        }
 	    );
@@ -975,8 +988,8 @@ void PrintObject::discover_vertical_shells()
                         polygons_append(cache.holes, offset(offset_ex(layer.slices, 0.3f * perimeter_min_spacing), - perimeter_offset - 0.3f * perimeter_min_spacing));
 #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
                         {
-                            Slic3r::SVG svg(debug_out_path("discover_vertical_shells-extra-holes-%d.svg", debug_idx), get_extents(layer.slices.expolygons));
-                            svg.draw(layer.slices.expolygons, "blue");
+                            Slic3r::SVG svg(debug_out_path("discover_vertical_shells-extra-holes-%d.svg", debug_idx), get_extents(layer.slices));
+                            svg.draw(layer.slices, "blue");
                             svg.draw(union_ex(cache.holes), "red");
                             svg.draw_outline(union_ex(cache.holes), "black", "blue", scale_(0.05));
                             svg.Close(); 
@@ -1659,25 +1672,26 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
                     // Trim volumes in a single layer, one by the other, possibly apply upscaling.
                     {
                         Polygons processed;
-                        for (SlicedVolume &sliced_volume : sliced_volumes) {
-                            ExPolygons slices = std::move(sliced_volume.expolygons_by_layer[layer_id]);
-                            if (upscale)
-                                slices = offset_ex(std::move(slices), delta);
-                            if (! processed.empty())
-                                // Trim by the slices of already processed regions.
-                                slices = diff_ex(to_polygons(std::move(slices)), processed);
-                            if (size_t(&sliced_volume - &sliced_volumes.front()) + 1 < sliced_volumes.size())
-                                // Collect the already processed regions to trim the to be processed regions.
-                                polygons_append(processed, slices);
-                            sliced_volume.expolygons_by_layer[layer_id] = std::move(slices);
-                        }
+                        for (SlicedVolume &sliced_volume : sliced_volumes) 
+                        	if (! sliced_volume.expolygons_by_layer.empty()) {
+	                            ExPolygons slices = std::move(sliced_volume.expolygons_by_layer[layer_id]);
+	                            if (upscale)
+	                                slices = offset_ex(std::move(slices), delta);
+	                            if (! processed.empty())
+	                                // Trim by the slices of already processed regions.
+	                                slices = diff_ex(to_polygons(std::move(slices)), processed);
+	                            if (size_t(&sliced_volume - &sliced_volumes.front()) + 1 < sliced_volumes.size())
+	                                // Collect the already processed regions to trim the to be processed regions.
+	                                polygons_append(processed, slices);
+	                            sliced_volume.expolygons_by_layer[layer_id] = std::move(slices);
+	                        }
                     }
                     // Collect and union volumes of a single region.
                     for (int region_id = 0; region_id < (int)this->region_volumes.size(); ++ region_id) {
                         ExPolygons expolygons;
                         size_t     num_volumes = 0;
                         for (SlicedVolume &sliced_volume : sliced_volumes)
-                            if (sliced_volume.region_id == region_id && ! sliced_volume.expolygons_by_layer[layer_id].empty()) {
+                            if (sliced_volume.region_id == region_id && ! sliced_volume.expolygons_by_layer.empty() && ! sliced_volume.expolygons_by_layer[layer_id].empty()) {
                                 ++ num_volumes;
                                 append(expolygons, std::move(sliced_volume.expolygons_by_layer[layer_id]));
                             }
@@ -2140,7 +2154,7 @@ std::string PrintObject::_fix_slicing_errors()
     BOOST_LOG_TRIVIAL(debug) << "Slicing objects - fixing slicing errors in parallel - end";
 
     // remove empty layers from bottom
-    while (! m_layers.empty() && m_layers.front()->slices.expolygons.empty()) {
+    while (! m_layers.empty() && m_layers.front()->slices.empty()) {
         delete m_layers.front();
         m_layers.erase(m_layers.begin());
         m_layers.front()->lower_layer = nullptr;
@@ -2167,115 +2181,17 @@ void PrintObject::_simplify_slices(double distance)
                 Layer *layer = m_layers[layer_idx];
                 for (size_t region_idx = 0; region_idx < layer->m_regions.size(); ++ region_idx)
                     layer->m_regions[region_idx]->slices.simplify(distance);
-                layer->slices.simplify(distance);
+				{
+					ExPolygons simplified;
+					for (const ExPolygon& expoly : layer->slices)
+						expoly.simplify(distance, &simplified);
+					layer->slices = std::move(simplified);
+				}
             }
         });
     BOOST_LOG_TRIVIAL(debug) << "Slicing objects - siplifying slices in parallel - end";
 }
 
-void PrintObject::_make_perimeters()
-{
-    if (! this->set_started(posPerimeters))
-        return;
-
-    BOOST_LOG_TRIVIAL(info) << "Generating perimeters..." << log_memory_info();
-    
-    // merge slices if they were split into types
-    if (this->typed_slices) {
-        for (Layer *layer : m_layers)
-            layer->merge_slices();
-        this->typed_slices = false;
-        this->invalidate_step(posPrepareInfill);
-    }
-    
-    // compare each layer to the one below, and mark those slices needing
-    // one additional inner perimeter, like the top of domed objects-
-    
-    // this algorithm makes sure that at least one perimeter is overlapping
-    // but we don't generate any extra perimeter if fill density is zero, as they would be floating
-    // inside the object - infill_only_where_needed should be the method of choice for printing
-    // hollow objects
-    for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
-        const PrintRegion &region = *m_print->regions()[region_id];
-        if (! region.config().extra_perimeters || region.config().perimeters == 0 || region.config().fill_density == 0 || this->layer_count() < 2)
-            continue;
-        
-        BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - start";
-        tbb::parallel_for(
-            tbb::blocked_range<size_t>(0, m_layers.size() - 1),
-            [this, &region, region_id](const tbb::blocked_range<size_t>& range) {
-                for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
-                    LayerRegion &layerm                     = *m_layers[layer_idx]->regions()[region_id];
-                    const LayerRegion &upper_layerm         = *m_layers[layer_idx+1]->regions()[region_id];
-                    const Polygons upper_layerm_polygons    = upper_layerm.slices;
-                    // Filter upper layer polygons in intersection_ppl by their bounding boxes?
-                    // my $upper_layerm_poly_bboxes= [ map $_->bounding_box, @{$upper_layerm_polygons} ];
-                    const double total_loop_length      = total_length(upper_layerm_polygons);
-                    const coord_t perimeter_spacing     = layerm.flow(frPerimeter).scaled_spacing();
-                    const Flow ext_perimeter_flow       = layerm.flow(frExternalPerimeter);
-                    const coord_t ext_perimeter_width   = ext_perimeter_flow.scaled_width();
-                    const coord_t ext_perimeter_spacing = ext_perimeter_flow.scaled_spacing();
-
-                    for (Surface &slice : layerm.slices.surfaces) {
-                        for (;;) {
-                            // compute the total thickness of perimeters
-                            const coord_t perimeters_thickness = ext_perimeter_width/2 + ext_perimeter_spacing/2
-                                + (region.config().perimeters-1 + slice.extra_perimeters) * perimeter_spacing;
-                            // define a critical area where we don't want the upper slice to fall into
-                            // (it should either lay over our perimeters or outside this area)
-                            const coord_t critical_area_depth = coord_t(perimeter_spacing * 1.5);
-                            const Polygons critical_area = diff(
-                                offset(slice.expolygon, float(- perimeters_thickness)),
-                                offset(slice.expolygon, float(- perimeters_thickness - critical_area_depth))
-                            );
-                            // check whether a portion of the upper slices falls inside the critical area
-                            const Polylines intersection = intersection_pl(to_polylines(upper_layerm_polygons), critical_area);
-                            // only add an additional loop if at least 30% of the slice loop would benefit from it
-                            if (total_length(intersection) <=  total_loop_length*0.3)
-                                break;
-                            /*
-                            if (0) {
-                                require "Slic3r/SVG.pm";
-                                Slic3r::SVG::output(
-                                    "extra.svg",
-                                    no_arrows   => 1,
-                                    expolygons  => union_ex($critical_area),
-                                    polylines   => [ map $_->split_at_first_point, map $_->p, @{$upper_layerm->slices} ],
-                                );
-                            }
-                            */
-                            ++ slice.extra_perimeters;
-                        }
-                        #ifdef DEBUG
-                            if (slice.extra_perimeters > 0)
-                                printf("  adding %d more perimeter(s) at layer %zu\n", slice.extra_perimeters, layer_idx);
-                        #endif
-                    }
-                }
-            });
-        BOOST_LOG_TRIVIAL(debug) << "Generating extra perimeters for region " << region_id << " in parallel - end";
-    }
-
-    BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - start";
-    tbb::parallel_for(
-        tbb::blocked_range<size_t>(0, m_layers.size()),
-        [this](const tbb::blocked_range<size_t>& range) {
-            for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx)
-                m_layers[layer_idx]->make_perimeters();
-        }
-    );
-    BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - end";
-
-    /*
-        simplify slices (both layer and region slices),
-        we only need the max resolution for perimeters
-    ### This makes this method not-idempotent, so we keep it disabled for now.
-    ###$self->_simplify_slices(&Slic3r::SCALED_RESOLUTION);
-    */
-    
-    this->set_done(posPerimeters);
-}
-
 // Only active if config->infill_only_where_needed. This step trims the sparse infill,
 // so it acts as an internal support. It maintains all other infill types intact.
 // Here the internal surfaces and perimeters have to be supported by the sparse infill.
@@ -2301,7 +2217,7 @@ void PrintObject::clip_fill_surfaces()
         // Detect things that we need to support.
         // Cummulative slices.
         Polygons slices;
-        polygons_append(slices, layer->slices.expolygons);
+        polygons_append(slices, layer->slices);
         // Cummulative fill surfaces.
         Polygons fill_surfaces;
         // Solid surfaces to be supported.
diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp
index a6648f108..179b35f59 100644
--- a/src/libslic3r/SupportMaterial.cpp
+++ b/src/libslic3r/SupportMaterial.cpp
@@ -445,8 +445,8 @@ Polygons collect_region_slices_by_type(const Layer &layer, SurfaceType surface_t
 Polygons collect_slices_outer(const Layer &layer)
 {
     Polygons out;
-    out.reserve(out.size() + layer.slices.expolygons.size());
-    for (const ExPolygon &expoly : layer.slices.expolygons)
+    out.reserve(out.size() + layer.slices.size());
+    for (const ExPolygon &expoly : layer.slices)
         out.emplace_back(expoly.contour);
     return out;
 }
@@ -907,9 +907,13 @@ namespace SupportMaterialInternal {
                     polyline.extend_start(fw);
                     polyline.extend_end(fw);
                     // Is the straight perimeter segment supported at both sides?
-                    if (lower_layer.slices.contains(polyline.first_point()) && lower_layer.slices.contains(polyline.last_point()))
-                        // Offset a polyline into a thick line.
-                        polygons_append(bridges, offset(polyline, 0.5f * w + 10.f));
+					for (size_t i = 0; i < lower_layer.slices.size(); ++ i)
+						if (lower_layer.slices_bboxes[i].contains(polyline.first_point()) && lower_layer.slices_bboxes[i].contains(polyline.last_point()) && 
+							lower_layer.slices[i].contains(polyline.first_point()) && lower_layer.slices[i].contains(polyline.last_point())) {
+							// Offset a polyline into a thick line.
+							polygons_append(bridges, offset(polyline, 0.5f * w + 10.f));
+							break;
+						}
                 }
             bridges = union_(bridges);
         }
@@ -994,7 +998,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
             // inflate the polygons over and over.
             Polygons &covered = buildplate_covered[layer_id];
             covered = buildplate_covered[layer_id - 1];
-            polygons_append(covered, offset(lower_layer.slices.expolygons, scale_(0.01)));
+            polygons_append(covered, offset(lower_layer.slices, scale_(0.01)));
             covered = union_(covered, false); // don't apply the safety offset.
         }
     }
@@ -1023,7 +1027,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
                 Polygons contact_polygons;
                 Polygons slices_margin_cached;
                 float    slices_margin_cached_offset = -1.;
-                Polygons lower_layer_polygons = (layer_id == 0) ? Polygons() : to_polygons(object.layers()[layer_id-1]->slices.expolygons);
+                Polygons lower_layer_polygons = (layer_id == 0) ? Polygons() : to_polygons(object.layers()[layer_id-1]->slices);
                 // Offset of the lower layer, to trim the support polygons with to calculate dense supports.
                 float    no_interface_offset = 0.f;
                 if (layer_id == 0) {
@@ -1162,7 +1166,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
                                 slices_margin_cached_offset = slices_margin_offset;
                                 slices_margin_cached = (slices_margin_offset == 0.f) ? 
                                     lower_layer_polygons :
-                                    offset2(to_polygons(lower_layer.slices.expolygons), - no_interface_offset * 0.5f, slices_margin_offset + no_interface_offset * 0.5f, SUPPORT_SURFACES_OFFSET_PARAMETERS);
+                                    offset2(to_polygons(lower_layer.slices), - no_interface_offset * 0.5f, slices_margin_offset + no_interface_offset * 0.5f, SUPPORT_SURFACES_OFFSET_PARAMETERS);
                                 if (! buildplate_covered.empty()) {
                                     // Trim the inflated contact surfaces by the top surfaces as well.
                                     polygons_append(slices_margin_cached, buildplate_covered[layer_id]);
@@ -1468,7 +1472,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
                         svg.draw(union_ex(top, false), "blue", 0.5f);
                         svg.draw(union_ex(projection_raw, true), "red", 0.5f);
                         svg.draw_outline(union_ex(projection_raw, true), "red", "blue", scale_(0.1f));
-                        svg.draw(layer.slices.expolygons, "green", 0.5f);
+                        svg.draw(layer.slices, "green", 0.5f);
                     }
         #endif /* SLIC3R_DEBUG */
 
@@ -1568,8 +1572,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
             Polygons &layer_support_area = layer_support_areas[layer_id];
             task_group.run([this, &projection, &projection_raw, &layer, &layer_support_area, layer_id] {
                 // Remove the areas that touched from the projection that will continue on next, lower, top surfaces.
-    //            Polygons trimming = union_(to_polygons(layer.slices.expolygons), touching, true);
-                Polygons trimming = offset(layer.slices.expolygons, float(SCALED_EPSILON));
+    //            Polygons trimming = union_(to_polygons(layer.slices), touching, true);
+                Polygons trimming = offset(layer.slices, float(SCALED_EPSILON));
                 projection = diff(projection_raw, trimming, false);
     #ifdef SLIC3R_DEBUG
                 {
@@ -2101,7 +2105,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
                     const Layer &object_layer = *object.layers()[i];
                     if (object_layer.print_z - object_layer.height > support_layer.print_z + gap_extra_above - EPSILON)
                         break;
-                    polygons_append(polygons_trimming, offset(object_layer.slices.expolygons, gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS));
+                    polygons_append(polygons_trimming, offset(object_layer.slices, gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS));
                 }
                 if (! m_slicing_params.soluble_interface) {
                     // Collect all bottom surfaces, which will be extruded with a bridging flow.
@@ -2214,7 +2218,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
         // Expand the bases of the support columns in the 1st layer.
         columns_base->polygons = diff(
             offset(columns_base->polygons, inflate_factor_1st_layer),
-            offset(m_object->layers().front()->slices.expolygons, (float)scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS));
+            offset(m_object->layers().front()->slices, (float)scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS));
         if (contacts != nullptr)
             columns_base->polygons = diff(columns_base->polygons, interface_polygons);
     }
diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp
index c9cdff162..9ca08809b 100644
--- a/src/slic3r/GUI/ConfigManipulation.cpp
+++ b/src/slic3r/GUI/ConfigManipulation.cpp
@@ -354,8 +354,7 @@ void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config)
     toggle_field("pad_wall_slope", pad_en);
     toggle_field("pad_around_object", pad_en);
 
-    bool has_suppad = pad_en && supports_en;
-    bool zero_elev = config->opt_bool("pad_around_object") && has_suppad;
+    bool zero_elev = config->opt_bool("pad_around_object") && pad_en;
 
     toggle_field("support_object_elevation", supports_en && !zero_elev);
     toggle_field("pad_object_gap", zero_elev);
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 803a5cf08..d3f331442 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -1808,7 +1808,10 @@ void TabPrinter::build_fff()
         optgroup->append_single_option_line("single_extruder_multi_material");
 
         optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value) {
-            size_t extruders_count = boost::any_cast<size_t>(optgroup->get_value("extruders_count"));
+            // optgroup->get_value() return int for def.type == coInt,
+            // Thus, there should be boost::any_cast<int> !
+            // Otherwise, boost::any_cast<size_t> causes an "unhandled unknown exception"
+            size_t extruders_count = size_t(boost::any_cast<int>(optgroup->get_value("extruders_count")));
             wxTheApp->CallAfter([this, opt_key, value, extruders_count]() {
                 if (opt_key == "extruders_count" || opt_key == "single_extruder_multi_material") {
                     extruders_count_changed(extruders_count);
diff --git a/xs/xsp/Layer.xsp b/xs/xsp/Layer.xsp
index fc94d5115..6f3164707 100644
--- a/xs/xsp/Layer.xsp
+++ b/xs/xsp/Layer.xsp
@@ -3,6 +3,7 @@
 %{
 #include <xsinit.h>
 #include "libslic3r/Layer.hpp"
+#include "libslic3r/ExPolygonCollection.hpp"
 %}
 
 %name{Slic3r::Layer::Region} class LayerRegion {
@@ -59,8 +60,8 @@
     Ref<LayerRegion> get_region(int idx);
     Ref<LayerRegion> add_region(PrintRegion* print_region);
 
-    Ref<ExPolygonCollection> slices()
-        %code%{ RETVAL = &THIS->slices; %};
+    ExPolygonCollection* slices()
+        %code%{ RETVAL = new ExPolygonCollection(THIS->slices); %};
 
     int ptr()
         %code%{ RETVAL = (int)(intptr_t)THIS; %};
@@ -108,8 +109,8 @@
     Ref<LayerRegion> get_region(int idx);
     Ref<LayerRegion> add_region(PrintRegion* print_region);
 
-    Ref<ExPolygonCollection> slices()
-        %code%{ RETVAL = &THIS->slices; %};
+    ExPolygonCollection* slices()
+        %code%{ RETVAL = new ExPolygonCollection(THIS->slices); %};
     
     void export_region_slices_to_svg(const char *path);
     void export_region_fill_surfaces_to_svg(const char *path);
diff --git a/xs/xsp/PerimeterGenerator.xsp b/xs/xsp/PerimeterGenerator.xsp
index 2e8213795..07059de61 100644
--- a/xs/xsp/PerimeterGenerator.xsp
+++ b/xs/xsp/PerimeterGenerator.xsp
@@ -19,7 +19,7 @@
     ~PerimeterGenerator();
     
     void set_lower_slices(ExPolygonCollection* lower_slices)
-        %code{% THIS->lower_slices = lower_slices; %};
+        %code{% THIS->lower_slices = &lower_slices->expolygons; %};
     void set_layer_id(int layer_id)
         %code{% THIS->layer_id = layer_id; %};
     void set_perimeter_flow(Flow* flow)