Implement asm trampoline rather forwardInvocation

Summary: public

The profiler overrides all the methods of all the BridgeModules, and in order to
`start` and `end` the profiler at the function invocation time it used `NSInvocation`,
which is slow.

Replace it with a simple assembly method based on `objc_msgSend`.

Reviewed By: jspahrsummers

Differential Revision: D2550807

fb-gh-sync-id: 88ca08f9d6bfcd3035bda9304c93566c8818b46f
This commit is contained in:
Tadeu Zagallo 2015-10-20 04:11:38 -07:00 committed by facebook-github-bot-5
parent 1b29690496
commit 89c1747c33
8 changed files with 540 additions and 57 deletions

View File

@ -7,7 +7,9 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
#if __OBJC__
# import <Foundation/Foundation.h>
#endif
/**
* Make global functions usable in C++

View File

@ -9,6 +9,8 @@
#import "RCTProfile.h"
#import <dlfcn.h>
#import <mach/mach.h>
#import <objc/message.h>
#import <objc/runtime.h>
@ -153,21 +155,11 @@ static NSDictionary *RCTProfileMergeArgs(NSDictionary *args0, NSDictionary *args
#pragma mark - Module hooks
static const char *RCTProfileProxyClassName(Class);
static const char *RCTProfileProxyClassName(Class class)
{
return [RCTProfilePrefix stringByAppendingString:NSStringFromClass(class)].UTF8String;
}
static SEL RCTProfileProxySelector(SEL);
static SEL RCTProfileProxySelector(SEL selector)
{
NSString *selectorName = NSStringFromSelector(selector);
return NSSelectorFromString([RCTProfilePrefix stringByAppendingString:selectorName]);
}
static dispatch_group_t RCTProfileGetUnhookGroup(void);
static dispatch_group_t RCTProfileGetUnhookGroup(void)
{
static dispatch_group_t unhookGroup;
@ -179,45 +171,55 @@ static dispatch_group_t RCTProfileGetUnhookGroup(void)
return unhookGroup;
}
static void RCTProfileForwardInvocation(NSObject *, SEL, NSInvocation *);
static void RCTProfileForwardInvocation(NSObject *self, __unused SEL cmd, NSInvocation *invocation)
RCT_EXTERN IMP RCTProfileGetImplementation(id obj, SEL cmd);
IMP RCTProfileGetImplementation(id obj, SEL cmd)
{
/**
* This is still not thread safe, but should reduce reasonably the number of crashes
*/
dispatch_group_wait(RCTProfileGetUnhookGroup(), DISPATCH_TIME_FOREVER);
NSString *name = [NSString stringWithFormat:@"-[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(invocation.selector)];
SEL newSel = RCTProfileProxySelector(invocation.selector);
if ([object_getClass(self) instancesRespondToSelector:newSel]) {
invocation.selector = newSel;
RCTProfileBeginEvent(0, name, nil);
[invocation invoke];
RCTProfileEndEvent(0, @"objc_call,modules,auto", nil);
} else if ([self respondsToSelector:invocation.selector]) {
[invocation invoke];
} else {
// Use original selector to don't change error message
[self doesNotRecognizeSelector:invocation.selector];
}
return class_getMethodImplementation([obj class], cmd);
}
static IMP RCTProfileMsgForward(NSObject *, SEL);
static IMP RCTProfileMsgForward(NSObject *self, SEL selector)
/**
* 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: x86, x86_64, arm, arm64.
*/
static IMP RCTProfileGetTrampoline(void)
{
IMP imp = (IMP)_objc_msgForward;
#if !defined(__arm64__)
NSMethodSignature *signature = [self methodSignatureForSelector:selector];
if (signature.methodReturnType[0] == _C_STRUCT_B && signature.methodReturnLength > 8) {
imp = (IMP)_objc_msgForward_stret;
}
#endif
return imp;
static void (*RCTProfileTrampoline)(void);
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
RCTProfileTrampoline = dlsym(RTLD_DEFAULT, "RCTProfileTrampoline");
});
return (IMP)RCTProfileTrampoline;
}
RCT_EXTERN void RCTProfileTrampolineStart(id, SEL);
void RCTProfileTrampolineStart(id self, SEL cmd)
{
NSString *name = [NSString stringWithFormat:@"-[%s %s]", class_getName([self class]), sel_getName(cmd)];
RCTProfileBeginEvent(0, name, nil);
}
RCT_EXTERN void RCTProfileTrampolineEnd(void);
void RCTProfileTrampolineEnd(void)
{
RCTProfileEndEvent(0, @"objc_call,modules,auto", nil);
}
void RCTProfileHookModules(RCTBridge *bridge)
{
if (RCTProfileGetTrampoline() == NULL) {
return;
}
for (RCTModuleData *moduleData in [bridge valueForKey:@"moduleDataByID"]) {
[moduleData dispatchBlock:^{
Class moduleClass = moduleData.moduleClass;
@ -235,10 +237,9 @@ void RCTProfileHookModules(RCTBridge *bridge)
if ([NSStringFromSelector(selector) hasPrefix:@"rct"] || [NSObject instancesRespondToSelector:selector]) {
continue;
}
IMP originalIMP = method_getImplementation(method);
const char *returnType = method_getTypeEncoding(method);
class_addMethod(proxyClass, selector, RCTProfileMsgForward(moduleData.instance, selector), returnType);
class_addMethod(proxyClass, RCTProfileProxySelector(selector), originalIMP, returnType);
const char *types = method_getTypeEncoding(method);
class_addMethod(proxyClass, selector, RCTProfileGetTrampoline(), types);
}
free(methods);
@ -249,11 +250,6 @@ void RCTProfileHookModules(RCTBridge *bridge)
class_replaceMethod(cls, @selector(class), imp_implementationWithBlock(^{ return moduleClass; }), method_getTypeEncoding(oldImp));
}
IMP originalFwd = class_replaceMethod(moduleClass, @selector(forwardInvocation:), (IMP)RCTProfileForwardInvocation, "v@:@");
if (originalFwd != NULL) {
class_addMethod(proxyClass, RCTProfileProxySelector(@selector(forwardInvocation:)), originalFwd, "v@:@");
}
objc_registerClassPair(proxyClass);
object_setClass(moduleData.instance, proxyClass);
}];

View File

@ -0,0 +1,85 @@
#include "RCTDefines.h"
#if RCT_DEV && defined(__arm__)
.align 5
.globl _RCTProfileTrampoline
_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 _malloc
/**
* 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 _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 _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 _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 _free
pop {lr} // pop the caller
pop {r0} // pop the return value
bx lr // jump to the calleer
#endif

View File

@ -0,0 +1,117 @@
#include "RCTDefines.h"
#if RCT_DEV && defined(__arm64__)
.align 5
.globl _RCTProfileTrampoline
_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 _malloc
// 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 _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 _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 _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 _free
// 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

View File

@ -0,0 +1,89 @@
#include "RCTDefines.h"
#if RCT_DEV && defined(__i386__)
.globl _RCTProfileTrampoline
_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 _malloc
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 _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 _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 _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 _free
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

View File

@ -0,0 +1,170 @@
#include "RCTDefines.h"
#if RCT_DEV && defined(__x86_64__)
.globl _RCTProfileTrampoline
_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
*/
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 _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 _malloc
// 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 0x48(%rsp), %r13 // caller of RCTProfileTrampoline
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 _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
/**
* 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
// align stack
pushq %r12
movq %rsp, %r12
andq $-0x10, %rsp
// void RCTProfileTrampolineEnd(void) in RCTProfile.m - just ends this profile
callq _RCTProfileTrampolineEnd
// unalign stack and restore %r12
movq %r12, %rsp
popq %r12
// save the return of the actual function call
popq %rax
/**
* Restore the initial value of the callee saved registers, saved in the
* memory allocated.
*/
movq %r13, %rcx
movq %r14, %rdx
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 %rax
pushq %r12
movq %rsp, %r12
andq $-0x10, %rsp
// Free the memory allocated to stash callee saved registers
movq %rdx, %rdi
callq _free
// unalign stack and restore %r12
movq %r12, %rsp
popq %r12
/**
* pop the caller address to %rcx and the actual function return value to
* %rax, so it's the return value of RCTProfileTrampoline
*/
popq %rax
popq %rcx
// jump to caller
jmpq *%rcx
#endif

View File

@ -54,6 +54,11 @@
142014191B32094000CC17BA /* RCTPerformanceLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 142014171B32094000CC17BA /* RCTPerformanceLogger.m */; };
14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 14435CE21AAC4AE100FC20F4 /* RCTMap.m */; };
14435CE61AAC4AE100FC20F4 /* RCTMapManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14435CE41AAC4AE100FC20F4 /* RCTMapManager.m */; };
1450FF861BCFF28A00208362 /* RCTProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF811BCFF28A00208362 /* RCTProfile.m */; settings = {ASSET_TAGS = (); }; };
1450FF871BCFF28A00208362 /* RCTProfileTrampoline-arm.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */; settings = {ASSET_TAGS = (); }; };
1450FF881BCFF28A00208362 /* RCTProfileTrampoline-arm64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */; settings = {ASSET_TAGS = (); }; };
1450FF891BCFF28A00208362 /* RCTProfileTrampoline-x86.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF841BCFF28A00208362 /* RCTProfileTrampoline-x86.S */; settings = {ASSET_TAGS = (); }; };
1450FF8A1BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */; settings = {ASSET_TAGS = (); }; };
146459261B06C49500B389AA /* RCTFPSGraph.m in Sources */ = {isa = PBXBuildFile; fileRef = 146459251B06C49500B389AA /* RCTFPSGraph.m */; };
14C2CA711B3AC63800E6CBB2 /* RCTModuleMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */; };
14C2CA741B3AC64300E6CBB2 /* RCTModuleData.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA731B3AC64300E6CBB2 /* RCTModuleData.m */; };
@ -62,7 +67,6 @@
14F3620D1AABD06A001CE568 /* RCTSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F362081AABD06A001CE568 /* RCTSwitch.m */; };
14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */; };
14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */; };
14F4D38B1AE1B7E40049C042 /* RCTProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F4D38A1AE1B7E40049C042 /* RCTProfile.m */; };
58114A161AAE854800E7D092 /* RCTPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A131AAE854800E7D092 /* RCTPicker.m */; };
58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A151AAE854800E7D092 /* RCTPickerManager.m */; };
58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A4E1AAE93D500E7D092 /* RCTAsyncLocalStorage.m */; };
@ -203,6 +207,12 @@
14435CE21AAC4AE100FC20F4 /* RCTMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMap.m; sourceTree = "<group>"; };
14435CE31AAC4AE100FC20F4 /* RCTMapManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMapManager.h; sourceTree = "<group>"; };
14435CE41AAC4AE100FC20F4 /* RCTMapManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMapManager.m; sourceTree = "<group>"; };
1450FF801BCFF28A00208362 /* RCTProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTProfile.h; sourceTree = "<group>"; };
1450FF811BCFF28A00208362 /* RCTProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTProfile.m; sourceTree = "<group>"; };
1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-arm.S"; sourceTree = "<group>"; };
1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-arm64.S"; sourceTree = "<group>"; };
1450FF841BCFF28A00208362 /* RCTProfileTrampoline-x86.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-x86.S"; sourceTree = "<group>"; };
1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-x86_64.S"; sourceTree = "<group>"; };
146459241B06C49500B389AA /* RCTFPSGraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTFPSGraph.h; sourceTree = "<group>"; };
146459251B06C49500B389AA /* RCTFPSGraph.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTFPSGraph.m; sourceTree = "<group>"; };
1482F9E61B55B927000ADFF3 /* RCTBridgeDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTBridgeDelegate.h; sourceTree = "<group>"; };
@ -218,8 +228,6 @@
14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSwitchManager.m; sourceTree = "<group>"; };
14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSliderManager.h; sourceTree = "<group>"; };
14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSliderManager.m; sourceTree = "<group>"; };
14F4D3891AE1B7E40049C042 /* RCTProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTProfile.h; sourceTree = "<group>"; };
14F4D38A1AE1B7E40049C042 /* RCTProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTProfile.m; sourceTree = "<group>"; };
58114A121AAE854800E7D092 /* RCTPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPicker.h; sourceTree = "<group>"; };
58114A131AAE854800E7D092 /* RCTPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPicker.m; sourceTree = "<group>"; };
58114A141AAE854800E7D092 /* RCTPickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPickerManager.h; sourceTree = "<group>"; };
@ -422,6 +430,19 @@
path = Views;
sourceTree = "<group>";
};
1450FF7F1BCFF28A00208362 /* Profiler */ = {
isa = PBXGroup;
children = (
1450FF801BCFF28A00208362 /* RCTProfile.h */,
1450FF811BCFF28A00208362 /* RCTProfile.m */,
1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */,
1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */,
1450FF841BCFF28A00208362 /* RCTProfileTrampoline-x86.S */,
1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */,
);
path = Profiler;
sourceTree = "<group>";
};
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
@ -447,6 +468,7 @@
134FCB381A6E7F0800051CC8 /* Executors */,
13B07FC41A68125100A75B9A /* Layout */,
13B07FE01A69315300A75B9A /* Modules */,
1450FF7F1BCFF28A00208362 /* Profiler */,
13B07FF31A6947C200A75B9A /* Views */,
);
name = React;
@ -491,8 +513,6 @@
142014171B32094000CC17BA /* RCTPerformanceLogger.m */,
1403F2B11B0AE60700C2A9A4 /* RCTPerfStats.h */,
1403F2B21B0AE60700C2A9A4 /* RCTPerfStats.m */,
14F4D3891AE1B7E40049C042 /* RCTProfile.h */,
14F4D38A1AE1B7E40049C042 /* RCTProfile.m */,
830A229C1A66C68A008503DA /* RCTRootView.h */,
830A229D1A66C68A008503DA /* RCTRootView.m */,
83BEE46C1A6D19BC00B5863B /* RCTSparseArray.h */,
@ -614,13 +634,14 @@
8385CF351B8B77CD00C6273E /* RCTKeyboardObserver.m in Sources */,
58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */,
832348161A77A5AA00B55238 /* Layout.c in Sources */,
14F4D38B1AE1B7E40049C042 /* RCTProfile.m in Sources */,
13513F3C1B1F43F400FCE529 /* RCTProgressViewManager.m in Sources */,
14F3620D1AABD06A001CE568 /* RCTSwitch.m in Sources */,
14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */,
13B080201A69489C00A75B9A /* RCTActivityIndicatorViewManager.m in Sources */,
13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */,
58C571C11AA56C1900CDF9C8 /* RCTDatePickerManager.m in Sources */,
1450FF8A1BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S in Sources */,
1450FF881BCFF28A00208362 /* RCTProfileTrampoline-arm64.S in Sources */,
13B080061A6947C200A75B9A /* RCTScrollViewManager.m in Sources */,
146459261B06C49500B389AA /* RCTFPSGraph.m in Sources */,
14200DAA1AC179B3008EE6BA /* RCTJavaScriptLoader.m in Sources */,
@ -654,6 +675,7 @@
137327E81AA5CF210034F82E /* RCTTabBarItem.m in Sources */,
83A1FE8C1B62640A00BE0E65 /* RCTModalHostView.m in Sources */,
13E067551A70F44B002CDEE1 /* RCTShadowView.m in Sources */,
1450FF871BCFF28A00208362 /* RCTProfileTrampoline-arm.S in Sources */,
131B6AF51AF1093D00FFC3E0 /* RCTSegmentedControlManager.m in Sources */,
58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */,
13B0801A1A69489C00A75B9A /* RCTNavigator.m in Sources */,
@ -662,6 +684,7 @@
13F17A851B8493E5007D4C75 /* RCTRedBox.m in Sources */,
83392EB31B6634E10013B15F /* RCTModalHostViewController.m in Sources */,
14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */,
1450FF891BCFF28A00208362 /* RCTProfileTrampoline-x86.S in Sources */,
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */,
13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */,
1385D0341B665AAE000A309B /* RCTModuleMap.m in Sources */,
@ -669,6 +692,7 @@
83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */,
83A1FE8F1B62643A00BE0E65 /* RCTModalHostViewManager.m in Sources */,
13E0674A1A70F434002CDEE1 /* RCTUIManager.m in Sources */,
1450FF861BCFF28A00208362 /* RCTProfile.m in Sources */,
13AB90C11B6FA36700713B4F /* RCTComponentData.m in Sources */,
13B0801B1A69489C00A75B9A /* RCTNavigatorManager.m in Sources */,
);