Thursday, September 22, 2016

Buggy Crossbridge

1. The Problem

Our game client is made up of two swf files (e.g. preloader.swf and game.swf, and preloader.swf will load game.swf), each of which has to do some md5 caculations.
We implemented the md5 algorithm in C and compile it to md5.swc via crossbridge, because we found that md5 algorithm implemention in AS3 is far more slower than implemention in C (and compiled by Crossbridge).
These two swf files are maintained by 2 different teams and the building environment is not very smart, so we distributed the binary md5.swc file to them manually.
It work pretty well at first, until one day one of the team compiled a new md5.swc with the exact same code. Theoretically these was no problem there, but strangly the preloader.swf would now unable to load game.swf any more. In fact, we found we always have to use the same md5.swf. Even with the same code and same building envrionment, two md5.swf generated at two different times will always cause error.

2. The Root cause

The md5.swc compiled via Crossbridge contains two main namespaces:
  • a public namespace with name provide by developer
  • a private namespace with some random name
These two namespaces reference each other. In fact, when loading, code in private namespace may perform some initializion by calling code in public namespace.
Two build of the same code with have:
  • same public namespace
  • two different private namespace
So when preloader.swf loads game.swf with a different md5.swc, the public namespace may be initialized twice.

3. The solution

There are two solutions: - Make sure these two swf always use the same build of md5.swc - Change crossbridge to not generate random name for private namespace.
The path for the second solution is:
 llvm-2.9/lib/Target/AVM2/AVM2AsmPrinter.cpp | 16 +---------------
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/llvm-2.9/lib/Target/AVM2/AVM2AsmPrinter.cpp b/llvm-2.9/lib/Target/AVM2/AVM2AsmPrinter.cpp
index af61a9d..8b433fb 100644
--- a/llvm-2.9/lib/Target/AVM2/AVM2AsmPrinter.cpp
+++ b/llvm-2.9/lib/Target/AVM2/AVM2AsmPrinter.cpp
@@ -668,21 +668,7 @@ public:
     }

     std::string getModulePackageName(const Module &M) const {
- // need to add a UUID to the module ident so it's really unique
- static std::map<const Module *, UUID> modUUIDs;
-
-        std::string uuid = modUUIDs[&M].str();
-        std::string EID = M.getModuleIdentifier();
-        std::replace(EID.begin(), EID.end(), '@', '_'); // Mangler allows '@' but we don't.. should be only char Mangler thinks is ok that we don't like
-
-        EID += ":";
-        EID += uuid;
-
-        Twine TMN = EID;
-        SmallString<256> MN;
-        Mang->getNameWithPrefix(MN, TMN);
-        std::string R = MN.str();
-        return getPackageName(M) + R;
+  return "C_Run_internal";
     }

     // Following the behavior of llvm-2.9/tools/lto/LTOModule.cpp
The result is as following(The top one is changed, the bottom one is original):
crossbridge namespace.png

Thursday, September 01, 2016

Introducing Lightmc - A Netty based RPC Library

1. Backgound

Our game system are composed of more than 10 kinds of java services, and some of them have hundreds of instances.
For underlying communication library, we investigated several open source candidates. They can be mainly divided into two categories:
  • rpc based, such as
    • finagle
    • thrift
    • grpc
    • KryoNet
  • message based, such as
    • akka
    • zeromq