Skip to content

Commit

Permalink
Drastic performance enhancement by using a perfect hash instead of an…
Browse files Browse the repository at this point in the history
… sqlite3 database.
  • Loading branch information
saurik committed Nov 19, 2009
1 parent 52df64f commit 57e9ebe
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 162 deletions.
45 changes: 45 additions & 0 deletions Bridge.cpp
@@ -0,0 +1,45 @@
/* Cycript - Inlining/Optimizing JavaScript Compiler
* Copyright (C) 2009 Jay Freeman (saurik)
*/

/* Modified BSD License {{{ */
/*
* Redistribution and use in source and binary
* forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the
* above copyright notice, this list of conditions
* and the following disclaimer.
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions
* and the following disclaimer in the documentation
* and/or other materials provided with the
* distribution.
* 3. The name of the author may not be used to endorse
* or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* }}} */

#include <cstdlib>
#include "Bridge.hpp"

extern "C" struct CYBridgeEntry *CYBridgeHash(const char *data, size_t size) {
return CYBridgeHash_(data, size);
}
9 changes: 2 additions & 7 deletions Bridge.def
Expand Up @@ -205,7 +205,7 @@ C UITableViewRowAnimationFade 0
C UITableViewRowAnimationRight 1
C UITableViewRowAnimationLeft 2
C UITableViewRowAnimationTop 3
C UITableViewRowAnimationTop 4
C UITableViewRowAnimationBottom 4
C UITableViewRowAnimationNone 5

V UITableViewIndexSearch @
Expand Down Expand Up @@ -424,11 +424,6 @@ V kUIButtonBarButtonTitleVerticalHeight @
V kUIButtonBarButtonTitleWidth @
V kUIButtonBarButtonType @

V UIKeyboardAnimationCurveUserInfoKey @
V UIKeyboardAnimationDurationUserInfoKey @
V UIKeyboardBoundsUserInfoKey @
V UIKeyboardCenterBeginUserInfoKey @
V UIKeyboardCenterEndUserInfoKey @
V UIKeyboardRequiresInternationalKey @

V UIKeyboardCandidateCorrectionDidChangeNotification @
Expand Down Expand Up @@ -678,7 +673,7 @@ V NSMigrationSourceObjectKey @
V NSMigrationDestinationObjectKey @
V NSMigrationEntityMappingKey @
V NSMigrationPropertyMappingKey @
V NSMigrationPropertyMappingKey @
V NSMigrationEntityPolicyKey @

C NSManagedObjectResultType 0x00
C NSManagedObjectIDResultType 0x01
Expand Down
29 changes: 29 additions & 0 deletions Bridge.sh
@@ -0,0 +1,29 @@
#!/usr/bin/env bash

cat << EOF
%{
#include <cstring>
#include "Execute.hpp"
%}
%language=ANSI-C
%define lookup-function-name CYBridgeHash_
%define slot-name name_
%struct-type
%omit-struct-type
%pic
struct CYBridgeEntry {
int name_;
const char *value_;
};
%%
EOF

grep '^[CFV]' "$1" | sed -e 's/^C/0/;s/^F/1/;s/^V/2/' | sed -e 's/"/\\"/g;s/^\([^ ]*\) \([^ ]*\) \(.*\)$/\1\2, "\3"/';
grep '^[EST]' "$1" | sed -e 's/^S/3/;s/^T/4/;s/^E/5/' | sed -e 's/^5\(.*\)$/4\1 i/;s/"/\\"/g' | sed -e 's/^\([^ ]*\) \([^ ]*\) \(.*\)$/\1\2, "\3"/';
grep '^:' "$1" | sed -e 's/^: \([^ ]*\) \(.*\)/6\1, "\2"/';
2 changes: 1 addition & 1 deletion Darwin-arm.mk
Expand Up @@ -4,7 +4,7 @@ all += #cyrver

arch := iphoneos-arm
console += -framework UIKit
depends += apr-lib readline libffi mobilesubstrate sqlite3-lib
depends += apr-lib readline libffi mobilesubstrate
#library += -framework CFNetwork
library += -framework WebCore
# XXX: all Darwin, maybe all device, should have this
Expand Down
164 changes: 56 additions & 108 deletions Execute.cpp
Expand Up @@ -37,8 +37,6 @@
*/
/* }}} */

#include <sqlite3.h>

#include "Internal.hpp"

#include <dlfcn.h>
Expand All @@ -50,6 +48,7 @@
#include "sig/ffi_type.hpp"

#include "Pooling.hpp"
#include "Execute.hpp"

#include <sys/mman.h>

Expand All @@ -68,12 +67,6 @@
#include "JavaScript.hpp"
#include "String.hpp"

char *sqlite3_column_pooled(apr_pool_t *pool, sqlite3_stmt *stmt, int n) {
if (const unsigned char *value = sqlite3_column_text(stmt, n))
return apr_pstrdup(pool, (const char *) value);
else return NULL;
}

struct CYHooks *hooks_;

/* JavaScript Properties {{{ */
Expand Down Expand Up @@ -175,8 +168,6 @@ JSStringRef toJSON_s;

static JSStringRef Result_;

sqlite3 *Bridge_;

void CYFinalize(JSObjectRef object) {
delete reinterpret_cast<CYData *>(JSObjectGetPrivate(object));
}
Expand All @@ -196,49 +187,27 @@ void Structor_(apr_pool_t *pool, sig::Type *&type) {
if (type->primitive != sig::struct_P || type->name == NULL)
return;

sqlite3_stmt *statement;

_sqlcall(sqlite3_prepare(Bridge_,
"select "
"\"bridge\".\"mode\", "
"\"bridge\".\"value\" "
"from \"bridge\" "
"where"
" \"bridge\".\"mode\" in (3, 4) and"
" \"bridge\".\"name\" = ?"
" limit 1"
, -1, &statement, NULL));

_sqlcall(sqlite3_bind_text(statement, 1, type->name, -1, SQLITE_STATIC));

int mode;
const char *value;

if (_sqlcall(sqlite3_step(statement)) == SQLITE_DONE) {
mode = -1;
value = NULL;
} else {
mode = sqlite3_column_int(statement, 0);
value = sqlite3_column_pooled(pool, statement, 1);
}

_sqlcall(sqlite3_finalize(statement));

switch (mode) {
default:
_assert(false);
case -1:
break;

case 3: {
sig::Parse(pool, &type->data.signature, value, &Structor_);
} break;

case 4: {
sig::Signature signature;
sig::Parse(pool, &signature, value, &Structor_);
type = signature.elements[0].type;
} break;
size_t length(strlen(type->name));
char keyed[length + 2];
memcpy(keyed + 1, type->name, length + 1);

static const char *modes = "34";
for (size_t i(0); i != 2; ++i) {
char mode(modes[i]);
keyed[0] = mode;

if (CYBridgeEntry *entry = CYBridgeHash(keyed, length + 1))
switch (mode) {
case '3':
sig::Parse(pool, &type->data.signature, entry->value_, &Structor_);
break;

case '4': {
sig::Signature signature;
sig::Parse(pool, &signature, entry->value_, &Structor_);
type = signature.elements[0].type;
} break;
}
}
}

Expand Down Expand Up @@ -968,61 +937,42 @@ static JSValueRef All_getProperty(JSContextRef context, JSObjectRef object, JSSt
if (JSValueRef value = (*hooks_->RuntimeProperty)(context, name))
return value;

sqlite3_stmt *statement;

_sqlcall(sqlite3_prepare(Bridge_,
"select "
"\"bridge\".\"mode\", "
"\"bridge\".\"value\" "
"from \"bridge\" "
"where"
" \"bridge\".\"name\" = ?"
" limit 1"
, -1, &statement, NULL));

_sqlcall(sqlite3_bind_text(statement, 1, name.data, name.size, SQLITE_STATIC));

int mode;
const char *value;

if (_sqlcall(sqlite3_step(statement)) == SQLITE_DONE) {
mode = -1;
value = NULL;
} else {
mode = sqlite3_column_int(statement, 0);
value = sqlite3_column_pooled(pool, statement, 1);
size_t length(name.size);
char keyed[length + 2];
memcpy(keyed + 1, name.data, length + 1);

static const char *modes = "0124";
for (size_t i(0); i != 4; ++i) {
char mode(modes[i]);
keyed[0] = mode;

if (CYBridgeEntry *entry = CYBridgeHash(keyed, length + 1))
switch (mode) {
case '0':
return JSEvaluateScript(CYGetJSContext(context), CYJSString(entry->value_), NULL, NULL, 0, NULL);

case '1':
if (void (*symbol)() = reinterpret_cast<void (*)()>(CYCastSymbol(name.data)))
return CYMakeFunctor(context, symbol, entry->value_);
else return NULL;

case '2':
if (void *symbol = CYCastSymbol(name.data)) {
// XXX: this is horrendously inefficient
sig::Signature signature;
sig::Parse(pool, &signature, entry->value_, &Structor_);
ffi_cif cif;
sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
return CYFromFFI(context, signature.elements[0].type, cif.rtype, symbol);
} else return NULL;

// XXX: implement case 3
case '4':
return CYMakeType(context, entry->value_);
}
}

_sqlcall(sqlite3_finalize(statement));

switch (mode) {
default:
CYThrow("invalid mode from bridge table: %d", mode);
case -1:
return NULL;

case 0:
return JSEvaluateScript(CYGetJSContext(context), CYJSString(value), NULL, NULL, 0, NULL);

case 1:
if (void (*symbol)() = reinterpret_cast<void (*)()>(CYCastSymbol(name.data)))
return CYMakeFunctor(context, symbol, value);
else return NULL;

case 2:
if (void *symbol = CYCastSymbol(name.data)) {
// XXX: this is horrendously inefficient
sig::Signature signature;
sig::Parse(pool, &signature, value, &Structor_);
ffi_cif cif;
sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
return CYFromFFI(context, signature.elements[0].type, cif.rtype, symbol);
} else return NULL;

// XXX: implement case 3
case 4:
return CYMakeType(context, value);
}
return NULL;
} CYCatch }

static JSObjectRef Pointer_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
Expand Down Expand Up @@ -1280,8 +1230,6 @@ void CYInitializeDynamic() {

CYInitializeStatic();

_sqlcall(sqlite3_open("/usr/lib/libcycript.db", &Bridge_));

JSObjectMakeArray$ = reinterpret_cast<JSObjectRef (*)(JSContextRef, size_t, const JSValueRef[], JSValueRef *)>(dlsym(RTLD_DEFAULT, "JSObjectMakeArray"));

JSClassDefinition definition;
Expand Down
50 changes: 50 additions & 0 deletions Execute.hpp
@@ -0,0 +1,50 @@
/* Cycript - Inlining/Optimizing JavaScript Compiler
* Copyright (C) 2009 Jay Freeman (saurik)
*/

/* Modified BSD License {{{ */
/*
* Redistribution and use in source and binary
* forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the
* above copyright notice, this list of conditions
* and the following disclaimer.
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions
* and the following disclaimer in the documentation
* and/or other materials provided with the
* distribution.
* 3. The name of the author may not be used to endorse
* or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* }}} */

#ifndef CYCRIPT_EXECUTE_HPP
#define CYCRIPT_EXECUTE_HPP

struct CYBridgeEntry {
int name_;
const char *value_;
};

extern "C" struct CYBridgeEntry *CYBridgeHash(const char *data, size_t size);

#endif/*CYCRIPT_EXECUTE_HPP*/

0 comments on commit 57e9ebe

Please sign in to comment.