[RCS] Add explicit tests for function callbacks

This CL adds a very crude unittest to check that RuntimeCallStats work
correctly with api callbacks present. This currently doesn't check that
all parent timers (namely FunctionCallback) are handled properly.

Drive-by-Fix:
- Use Microseconds for all RCS timer tests
- Add TestWithContext::SetGlobalProperty helper
- Use explicit v8:: prefix in test-utils.{h,cc}

Change-Id: I054e78abca0b87a3b9e07d3b06cccdad15403bae
Reviewed-on: https://chromium-review.googlesource.com/766429
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49348}
This commit is contained in:
Camillo Bruni 2017-11-14 10:15:41 +01:00 committed by Commit Bot
parent ebe6d7a97f
commit 6526c6dd10
7 changed files with 249 additions and 58 deletions

View File

@ -683,6 +683,7 @@ void Accessors::FunctionLengthGetter(
v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
RuntimeCallTimerScope timer(isolate, &RuntimeCallStats::FunctionLengthGetter);
HandleScope scope(isolate);
Handle<JSFunction> function =
Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));

View File

@ -527,6 +527,11 @@ bool RuntimeCallStats::IsCalledOnTheSameThread() {
return true;
}
void RuntimeCallStats::Print() {
OFStream os(stdout);
Print(os);
}
void RuntimeCallStats::Print(std::ostream& os) {
RuntimeCallStatEntries entries;
if (current_timer_.Value() != nullptr) {

View File

@ -803,6 +803,7 @@ class RuntimeCallTimer final {
V(FunctionCallback) \
V(FunctionPrototypeGetter) \
V(FunctionPrototypeSetter) \
V(FunctionLengthGetter) \
V(GC_Custom_AllAvailableGarbage) \
V(GC_Custom_IncrementalMarkingObserver) \
V(GC_Custom_SlowAllocateRaw) \
@ -956,6 +957,7 @@ class RuntimeCallStats final : public ZoneObject {
// Add all entries from another stats object.
void Add(RuntimeCallStats* other);
V8_EXPORT_PRIVATE void Print(std::ostream& os);
V8_EXPORT_PRIVATE void Print();
V8_NOINLINE void Dump(v8::tracing::TracedValue* value);
ThreadId thread_id() const { return thread_id_; }

View File

@ -3033,8 +3033,7 @@ void Isolate::DumpAndResetStats() {
turbo_statistics_ = nullptr;
if (V8_UNLIKELY(FLAG_runtime_stats ==
v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE)) {
OFStream os(stdout);
counters()->runtime_call_stats()->Print(os);
counters()->runtime_call_stats()->Print();
counters()->runtime_call_stats()->Reset();
}
}

View File

@ -10,6 +10,8 @@
#include "src/handles-inl.h"
#include "src/objects-inl.h"
#include "src/tracing/tracing-category-observer.h"
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
@ -44,50 +46,103 @@ class AggregatedMemoryHistogramTest : public ::testing::Test {
};
static base::TimeTicks runtime_call_stats_test_time_ = base::TimeTicks();
// Time source used for the RuntimeCallTimer during tests. We cannot rely on
// the native timer since it's too unpredictable on the build bots.
static base::TimeTicks RuntimeCallStatsTestNow() {
return runtime_call_stats_test_time_;
}
class RuntimeCallStatsTest : public ::testing::Test {
class RuntimeCallStatsTest : public TestWithNativeContext {
public:
RuntimeCallStatsTest() {
FLAG_runtime_stats =
v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE;
RuntimeCallTimer::Now = &RuntimeCallStatsTestNow;
// We need to set {time_} to a non-zero value since it would otherwise
// cause runtime call timers to think they are uninitialized.
Sleep(1);
stats()->Reset();
}
virtual ~RuntimeCallStatsTest() {
~RuntimeCallStatsTest() {
// Disable RuntimeCallStats before tearing down the isolate to prevent
// printing the tests table. Comment the following line for debugging
// purposes.
FLAG_runtime_stats = 0;
}
static void SetUpTestCase() {
TestWithIsolate::SetUpTestCase();
// Use a custom time source to precisly emulate system time.
RuntimeCallTimer::Now = &RuntimeCallStatsTestNow;
}
static void TearDownTestCase() {
TestWithIsolate::TearDownTestCase();
// Restore the original time source.
RuntimeCallTimer::Now = &base::TimeTicks::HighResolutionNow;
}
RuntimeCallStats* stats() { return &stats_; }
RuntimeCallStats* stats() {
return isolate()->counters()->runtime_call_stats();
}
// Print current RuntimeCallStats table. For debugging purposes.
void PrintStats() { stats()->Print(); }
RuntimeCallStats::CounterId counter_id() {
return &RuntimeCallStats::TestCounter1;
}
RuntimeCallStats::CounterId counter_id2() {
return &RuntimeCallStats::TestCounter2;
}
RuntimeCallStats::CounterId counter_id3() {
return &RuntimeCallStats::TestCounter3;
}
RuntimeCallCounter* js_counter() { return &stats()->JS_Execution; }
RuntimeCallCounter* counter() { return &(stats()->*counter_id()); }
RuntimeCallCounter* counter2() { return &(stats()->*counter_id2()); }
RuntimeCallCounter* counter3() { return &(stats()->*counter_id3()); }
void Sleep(int32_t milliseconds) {
base::TimeDelta delta = base::TimeDelta::FromMilliseconds(milliseconds);
void Sleep(int64_t microseconds) {
base::TimeDelta delta = base::TimeDelta::FromMicroseconds(microseconds);
time_ += delta;
runtime_call_stats_test_time_ =
base::TimeTicks::FromInternalValue(time_.InMicroseconds());
}
private:
RuntimeCallStats stats_;
base::TimeDelta time_;
};
// Temporarily use the native time to modify the test time.
class ElapsedTimeScope {
public:
explicit ElapsedTimeScope(RuntimeCallStatsTest* test) : test_(test) {
timer_.Start();
}
~ElapsedTimeScope() { test_->Sleep(timer_.Elapsed().InMicroseconds()); }
private:
base::ElapsedTimer timer_;
RuntimeCallStatsTest* test_;
};
// Temporarily use the default time source.
class NativeTimeScope {
public:
NativeTimeScope() {
CHECK_EQ(RuntimeCallTimer::Now, &RuntimeCallStatsTestNow);
RuntimeCallTimer::Now = &base::TimeTicks::HighResolutionNow;
}
~NativeTimeScope() {
CHECK_EQ(RuntimeCallTimer::Now, &base::TimeTicks::HighResolutionNow);
RuntimeCallTimer::Now = &RuntimeCallStatsTestNow;
}
};
} // namespace
@ -257,7 +312,7 @@ TEST_F(RuntimeCallStatsTest, RuntimeCallTimer) {
Sleep(50);
EXPECT_FALSE(timer.IsStarted());
EXPECT_EQ(1, counter()->count());
EXPECT_EQ(100, counter()->time().InMilliseconds());
EXPECT_EQ(100, counter()->time().InMicroseconds());
}
TEST_F(RuntimeCallStatsTest, RuntimeCallTimerSubTimer) {
@ -290,8 +345,8 @@ TEST_F(RuntimeCallStatsTest, RuntimeCallTimerSubTimer) {
EXPECT_FALSE(timer2.IsStarted());
EXPECT_EQ(0, counter()->count());
EXPECT_EQ(1, counter2()->count());
EXPECT_EQ(0, counter()->time().InMilliseconds());
EXPECT_EQ(100, counter2()->time().InMilliseconds());
EXPECT_EQ(0, counter()->time().InMicroseconds());
EXPECT_EQ(100, counter2()->time().InMicroseconds());
EXPECT_EQ(&timer, stats()->current_timer());
Sleep(100);
@ -300,8 +355,8 @@ TEST_F(RuntimeCallStatsTest, RuntimeCallTimerSubTimer) {
EXPECT_FALSE(timer.IsStarted());
EXPECT_EQ(1, counter()->count());
EXPECT_EQ(1, counter2()->count());
EXPECT_EQ(150, counter()->time().InMilliseconds());
EXPECT_EQ(100, counter2()->time().InMilliseconds());
EXPECT_EQ(150, counter()->time().InMicroseconds());
EXPECT_EQ(100, counter2()->time().InMicroseconds());
EXPECT_EQ(nullptr, stats()->current_timer());
}
@ -329,14 +384,14 @@ TEST_F(RuntimeCallStatsTest, RuntimeCallTimerRecursive) {
EXPECT_FALSE(timer2.IsStarted());
EXPECT_TRUE(timer.IsStarted());
EXPECT_EQ(1, counter()->count());
EXPECT_EQ(50, counter()->time().InMilliseconds());
EXPECT_EQ(50, counter()->time().InMicroseconds());
Sleep(100);
RuntimeCallStats::Leave(stats(), &timer);
EXPECT_FALSE(timer.IsStarted());
EXPECT_EQ(2, counter()->count());
EXPECT_EQ(150, counter()->time().InMilliseconds());
EXPECT_EQ(150, counter()->time().InMicroseconds());
}
TEST_F(RuntimeCallStatsTest, RuntimeCallTimerScope) {
@ -346,13 +401,13 @@ TEST_F(RuntimeCallStatsTest, RuntimeCallTimerScope) {
}
Sleep(100);
EXPECT_EQ(1, counter()->count());
EXPECT_EQ(50, counter()->time().InMilliseconds());
EXPECT_EQ(50, counter()->time().InMicroseconds());
{
RuntimeCallTimerScope scope(stats(), counter_id());
Sleep(50);
}
EXPECT_EQ(2, counter()->count());
EXPECT_EQ(100, counter()->time().InMilliseconds());
EXPECT_EQ(100, counter()->time().InMicroseconds());
}
TEST_F(RuntimeCallStatsTest, RuntimeCallTimerScopeRecursive) {
@ -360,16 +415,16 @@ TEST_F(RuntimeCallStatsTest, RuntimeCallTimerScopeRecursive) {
RuntimeCallTimerScope scope(stats(), counter_id());
Sleep(50);
EXPECT_EQ(0, counter()->count());
EXPECT_EQ(0, counter()->time().InMilliseconds());
EXPECT_EQ(0, counter()->time().InMicroseconds());
{
RuntimeCallTimerScope scope(stats(), counter_id());
Sleep(50);
}
EXPECT_EQ(1, counter()->count());
EXPECT_EQ(50, counter()->time().InMilliseconds());
EXPECT_EQ(50, counter()->time().InMicroseconds());
}
EXPECT_EQ(2, counter()->count());
EXPECT_EQ(100, counter()->time().InMilliseconds());
EXPECT_EQ(100, counter()->time().InMicroseconds());
}
TEST_F(RuntimeCallStatsTest, RenameTimer) {
@ -378,8 +433,8 @@ TEST_F(RuntimeCallStatsTest, RenameTimer) {
Sleep(50);
EXPECT_EQ(0, counter()->count());
EXPECT_EQ(0, counter2()->count());
EXPECT_EQ(0, counter()->time().InMilliseconds());
EXPECT_EQ(0, counter2()->time().InMilliseconds());
EXPECT_EQ(0, counter()->time().InMicroseconds());
EXPECT_EQ(0, counter2()->time().InMicroseconds());
{
RuntimeCallTimerScope scope(stats(), counter_id());
Sleep(100);
@ -387,13 +442,13 @@ TEST_F(RuntimeCallStatsTest, RenameTimer) {
CHANGE_CURRENT_RUNTIME_COUNTER(stats(), TestCounter2);
EXPECT_EQ(1, counter()->count());
EXPECT_EQ(0, counter2()->count());
EXPECT_EQ(100, counter()->time().InMilliseconds());
EXPECT_EQ(0, counter2()->time().InMilliseconds());
EXPECT_EQ(100, counter()->time().InMicroseconds());
EXPECT_EQ(0, counter2()->time().InMicroseconds());
}
EXPECT_EQ(1, counter()->count());
EXPECT_EQ(1, counter2()->count());
EXPECT_EQ(100, counter()->time().InMilliseconds());
EXPECT_EQ(50, counter2()->time().InMilliseconds());
EXPECT_EQ(100, counter()->time().InMicroseconds());
EXPECT_EQ(50, counter2()->time().InMicroseconds());
}
TEST_F(RuntimeCallStatsTest, BasicPrintAndSnapshot) {
@ -402,9 +457,9 @@ TEST_F(RuntimeCallStatsTest, BasicPrintAndSnapshot) {
EXPECT_EQ(0, counter()->count());
EXPECT_EQ(0, counter2()->count());
EXPECT_EQ(0, counter3()->count());
EXPECT_EQ(0, counter()->time().InMilliseconds());
EXPECT_EQ(0, counter2()->time().InMilliseconds());
EXPECT_EQ(0, counter3()->time().InMilliseconds());
EXPECT_EQ(0, counter()->time().InMicroseconds());
EXPECT_EQ(0, counter2()->time().InMicroseconds());
EXPECT_EQ(0, counter3()->time().InMicroseconds());
{
RuntimeCallTimerScope scope(stats(), counter_id());
@ -415,9 +470,9 @@ TEST_F(RuntimeCallStatsTest, BasicPrintAndSnapshot) {
EXPECT_EQ(1, counter()->count());
EXPECT_EQ(0, counter2()->count());
EXPECT_EQ(0, counter3()->count());
EXPECT_EQ(50, counter()->time().InMilliseconds());
EXPECT_EQ(0, counter2()->time().InMilliseconds());
EXPECT_EQ(0, counter3()->time().InMilliseconds());
EXPECT_EQ(50, counter()->time().InMicroseconds());
EXPECT_EQ(0, counter2()->time().InMicroseconds());
EXPECT_EQ(0, counter3()->time().InMicroseconds());
}
TEST_F(RuntimeCallStatsTest, PrintAndSnapshot) {
@ -425,11 +480,11 @@ TEST_F(RuntimeCallStatsTest, PrintAndSnapshot) {
RuntimeCallTimerScope scope(stats(), counter_id());
Sleep(100);
EXPECT_EQ(0, counter()->count());
EXPECT_EQ(0, counter()->time().InMilliseconds());
EXPECT_EQ(0, counter()->time().InMicroseconds());
{
RuntimeCallTimerScope scope(stats(), counter_id2());
EXPECT_EQ(0, counter2()->count());
EXPECT_EQ(0, counter2()->time().InMilliseconds());
EXPECT_EQ(0, counter2()->time().InMicroseconds());
Sleep(50);
// This calls Snapshot on the current active timer and sychronizes and
@ -438,35 +493,35 @@ TEST_F(RuntimeCallStatsTest, PrintAndSnapshot) {
stats()->Print(out);
EXPECT_EQ(0, counter()->count());
EXPECT_EQ(0, counter2()->count());
EXPECT_EQ(100, counter()->time().InMilliseconds());
EXPECT_EQ(50, counter2()->time().InMilliseconds());
EXPECT_EQ(100, counter()->time().InMicroseconds());
EXPECT_EQ(50, counter2()->time().InMicroseconds());
// Calling Print several times shouldn't have a (big) impact on the
// measured times.
stats()->Print(out);
EXPECT_EQ(0, counter()->count());
EXPECT_EQ(0, counter2()->count());
EXPECT_EQ(100, counter()->time().InMilliseconds());
EXPECT_EQ(50, counter2()->time().InMilliseconds());
EXPECT_EQ(100, counter()->time().InMicroseconds());
EXPECT_EQ(50, counter2()->time().InMicroseconds());
Sleep(50);
stats()->Print(out);
EXPECT_EQ(0, counter()->count());
EXPECT_EQ(0, counter2()->count());
EXPECT_EQ(100, counter()->time().InMilliseconds());
EXPECT_EQ(100, counter2()->time().InMilliseconds());
EXPECT_EQ(100, counter()->time().InMicroseconds());
EXPECT_EQ(100, counter2()->time().InMicroseconds());
Sleep(50);
}
Sleep(50);
EXPECT_EQ(0, counter()->count());
EXPECT_EQ(1, counter2()->count());
EXPECT_EQ(100, counter()->time().InMilliseconds());
EXPECT_EQ(150, counter2()->time().InMilliseconds());
EXPECT_EQ(100, counter()->time().InMicroseconds());
EXPECT_EQ(150, counter2()->time().InMicroseconds());
Sleep(50);
}
EXPECT_EQ(1, counter()->count());
EXPECT_EQ(1, counter2()->count());
EXPECT_EQ(200, counter()->time().InMilliseconds());
EXPECT_EQ(150, counter2()->time().InMilliseconds());
EXPECT_EQ(200, counter()->time().InMicroseconds());
EXPECT_EQ(150, counter2()->time().InMicroseconds());
}
TEST_F(RuntimeCallStatsTest, NestedScopes) {
@ -497,9 +552,124 @@ TEST_F(RuntimeCallStatsTest, NestedScopes) {
EXPECT_EQ(1, counter()->count());
EXPECT_EQ(2, counter2()->count());
EXPECT_EQ(2, counter3()->count());
EXPECT_EQ(250, counter()->time().InMilliseconds());
EXPECT_EQ(300, counter2()->time().InMilliseconds());
EXPECT_EQ(100, counter3()->time().InMilliseconds());
EXPECT_EQ(250, counter()->time().InMicroseconds());
EXPECT_EQ(300, counter2()->time().InMicroseconds());
EXPECT_EQ(100, counter3()->time().InMicroseconds());
}
TEST_F(RuntimeCallStatsTest, BasicJavaScript) {
RuntimeCallCounter* counter = &stats()->JS_Execution;
EXPECT_EQ(0, counter->count());
EXPECT_EQ(0, counter->time().InMicroseconds());
{
NativeTimeScope native_timer_scope;
RunJS("function f() { return 1; }");
}
EXPECT_EQ(1, counter->count());
int64_t time = counter->time().InMicroseconds();
EXPECT_LT(0, time);
{
NativeTimeScope native_timer_scope;
RunJS("f()");
}
EXPECT_EQ(2, counter->count());
EXPECT_LE(time, counter->time().InMicroseconds());
}
TEST_F(RuntimeCallStatsTest, FunctionLengthGetter) {
RuntimeCallCounter* getter_counter = &stats()->FunctionLengthGetter;
RuntimeCallCounter* js_counter = &stats()->JS_Execution;
EXPECT_EQ(0, getter_counter->count());
EXPECT_EQ(0, js_counter->count());
EXPECT_EQ(0, getter_counter->time().InMicroseconds());
EXPECT_EQ(0, js_counter->time().InMicroseconds());
{
NativeTimeScope native_timer_scope;
RunJS("function f(array) { return array.length; }");
}
EXPECT_EQ(0, getter_counter->count());
EXPECT_EQ(1, js_counter->count());
EXPECT_EQ(0, getter_counter->time().InMicroseconds());
int64_t js_time = js_counter->time().InMicroseconds();
EXPECT_LT(0, js_time);
{
NativeTimeScope native_timer_scope;
RunJS("f.length");
}
EXPECT_EQ(1, getter_counter->count());
EXPECT_EQ(2, js_counter->count());
EXPECT_LE(0, getter_counter->time().InMicroseconds());
EXPECT_LT(js_time, js_counter->time().InMicroseconds());
{
NativeTimeScope native_timer_scope;
RunJS("for (let i = 0; i < 50; i++) { f.length }");
}
EXPECT_EQ(51, getter_counter->count());
EXPECT_EQ(3, js_counter->count());
}
namespace {
static RuntimeCallStatsTest* current_test;
static const int kCustomCallbackTime = 1234;
static void CustomCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
RuntimeCallTimerScope scope(current_test->stats(),
current_test->counter_id2());
current_test->Sleep(kCustomCallbackTime);
}
} // namespace
TEST_F(RuntimeCallStatsTest, CustomCallback) {
current_test = this;
// Set up a function template with a custom callback.
v8::Isolate* isolate = v8_isolate();
v8::HandleScope scope(isolate);
v8::Local<v8::ObjectTemplate> object_template =
v8::ObjectTemplate::New(isolate);
object_template->Set(isolate, "callback",
v8::FunctionTemplate::New(isolate, CustomCallback));
v8::Local<v8::Object> object =
object_template->NewInstance(v8_context()).ToLocalChecked();
SetGlobalProperty("custom_object", object);
// TODO(cbruni): Check api accessor timer (one above the custom callback).
EXPECT_EQ(0, js_counter()->count());
EXPECT_EQ(0, counter()->count());
EXPECT_EQ(0, counter2()->count());
{
RuntimeCallTimerScope scope(stats(), counter_id());
Sleep(100);
RunJS("custom_object.callback();");
}
EXPECT_EQ(1, js_counter()->count());
// Given that no native timers are used, only the two scopes explitly
// mentioned above will track the time.
EXPECT_EQ(0, js_counter()->time().InMicroseconds());
EXPECT_EQ(1, counter()->count());
EXPECT_EQ(100, counter()->time().InMicroseconds());
EXPECT_EQ(1, counter2()->count());
EXPECT_EQ(kCustomCallbackTime, counter2()->time().InMicroseconds());
RunJS("for (let i = 0; i < 9; i++) { custom_object.callback() };");
EXPECT_EQ(2, js_counter()->count());
EXPECT_EQ(0, js_counter()->time().InMicroseconds());
EXPECT_EQ(1, counter()->count());
EXPECT_EQ(100, counter()->time().InMicroseconds());
EXPECT_EQ(10, counter2()->count());
EXPECT_EQ(kCustomCallbackTime * 10, counter2()->time().InMicroseconds());
RunJS("for (let i = 0; i < 4000; i++) { custom_object.callback() };");
EXPECT_EQ(3, js_counter()->count());
EXPECT_EQ(0, js_counter()->time().InMicroseconds());
EXPECT_EQ(1, counter()->count());
EXPECT_EQ(100, counter()->time().InMicroseconds());
EXPECT_EQ(4010, counter2()->count());
EXPECT_EQ(kCustomCallbackTime * 4010, counter2()->time().InMicroseconds());
}
} // namespace internal

View File

@ -68,6 +68,17 @@ TestWithContext::TestWithContext()
TestWithContext::~TestWithContext() {}
void TestWithContext::SetGlobalProperty(const char* name,
v8::Local<v8::Value> value) {
v8::Local<v8::String> property_name =
v8::String::NewFromUtf8(v8_isolate(), name, v8::NewStringType::kNormal)
.ToLocalChecked();
CHECK(v8_context()
->Global()
->Set(v8_context(), property_name, value)
.FromJust());
}
namespace internal {
TestWithIsolate::~TestWithIsolate() {}

View File

@ -29,7 +29,9 @@ class TestWithIsolate : public virtual ::testing::Test {
TestWithIsolate();
virtual ~TestWithIsolate();
Isolate* isolate() const { return isolate_; }
v8::Isolate* isolate() const { return v8_isolate(); }
v8::Isolate* v8_isolate() const { return isolate_; }
v8::internal::Isolate* i_isolate() const {
return reinterpret_cast<v8::internal::Isolate*>(isolate());
@ -42,25 +44,28 @@ class TestWithIsolate : public virtual ::testing::Test {
private:
static v8::ArrayBuffer::Allocator* array_buffer_allocator_;
static Isolate* isolate_;
Isolate::Scope isolate_scope_;
HandleScope handle_scope_;
static v8::Isolate* isolate_;
v8::Isolate::Scope isolate_scope_;
v8::HandleScope handle_scope_;
DISALLOW_COPY_AND_ASSIGN(TestWithIsolate);
};
// Use v8::internal::TestWithNativeContext if you are testing internals,
// aka. directly work with Handles.
class TestWithContext : public virtual TestWithIsolate {
class TestWithContext : public virtual v8::TestWithIsolate {
public:
TestWithContext();
virtual ~TestWithContext();
const Local<Context>& context() const { return context_; }
const Local<Context>& context() const { return v8_context(); }
const Local<Context>& v8_context() const { return context_; }
void SetGlobalProperty(const char* name, v8::Local<v8::Value> value);
private:
Local<Context> context_;
Context::Scope context_scope_;
v8::Context::Scope context_scope_;
DISALLOW_COPY_AND_ASSIGN(TestWithContext);
};
@ -77,9 +82,7 @@ class TestWithIsolate : public virtual ::v8::TestWithIsolate {
virtual ~TestWithIsolate();
Factory* factory() const;
Isolate* isolate() const {
return reinterpret_cast<Isolate*>(::v8::TestWithIsolate::isolate());
}
Isolate* isolate() const { return i_isolate(); }
template <typename T = Object>
Handle<T> RunJS(const char* source) {
Handle<Object> result =