Title: [201976] trunk/Source/_javascript_Core
Revision
201976
Author
[email protected]
Date
2016-06-11 12:58:07 -0700 (Sat, 11 Jun 2016)

Log Message

Minimize the amount of memcpy done for allocating Error stacks.
https://bugs.webkit.org/show_bug.cgi?id=158664

Reviewed by Darin Adler.

Currently, Vector<StackFrame> are being copied around multiple times in the
process of creating Error stacks.

This patch avoids this unnecessary copying by:
1. Sizing the StackFrame vector correctly to begin with, and skipping
   undesirable top frames before filling in the vector.
2. Using perfect forwarding or passing by reference to pass the vector data around
   instead of copying the vectors.
3. Changing the Exception object to take a Vector<StackFrame> instead of a
   RefCountedArray<StackFrame>.

This patch has passed the JSC and layout tests.  Benchmarks show that perf is
neutral.

* API/tests/testapi.mm:
(testObjectiveCAPI):
* inspector/ScriptCallStackFactory.cpp:
(Inspector::createScriptCallStackFromException):
* interpreter/Interpreter.cpp:
(JSC::GetStackTraceFunctor::GetStackTraceFunctor):
(JSC::GetStackTraceFunctor::operator()):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::stackTraceAsString):
(JSC::findExceptionHandler):
* interpreter/Interpreter.h:
* runtime/Error.cpp:
(JSC::addErrorInfoAndGetBytecodeOffset):
* runtime/Exception.cpp:
(JSC::Exception::finishCreation):
* runtime/Exception.h:
(JSC::Exception::valueOffset):
(JSC::Exception::value):
(JSC::Exception::stack):
(JSC::Exception::didNotifyInspectorOfThrow):
(JSC::Exception::setDidNotifyInspectorOfThrow):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (201975 => 201976)


--- trunk/Source/_javascript_Core/ChangeLog	2016-06-11 19:48:48 UTC (rev 201975)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-06-11 19:58:07 UTC (rev 201976)
@@ -1,5 +1,48 @@
 2016-06-11  Mark Lam  <[email protected]>
 
+        Minimize the amount of memcpy done for allocating Error stacks.
+        https://bugs.webkit.org/show_bug.cgi?id=158664
+
+        Reviewed by Darin Adler.
+
+        Currently, Vector<StackFrame> are being copied around multiple times in the
+        process of creating Error stacks.
+
+        This patch avoids this unnecessary copying by:
+        1. Sizing the StackFrame vector correctly to begin with, and skipping
+           undesirable top frames before filling in the vector.
+        2. Using perfect forwarding or passing by reference to pass the vector data around
+           instead of copying the vectors.
+        3. Changing the Exception object to take a Vector<StackFrame> instead of a
+           RefCountedArray<StackFrame>.
+
+        This patch has passed the JSC and layout tests.  Benchmarks show that perf is
+        neutral.
+
+        * API/tests/testapi.mm:
+        (testObjectiveCAPI):
+        * inspector/ScriptCallStackFactory.cpp:
+        (Inspector::createScriptCallStackFromException):
+        * interpreter/Interpreter.cpp:
+        (JSC::GetStackTraceFunctor::GetStackTraceFunctor):
+        (JSC::GetStackTraceFunctor::operator()):
+        (JSC::Interpreter::getStackTrace):
+        (JSC::Interpreter::stackTraceAsString):
+        (JSC::findExceptionHandler):
+        * interpreter/Interpreter.h:
+        * runtime/Error.cpp:
+        (JSC::addErrorInfoAndGetBytecodeOffset):
+        * runtime/Exception.cpp:
+        (JSC::Exception::finishCreation):
+        * runtime/Exception.h:
+        (JSC::Exception::valueOffset):
+        (JSC::Exception::value):
+        (JSC::Exception::stack):
+        (JSC::Exception::didNotifyInspectorOfThrow):
+        (JSC::Exception::setDidNotifyInspectorOfThrow):
+
+2016-06-11  Mark Lam  <[email protected]>
+
         Tests that overflows the stack should not be run with the sampling profiler.
         https://bugs.webkit.org/show_bug.cgi?id=158663
 

Modified: trunk/Source/_javascript_Core/inspector/ScriptCallStackFactory.cpp (201975 => 201976)


--- trunk/Source/_javascript_Core/inspector/ScriptCallStackFactory.cpp	2016-06-11 19:48:48 UTC (rev 201975)
+++ trunk/Source/_javascript_Core/inspector/ScriptCallStackFactory.cpp	2016-06-11 19:58:07 UTC (rev 201976)
@@ -137,7 +137,7 @@
 Ref<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* exec, JSC::Exception* exception, size_t maxStackSize)
 {
     Vector<ScriptCallFrame> frames;
-    RefCountedArray<StackFrame> stackTrace = exception->stack();
+    auto& stackTrace = exception->stack();
     VM& vm = exec->vm();
     for (size_t i = 0; i < stackTrace.size() && i < maxStackSize; i++) {
         unsigned line;

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (201975 => 201976)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2016-06-11 19:48:48 UTC (rev 201975)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2016-06-11 19:58:07 UTC (rev 201976)
@@ -498,29 +498,35 @@
 
 class GetStackTraceFunctor {
 public:
-    GetStackTraceFunctor(VM& vm, Vector<StackFrame>& results, size_t remainingCapacity)
+    GetStackTraceFunctor(VM& vm, Vector<StackFrame>& results, size_t framesToSkip, size_t capacity)
         : m_vm(vm)
         , m_results(results)
-        , m_remainingCapacityForFrameCapture(remainingCapacity)
+        , m_framesToSkip(framesToSkip)
+        , m_remainingCapacityForFrameCapture(capacity)
     {
+        m_results.reserveInitialCapacity(capacity);
     }
 
     StackVisitor::Status operator()(StackVisitor& visitor) const
     {
-        VM& vm = m_vm;
+        if (m_framesToSkip > 0) {
+            m_framesToSkip--;
+            return StackVisitor::Continue;
+        }
+
         if (m_remainingCapacityForFrameCapture) {
             if (visitor->isJSFrame()
                 && !isWebAssemblyExecutable(visitor->codeBlock()->ownerExecutable())
                 && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) {
                 StackFrame s = {
-                    Strong<JSObject>(vm, visitor->callee()),
-                    Strong<CodeBlock>(vm, visitor->codeBlock()),
+                    Strong<JSObject>(m_vm, visitor->callee()),
+                    Strong<CodeBlock>(m_vm, visitor->codeBlock()),
                     visitor->bytecodeOffset()
                 };
                 m_results.append(s);
             } else {
                 StackFrame s = {
-                    Strong<JSObject>(vm, visitor->callee()),
+                    Strong<JSObject>(m_vm, visitor->callee()),
                     Strong<CodeBlock>(),
                     0 // unused value because codeBlock is null.
                 };
@@ -536,31 +542,43 @@
 private:
     VM& m_vm;
     Vector<StackFrame>& m_results;
+    mutable size_t m_framesToSkip;
     mutable size_t m_remainingCapacityForFrameCapture;
 };
 
-void Interpreter::getStackTrace(Vector<StackFrame>& results, size_t maxStackSize)
+void Interpreter::getStackTrace(Vector<StackFrame>& results, size_t framesToSkip, size_t maxStackSize)
 {
     VM& vm = m_vm;
     CallFrame* callFrame = vm.topCallFrame;
     if (!callFrame)
         return;
 
-    GetStackTraceFunctor functor(vm, results, maxStackSize);
+    size_t framesCount = 0;
+    callFrame->iterate([&] (StackVisitor&) -> StackVisitor::Status {
+        framesCount++;
+        return StackVisitor::Continue;
+    });
+    if (framesCount <= framesToSkip)
+        return;
+
+    framesCount -= framesToSkip;
+    framesCount = std::min(maxStackSize, framesCount);
+
+    GetStackTraceFunctor functor(vm, results, framesToSkip, framesCount);
     callFrame->iterate(functor);
+    ASSERT(results.size() == results.capacity());
 }
 
-JSString* Interpreter::stackTraceAsString(ExecState* exec, Vector<StackFrame> stackTrace)
+JSString* Interpreter::stackTraceAsString(VM& vm, const Vector<StackFrame>& stackTrace)
 {
     // FIXME: JSStringJoiner could be more efficient than StringBuilder here.
     StringBuilder builder;
-    VM& vm = exec->vm();
     for (unsigned i = 0; i < stackTrace.size(); i++) {
         builder.append(String(stackTrace[i].toString(vm)));
         if (i != stackTrace.size() - 1)
             builder.append('\n');
     }
-    return jsString(&exec->vm(), builder.toString());
+    return jsString(&vm, builder.toString());
 }
 
 ALWAYS_INLINE static HandlerInfo* findExceptionHandler(StackVisitor& visitor, CodeBlock* codeBlock, CodeBlock::RequiredHandler requiredHandler)

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.h (201975 => 201976)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.h	2016-06-11 19:48:48 UTC (rev 201975)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.h	2016-06-11 19:58:07 UTC (rev 201976)
@@ -217,7 +217,7 @@
         NEVER_INLINE HandlerInfo* unwind(VM&, CallFrame*&, Exception*, UnwindStart);
         void notifyDebuggerOfExceptionToBeThrown(CallFrame*, Exception*);
         NEVER_INLINE void debug(CallFrame*, DebugHookID);
-        JSString* stackTraceAsString(ExecState*, Vector<StackFrame>);
+        static JSString* stackTraceAsString(VM&, const Vector<StackFrame>&);
 
         static EncodedJSValue JSC_HOST_CALL constructWithErrorConstructor(ExecState*);
         static EncodedJSValue JSC_HOST_CALL callErrorConstructor(ExecState*);
@@ -226,7 +226,7 @@
 
         JS_EXPORT_PRIVATE void dumpCallFrame(CallFrame*);
 
-        void getStackTrace(Vector<StackFrame>& results, size_t maxStackSize = std::numeric_limits<size_t>::max());
+        void getStackTrace(Vector<StackFrame>& results, size_t framesToSkip = 0, size_t maxStackSize = std::numeric_limits<size_t>::max());
 
     private:
         enum ExecutionFlag { Normal, InitializeAndReturn };

Modified: trunk/Source/_javascript_Core/runtime/Error.cpp (201975 => 201976)


--- trunk/Source/_javascript_Core/runtime/Error.cpp	2016-06-11 19:48:48 UTC (rev 201975)
+++ trunk/Source/_javascript_Core/runtime/Error.cpp	2016-06-11 19:58:07 UTC (rev 201976)
@@ -143,7 +143,8 @@
 {
     Vector<StackFrame> stackTrace = Vector<StackFrame>();
 
-    vm.interpreter->getStackTrace(stackTrace);
+    size_t framesToSkip = useCurrentFrame ? 0 : 1;
+    vm.interpreter->getStackTrace(stackTrace, framesToSkip);
     if (!stackTrace.isEmpty()) {
 
         ASSERT(exec == vm.topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec());
@@ -173,9 +174,7 @@
         if (!frameSourceURL.isEmpty())
             obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, frameSourceURL), ReadOnly | DontDelete);
 
-        if (!useCurrentFrame)
-            stackTrace.remove(0);
-        obj->putDirect(vm, vm.propertyNames->stack, vm.interpreter->stackTraceAsString(vm.topCallFrame, stackTrace), DontEnum);
+        obj->putDirect(vm, vm.propertyNames->stack, Interpreter::stackTraceAsString(vm, stackTrace), DontEnum);
 
         return true;
     }

Modified: trunk/Source/_javascript_Core/runtime/Exception.cpp (201975 => 201976)


--- trunk/Source/_javascript_Core/runtime/Exception.cpp	2016-06-11 19:48:48 UTC (rev 201975)
+++ trunk/Source/_javascript_Core/runtime/Exception.cpp	2016-06-11 19:58:07 UTC (rev 201976)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -77,7 +77,7 @@
     Vector<StackFrame> stackTrace;
     if (action == StackCaptureAction::CaptureStack)
         vm.interpreter->getStackTrace(stackTrace);
-    m_stack = RefCountedArray<StackFrame>(stackTrace);
+    m_stack = WTFMove(stackTrace);
 }
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/Exception.h (201975 => 201976)


--- trunk/Source/_javascript_Core/runtime/Exception.h	2016-06-11 19:48:48 UTC (rev 201975)
+++ trunk/Source/_javascript_Core/runtime/Exception.h	2016-06-11 19:58:07 UTC (rev 201976)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,7 +27,7 @@
 #define Exception_h
 
 #include "Interpreter.h"
-#include <wtf/RefCountedArray.h>
+#include <wtf/Vector.h>
 
 namespace JSC {
     
@@ -57,7 +57,7 @@
     }
 
     JSValue value() const { return m_value.get(); }
-    const RefCountedArray<StackFrame>& stack() const { return m_stack; }
+    const Vector<StackFrame>& stack() const { return m_stack; }
 
     bool didNotifyInspectorOfThrow() const { return m_didNotifyInspectorOfThrow; }
     void setDidNotifyInspectorOfThrow() { m_didNotifyInspectorOfThrow = true; }
@@ -69,7 +69,7 @@
     void finishCreation(VM&, JSValue thrownValue, StackCaptureAction);
 
     WriteBarrier<Unknown> m_value;
-    RefCountedArray<StackFrame> m_stack;
+    Vector<StackFrame> m_stack;
     bool m_didNotifyInspectorOfThrow { false };
 
     friend class LLIntOffsetsExtractor;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to