Fix all LA memory leaks forever!

Bug: 27072626

Or at least fix this one and make it harder to leak
going forward. static_asserts are cool, use them liberally

Also makes allocation via LA (slightly) faster by fixing create*
variants to use rvalue references & std::forward, preventing
an accidental pass-by-value

Change-Id: I5e0e36e72c6dd93324194ebf9a95f8204f05f261
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index 3db28c9..5a5845a 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -100,7 +100,7 @@
     static BakedOpState* tryConstruct(LinearAllocator& allocator,
             Snapshot& snapshot, const RecordedOp& recordedOp) {
         if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
-        BakedOpState* bakedState = new (allocator) BakedOpState(
+        BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
                 allocator, snapshot, recordedOp, false);
         if (bakedState->computedState.clippedBounds.isEmpty()) {
             // bounds are empty, so op is rejected
@@ -124,7 +124,7 @@
                 ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
                 : true;
 
-        BakedOpState* bakedState = new (allocator) BakedOpState(
+        BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
                 allocator, snapshot, recordedOp, expandForStroke);
         if (bakedState->computedState.clippedBounds.isEmpty()) {
             // bounds are empty, so op is rejected
@@ -140,16 +140,12 @@
         if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
 
         // clip isn't empty, so construct the op
-        return new (allocator) BakedOpState(allocator, snapshot, shadowOpPtr);
+        return allocator.create_trivial<BakedOpState>(allocator, snapshot, shadowOpPtr);
     }
 
     static BakedOpState* directConstruct(LinearAllocator& allocator,
             const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
-        return new (allocator) BakedOpState(clip, dstRect, recordedOp);
-    }
-
-    static void* operator new(size_t size, LinearAllocator& allocator) {
-        return allocator.alloc(size);
+        return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp);
     }
 
     // computed state:
@@ -162,6 +158,8 @@
     const RecordedOp* op;
 
 private:
+    friend class LinearAllocator;
+
     BakedOpState(LinearAllocator& allocator, Snapshot& snapshot,
             const RecordedOp& recordedOp, bool expandForStroke)
             : computedState(allocator, snapshot, recordedOp, expandForStroke)
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index c2e14a2..6d5833b 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -45,7 +45,7 @@
 };
 
 DamageAccumulator::DamageAccumulator() {
-    mHead = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
+    mHead = mAllocator.create_trivial<DirtyStack>();
     memset(mHead, 0, sizeof(DirtyStack));
     // Create a root that we will not pop off
     mHead->prev = mHead;
@@ -78,7 +78,7 @@
 
 void DamageAccumulator::pushCommon() {
     if (!mHead->next) {
-        DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
+        DirtyStack* nextFrame = mAllocator.create_trivial<DirtyStack>();
         nextFrame->next = nullptr;
         nextFrame->prev = mHead;
         mHead->next = nextFrame;
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 2d5979f..5c66b47 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -50,9 +50,6 @@
 class DeferredDisplayState {
 public:
     static void* operator new(size_t size) = delete;
-    static void* operator new(size_t size, LinearAllocator& allocator) {
-        return allocator.alloc(size);
-    }
 
     // global op bounds, mapped by mMatrix to be in screen space coordinates, clipped
     Rect mBounds;
@@ -124,7 +121,7 @@
     DeferredDisplayList(const DeferredDisplayList& other); // disallow copy
 
     DeferredDisplayState* createState() {
-        return new (mAllocator) DeferredDisplayState();
+        return mAllocator.create_trivial<DeferredDisplayState>();
     }
 
     void tryRecycleState(DeferredDisplayState* state) {
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index e5711e3..a703e22 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -251,7 +251,7 @@
     inline const T* refBuffer(const T* srcBuffer, int32_t count) {
         if (!srcBuffer) return nullptr;
 
-        T* dstBuffer = (T*) mDisplayList->allocator.alloc(count * sizeof(T));
+        T* dstBuffer = (T*) mDisplayList->allocator.alloc<T>(count * sizeof(T));
         memcpy(dstBuffer, srcBuffer, count * sizeof(T));
         return dstBuffer;
     }
@@ -320,8 +320,7 @@
         // correctly, such as creating the bitmap from scratch, drawing with it, changing its
         // contents, and drawing again. The only fix would be to always copy it the first time,
         // which doesn't seem worth the extra cycles for this unlikely case.
-        SkBitmap* localBitmap = new (alloc()) SkBitmap(bitmap);
-        alloc().autoDestroy(localBitmap);
+        SkBitmap* localBitmap = alloc().create<SkBitmap>(bitmap);
         mDisplayList->bitmapResources.push_back(localBitmap);
         return localBitmap;
     }
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 20501ba..98315d0 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -64,7 +64,9 @@
     static void operator delete(void* ptr) { LOG_ALWAYS_FATAL("delete not supported"); }
     static void* operator new(size_t size) = delete; /** PURPOSELY OMITTED **/
     static void* operator new(size_t size, LinearAllocator& allocator) {
-        return allocator.alloc(size);
+        // FIXME: Quick hack to keep old pipeline working, delete this when
+        // we no longer need to support HWUI_NEWOPS := false
+        return allocator.alloc<char>(size);
     }
 
     enum OpLogFlag {
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 185acce..4f51036 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -209,7 +209,7 @@
         // not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer)
         if (node.getLayer()) {
             // HW layer
-            LayerOp* drawLayerOp = new (mAllocator) LayerOp(node);
+            LayerOp* drawLayerOp = mAllocator.create_trivial<LayerOp>(node);
             BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
             if (bakedOpState) {
                 // Node's layer already deferred, schedule it to render into parent layer
@@ -220,13 +220,13 @@
             // (temp layers are clipped to viewport, since they don't persist offscreen content)
             SkPaint saveLayerPaint;
             saveLayerPaint.setAlpha(properties.getAlpha());
-            deferBeginLayerOp(*new (mAllocator) BeginLayerOp(
+            deferBeginLayerOp(*mAllocator.create_trivial<BeginLayerOp>(
                     saveLayerBounds,
                     Matrix4::identity(),
                     nullptr, // no record-time clip - need only respect defer-time one
                     &saveLayerPaint));
             deferNodeOps(node);
-            deferEndLayerOp(*new (mAllocator) EndLayerOp());
+            deferEndLayerOp(*mAllocator.create_trivial<EndLayerOp>());
         } else {
             deferNodeOps(node);
         }
@@ -549,7 +549,7 @@
 void FrameBuilder::deferVectorDrawableOp(const VectorDrawableOp& op) {
     const SkBitmap& bitmap = op.vectorDrawable->getBitmapUpdateIfDirty();
     SkPaint* paint = op.vectorDrawable->getPaint();
-    const BitmapRectOp* resolvedOp = new (mAllocator) BitmapRectOp(op.unmappedBounds,
+    const BitmapRectOp* resolvedOp = mAllocator.create_trivial<BitmapRectOp>(op.unmappedBounds,
             op.localMatrix,
             op.localClip,
             paint,
@@ -565,7 +565,7 @@
     float y = *(op.y);
     float radius = *(op.radius);
     Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius);
-    const OvalOp* resolvedOp = new (mAllocator) OvalOp(
+    const OvalOp* resolvedOp = mAllocator.create_trivial<OvalOp>(
             unmappedBounds,
             op.localMatrix,
             op.localClip,
@@ -626,7 +626,7 @@
 void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
     // allocate a temporary round rect op (with mAllocator, so it persists until render), so the
     // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
-    const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp(
+    const RoundRectOp* resolvedOp = mAllocator.create_trivial<RoundRectOp>(
             Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)),
             op.localMatrix,
             op.localClip,
@@ -754,7 +754,7 @@
 
     // record the draw operation into the previous layer's list of draw commands
     // uses state from the associated beginLayerOp, since it has all the state needed for drawing
-    LayerOp* drawLayerOp = new (mAllocator) LayerOp(
+    LayerOp* drawLayerOp = mAllocator.create_trivial<LayerOp>(
             beginLayerOp.unmappedBounds,
             beginLayerOp.localMatrix,
             beginLayerOp.localClip,
@@ -788,7 +788,7 @@
     /**
      * First, defer an operation to copy out the content from the rendertarget into a layer.
      */
-    auto copyToOp = new (mAllocator) CopyToLayerOp(op, layerHandle);
+    auto copyToOp = mAllocator.create_trivial<CopyToLayerOp>(op, layerHandle);
     BakedOpState* bakedState = BakedOpState::directConstruct(mAllocator,
             &(currentLayer().viewportClip), dstRect, *copyToOp);
     currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer);
@@ -803,7 +803,7 @@
      * And stash an operation to copy that layer back under the rendertarget until
      * a balanced EndUnclippedLayerOp is seen
      */
-    auto copyFromOp = new (mAllocator) CopyFromLayerOp(op, layerHandle);
+    auto copyFromOp = mAllocator.create_trivial<CopyFromLayerOp>(op, layerHandle);
     bakedState = BakedOpState::directConstruct(mAllocator,
             &(currentLayer().viewportClip), dstRect, *copyFromOp);
     currentLayer().activeUnclippedSaveLayers.push_back(bakedState);
diff --git a/libs/hwui/LayerBuilder.cpp b/libs/hwui/LayerBuilder.cpp
index 7170d4f..1ba3bf2 100644
--- a/libs/hwui/LayerBuilder.cpp
+++ b/libs/hwui/LayerBuilder.cpp
@@ -64,10 +64,6 @@
 
 class OpBatch : public BatchBase {
 public:
-    static void* operator new(size_t size, LinearAllocator& allocator) {
-        return allocator.alloc(size);
-    }
-
     OpBatch(batchid_t batchId, BakedOpState* op)
             : BatchBase(batchId, op, false) {
     }
@@ -80,10 +76,6 @@
 
 class MergingOpBatch : public BatchBase {
 public:
-    static void* operator new(size_t size, LinearAllocator& allocator) {
-        return allocator.alloc(size);
-    }
-
     MergingOpBatch(batchid_t batchId, BakedOpState* op)
             : BatchBase(batchId, op, true)
             , mClipSideFlags(op->computedState.clipSideFlags) {
@@ -247,7 +239,7 @@
         // put the verts in the frame allocator, since
         //     1) SimpleRectsOps needs verts, not rects
         //     2) even if mClearRects stored verts, std::vectors will move their contents
-        Vertex* const verts = (Vertex*) allocator.alloc(vertCount * sizeof(Vertex));
+        Vertex* const verts = (Vertex*) allocator.alloc<Vertex>(vertCount * sizeof(Vertex));
 
         Vertex* currentVert = verts;
         Rect bounds = mClearRects[0];
@@ -264,7 +256,7 @@
         // Flush all of these clears with a single draw
         SkPaint* paint = allocator.create<SkPaint>();
         paint->setXfermodeMode(SkXfermode::kClear_Mode);
-        SimpleRectsOp* op = new (allocator) SimpleRectsOp(bounds,
+        SimpleRectsOp* op = allocator.create_trivial<SimpleRectsOp>(bounds,
                 Matrix4::identity(), nullptr, paint,
                 verts, vertCount);
         BakedOpState* bakedState = BakedOpState::directConstruct(allocator,
@@ -292,7 +284,7 @@
         targetBatch->batchOp(op);
     } else  {
         // new non-merging batch
-        targetBatch = new (allocator) OpBatch(batchId, op);
+        targetBatch = allocator.create<OpBatch>(batchId, op);
         mBatchLookup[batchId] = targetBatch;
         mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
     }
@@ -323,7 +315,7 @@
         targetBatch->mergeOp(op);
     } else  {
         // new merging batch
-        targetBatch = new (allocator) MergingOpBatch(batchId, op);
+        targetBatch = allocator.create<MergingOpBatch>(batchId, op);
         mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch));
 
         mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 16929b8..269e590 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -83,9 +83,9 @@
 
 void RecordingCanvas::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
     if (removed.flags & Snapshot::kFlagIsFboLayer) {
-        addOp(new (alloc()) EndLayerOp());
+        addOp(alloc().create_trivial<EndLayerOp>());
     } else if (removed.flags & Snapshot::kFlagIsLayer) {
-        addOp(new (alloc()) EndUnclippedLayerOp());
+        addOp(alloc().create_trivial<EndUnclippedLayerOp>());
     }
 }
 
@@ -167,7 +167,7 @@
         snapshot.resetClip(clip.left, clip.top, clip.right, clip.bottom);
         snapshot.roundRectClipState = nullptr;
 
-        addOp(new (alloc()) BeginLayerOp(
+        addOp(alloc().create_trivial<BeginLayerOp>(
                 unmappedBounds,
                 *previous.transform, // transform to *draw* with
                 previousClip, // clip to *draw* with
@@ -175,7 +175,7 @@
     } else {
         snapshot.flags |= Snapshot::kFlagIsLayer;
 
-        addOp(new (alloc()) BeginUnclippedLayerOp(
+        addOp(alloc().create_trivial<BeginUnclippedLayerOp>(
                 unmappedBounds,
                 *mState.currentSnapshot()->transform,
                 getRecordedClip(),
@@ -241,7 +241,7 @@
 }
 
 void RecordingCanvas::drawPaint(const SkPaint& paint) {
-    addOp(new (alloc()) RectOp(
+    addOp(alloc().create_trivial<RectOp>(
             mState.getRenderTargetClipBounds(), // OK, since we've not passed transform
             Matrix4::identity(),
             getRecordedClip(),
@@ -261,7 +261,7 @@
     if (floatCount < 2) return;
     floatCount &= ~0x1; // round down to nearest two
 
-    addOp(new (alloc()) PointsOp(
+    addOp(alloc().create_trivial<PointsOp>(
             calcBoundsOfPoints(points, floatCount),
             *mState.currentSnapshot()->transform,
             getRecordedClip(),
@@ -272,7 +272,7 @@
     if (floatCount < 4) return;
     floatCount &= ~0x3; // round down to nearest four
 
-    addOp(new (alloc()) LinesOp(
+    addOp(alloc().create_trivial<LinesOp>(
             calcBoundsOfPoints(points, floatCount),
             *mState.currentSnapshot()->transform,
             getRecordedClip(),
@@ -280,7 +280,7 @@
 }
 
 void RecordingCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
-    addOp(new (alloc()) RectOp(
+    addOp(alloc().create_trivial<RectOp>(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
@@ -290,7 +290,7 @@
 void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint) {
     if (rects == nullptr) return;
 
-    Vertex* rectData = (Vertex*) mDisplayList->allocator.alloc(vertexCount * sizeof(Vertex));
+    Vertex* rectData = (Vertex*) mDisplayList->allocator.alloc<Vertex>(vertexCount * sizeof(Vertex));
     Vertex* vertex = rectData;
 
     float left = FLT_MAX;
@@ -313,7 +313,7 @@
         right = std::max(right, r);
         bottom = std::max(bottom, b);
     }
-    addOp(new (alloc()) SimpleRectsOp(
+    addOp(alloc().create_trivial<SimpleRectsOp>(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
@@ -347,7 +347,7 @@
 }
 void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom,
             float rx, float ry, const SkPaint& paint) {
-    addOp(new (alloc()) RoundRectOp(
+    addOp(alloc().create_trivial<RoundRectOp>(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
@@ -367,7 +367,7 @@
     mDisplayList->ref(ry);
     mDisplayList->ref(paint);
     refBitmapsInShader(paint->value.getShader());
-    addOp(new (alloc()) RoundRectPropsOp(
+    addOp(alloc().create_trivial<RoundRectPropsOp>(
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
             &paint->value,
@@ -389,7 +389,7 @@
     mDisplayList->ref(radius);
     mDisplayList->ref(paint);
     refBitmapsInShader(paint->value.getShader());
-    addOp(new (alloc()) CirclePropsOp(
+    addOp(alloc().create_trivial<CirclePropsOp>(
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
             &paint->value,
@@ -397,7 +397,7 @@
 }
 
 void RecordingCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
-    addOp(new (alloc()) OvalOp(
+    addOp(alloc().create_trivial<OvalOp>(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
@@ -406,7 +406,7 @@
 
 void RecordingCanvas::drawArc(float left, float top, float right, float bottom,
         float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
-    addOp(new (alloc()) ArcOp(
+    addOp(alloc().create_trivial<ArcOp>(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
@@ -415,7 +415,7 @@
 }
 
 void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
-    addOp(new (alloc()) PathOp(
+    addOp(alloc().create_trivial<PathOp>(
             Rect(path.getBounds()),
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
@@ -424,7 +424,7 @@
 
 void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
     mDisplayList->ref(tree);
-    addOp(new (alloc()) VectorDrawableOp(
+    addOp(alloc().create_trivial<VectorDrawableOp>(
             tree,
             Rect(tree->getBounds()),
             *(mState.currentSnapshot()->transform),
@@ -475,7 +475,7 @@
         drawBitmap(&bitmap, paint);
         restore();
     } else {
-        addOp(new (alloc()) BitmapRectOp(
+        addOp(alloc().create_trivial<BitmapRectOp>(
                 Rect(dstLeft, dstTop, dstRight, dstBottom),
                 *(mState.currentSnapshot()->transform),
                 getRecordedClip(),
@@ -487,7 +487,7 @@
 void RecordingCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
             const float* vertices, const int* colors, const SkPaint* paint) {
     int vertexCount = (meshWidth + 1) * (meshHeight + 1);
-    addOp(new (alloc()) BitmapMeshOp(
+    addOp(alloc().create_trivial<BitmapMeshOp>(
             calcBoundsOfPoints(vertices, vertexCount * 2),
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
@@ -499,7 +499,7 @@
 void RecordingCanvas::drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& patch,
             float dstLeft, float dstTop, float dstRight, float dstBottom,
             const SkPaint* paint) {
-    addOp(new (alloc()) PatchOp(
+    addOp(alloc().create_trivial<PatchOp>(
             Rect(dstLeft, dstTop, dstRight, dstBottom),
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
@@ -515,7 +515,7 @@
     positions = refBuffer<float>(positions, glyphCount * 2);
 
     // TODO: either must account for text shadow in bounds, or record separate ops for text shadows
-    addOp(new (alloc()) TextOp(
+    addOp(alloc().create_trivial<TextOp>(
             Rect(boundsLeft, boundsTop, boundsRight, boundsBottom),
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
@@ -527,7 +527,7 @@
             float hOffset, float vOffset, const SkPaint& paint) {
     if (!glyphs || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
     glyphs = refBuffer<glyph_t>(glyphs, glyphCount);
-    addOp(new (alloc()) TextOnPathOp(
+    addOp(alloc().create_trivial<TextOnPathOp>(
             mState.getLocalClipBounds(), // TODO: explicitly define bounds
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
@@ -535,7 +535,7 @@
 }
 
 void RecordingCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
-    addOp(new (alloc()) BitmapOp(
+    addOp(alloc().create_trivial<BitmapOp>(
             Rect(bitmap->width(), bitmap->height()),
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
@@ -544,7 +544,7 @@
 
 void RecordingCanvas::drawRenderNode(RenderNode* renderNode) {
     auto&& stagingProps = renderNode->stagingProperties();
-    RenderNodeOp* op = new (alloc()) RenderNodeOp(
+    RenderNodeOp* op = alloc().create_trivial<RenderNodeOp>(
             Rect(stagingProps.getWidth(), stagingProps.getHeight()),
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
@@ -570,7 +570,7 @@
     Matrix4 totalTransform(*(mState.currentSnapshot()->transform));
     totalTransform.multiply(layer->getTransform());
 
-    addOp(new (alloc()) TextureLayerOp(
+    addOp(alloc().create_trivial<TextureLayerOp>(
             Rect(layer->getWidth(), layer->getHeight()),
             totalTransform,
             getRecordedClip(),
@@ -579,7 +579,7 @@
 
 void RecordingCanvas::callDrawGLFunction(Functor* functor) {
     mDisplayList->functors.push_back(functor);
-    addOp(new (alloc()) FunctorOp(
+    addOp(alloc().create_trivial<FunctorOp>(
             mState.getLocalClipBounds(), // TODO: explicitly define bounds
             *(mState.currentSnapshot()->transform),
             getRecordedClip(),
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index cc14e61..719872d 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -219,7 +219,7 @@
     inline const T* refBuffer(const T* srcBuffer, int32_t count) {
         if (!srcBuffer) return nullptr;
 
-        T* dstBuffer = (T*) mDisplayList->allocator.alloc(count * sizeof(T));
+        T* dstBuffer = (T*) mDisplayList->allocator.alloc<T>(count * sizeof(T));
         memcpy(dstBuffer, srcBuffer, count * sizeof(T));
         return dstBuffer;
     }
@@ -290,8 +290,7 @@
         // correctly, such as creating the bitmap from scratch, drawing with it, changing its
         // contents, and drawing again. The only fix would be to always copy it the first time,
         // which doesn't seem worth the extra cycles for this unlikely case.
-        SkBitmap* localBitmap = new (alloc()) SkBitmap(bitmap);
-        alloc().autoDestroy(localBitmap);
+        SkBitmap* localBitmap = alloc().create<SkBitmap>(bitmap);
         mDisplayList->bitmapResources.push_back(localBitmap);
         return localBitmap;
     }
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index dbaa905..0ac2f14 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -46,7 +46,7 @@
 public:
     /** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
     static void* operator new(size_t size, LinearAllocator& allocator) {
-        return allocator.alloc(size);
+        return allocator.alloc<RoundRectClipState>(size);
     }
 
     bool areaRequiresRoundRectClip(const Rect& rect) const {
@@ -67,7 +67,7 @@
 public:
     /** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
     static void* operator new(size_t size, LinearAllocator& allocator) {
-        return allocator.alloc(size);
+        return allocator.alloc<ProjectionPathMask>(size);
     }
 
     const SkPath* projectionMask;
diff --git a/libs/hwui/tests/unit/LinearAllocatorTests.cpp b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
index 5c44290..402a09c 100644
--- a/libs/hwui/tests/unit/LinearAllocatorTests.cpp
+++ b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
@@ -30,7 +30,7 @@
 TEST(LinearAllocator, create) {
     LinearAllocator la;
     EXPECT_EQ(0u, la.usedSize());
-    la.alloc(64);
+    la.alloc<char>(64);
     // There's some internal tracking as well as padding
     // so the usedSize isn't strictly defined
     EXPECT_LE(64u, la.usedSize());
@@ -50,13 +50,12 @@
             la.create<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
             la.create<SimplePair>();
         }
-        la.alloc(100);
+        la.alloc<char>(100);
         for (int i = 0; i < 5; i++) {
-            auto sd = new (la) TestUtils::SignalingDtor(destroyed + 5 + i);
-            la.autoDestroy(sd);
-            new (la) SimplePair();
+            la.create<TestUtils::SignalingDtor>(destroyed + 5 + i);
+            la.create_trivial<SimplePair>();
         }
-        la.alloc(100);
+        la.alloc<char>(100);
         for (int i = 0; i < 10; i++) {
             EXPECT_EQ(0, destroyed[i]);
         }
@@ -70,7 +69,7 @@
     int destroyed = 0;
     {
         LinearAllocator la;
-        auto addr = la.alloc(100);
+        auto addr = la.alloc<char>(100);
         EXPECT_LE(100u, la.usedSize());
         la.rewindIfLastAlloc(addr, 100);
         EXPECT_GT(16u, la.usedSize());
diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp
index e6a4c03..5bba420 100644
--- a/libs/hwui/utils/LinearAllocator.cpp
+++ b/libs/hwui/utils/LinearAllocator.cpp
@@ -81,10 +81,6 @@
 
 #define min(x,y) (((x) < (y)) ? (x) : (y))
 
-void* operator new(std::size_t size, android::uirenderer::LinearAllocator& la) {
-    return la.alloc(size);
-}
-
 namespace android {
 namespace uirenderer {
 
@@ -171,7 +167,7 @@
     mNext = start(mCurrentPage);
 }
 
-void* LinearAllocator::alloc(size_t size) {
+void* LinearAllocator::allocImpl(size_t size) {
     size = ALIGN(size);
     if (size > mMaxAllocSize && !fitsInCurrentPage(size)) {
         ALOGV("Exceeded max size %zu > %zu", size, mMaxAllocSize);
@@ -196,7 +192,7 @@
                   "DestructorNode must have standard layout");
     static_assert(std::is_trivially_destructible<DestructorNode>::value,
                   "DestructorNode must be trivially destructable");
-    auto node = new (*this) DestructorNode();
+    auto node = new (allocImpl(sizeof(DestructorNode))) DestructorNode();
     node->dtor = dtor;
     node->addr = addr;
     node->next = mDtorList;
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index dcbc0dd..0a0e185 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -52,30 +52,36 @@
      * The lifetime of the returned buffers is tied to that of the LinearAllocator. If calling
      * delete() on an object stored in a buffer is needed, it should be overridden to use
      * rewindIfLastAlloc()
+     *
+     * Note that unlike create, for alloc the type is purely for compile-time error
+     * checking and does not affect size.
      */
-    void* alloc(size_t size);
+    template<class T>
+    void* alloc(size_t size) {
+        static_assert(std::is_trivially_destructible<T>::value,
+                "Error, type is non-trivial! did you mean to use create()?");
+        return allocImpl(size);
+    }
 
     /**
      * Allocates an instance of the template type with the given construction parameters
      * and adds it to the automatic destruction list.
      */
     template<class T, typename... Params>
-    T* create(Params... params) {
-        T* ret = new (*this) T(params...);
-        autoDestroy(ret);
+    T* create(Params&&... params) {
+        T* ret = new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
+        if (!std::is_trivially_destructible<T>::value) {
+            auto dtor = [](void* ret) { ((T*)ret)->~T(); };
+            addToDestructionList(dtor, ret);
+        }
         return ret;
     }
 
-    /**
-     * Adds the pointer to the tracking list to have its destructor called
-     * when the LinearAllocator is destroyed.
-     */
-    template<class T>
-    void autoDestroy(T* addr) {
-        if (!std::is_trivially_destructible<T>::value) {
-            auto dtor = [](void* addr) { ((T*)addr)->~T(); };
-            addToDestructionList(dtor, addr);
-        }
+    template<class T, typename... Params>
+    T* create_trivial(Params&&... params) {
+        static_assert(std::is_trivially_destructible<T>::value,
+                "Error, called create_trivial on a non-trivial type");
+        return new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
     }
 
     /**
@@ -114,6 +120,8 @@
         DestructorNode* next = nullptr;
     };
 
+    void* allocImpl(size_t size);
+
     void addToDestructionList(Destructor, void* addr);
     void runDestructorFor(void* addr);
     Page* newPage(size_t pageSize);
@@ -159,7 +167,7 @@
             : linearAllocator(other.linearAllocator) {}
 
     T* allocate(size_t num, const void* = 0) {
-        return (T*)(linearAllocator.alloc(num * sizeof(T)));
+        return (T*)(linearAllocator.alloc<void*>(num * sizeof(T)));
     }
 
     void deallocate(pointer p, size_t num) {
@@ -187,6 +195,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-void* operator new(std::size_t size, android::uirenderer::LinearAllocator& la);
-
 #endif // ANDROID_LINEARALLOCATOR_H