yeet
This commit is contained in:
16
node_modules/react-native/React/Profiler/RCTMacros.h
generated
vendored
Normal file
16
node_modules/react-native/React/Profiler/RCTMacros.h
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#define _CONCAT(A, B) A##B
|
||||
#define CONCAT(A, B) _CONCAT(A, B)
|
||||
|
||||
#if !defined(PIC_MODIFIER)
|
||||
#define PIC_MODIFIER
|
||||
#endif
|
||||
|
||||
#define SYMBOL_NAME(name) CONCAT(__USER_LABEL_PREFIX__, name)
|
||||
#define SYMBOL_NAME_PIC(name) CONCAT(SYMBOL_NAME(name), PIC_MODIFIER)
|
226
node_modules/react-native/React/Profiler/RCTProfile.h
generated
vendored
Normal file
226
node_modules/react-native/React/Profiler/RCTProfile.h
generated
vendored
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <React/RCTAssert.h>
|
||||
#import <React/RCTDefines.h>
|
||||
|
||||
/**
|
||||
* RCTProfile
|
||||
*
|
||||
* This file provides a set of functions and macros for performance profiling
|
||||
*
|
||||
* NOTE: This API is a work in progress, please consider carefully before
|
||||
* using it.
|
||||
*/
|
||||
|
||||
RCT_EXTERN NSString *const RCTProfileDidStartProfiling;
|
||||
RCT_EXTERN NSString *const RCTProfileDidEndProfiling;
|
||||
|
||||
RCT_EXTERN const uint64_t RCTProfileTagAlways;
|
||||
|
||||
#if RCT_PROFILE
|
||||
|
||||
@class RCTBridge;
|
||||
|
||||
#define RCTProfileBeginFlowEvent() \
|
||||
_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\"") NSUInteger __rct_profile_flow_id = \
|
||||
_RCTProfileBeginFlowEvent(); \
|
||||
_Pragma("clang diagnostic pop")
|
||||
|
||||
#define RCTProfileEndFlowEvent() _RCTProfileEndFlowEvent(__rct_profile_flow_id)
|
||||
|
||||
RCT_EXTERN dispatch_queue_t RCTProfileGetQueue(void);
|
||||
|
||||
RCT_EXTERN NSUInteger _RCTProfileBeginFlowEvent(void);
|
||||
RCT_EXTERN void _RCTProfileEndFlowEvent(NSUInteger);
|
||||
|
||||
/**
|
||||
* Returns YES if the profiling information is currently being collected
|
||||
*/
|
||||
RCT_EXTERN BOOL RCTProfileIsProfiling(void);
|
||||
|
||||
/**
|
||||
* Start collecting profiling information
|
||||
*/
|
||||
RCT_EXTERN void RCTProfileInit(RCTBridge *);
|
||||
|
||||
/**
|
||||
* Stop profiling and return a JSON string of the collected data - The data
|
||||
* returned is compliant with google's trace event format - the format used
|
||||
* as input to trace-viewer
|
||||
*/
|
||||
RCT_EXTERN void RCTProfileEnd(RCTBridge *, void (^)(NSString *));
|
||||
|
||||
/**
|
||||
* Collects the initial event information for the event and returns a reference ID
|
||||
*/
|
||||
RCT_EXTERN void _RCTProfileBeginEvent(
|
||||
NSThread *calleeThread,
|
||||
NSTimeInterval time,
|
||||
uint64_t tag,
|
||||
NSString *name,
|
||||
NSDictionary<NSString *, NSString *> *args);
|
||||
#define RCT_PROFILE_BEGIN_EVENT(tag, name, args) \
|
||||
do { \
|
||||
if (RCTProfileIsProfiling()) { \
|
||||
NSThread *__calleeThread = [NSThread currentThread]; \
|
||||
NSTimeInterval __time = CACurrentMediaTime(); \
|
||||
_RCTProfileBeginEvent(__calleeThread, __time, tag, name, args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* The ID returned by BeginEvent should then be passed into EndEvent, with the
|
||||
* rest of the event information. Just at this point the event will actually be
|
||||
* registered
|
||||
*/
|
||||
RCT_EXTERN void _RCTProfileEndEvent(
|
||||
NSThread *calleeThread,
|
||||
NSString *threadName,
|
||||
NSTimeInterval time,
|
||||
uint64_t tag,
|
||||
NSString *category);
|
||||
|
||||
#define RCT_PROFILE_END_EVENT(tag, category) \
|
||||
do { \
|
||||
if (RCTProfileIsProfiling()) { \
|
||||
NSThread *__calleeThread = [NSThread currentThread]; \
|
||||
NSString *__threadName = RCTCurrentThreadName(); \
|
||||
NSTimeInterval __time = CACurrentMediaTime(); \
|
||||
_RCTProfileEndEvent(__calleeThread, __threadName, __time, tag, category); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Collects the initial event information for the event and returns a reference ID
|
||||
*/
|
||||
RCT_EXTERN NSUInteger
|
||||
RCTProfileBeginAsyncEvent(uint64_t tag, NSString *name, NSDictionary<NSString *, NSString *> *args);
|
||||
|
||||
/**
|
||||
* The ID returned by BeginEvent should then be passed into EndEvent, with the
|
||||
* rest of the event information. Just at this point the event will actually be
|
||||
* registered
|
||||
*/
|
||||
RCT_EXTERN void
|
||||
RCTProfileEndAsyncEvent(uint64_t tag, NSString *category, NSUInteger cookie, NSString *name, NSString *threadName);
|
||||
|
||||
/**
|
||||
* An event that doesn't have a duration (i.e. Notification, VSync, etc)
|
||||
*/
|
||||
RCT_EXTERN void RCTProfileImmediateEvent(uint64_t tag, NSString *name, NSTimeInterval time, char scope);
|
||||
|
||||
/**
|
||||
* Helper to profile the duration of the execution of a block. This method uses
|
||||
* self and _cmd to name this event for simplicity sake.
|
||||
*
|
||||
* NOTE: The block can't expect any argument
|
||||
*
|
||||
* DEPRECATED: this approach breaks debugging and stepping through instrumented block functions
|
||||
*/
|
||||
#define RCTProfileBlock(block, tag, category, arguments) \
|
||||
^{ \
|
||||
RCT_PROFILE_BEGIN_EVENT(tag, @(__PRETTY_FUNCTION__), nil); \
|
||||
block(); \
|
||||
RCT_PROFILE_END_EVENT(tag, category, arguments); \
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook into a bridge instance to log all bridge module's method calls
|
||||
*/
|
||||
RCT_EXTERN void RCTProfileHookModules(RCTBridge *);
|
||||
|
||||
/**
|
||||
* Unhook from a given bridge instance's modules
|
||||
*/
|
||||
RCT_EXTERN void RCTProfileUnhookModules(RCTBridge *);
|
||||
|
||||
/**
|
||||
* Hook into all of a module's methods
|
||||
*/
|
||||
RCT_EXTERN void RCTProfileHookInstance(id instance);
|
||||
|
||||
/**
|
||||
* Send systrace or cpu profiling information to the packager
|
||||
* to present to the user
|
||||
*/
|
||||
RCT_EXTERN void RCTProfileSendResult(RCTBridge *bridge, NSString *route, NSData *profileData);
|
||||
|
||||
/**
|
||||
* Systrace gluecode
|
||||
*
|
||||
* allow to use systrace to back RCTProfile
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
const char *key;
|
||||
unsigned long key_len;
|
||||
const char *value;
|
||||
unsigned long value_len;
|
||||
} systrace_arg_t;
|
||||
|
||||
typedef struct {
|
||||
char *(*start)(void);
|
||||
void (*stop)(void);
|
||||
|
||||
void (*begin_section)(uint64_t tag, const char *name, size_t numArgs, systrace_arg_t *args);
|
||||
void (*end_section)(uint64_t tag, size_t numArgs, systrace_arg_t *args);
|
||||
|
||||
void (*begin_async_section)(uint64_t tag, const char *name, int cookie, size_t numArgs, systrace_arg_t *args);
|
||||
void (*end_async_section)(uint64_t tag, const char *name, int cookie, size_t numArgs, systrace_arg_t *args);
|
||||
|
||||
void (*instant_section)(uint64_t tag, const char *name, char scope);
|
||||
|
||||
void (*begin_async_flow)(uint64_t tag, const char *name, int cookie);
|
||||
void (*end_async_flow)(uint64_t tag, const char *name, int cookie);
|
||||
} RCTProfileCallbacks;
|
||||
|
||||
RCT_EXTERN void RCTProfileRegisterCallbacks(RCTProfileCallbacks *);
|
||||
|
||||
/**
|
||||
* Systrace control window
|
||||
*/
|
||||
RCT_EXTERN void RCTProfileShowControls(void);
|
||||
RCT_EXTERN void RCTProfileHideControls(void);
|
||||
|
||||
#else
|
||||
|
||||
#define RCTProfileBeginFlowEvent()
|
||||
#define _RCTProfileBeginFlowEvent() @0
|
||||
|
||||
#define RCTProfileEndFlowEvent()
|
||||
#define _RCTProfileEndFlowEvent(...)
|
||||
|
||||
#define RCTProfileIsProfiling(...) NO
|
||||
#define RCTProfileInit(...)
|
||||
#define RCTProfileEnd(...) @""
|
||||
|
||||
#define _RCTProfileBeginEvent(...)
|
||||
#define _RCTProfileEndEvent(...)
|
||||
|
||||
#define RCT_PROFILE_BEGIN_EVENT(...)
|
||||
#define RCT_PROFILE_END_EVENT(...)
|
||||
|
||||
#define RCTProfileBeginAsyncEvent(...) 0
|
||||
#define RCTProfileEndAsyncEvent(...)
|
||||
|
||||
#define RCTProfileImmediateEvent(...)
|
||||
|
||||
#define RCTProfileBlock(block, ...) block
|
||||
|
||||
#define RCTProfileHookModules(...)
|
||||
#define RCTProfileHookInstance(...)
|
||||
#define RCTProfileUnhookModules(...)
|
||||
|
||||
#define RCTProfileSendResult(...)
|
||||
|
||||
#define RCTProfileShowControls(...)
|
||||
#define RCTProfileHideControls(...)
|
||||
|
||||
#endif
|
807
node_modules/react-native/React/Profiler/RCTProfile.m
generated
vendored
Normal file
807
node_modules/react-native/React/Profiler/RCTProfile.m
generated
vendored
Normal file
@ -0,0 +1,807 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "RCTProfile.h"
|
||||
|
||||
#import <dlfcn.h>
|
||||
#import <mach/mach.h>
|
||||
#import <objc/message.h>
|
||||
#import <objc/runtime.h>
|
||||
#import <stdatomic.h>
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTBridge+Private.h"
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTComponentData.h"
|
||||
#import "RCTDefines.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTModuleData.h"
|
||||
#import "RCTUIManager.h"
|
||||
#import "RCTUIManagerUtils.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
NSString *const RCTProfileDidStartProfiling = @"RCTProfileDidStartProfiling";
|
||||
NSString *const RCTProfileDidEndProfiling = @"RCTProfileDidEndProfiling";
|
||||
|
||||
const uint64_t RCTProfileTagAlways = 1L << 0;
|
||||
|
||||
#if RCT_PROFILE
|
||||
|
||||
#pragma mark - Constants
|
||||
|
||||
static NSString *const kProfileTraceEvents = @"traceEvents";
|
||||
static NSString *const kProfileSamples = @"samples";
|
||||
static NSString *const kProfilePrefix = @"rct_profile_";
|
||||
|
||||
#pragma mark - Variables
|
||||
|
||||
static atomic_bool RCTProfileProfiling = ATOMIC_VAR_INIT(NO);
|
||||
|
||||
static NSDictionary *RCTProfileInfo;
|
||||
static NSMutableDictionary *RCTProfileOngoingEvents;
|
||||
static NSTimeInterval RCTProfileStartTime;
|
||||
static NSUInteger RCTProfileEventID = 0;
|
||||
static CADisplayLink *RCTProfileDisplayLink;
|
||||
static __weak RCTBridge *_RCTProfilingBridge;
|
||||
static UIWindow *RCTProfileControlsWindow;
|
||||
|
||||
#pragma mark - Macros
|
||||
|
||||
#define RCTProfileAddEvent(type, props...) \
|
||||
[RCTProfileInfo[type] addObject:@{@"pid" : @([[NSProcessInfo processInfo] processIdentifier]), props}];
|
||||
|
||||
#define CHECK(...) \
|
||||
if (!RCTProfileIsProfiling()) { \
|
||||
return __VA_ARGS__; \
|
||||
}
|
||||
|
||||
#pragma mark - systrace glue code
|
||||
|
||||
static RCTProfileCallbacks *callbacks;
|
||||
static char *systrace_buffer;
|
||||
|
||||
static systrace_arg_t *newSystraceArgsFromDictionary(NSDictionary<NSString *, NSString *> *args)
|
||||
{
|
||||
if (args.count == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
systrace_arg_t *systrace_args = malloc(sizeof(systrace_arg_t) * args.count);
|
||||
if (systrace_args) {
|
||||
__block size_t i = 0;
|
||||
[args enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, __unused BOOL *stop) {
|
||||
systrace_args[i].key = [key UTF8String];
|
||||
systrace_args[i].key_len = [key length];
|
||||
systrace_args[i].value = [value UTF8String];
|
||||
systrace_args[i].value_len = [value length];
|
||||
i++;
|
||||
}];
|
||||
}
|
||||
return systrace_args;
|
||||
}
|
||||
|
||||
void RCTProfileRegisterCallbacks(RCTProfileCallbacks *cb)
|
||||
{
|
||||
callbacks = cb;
|
||||
}
|
||||
|
||||
#pragma mark - Private Helpers
|
||||
|
||||
static RCTBridge *RCTProfilingBridge(void)
|
||||
{
|
||||
return _RCTProfilingBridge ?: [RCTBridge currentBridge];
|
||||
}
|
||||
|
||||
static NSNumber *RCTProfileTimestamp(NSTimeInterval timestamp)
|
||||
{
|
||||
return @((timestamp - RCTProfileStartTime) * 1e6);
|
||||
}
|
||||
|
||||
static NSString *RCTProfileMemory(vm_size_t memory)
|
||||
{
|
||||
double mem = ((double)memory) / 1024 / 1024;
|
||||
return [NSString stringWithFormat:@"%.2lfmb", mem];
|
||||
}
|
||||
|
||||
static NSDictionary *RCTProfileGetMemoryUsage(void)
|
||||
{
|
||||
struct task_basic_info info;
|
||||
mach_msg_type_number_t size = sizeof(info);
|
||||
kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
|
||||
if (kerr == KERN_SUCCESS) {
|
||||
return @{
|
||||
@"suspend_count" : @(info.suspend_count),
|
||||
@"virtual_size" : RCTProfileMemory(info.virtual_size),
|
||||
@"resident_size" : RCTProfileMemory(info.resident_size),
|
||||
};
|
||||
} else {
|
||||
return @{};
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Module hooks
|
||||
|
||||
static const char *RCTProfileProxyClassName(Class class)
|
||||
{
|
||||
return [kProfilePrefix stringByAppendingString:NSStringFromClass(class)].UTF8String;
|
||||
}
|
||||
|
||||
static dispatch_group_t RCTProfileGetUnhookGroup(void)
|
||||
{
|
||||
static dispatch_group_t unhookGroup;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
unhookGroup = dispatch_group_create();
|
||||
});
|
||||
|
||||
return unhookGroup;
|
||||
}
|
||||
|
||||
// Used by RCTProfileTrampoline assembly file to call libc`malloc
|
||||
RCT_EXTERN void *RCTProfileMalloc(size_t size);
|
||||
void *RCTProfileMalloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
// Used by RCTProfileTrampoline assembly file to call libc`free
|
||||
RCT_EXTERN void RCTProfileFree(void *buf);
|
||||
void RCTProfileFree(void *buf)
|
||||
{
|
||||
free(buf);
|
||||
}
|
||||
|
||||
RCT_EXTERN IMP RCTProfileGetImplementation(id obj, SEL cmd);
|
||||
IMP RCTProfileGetImplementation(id obj, SEL cmd)
|
||||
{
|
||||
return class_getMethodImplementation([obj class], cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the profiling we have to execute some code before and after every
|
||||
* function being profiled, the only way of doing that with pure Objective-C is
|
||||
* by using `-forwardInvocation:`, which is slow and could skew the profile
|
||||
* results.
|
||||
*
|
||||
* The alternative in assembly is much simpler, we just need to store all the
|
||||
* state at the beginning of the function, start the profiler, restore all the
|
||||
* state, call the actual function we want to profile and stop the profiler.
|
||||
*
|
||||
* The implementation can be found in RCTProfileTrampoline-<arch>.s where arch
|
||||
* is one of: i386, x86_64, arm, arm64.
|
||||
*/
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm64__)
|
||||
|
||||
RCT_EXTERN void RCTProfileTrampoline(void);
|
||||
#else
|
||||
static void *RCTProfileTrampoline = NULL;
|
||||
#endif
|
||||
|
||||
RCT_EXTERN void RCTProfileTrampolineStart(id, SEL);
|
||||
void RCTProfileTrampolineStart(id self, SEL cmd)
|
||||
{
|
||||
/**
|
||||
* This call might be during dealloc, so we shouldn't retain the object in the
|
||||
* block.
|
||||
*/
|
||||
Class klass = [self class];
|
||||
RCT_PROFILE_BEGIN_EVENT(
|
||||
RCTProfileTagAlways, ([NSString stringWithFormat:@"-[%s %s]", class_getName(klass), sel_getName(cmd)]), nil);
|
||||
}
|
||||
|
||||
RCT_EXTERN void RCTProfileTrampolineEnd(void);
|
||||
void RCTProfileTrampolineEnd(void)
|
||||
{
|
||||
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"objc_call,modules,auto");
|
||||
}
|
||||
|
||||
static UIView *(*originalCreateView)(RCTComponentData *, SEL, NSNumber *, NSNumber *);
|
||||
static UIView *RCTProfileCreateView(RCTComponentData *self, SEL _cmd, NSNumber *tag, NSNumber *rootTag)
|
||||
{
|
||||
UIView *view = originalCreateView(self, _cmd, tag, rootTag);
|
||||
RCTProfileHookInstance(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
static void RCTProfileHookUIManager(RCTUIManager *uiManager)
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
for (id view in [uiManager valueForKey:@"viewRegistry"]) {
|
||||
RCTProfileHookInstance([uiManager viewForReactTag:view]);
|
||||
}
|
||||
|
||||
Method createView = class_getInstanceMethod([RCTComponentData class], @selector(createViewWithTag:rootTag:));
|
||||
|
||||
if (method_getImplementation(createView) != (IMP)RCTProfileCreateView) {
|
||||
originalCreateView = (typeof(originalCreateView))method_getImplementation(createView);
|
||||
method_setImplementation(createView, (IMP)RCTProfileCreateView);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RCTProfileHookInstance(id instance)
|
||||
{
|
||||
Class moduleClass = object_getClass(instance);
|
||||
|
||||
/**
|
||||
* We swizzle the instance -class method to return the original class, but
|
||||
* object_getClass will return the actual class.
|
||||
*
|
||||
* If they are different, it means that the object is returning the original
|
||||
* class, but it's actual class is the proxy subclass we created.
|
||||
*/
|
||||
if ([instance class] != moduleClass) {
|
||||
return;
|
||||
}
|
||||
|
||||
Class proxyClass = objc_allocateClassPair(moduleClass, RCTProfileProxyClassName(moduleClass), 0);
|
||||
|
||||
if (!proxyClass) {
|
||||
proxyClass = objc_getClass(RCTProfileProxyClassName(moduleClass));
|
||||
if (proxyClass) {
|
||||
object_setClass(instance, proxyClass);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int methodCount;
|
||||
Method *methods = class_copyMethodList(moduleClass, &methodCount);
|
||||
for (NSUInteger i = 0; i < methodCount; i++) {
|
||||
Method method = methods[i];
|
||||
SEL selector = method_getName(method);
|
||||
|
||||
/**
|
||||
* Bail out on struct returns (except arm64) - we don't use it enough
|
||||
* to justify writing a stret version
|
||||
*/
|
||||
#ifdef __arm64__
|
||||
BOOL returnsStruct = NO;
|
||||
#else
|
||||
const char *typeEncoding = method_getTypeEncoding(method);
|
||||
// bail out on structs and unions (since they might contain structs)
|
||||
BOOL returnsStruct = typeEncoding[0] == '{' || typeEncoding[0] == '(';
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Avoid hooking into NSObject methods, methods generated by React Native
|
||||
* and special methods that start `.` (e.g. .cxx_destruct)
|
||||
*/
|
||||
if ([NSStringFromSelector(selector) hasPrefix:@"rct"] || [NSObject instancesRespondToSelector:selector] ||
|
||||
sel_getName(selector)[0] == '.' || returnsStruct) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *types = method_getTypeEncoding(method);
|
||||
class_addMethod(proxyClass, selector, (IMP)RCTProfileTrampoline, types);
|
||||
}
|
||||
free(methods);
|
||||
|
||||
class_replaceMethod(
|
||||
object_getClass(proxyClass),
|
||||
@selector(initialize),
|
||||
imp_implementationWithBlock(^{
|
||||
}),
|
||||
"v@:");
|
||||
|
||||
for (Class cls in @[ proxyClass, object_getClass(proxyClass) ]) {
|
||||
Method oldImp = class_getInstanceMethod(cls, @selector(class));
|
||||
class_replaceMethod(
|
||||
cls,
|
||||
@selector(class),
|
||||
imp_implementationWithBlock(^{
|
||||
return moduleClass;
|
||||
}),
|
||||
method_getTypeEncoding(oldImp));
|
||||
}
|
||||
|
||||
objc_registerClassPair(proxyClass);
|
||||
object_setClass(instance, proxyClass);
|
||||
|
||||
if (moduleClass == [RCTUIManager class]) {
|
||||
RCTProfileHookUIManager((RCTUIManager *)instance);
|
||||
}
|
||||
}
|
||||
|
||||
void RCTProfileHookModules(RCTBridge *bridge)
|
||||
{
|
||||
_RCTProfilingBridge = bridge;
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
|
||||
if (RCTProfileTrampoline == NULL) {
|
||||
return;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"RCTProfileHookModules", nil);
|
||||
for (RCTModuleData *moduleData in [bridge valueForKey:@"moduleDataByID"]) {
|
||||
// Only hook modules with an instance, to prevent initializing everything
|
||||
if ([moduleData hasInstance]) {
|
||||
[bridge
|
||||
dispatchBlock:^{
|
||||
RCTProfileHookInstance(moduleData.instance);
|
||||
}
|
||||
queue:moduleData.methodQueue];
|
||||
}
|
||||
}
|
||||
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
|
||||
}
|
||||
|
||||
static void RCTProfileUnhookInstance(id instance)
|
||||
{
|
||||
if ([instance class] != object_getClass(instance)) {
|
||||
object_setClass(instance, [instance class]);
|
||||
}
|
||||
}
|
||||
|
||||
void RCTProfileUnhookModules(RCTBridge *bridge)
|
||||
{
|
||||
_RCTProfilingBridge = nil;
|
||||
|
||||
dispatch_group_enter(RCTProfileGetUnhookGroup());
|
||||
|
||||
NSDictionary *moduleDataByID = [bridge valueForKey:@"moduleDataByID"];
|
||||
for (RCTModuleData *moduleData in moduleDataByID) {
|
||||
if ([moduleData hasInstance]) {
|
||||
RCTProfileUnhookInstance(moduleData.instance);
|
||||
}
|
||||
}
|
||||
|
||||
if ([bridge moduleIsInitialized:[RCTUIManager class]]) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
for (id view in [bridge.uiManager valueForKey:@"viewRegistry"]) {
|
||||
RCTProfileUnhookInstance([bridge.uiManager viewForReactTag:view]);
|
||||
}
|
||||
|
||||
dispatch_group_leave(RCTProfileGetUnhookGroup());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private ObjC class only used for the vSYNC CADisplayLink target
|
||||
|
||||
@interface RCTProfile : NSObject
|
||||
@end
|
||||
|
||||
@implementation RCTProfile
|
||||
|
||||
+ (void)vsync:(CADisplayLink *)displayLink
|
||||
{
|
||||
RCTProfileImmediateEvent(RCTProfileTagAlways, @"VSYNC", displayLink.timestamp, 'g');
|
||||
}
|
||||
|
||||
+ (void)reload
|
||||
{
|
||||
[RCTProfilingBridge() reloadWithReason:@"Profiling controls"];
|
||||
}
|
||||
|
||||
+ (void)toggle:(UIButton *)target
|
||||
{
|
||||
BOOL isProfiling = RCTProfileIsProfiling();
|
||||
|
||||
// Start and Stop are switched here, since we're going to toggle isProfiling
|
||||
[target setTitle:isProfiling ? @"Start" : @"Stop" forState:UIControlStateNormal];
|
||||
|
||||
if (isProfiling) {
|
||||
RCTProfileEnd(RCTProfilingBridge(), ^(NSString *result) {
|
||||
NSString *outFile = [NSTemporaryDirectory() stringByAppendingString:@"tmp_trace.json"];
|
||||
[result writeToFile:outFile atomically:YES encoding:NSUTF8StringEncoding error:nil];
|
||||
#if !TARGET_OS_TV
|
||||
UIActivityViewController *activityViewController =
|
||||
[[UIActivityViewController alloc] initWithActivityItems:@[ [NSURL fileURLWithPath:outFile] ]
|
||||
applicationActivities:nil];
|
||||
activityViewController.completionWithItemsHandler =
|
||||
^(__unused UIActivityType activityType,
|
||||
__unused BOOL completed,
|
||||
__unused NSArray *items,
|
||||
__unused NSError *error) {
|
||||
RCTProfileControlsWindow.hidden = NO;
|
||||
};
|
||||
RCTProfileControlsWindow.hidden = YES;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[[[RCTSharedApplication() delegate] window] rootViewController] presentViewController:activityViewController
|
||||
animated:YES
|
||||
completion:nil];
|
||||
});
|
||||
#endif
|
||||
});
|
||||
} else {
|
||||
RCTProfileInit(RCTProfilingBridge());
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)drag:(UIPanGestureRecognizer *)gestureRecognizer
|
||||
{
|
||||
CGPoint translation = [gestureRecognizer translationInView:RCTProfileControlsWindow];
|
||||
RCTProfileControlsWindow.center =
|
||||
CGPointMake(RCTProfileControlsWindow.center.x + translation.x, RCTProfileControlsWindow.center.y + translation.y);
|
||||
[gestureRecognizer setTranslation:CGPointMake(0, 0) inView:RCTProfileControlsWindow];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Public Functions
|
||||
|
||||
dispatch_queue_t RCTProfileGetQueue(void)
|
||||
{
|
||||
static dispatch_queue_t queue;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
queue = dispatch_queue_create("com.facebook.react.Profiler", DISPATCH_QUEUE_SERIAL);
|
||||
});
|
||||
return queue;
|
||||
}
|
||||
|
||||
BOOL RCTProfileIsProfiling(void)
|
||||
{
|
||||
return atomic_load(&RCTProfileProfiling);
|
||||
}
|
||||
|
||||
void RCTProfileInit(RCTBridge *bridge)
|
||||
{
|
||||
// TODO: enable assert JS thread from any file (and assert here)
|
||||
BOOL wasProfiling = atomic_fetch_or(&RCTProfileProfiling, 1);
|
||||
if (wasProfiling) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callbacks != NULL) {
|
||||
systrace_buffer = callbacks->start();
|
||||
} else {
|
||||
NSTimeInterval time = CACurrentMediaTime();
|
||||
dispatch_async(RCTProfileGetQueue(), ^{
|
||||
RCTProfileStartTime = time;
|
||||
RCTProfileOngoingEvents = [NSMutableDictionary new];
|
||||
RCTProfileInfo = @{
|
||||
kProfileTraceEvents : [NSMutableArray new],
|
||||
kProfileSamples : [NSMutableArray new],
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Set up thread ordering
|
||||
dispatch_async(RCTProfileGetQueue(), ^{
|
||||
NSArray *orderedThreads =
|
||||
@[ @"JS async", @"RCTPerformanceLogger", @"com.facebook.react.JavaScript", @(RCTUIManagerQueueName), @"main" ];
|
||||
[orderedThreads enumerateObjectsUsingBlock:^(NSString *thread, NSUInteger idx, __unused BOOL *stop) {
|
||||
RCTProfileAddEvent(kProfileTraceEvents,
|
||||
@"ph"
|
||||
: @"M", // metadata event
|
||||
@"name"
|
||||
: @"thread_sort_index", @"tid"
|
||||
: thread, @"args"
|
||||
:
|
||||
@{@"sort_index" : @(-1000 + (NSInteger)idx)});
|
||||
}];
|
||||
});
|
||||
|
||||
RCTProfileHookModules(bridge);
|
||||
|
||||
RCTProfileDisplayLink = [CADisplayLink displayLinkWithTarget:[RCTProfile class] selector:@selector(vsync:)];
|
||||
[RCTProfileDisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTProfileDidStartProfiling object:bridge];
|
||||
}
|
||||
|
||||
void RCTProfileEnd(RCTBridge *bridge, void (^callback)(NSString *))
|
||||
{
|
||||
// assert JavaScript thread here again
|
||||
BOOL wasProfiling = atomic_fetch_and(&RCTProfileProfiling, 0);
|
||||
if (!wasProfiling) {
|
||||
return;
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTProfileDidEndProfiling object:bridge];
|
||||
|
||||
[RCTProfileDisplayLink invalidate];
|
||||
RCTProfileDisplayLink = nil;
|
||||
|
||||
RCTProfileUnhookModules(bridge);
|
||||
|
||||
if (callbacks != NULL) {
|
||||
if (systrace_buffer) {
|
||||
callbacks->stop();
|
||||
callback(@(systrace_buffer));
|
||||
}
|
||||
} else {
|
||||
dispatch_async(RCTProfileGetQueue(), ^{
|
||||
NSString *log = RCTJSONStringify(RCTProfileInfo, NULL);
|
||||
RCTProfileEventID = 0;
|
||||
RCTProfileInfo = nil;
|
||||
RCTProfileOngoingEvents = nil;
|
||||
|
||||
callback(log);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static NSMutableArray<NSArray *> *RCTProfileGetThreadEvents(NSThread *thread)
|
||||
{
|
||||
static NSString *const RCTProfileThreadEventsKey = @"RCTProfileThreadEventsKey";
|
||||
NSMutableArray<NSArray *> *threadEvents = thread.threadDictionary[RCTProfileThreadEventsKey];
|
||||
if (!threadEvents) {
|
||||
threadEvents = [NSMutableArray new];
|
||||
thread.threadDictionary[RCTProfileThreadEventsKey] = threadEvents;
|
||||
}
|
||||
return threadEvents;
|
||||
}
|
||||
|
||||
void _RCTProfileBeginEvent(
|
||||
NSThread *calleeThread,
|
||||
NSTimeInterval time,
|
||||
uint64_t tag,
|
||||
NSString *name,
|
||||
NSDictionary<NSString *, NSString *> *args)
|
||||
{
|
||||
CHECK();
|
||||
|
||||
if (callbacks != NULL) {
|
||||
systrace_arg_t *systraceArgs = newSystraceArgsFromDictionary(args);
|
||||
callbacks->begin_section(tag, name.UTF8String, args.count, systraceArgs);
|
||||
free(systraceArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(RCTProfileGetQueue(), ^{
|
||||
NSMutableArray *events = RCTProfileGetThreadEvents(calleeThread);
|
||||
[events addObject:@[
|
||||
RCTProfileTimestamp(time),
|
||||
name,
|
||||
RCTNullIfNil(args),
|
||||
]];
|
||||
});
|
||||
}
|
||||
|
||||
void _RCTProfileEndEvent(
|
||||
NSThread *calleeThread,
|
||||
NSString *threadName,
|
||||
NSTimeInterval time,
|
||||
uint64_t tag,
|
||||
NSString *category)
|
||||
{
|
||||
CHECK();
|
||||
|
||||
if (callbacks != NULL) {
|
||||
callbacks->end_section(tag, 0, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(RCTProfileGetQueue(), ^{
|
||||
NSMutableArray<NSArray *> *events = RCTProfileGetThreadEvents(calleeThread);
|
||||
NSArray *event = events.lastObject;
|
||||
[events removeLastObject];
|
||||
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSNumber *start = event[0];
|
||||
RCTProfileAddEvent(kProfileTraceEvents, @"tid"
|
||||
: threadName, @"name"
|
||||
: event[1], @"cat"
|
||||
: category, @"ph"
|
||||
: @"X", @"ts"
|
||||
: start, @"dur"
|
||||
: @(RCTProfileTimestamp(time).doubleValue - start.doubleValue), @"args"
|
||||
: event[2], );
|
||||
});
|
||||
}
|
||||
|
||||
NSUInteger RCTProfileBeginAsyncEvent(uint64_t tag, NSString *name, NSDictionary<NSString *, NSString *> *args)
|
||||
{
|
||||
CHECK(0);
|
||||
|
||||
static NSUInteger eventID = 0;
|
||||
|
||||
NSTimeInterval time = CACurrentMediaTime();
|
||||
NSUInteger currentEventID = ++eventID;
|
||||
|
||||
if (callbacks != NULL) {
|
||||
systrace_arg_t *systraceArgs = newSystraceArgsFromDictionary(args);
|
||||
callbacks->begin_async_section(tag, name.UTF8String, (int)(currentEventID % INT_MAX), args.count, systraceArgs);
|
||||
free(systraceArgs);
|
||||
} else {
|
||||
dispatch_async(RCTProfileGetQueue(), ^{
|
||||
RCTProfileOngoingEvents[@(currentEventID)] = @[
|
||||
RCTProfileTimestamp(time),
|
||||
name,
|
||||
RCTNullIfNil(args),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
return currentEventID;
|
||||
}
|
||||
|
||||
void RCTProfileEndAsyncEvent(uint64_t tag, NSString *category, NSUInteger cookie, NSString *name, NSString *threadName)
|
||||
{
|
||||
CHECK();
|
||||
|
||||
if (callbacks != NULL) {
|
||||
callbacks->end_async_section(tag, name.UTF8String, (int)(cookie % INT_MAX), 0, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
NSTimeInterval time = CACurrentMediaTime();
|
||||
|
||||
dispatch_async(RCTProfileGetQueue(), ^{
|
||||
NSArray *event = RCTProfileOngoingEvents[@(cookie)];
|
||||
|
||||
if (event) {
|
||||
NSNumber *endTimestamp = RCTProfileTimestamp(time);
|
||||
|
||||
RCTProfileAddEvent(kProfileTraceEvents, @"tid"
|
||||
: threadName, @"name"
|
||||
: event[1], @"cat"
|
||||
: category, @"ph"
|
||||
: @"X", @"ts"
|
||||
: event[0], @"dur"
|
||||
: @(endTimestamp.doubleValue - [event[0] doubleValue]), @"args"
|
||||
: event[2], );
|
||||
[RCTProfileOngoingEvents removeObjectForKey:@(cookie)];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RCTProfileImmediateEvent(uint64_t tag, NSString *name, NSTimeInterval time, char scope)
|
||||
{
|
||||
CHECK();
|
||||
|
||||
if (callbacks != NULL) {
|
||||
callbacks->instant_section(tag, name.UTF8String, scope);
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *threadName = RCTCurrentThreadName();
|
||||
|
||||
dispatch_async(RCTProfileGetQueue(), ^{
|
||||
RCTProfileAddEvent(kProfileTraceEvents, @"tid"
|
||||
: threadName, @"name"
|
||||
: name, @"ts"
|
||||
: RCTProfileTimestamp(time), @"scope"
|
||||
: @(scope), @"ph"
|
||||
: @"i", @"args"
|
||||
: RCTProfileGetMemoryUsage(), );
|
||||
});
|
||||
}
|
||||
|
||||
NSUInteger _RCTProfileBeginFlowEvent(void)
|
||||
{
|
||||
static NSUInteger flowID = 0;
|
||||
|
||||
CHECK(0);
|
||||
|
||||
NSUInteger cookie = ++flowID;
|
||||
if (callbacks != NULL) {
|
||||
callbacks->begin_async_flow(1, "flow", (int)cookie);
|
||||
return cookie;
|
||||
}
|
||||
|
||||
NSTimeInterval time = CACurrentMediaTime();
|
||||
NSString *threadName = RCTCurrentThreadName();
|
||||
|
||||
dispatch_async(RCTProfileGetQueue(), ^{
|
||||
RCTProfileAddEvent(kProfileTraceEvents, @"tid"
|
||||
: threadName, @"name"
|
||||
: @"flow", @"id"
|
||||
: @(cookie), @"cat"
|
||||
: @"flow", @"ph"
|
||||
: @"s", @"ts"
|
||||
: RCTProfileTimestamp(time), );
|
||||
});
|
||||
|
||||
return cookie;
|
||||
}
|
||||
|
||||
void _RCTProfileEndFlowEvent(NSUInteger cookie)
|
||||
{
|
||||
CHECK();
|
||||
|
||||
if (callbacks != NULL) {
|
||||
callbacks->end_async_flow(1, "flow", (int)cookie);
|
||||
return;
|
||||
}
|
||||
|
||||
NSTimeInterval time = CACurrentMediaTime();
|
||||
NSString *threadName = RCTCurrentThreadName();
|
||||
|
||||
dispatch_async(RCTProfileGetQueue(), ^{
|
||||
RCTProfileAddEvent(kProfileTraceEvents, @"tid"
|
||||
: threadName, @"name"
|
||||
: @"flow", @"id"
|
||||
: @(cookie), @"cat"
|
||||
: @"flow", @"ph"
|
||||
: @"f", @"ts"
|
||||
: RCTProfileTimestamp(time), );
|
||||
});
|
||||
}
|
||||
|
||||
void RCTProfileSendResult(RCTBridge *bridge, NSString *route, NSData *data)
|
||||
{
|
||||
if (![bridge.bundleURL.scheme hasPrefix:@"http"]) {
|
||||
RCTLogWarn(
|
||||
@"Cannot upload profile information because you're not connected to the packager. The profiling data is still saved in the app container.");
|
||||
return;
|
||||
}
|
||||
|
||||
NSURL *URL = [NSURL URLWithString:[@"/" stringByAppendingString:route] relativeToURL:bridge.bundleURL];
|
||||
|
||||
NSMutableURLRequest *URLRequest = [NSMutableURLRequest requestWithURL:URL];
|
||||
URLRequest.HTTPMethod = @"POST";
|
||||
[URLRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
|
||||
NSURLSessionTask *task = [[NSURLSession sharedSession]
|
||||
uploadTaskWithRequest:URLRequest
|
||||
fromData:data
|
||||
completionHandler:^(NSData *responseData, __unused NSURLResponse *response, NSError *error) {
|
||||
if (error) {
|
||||
RCTLogError(@"%@", error.localizedDescription);
|
||||
} else {
|
||||
NSString *message = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
|
||||
|
||||
if (message.length) {
|
||||
#if !TARGET_OS_TV
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIAlertController *alertController =
|
||||
[UIAlertController alertControllerWithTitle:@"Profile"
|
||||
message:message
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"OK"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[RCTPresentedViewController() presentViewController:alertController animated:YES completion:nil];
|
||||
});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
[task resume];
|
||||
}
|
||||
|
||||
void RCTProfileShowControls(void)
|
||||
{
|
||||
static const CGFloat height = 30;
|
||||
static const CGFloat width = 60;
|
||||
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(20, 80, width * 2, height)];
|
||||
window.windowLevel = UIWindowLevelAlert + 1000;
|
||||
window.hidden = NO;
|
||||
window.backgroundColor = [UIColor lightGrayColor];
|
||||
window.layer.borderColor = [UIColor grayColor].CGColor;
|
||||
window.layer.borderWidth = 1;
|
||||
window.alpha = 0.8;
|
||||
|
||||
UIButton *startOrStop = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, width, height)];
|
||||
[startOrStop setTitle:RCTProfileIsProfiling() ? @"Stop" : @"Start" forState:UIControlStateNormal];
|
||||
[startOrStop addTarget:[RCTProfile class] action:@selector(toggle:) forControlEvents:UIControlEventTouchUpInside];
|
||||
startOrStop.titleLabel.font = [UIFont systemFontOfSize:12];
|
||||
|
||||
UIButton *reload = [[UIButton alloc] initWithFrame:CGRectMake(width, 0, width, height)];
|
||||
[reload setTitle:@"Reload" forState:UIControlStateNormal];
|
||||
[reload addTarget:[RCTProfile class] action:@selector(reload) forControlEvents:UIControlEventTouchUpInside];
|
||||
reload.titleLabel.font = [UIFont systemFontOfSize:12];
|
||||
|
||||
[window addSubview:startOrStop];
|
||||
[window addSubview:reload];
|
||||
|
||||
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:[RCTProfile class]
|
||||
action:@selector(drag:)];
|
||||
[window addGestureRecognizer:gestureRecognizer];
|
||||
|
||||
RCTProfileControlsWindow = window;
|
||||
}
|
||||
|
||||
void RCTProfileHideControls(void)
|
||||
{
|
||||
RCTProfileControlsWindow.hidden = YES;
|
||||
RCTProfileControlsWindow = nil;
|
||||
}
|
||||
|
||||
#endif
|
96
node_modules/react-native/React/Profiler/RCTProfileTrampoline-arm.S
generated
vendored
Normal file
96
node_modules/react-native/React/Profiler/RCTProfileTrampoline-arm.S
generated
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "RCTDefines.h"
|
||||
#include "RCTMacros.h"
|
||||
|
||||
#if RCT_PROFILE && defined(__arm__)
|
||||
|
||||
.thumb
|
||||
.thumb_func
|
||||
.globl SYMBOL_NAME(RCTProfileTrampoline)
|
||||
SYMBOL_NAME(RCTProfileTrampoline):
|
||||
/**
|
||||
* The explanation here is shorter, refer to the x86_64 implementation to a
|
||||
* richer explanation
|
||||
*/
|
||||
|
||||
/**
|
||||
* Save the parameter registers (r0-r3), r7 (frame pointer) and lr (link
|
||||
* register (contains the address of the caller of RCTProfileTrampoline)
|
||||
*/
|
||||
push {r0-r3, r7, lr}
|
||||
|
||||
/**
|
||||
* Allocate memory to store values across function calls: 12-bytes are
|
||||
* allocated to store 3 values: the previous value of the callee saved
|
||||
* register used to save the pointer to the allocated memory, the caller of
|
||||
* RCTProfileTrampoline and the address of the actual function we want to
|
||||
* profile
|
||||
*/
|
||||
mov r0, #0xc
|
||||
bl SYMBOL_NAME(RCTProfileMalloc)
|
||||
/**
|
||||
* r4 is the callee saved register we'll use to refer to the allocated memory,
|
||||
* store its initial value, so we can restore it later
|
||||
*/
|
||||
str r4, [r0]
|
||||
mov r4, r0
|
||||
|
||||
/**
|
||||
* void RCTProfileGetImplementation(id object, SEL selector) in RCTProfile.m
|
||||
*
|
||||
* Load the first 2 argumenters (self and _cmd) used to call
|
||||
* RCTProfileTrampoline from the stack and put them on the appropriate registers.
|
||||
*/
|
||||
ldr r0, [sp]
|
||||
ldr r1, [sp, #0x4]
|
||||
bl SYMBOL_NAME(RCTProfileGetImplementation)
|
||||
// store the actual function address in the allocated memory
|
||||
str r0, [r4, #0x4]
|
||||
|
||||
/**
|
||||
* void RCTProfileGetImplementation(id object, SEL selector) in RCTProfile.m
|
||||
*
|
||||
* Load the first 2 arguments again to start the profiler
|
||||
*/
|
||||
ldr r0, [sp]
|
||||
ldr r1, [sp, #0x4]
|
||||
bl SYMBOL_NAME(RCTProfileTrampolineStart)
|
||||
|
||||
/**
|
||||
* Restore the state to call the actual function we want to profile: pop
|
||||
* all the registers
|
||||
*/
|
||||
pop {r0-r3, r7, lr}
|
||||
|
||||
// store lr (the caller) since it'll be overridden by `blx` (call)
|
||||
str lr, [r4, #0x8]
|
||||
ldr r12, [r4, #0x4] // load the function address
|
||||
blx r12 // call it
|
||||
push {r0} // save return value
|
||||
|
||||
// void RCTProfileTrampolineEnd(void) in RCTProfile.m - just ends this profile
|
||||
bl SYMBOL_NAME(RCTProfileTrampolineEnd)
|
||||
|
||||
/**
|
||||
* Save the value we still need from the allocated memory (caller address),
|
||||
* restore r4 and free the allocated memory (put its address in r0)
|
||||
*/
|
||||
mov r0, r4
|
||||
ldr r1, [r4, #0x8]
|
||||
ldr r4, [r4]
|
||||
push {r1} // save the caller on the stack
|
||||
bl SYMBOL_NAME(RCTProfileFree)
|
||||
|
||||
pop {lr} // pop the caller
|
||||
pop {r0} // pop the return value
|
||||
bx lr // jump to the calleer
|
||||
|
||||
trap
|
||||
|
||||
#endif
|
125
node_modules/react-native/React/Profiler/RCTProfileTrampoline-arm64.S
generated
vendored
Normal file
125
node_modules/react-native/React/Profiler/RCTProfileTrampoline-arm64.S
generated
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "RCTDefines.h"
|
||||
#include "RCTMacros.h"
|
||||
|
||||
#if RCT_PROFILE && defined(__arm64__)
|
||||
|
||||
.align 5
|
||||
.globl SYMBOL_NAME(RCTProfileTrampoline)
|
||||
SYMBOL_NAME(RCTProfileTrampoline):
|
||||
/**
|
||||
* The explanation here is shorter, refer to the x86_64 implementation to a
|
||||
* richer explanation
|
||||
*/
|
||||
|
||||
// Basic prolog: save the frame pointer and the link register (caller address)
|
||||
stp fp, lr, [sp, #-16]!
|
||||
mov fp, sp
|
||||
|
||||
/**
|
||||
* Store the value of all the parameter registers (x0-x8, q0-q7) so we can
|
||||
* restore everything to the initial state at the time of the actual function
|
||||
* call
|
||||
*/
|
||||
sub sp, sp, #(10*8 + 8*16)
|
||||
stp q0, q1, [sp, #(0*16)]
|
||||
stp q2, q3, [sp, #(2*16)]
|
||||
stp q4, q5, [sp, #(4*16)]
|
||||
stp q6, q7, [sp, #(6*16)]
|
||||
stp x0, x1, [sp, #(8*16+0*8)]
|
||||
stp x2, x3, [sp, #(8*16+2*8)]
|
||||
stp x4, x5, [sp, #(8*16+4*8)]
|
||||
stp x6, x7, [sp, #(8*16+6*8)]
|
||||
str x8, [sp, #(8*16+8*8)]
|
||||
|
||||
/**
|
||||
* Allocate 16-bytes for the values that have to be preserved across the call
|
||||
* to the actual function, since the stack has to be in the exact initial
|
||||
* state. During its lifetimewe use it to store the initial value of the
|
||||
* callee saved registers we use to point the memory, the actual address of
|
||||
* the implementation and the caller address.
|
||||
*/
|
||||
mov x0, #0x10
|
||||
bl SYMBOL_NAME(RCTProfileMalloc)
|
||||
// store the initial value of r19, the callee saved register we'll use
|
||||
str x19, [x0]
|
||||
mov x19, x0
|
||||
|
||||
/**
|
||||
* void RCTProfileGetImplementation(id object, SEL selector)
|
||||
*
|
||||
* Load the 2 first arguments from the stack, they are the same used to call
|
||||
* this function
|
||||
*/
|
||||
ldp x0, x1, [sp, #(8*16+0*8)]
|
||||
bl SYMBOL_NAME(RCTProfileGetImplementation)
|
||||
str x0, [x19, #0x8] // store the actual function address
|
||||
|
||||
/**
|
||||
* void RCTProfileTrampolineStart(id, SEL) in RCTProfile.m
|
||||
*
|
||||
* start the profile, it takes the same first 2 arguments as above.
|
||||
*/
|
||||
ldp x0, x1, [sp, #(8*16+0*8)]
|
||||
bl SYMBOL_NAME(RCTProfileTrampolineStart)
|
||||
|
||||
// Restore all the parameter registers to the initial state.
|
||||
ldp q0, q1, [sp, #(0*16)]
|
||||
ldp q2, q3, [sp, #(2*16)]
|
||||
ldp q4, q5, [sp, #(4*16)]
|
||||
ldp q6, q7, [sp, #(6*16)]
|
||||
ldp x0, x1, [sp, #(8*16+0*8)]
|
||||
ldp x2, x3, [sp, #(8*16+2*8)]
|
||||
ldp x4, x5, [sp, #(8*16+4*8)]
|
||||
ldp x6, x7, [sp, #(8*16+6*8)]
|
||||
ldr x8, [sp, #(8*16+8*8)]
|
||||
|
||||
// Restore the stack pointer, frame pointer and link register
|
||||
mov sp, fp
|
||||
ldp fp, lr, [sp], #16
|
||||
|
||||
|
||||
ldr x9, [x19, #0x8] // Load the function
|
||||
str lr, [x19, #0x8] // store the address of the caller
|
||||
|
||||
blr x9 // call the actual function
|
||||
|
||||
/**
|
||||
* allocate 32-bytes on the stack, for the 2 return values + the caller
|
||||
* address that has to preserved across the call to `free`
|
||||
*/
|
||||
sub sp, sp, #0x20
|
||||
str q0, [sp, #0x0] // 16-byte return value
|
||||
str x0, [sp, #0x10] // 8-byte return value
|
||||
|
||||
// void RCTProfileTrampolineEnd(void) in RCTProfile.m - just ends this profile
|
||||
bl SYMBOL_NAME(RCTProfileTrampolineEnd)
|
||||
|
||||
/**
|
||||
* restore the callee saved registers, move the values we still need to the
|
||||
* stack and free the allocated memory
|
||||
*/
|
||||
mov x0, x19 // move the address of the memory to x0, first argument
|
||||
ldr x10, [x19, #0x8] // load the caller address
|
||||
ldr x19, [x19] // restore x19
|
||||
str x10, [sp, #0x18] // store x10 on the stack space allocated above
|
||||
bl SYMBOL_NAME(RCTProfileFree)
|
||||
|
||||
// Load both return values and link register from the stack
|
||||
ldr q0, [sp, #0x0]
|
||||
ldr x0, [sp, #0x10]
|
||||
ldr lr, [sp, #0x18]
|
||||
|
||||
// restore the stack pointer
|
||||
add sp, sp, #0x20
|
||||
|
||||
// jump to the calleer, without a link
|
||||
br lr
|
||||
|
||||
#endif
|
97
node_modules/react-native/React/Profiler/RCTProfileTrampoline-i386.S
generated
vendored
Normal file
97
node_modules/react-native/React/Profiler/RCTProfileTrampoline-i386.S
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "RCTDefines.h"
|
||||
#include "RCTMacros.h"
|
||||
|
||||
#if RCT_PROFILE && defined(__i386__)
|
||||
|
||||
.globl SYMBOL_NAME(RCTProfileTrampoline)
|
||||
SYMBOL_NAME(RCTProfileTrampoline):
|
||||
/**
|
||||
* The x86 version is much simpler, since all the arguments are passed in the
|
||||
* stack, so we just have to preserve the stack pointer (%esp) and the callee
|
||||
* saved register used to keep the memory allocated
|
||||
*
|
||||
* The explanation here is also shorter, refer to the x86_64 implementation to
|
||||
* a richer explanation
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allocate memory to save the caller of RCTProfileTrampoline (used afterwards
|
||||
* to return at the end of the function) and the initial value for the callee
|
||||
* saved register (%edi) that will be used to point to the memory allocated.
|
||||
*/
|
||||
subl $0x8, %esp // stack padding (16-byte alignment for function calls)
|
||||
pushl $0xc // allocate 12-bytes
|
||||
calll SYMBOL_NAME(RCTProfileMalloc)
|
||||
addl $0xc, %esp // restore stack (8-byte padding + 4-byte argument)
|
||||
|
||||
/**
|
||||
* actually store the values in the memory allocated
|
||||
*/
|
||||
movl %edi, 0x0(%eax) // previous value of edi
|
||||
popl 0x4(%eax) // caller of RCTProfileTrampoline
|
||||
|
||||
// save the pointer to the allocated memory in %edi
|
||||
movl %eax, %edi
|
||||
|
||||
/**
|
||||
* void RCTProfileGetImplementation(id object, SEL selector) in RCTProfile.m
|
||||
*
|
||||
* Get the address of the actual C function we have to profile
|
||||
*/
|
||||
calll SYMBOL_NAME(RCTProfileGetImplementation)
|
||||
movl %eax, 0x8(%edi) // Save it in the allocated memory
|
||||
|
||||
/**
|
||||
* void RCTProfileTrampolineStart(id, SEL) in RCTProfile.m
|
||||
*
|
||||
* start profile - the arguments are already in the right position in the
|
||||
* stack since it takes the same first 2 arguments as the any ObjC function -
|
||||
* "self" and "_cmd"
|
||||
*/
|
||||
calll SYMBOL_NAME(RCTProfileTrampolineStart)
|
||||
|
||||
/**
|
||||
* Call the actual function and save it's return value, since it should be the
|
||||
* return value of RCTProfileTrampoline
|
||||
*/
|
||||
calll *0x8(%edi)
|
||||
pushl %eax
|
||||
|
||||
// Align stack and end profile
|
||||
subl $0xc, %esp
|
||||
calll SYMBOL_NAME(RCTProfileTrampolineEnd)
|
||||
addl $0xc, %esp // restore the stack
|
||||
|
||||
/**
|
||||
* Move the values from the allocated memory to the stack, restore the
|
||||
* value of %edi, and prepare to free the allocated memory.
|
||||
*/
|
||||
pushl 0x4(%edi) // caller of RCTProfileTrampoline
|
||||
subl $0x4, %esp // Stack padding
|
||||
pushl %edi // push the memory address
|
||||
movl 0x0(%edi), %edi // restore the value of %edi
|
||||
|
||||
/**
|
||||
* Actually free the memory used to store the values across function calls,
|
||||
* the stack has already been padded and the first and only argument, the
|
||||
* memory address, is already in the bottom of the stack.
|
||||
*/
|
||||
calll SYMBOL_NAME(RCTProfileFree)
|
||||
addl $0x8, %esp
|
||||
|
||||
/**
|
||||
* pop the caller address to %ecx and the actual function return value to
|
||||
* %eax, so it's the return value of RCTProfileTrampoline
|
||||
*/
|
||||
popl %ecx
|
||||
popl %eax
|
||||
jmpl *%ecx
|
||||
|
||||
#endif
|
190
node_modules/react-native/React/Profiler/RCTProfileTrampoline-x86_64.S
generated
vendored
Normal file
190
node_modules/react-native/React/Profiler/RCTProfileTrampoline-x86_64.S
generated
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "RCTDefines.h"
|
||||
#include "RCTMacros.h"
|
||||
|
||||
#if RCT_PROFILE && defined(__x86_64__)
|
||||
|
||||
.globl SYMBOL_NAME(RCTProfileTrampoline)
|
||||
SYMBOL_NAME(RCTProfileTrampoline):
|
||||
|
||||
/**
|
||||
* Saves all the state so we can restore it before calling the functions being
|
||||
* profiled. Registers have the same value at the point of the function call,
|
||||
* the only thing we can change is the return value, so we return to
|
||||
* `RCTProfileTrampoline` rather than to its caller.
|
||||
*
|
||||
* Save all the parameters registers (%rdi, %rsi, %rdx, %rcx, %r8, %r9), they
|
||||
* have the 6 first arguments of the function call, and %rax which in special
|
||||
* cases might be a pointer used for struct returns.
|
||||
*
|
||||
* We have to save %r12 since its value should be preserved across function
|
||||
* calls and we'll use it to keep the stack pointer
|
||||
*/
|
||||
subq $0x80+8, %rsp // 8 x 16-bytes xmm registers + 8-bytes alignment
|
||||
movdqa %xmm0, 0x70(%rsp)
|
||||
movdqa %xmm1, 0x60(%rsp)
|
||||
movdqa %xmm2, 0x50(%rsp)
|
||||
movdqa %xmm3, 0x40(%rsp)
|
||||
movdqa %xmm4, 0x30(%rsp)
|
||||
movdqa %xmm5, 0x20(%rsp)
|
||||
movdqa %xmm6, 0x10(%rsp)
|
||||
movdqa %xmm7, 0x00(%rsp)
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
pushq %rdx
|
||||
pushq %rcx
|
||||
pushq %r8
|
||||
pushq %r9
|
||||
pushq %rax
|
||||
pushq %r12
|
||||
|
||||
/**
|
||||
* Store the stack pointer in the callee saved register %r12 and align the
|
||||
* stack - it has to 16-byte aligned at the point of the function call
|
||||
*/
|
||||
movq %rsp, %r12
|
||||
andq $-0x10, %rsp
|
||||
|
||||
/**
|
||||
* void RCTProfileGetImplementation(id object, SEL selector)
|
||||
*
|
||||
* This is a C function defined in `RCTProfile.m`, the object and the selector
|
||||
* already have to be on %rdi and %rsi respectively, as in any ObjC call.
|
||||
*/
|
||||
callq SYMBOL_NAME_PIC(RCTProfileGetImplementation)
|
||||
|
||||
// Restore/unalign the stack pointer, so we can access the registers we stored
|
||||
movq %r12, %rsp
|
||||
|
||||
/**
|
||||
* pop %r12 before pushing %rax, which contains the address of the actual
|
||||
* function we have to call, than we keep %r12 at the bottom of the stack to
|
||||
* reference the stack pointer
|
||||
*/
|
||||
popq %r12
|
||||
pushq %rax
|
||||
pushq %r12
|
||||
|
||||
// align stack
|
||||
movq %rsp, %r12
|
||||
andq $-0x10, %rsp
|
||||
|
||||
/**
|
||||
* Allocate memory to save parent before start profiling: the address is put
|
||||
* at the bottom of the stack at the function call, so ret can actually return
|
||||
* to the caller. In this case it has the address of RCTProfileTrampoline's
|
||||
* caller where we'll have to return to after we're finished.
|
||||
*
|
||||
* We can't store it on the stack or in any register, since we have to be in
|
||||
* the exact same state we were at the moment we were called, so the solution
|
||||
* is to allocate a tiny bit of memory to save this address
|
||||
*/
|
||||
|
||||
// allocate 16 bytes
|
||||
movq $0x10, %rdi
|
||||
callq SYMBOL_NAME_PIC(RCTProfileMalloc)
|
||||
|
||||
// store the initial value of calle saved registers %r13 and %r14
|
||||
movq %r13, 0x0(%rax)
|
||||
movq %r14, 0x8(%rax)
|
||||
|
||||
// mov the pointers we need to the callee saved registers
|
||||
movq 0xd8(%rsp), %r13 // caller of RCTProfileTrampoline (0xd8 is stack top)
|
||||
movq %rax, %r14 // allocated memory's address
|
||||
|
||||
/**
|
||||
* Move self and cmd back to the registers and call start profile: it uses
|
||||
* the object and the selector to label the call in the profile.
|
||||
*/
|
||||
movq 0x40(%r12), %rdi // object
|
||||
movq 0x38(%r12), %rsi // selector
|
||||
|
||||
// void RCTProfileTrampolineStart(id, SEL) in RCTProfile.m
|
||||
callq SYMBOL_NAME_PIC(RCTProfileTrampolineStart)
|
||||
|
||||
// unalign the stack and restore %r12
|
||||
movq %r12, %rsp
|
||||
popq %r12
|
||||
|
||||
// Restore registers for actual function call
|
||||
popq %r11
|
||||
popq %rax
|
||||
popq %r9
|
||||
popq %r8
|
||||
popq %rcx
|
||||
popq %rdx
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
movdqa 0x00(%rsp), %xmm7
|
||||
movdqa 0x10(%rsp), %xmm6
|
||||
movdqa 0x20(%rsp), %xmm5
|
||||
movdqa 0x30(%rsp), %xmm4
|
||||
movdqa 0x40(%rsp), %xmm3
|
||||
movdqa 0x50(%rsp), %xmm2
|
||||
movdqa 0x60(%rsp), %xmm1
|
||||
movdqa 0x70(%rsp), %xmm0
|
||||
addq $0x80+8, %rsp
|
||||
|
||||
/**
|
||||
* delete parent caller (saved in %r13) `call` will add the new address so
|
||||
* we return to RCTProfileTrampoline rather than to its caller
|
||||
*/
|
||||
addq $0x8, %rsp
|
||||
|
||||
// call the actual function and save the return value
|
||||
callq *%r11
|
||||
pushq %rax
|
||||
pushq %rdx
|
||||
subq $0x20, %rsp // 2 16-bytes xmm register
|
||||
movdqa %xmm0, 0x00(%rsp)
|
||||
movdqa %xmm1, 0x10(%rsp)
|
||||
|
||||
// void RCTProfileTrampolineEnd(void) in RCTProfile.m - just ends this profile
|
||||
callq SYMBOL_NAME_PIC(RCTProfileTrampolineEnd)
|
||||
|
||||
/**
|
||||
* Restore the initial value of the callee saved registers, saved in the
|
||||
* memory allocated.
|
||||
*/
|
||||
movq %r13, %rcx
|
||||
movq %r14, %rdi
|
||||
movq 0x0(%r14), %r13
|
||||
movq 0x8(%r14), %r14
|
||||
|
||||
/**
|
||||
* save caller address and actual function return (previously in the allocated
|
||||
* memory) and align the stack
|
||||
*/
|
||||
pushq %rcx
|
||||
pushq %r12
|
||||
movq %rsp, %r12
|
||||
andq $-0x10, %rsp
|
||||
|
||||
// Free the memory allocated to stash callee saved registers
|
||||
callq SYMBOL_NAME_PIC(RCTProfileFree)
|
||||
|
||||
// unalign stack and restore %r12
|
||||
movq %r12, %rsp
|
||||
popq %r12
|
||||
|
||||
/**
|
||||
* pop the caller address to %rcx and the actual function return value(s)
|
||||
* so it's the return value of RCTProfileTrampoline
|
||||
*/
|
||||
popq %rcx
|
||||
movdqa 0x00(%rsp), %xmm0
|
||||
movdqa 0x10(%rsp), %xmm1
|
||||
addq $0x20, %rsp
|
||||
popq %rdx
|
||||
popq %rax
|
||||
|
||||
// jump to caller
|
||||
jmpq *%rcx
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user