From 14feaf3477dc6eaa6270651fbfd910268902276c Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Sat, 10 Feb 2018 17:41:35 -0500 Subject: [PATCH] Bug 1434965 - Add AutoArraySchemaWriter::FreeFormElement so that FillUpTo can be private. r=njn This may seem like an unnecessary increase in complexity, and it probably is. But it makes it easier to reason about lifetimes if your mind is accustomed to Rust, which would enforce a similar solution. MozReview-Commit-ID: kJZifbjCSU --HG-- extra : rebase_source : a2906eb296975ca689c2c3a019c33062ba17b0f2 --- tools/profiler/core/ProfileBufferEntry.cpp | 133 +++++++++++++-------- 1 file changed, 80 insertions(+), 53 deletions(-) diff --git a/tools/profiler/core/ProfileBufferEntry.cpp b/tools/profiler/core/ProfileBufferEntry.cpp index 91a86fbe1913..018bbf08b8e5 100644 --- a/tools/profiler/core/ProfileBufferEntry.cpp +++ b/tools/profiler/core/ProfileBufferEntry.cpp @@ -160,6 +160,12 @@ public: // elements when writing new non-null elements. It also automatically opens and // closes an array element on the given JSON writer. // +// You grant the AutoArraySchemaWriter exclusive access to the JSONWriter and +// the UniqueJSONStrings objects for the lifetime of AutoArraySchemaWriter. Do +// not access them independently while the AutoArraySchemaWriter is alive. +// If you need to add complex objects, call FreeFormElement(), which will give +// you temporary access to the writer. +// // Example usage: // // // Define the schema of elements in this type of array: [FOO, BAR, BAZ] @@ -174,14 +180,10 @@ public: // writer.IntElement(FOO, getFoo()); // } // ... etc ... +// +// The elements need to be added in-order. class MOZ_RAII AutoArraySchemaWriter { - friend class AutoObjectWriter; - - SpliceableJSONWriter& mJSONWriter; - UniqueJSONStrings& mStrings; - uint32_t mNextFreeIndex; - public: AutoArraySchemaWriter(SpliceableJSONWriter& aWriter, UniqueJSONStrings& aStrings) : mJSONWriter(aWriter) @@ -195,12 +197,6 @@ public: mJSONWriter.EndArray(); } - void FillUpTo(uint32_t aIndex) { - MOZ_ASSERT(aIndex >= mNextFreeIndex); - mJSONWriter.NullElements(aIndex - mNextFreeIndex); - mNextFreeIndex = aIndex + 1; - } - void IntElement(uint32_t aIndex, uint32_t aValue) { FillUpTo(aIndex); mJSONWriter.IntElement(aValue); @@ -215,6 +211,25 @@ public: FillUpTo(aIndex); mStrings.WriteElement(mJSONWriter, aValue); } + + // Write an element using a callback that takes a JSONWriter& and a + // UniqueJSONStrings&. + template + void FreeFormElement(uint32_t aIndex, LambdaT aCallback) { + FillUpTo(aIndex); + aCallback(mJSONWriter, mStrings); + } + +private: + void FillUpTo(uint32_t aIndex) { + MOZ_ASSERT(aIndex >= mNextFreeIndex); + mJSONWriter.NullElements(aIndex - mNextFreeIndex); + mNextFreeIndex = aIndex + 1; + } + + SpliceableJSONWriter& mJSONWriter; + UniqueJSONStrings& mStrings; + uint32_t mNextFreeIndex; }; class StreamOptimizationAttemptsOp : public JS::ForEachTrackedOptimizationAttemptOp @@ -420,6 +435,54 @@ UniqueStacks::StreamNonJITFrame(const FrameKey& aFrame) } } +static void +StreamJITFrameOptimizations(SpliceableJSONWriter& aWriter, + UniqueJSONStrings& aUniqueStrings, + JSContext* aContext, + const JS::ProfiledFrameHandle& aJITFrame) +{ + aWriter.StartObjectElement(); + { + aWriter.StartArrayProperty("types"); + { + StreamOptimizationTypeInfoOp typeInfoOp(aWriter, aUniqueStrings); + aJITFrame.forEachOptimizationTypeInfo(typeInfoOp); + } + aWriter.EndArray(); + + JS::Rooted script(aContext); + jsbytecode* pc; + aWriter.StartObjectProperty("attempts"); + { + { + JSONSchemaWriter schema(aWriter); + schema.WriteField("strategy"); + schema.WriteField("outcome"); + } + + aWriter.StartArrayProperty("data"); + { + StreamOptimizationAttemptsOp attemptOp(aWriter, aUniqueStrings); + aJITFrame.forEachOptimizationAttempt(attemptOp, script.address(), &pc); + } + aWriter.EndArray(); + } + aWriter.EndObject(); + + if (JSAtom* name = js::GetPropertyNameFromPC(script, pc)) { + char buf[512]; + JS_PutEscapedFlatString(buf, mozilla::ArrayLength(buf), js::AtomToFlatString(name), 0); + aUniqueStrings.WriteProperty(aWriter, "propertyName", buf); + } + + unsigned line, column; + line = JS_PCToLineNumber(script, pc, &column); + aWriter.IntProperty("line", line); + aWriter.IntProperty("column", column); + } + aWriter.EndObject(); +} + void UniqueStacks::StreamJITFrame(const JS::ProfiledFrameHandle& aJITFrame) { @@ -444,47 +507,11 @@ UniqueStacks::StreamJITFrame(const JS::ProfiledFrameHandle& aJITFrame) : "baseline"); if (aJITFrame.hasTrackedOptimizations()) { - writer.FillUpTo(OPTIMIZATIONS); - mFrameTableWriter.StartObjectElement(); - { - mFrameTableWriter.StartArrayProperty("types"); - { - StreamOptimizationTypeInfoOp typeInfoOp(mFrameTableWriter, mUniqueStrings); - aJITFrame.forEachOptimizationTypeInfo(typeInfoOp); - } - mFrameTableWriter.EndArray(); - - JS::Rooted script(mContext); - jsbytecode* pc; - mFrameTableWriter.StartObjectProperty("attempts"); - { - { - JSONSchemaWriter schema(mFrameTableWriter); - schema.WriteField("strategy"); - schema.WriteField("outcome"); - } - - mFrameTableWriter.StartArrayProperty("data"); - { - StreamOptimizationAttemptsOp attemptOp(mFrameTableWriter, mUniqueStrings); - aJITFrame.forEachOptimizationAttempt(attemptOp, script.address(), &pc); - } - mFrameTableWriter.EndArray(); - } - mFrameTableWriter.EndObject(); - - if (JSAtom* name = js::GetPropertyNameFromPC(script, pc)) { - char buf[512]; - JS_PutEscapedFlatString(buf, mozilla::ArrayLength(buf), js::AtomToFlatString(name), 0); - mUniqueStrings.WriteProperty(mFrameTableWriter, "propertyName", buf); - } - - unsigned line, column; - line = JS_PCToLineNumber(script, pc, &column); - mFrameTableWriter.IntProperty("line", line); - mFrameTableWriter.IntProperty("column", column); - } - mFrameTableWriter.EndObject(); + writer.FreeFormElement(OPTIMIZATIONS, + [&](SpliceableJSONWriter& aWriter, UniqueJSONStrings& aUniqueStrings) { + StreamJITFrameOptimizations(aWriter, aUniqueStrings, mContext, + aJITFrame); + }); } }