react-native/React/Profiler/RCTProfileTrampoline-x86_64.S

193 lines
5.3 KiB
ArmAsm
Raw Normal View History

Refactored module access to allow for lazy loading Summary: public The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed. This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead. The rules are now as follows: * Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created * Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but `constantsToExport:` will still be called on the main thread. * All other modules will be initialized lazily when a method is first called on them. These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily. I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results: Out of the 65 modules included in UIExplorer: * 16 are initialized on the main thread when the bridge is created * A further 8 are initialized when the config is exported to JS * The remaining 41 will be initialized lazily on-demand Reviewed By: jspahrsummers Differential Revision: D2677695 fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
2015-11-25 11:09:00 +00:00
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include "RCTDefines.h"
#include "RCTMacros.h"
#if RCT_DEV && 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(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(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 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(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(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(free)
// 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