js/src/jsapi-tests/testProfileStrings.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  *
     4  * Tests the stack-based instrumentation profiler on a JSRuntime
     5  */
     6 /* This Source Code Form is subject to the terms of the Mozilla Public
     7  * License, v. 2.0. If a copy of the MPL was not distributed with this
     8  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    10 #include "jscntxt.h"
    12 #include "jsapi-tests/tests.h"
    14 static js::ProfileEntry pstack[10];
    15 static uint32_t psize = 0;
    16 static uint32_t max_stack = 0;
    18 static void
    19 reset(JSContext *cx)
    20 {
    21     psize = max_stack = 0;
    22     memset(pstack, 0, sizeof(pstack));
    23     cx->runtime()->spsProfiler.stringsReset();
    24     cx->runtime()->spsProfiler.enableSlowAssertions(true);
    25     js::EnableRuntimeProfilingStack(cx->runtime(), true);
    26 }
    28 static const JSClass ptestClass = {
    29     "Prof", 0, JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub,
    30     JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
    31 };
    33 static bool
    34 test_fn(JSContext *cx, unsigned argc, jsval *vp)
    35 {
    36     max_stack = psize;
    37     return true;
    38 }
    40 static bool
    41 test_fn2(JSContext *cx, unsigned argc, jsval *vp)
    42 {
    43     JS::RootedValue r(cx);
    44     JS::RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
    45     return JS_CallFunctionName(cx, global, "d", JS::HandleValueArray::empty(), &r);
    46 }
    48 static bool
    49 enable(JSContext *cx, unsigned argc, jsval *vp)
    50 {
    51     js::EnableRuntimeProfilingStack(cx->runtime(), true);
    52     return true;
    53 }
    55 static bool
    56 disable(JSContext *cx, unsigned argc, jsval *vp)
    57 {
    58     js::EnableRuntimeProfilingStack(cx->runtime(), false);
    59     return true;
    60 }
    62 static bool
    63 Prof(JSContext* cx, unsigned argc, jsval *vp)
    64 {
    65     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    66     JSObject *obj = JS_NewObjectForConstructor(cx, &ptestClass, args);
    67     if (!obj)
    68         return false;
    69     args.rval().setObject(*obj);
    70     return true;
    71 }
    73 static const JSFunctionSpec ptestFunctions[] = {
    74     JS_FS("test_fn", test_fn, 0, 0),
    75     JS_FS("test_fn2", test_fn2, 0, 0),
    76     JS_FS("enable", enable, 0, 0),
    77     JS_FS("disable", disable, 0, 0),
    78     JS_FS_END
    79 };
    81 static JSObject*
    82 initialize(JSContext *cx)
    83 {
    84     js::SetRuntimeProfilingStack(cx->runtime(), pstack, &psize, 10);
    85     JS::RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
    86     return JS_InitClass(cx, global, js::NullPtr(), &ptestClass, Prof, 0,
    87                         nullptr, ptestFunctions, nullptr, nullptr);
    88 }
    90 BEGIN_TEST(testProfileStrings_isCalledWithInterpreter)
    91 {
    92     CHECK(initialize(cx));
    94     EXEC("function g() { var p = new Prof(); p.test_fn(); }");
    95     EXEC("function f() { g(); }");
    96     EXEC("function e() { f(); }");
    97     EXEC("function d() { e(); }");
    98     EXEC("function c() { d(); }");
    99     EXEC("function b() { c(); }");
   100     EXEC("function a() { b(); }");
   101     EXEC("function check() { var p = new Prof(); p.test_fn(); a(); }");
   102     EXEC("function check2() { var p = new Prof(); p.test_fn2(); }");
   104     reset(cx);
   105     {
   106         JS::RootedValue rval(cx);
   107         /* Make sure the stack resets and we have an entry for each stack */
   108         CHECK(JS_CallFunctionName(cx, global, "check", JS::HandleValueArray::empty(),
   109                                   &rval));
   110         CHECK(psize == 0);
   111         CHECK(max_stack >= 8);
   112         CHECK(cx->runtime()->spsProfiler.stringsCount() == 8);
   113         /* Make sure the stack resets and we added no new entries */
   114         max_stack = 0;
   115         CHECK(JS_CallFunctionName(cx, global, "check", JS::HandleValueArray::empty(),
   116                                   &rval));
   117         CHECK(psize == 0);
   118         CHECK(max_stack >= 8);
   119         CHECK(cx->runtime()->spsProfiler.stringsCount() == 8);
   120     }
   121     reset(cx);
   122     {
   123         JS::RootedValue rval(cx);
   124         CHECK(JS_CallFunctionName(cx, global, "check2", JS::HandleValueArray::empty(),
   125                                   &rval));
   126         CHECK(cx->runtime()->spsProfiler.stringsCount() == 5);
   127         CHECK(max_stack >= 6);
   128         CHECK(psize == 0);
   129     }
   130     js::EnableRuntimeProfilingStack(cx->runtime(), false);
   131     js::SetRuntimeProfilingStack(cx->runtime(), pstack, &psize, 3);
   132     reset(cx);
   133     {
   134         JS::RootedValue rval(cx);
   135         pstack[3].setLabel((char*) 1234);
   136         CHECK(JS_CallFunctionName(cx, global, "check", JS::HandleValueArray::empty(),
   137                                   &rval));
   138         CHECK((size_t) pstack[3].label() == 1234);
   139         CHECK(max_stack >= 8);
   140         CHECK(psize == 0);
   141     }
   142     return true;
   143 }
   144 END_TEST(testProfileStrings_isCalledWithInterpreter)
   146 BEGIN_TEST(testProfileStrings_isCalledWithJIT)
   147 {
   148     CHECK(initialize(cx));
   149     JS::RuntimeOptionsRef(cx).setBaseline(true)
   150                              .setIon(true);
   152     EXEC("function g() { var p = new Prof(); p.test_fn(); }");
   153     EXEC("function f() { g(); }");
   154     EXEC("function e() { f(); }");
   155     EXEC("function d() { e(); }");
   156     EXEC("function c() { d(); }");
   157     EXEC("function b() { c(); }");
   158     EXEC("function a() { b(); }");
   159     EXEC("function check() { var p = new Prof(); p.test_fn(); a(); }");
   160     EXEC("function check2() { var p = new Prof(); p.test_fn2(); }");
   162     reset(cx);
   163     {
   164         JS::RootedValue rval(cx);
   165         /* Make sure the stack resets and we have an entry for each stack */
   166         CHECK(JS_CallFunctionName(cx, global, "check", JS::HandleValueArray::empty(),
   167                                   &rval));
   168         CHECK(psize == 0);
   169         CHECK(max_stack >= 8);
   171         /* Make sure the stack resets and we added no new entries */
   172         uint32_t cnt = cx->runtime()->spsProfiler.stringsCount();
   173         max_stack = 0;
   174         CHECK(JS_CallFunctionName(cx, global, "check", JS::HandleValueArray::empty(),
   175                                   &rval));
   176         CHECK(psize == 0);
   177         CHECK(cx->runtime()->spsProfiler.stringsCount() == cnt);
   178         CHECK(max_stack >= 8);
   179     }
   181     js::EnableRuntimeProfilingStack(cx->runtime(), false);
   182     js::SetRuntimeProfilingStack(cx->runtime(), pstack, &psize, 3);
   183     reset(cx);
   184     {
   185         /* Limit the size of the stack and make sure we don't overflow */
   186         JS::RootedValue rval(cx);
   187         pstack[3].setLabel((char*) 1234);
   188         CHECK(JS_CallFunctionName(cx, global, "check", JS::HandleValueArray::empty(),
   189                                   &rval));
   190         CHECK(psize == 0);
   191         CHECK(max_stack >= 8);
   192         CHECK((size_t) pstack[3].label() == 1234);
   193     }
   194     return true;
   195 }
   196 END_TEST(testProfileStrings_isCalledWithJIT)
   198 BEGIN_TEST(testProfileStrings_isCalledWhenError)
   199 {
   200     CHECK(initialize(cx));
   201     JS::RuntimeOptionsRef(cx).setBaseline(true)
   202                              .setIon(true);
   204     EXEC("function check2() { throw 'a'; }");
   206     reset(cx);
   207     JS::ContextOptionsRef(cx).setDontReportUncaught(true);
   208     {
   209         JS::RootedValue rval(cx);
   210         /* Make sure the stack resets and we have an entry for each stack */
   211         bool ok = JS_CallFunctionName(cx, global, "check2", JS::HandleValueArray::empty(),
   212                                       &rval);
   213         CHECK(!ok);
   214         CHECK(psize == 0);
   215         CHECK(cx->runtime()->spsProfiler.stringsCount() == 1);
   217         JS_ClearPendingException(cx);
   218     }
   219     return true;
   220 }
   221 END_TEST(testProfileStrings_isCalledWhenError)
   223 BEGIN_TEST(testProfileStrings_worksWhenEnabledOnTheFly)
   224 {
   225     CHECK(initialize(cx));
   226     JS::RuntimeOptionsRef(cx).setBaseline(true)
   227                              .setIon(true);
   229     EXEC("function b(p) { p.test_fn(); }");
   230     EXEC("function a() { var p = new Prof(); p.enable(); b(p); }");
   231     reset(cx);
   232     js::EnableRuntimeProfilingStack(cx->runtime(), false);
   233     {
   234         /* enable it in the middle of JS and make sure things check out */
   235         JS::RootedValue rval(cx);
   236         JS_CallFunctionName(cx, global, "a", JS::HandleValueArray::empty(), &rval);
   237         CHECK(psize == 0);
   238         CHECK(max_stack >= 1);
   239         CHECK(cx->runtime()->spsProfiler.stringsCount() == 1);
   240     }
   242     EXEC("function d(p) { p.disable(); }");
   243     EXEC("function c() { var p = new Prof(); d(p); }");
   244     reset(cx);
   245     {
   246         /* now disable in the middle of js */
   247         JS::RootedValue rval(cx);
   248         JS_CallFunctionName(cx, global, "c", JS::HandleValueArray::empty(), &rval);
   249         CHECK(psize == 0);
   250     }
   252     EXEC("function e() { var p = new Prof(); d(p); p.enable(); b(p); }");
   253     reset(cx);
   254     {
   255         /* now disable in the middle of js, but re-enable before final exit */
   256         JS::RootedValue rval(cx);
   257         JS_CallFunctionName(cx, global, "e", JS::HandleValueArray::empty(), &rval);
   258         CHECK(psize == 0);
   259         CHECK(max_stack >= 3);
   260     }
   262     EXEC("function h() { }");
   263     EXEC("function g(p) { p.disable(); for (var i = 0; i < 100; i++) i++; }");
   264     EXEC("function f() { g(new Prof()); }");
   265     reset(cx);
   266     cx->runtime()->spsProfiler.enableSlowAssertions(false);
   267     {
   268         JS::RootedValue rval(cx);
   269         /* disable, and make sure that if we try to re-enter the JIT the pop
   270          * will still happen */
   271         JS_CallFunctionName(cx, global, "f", JS::HandleValueArray::empty(), &rval);
   272         CHECK(psize == 0);
   273     }
   274     return true;
   275 }
   276 END_TEST(testProfileStrings_worksWhenEnabledOnTheFly)

mercurial