Skip to content

Commit

Permalink
Basic script snapshot support (no versioning yet)
Browse files Browse the repository at this point in the history
  • Loading branch information
sam-mccall committed May 25, 2012
1 parent 51beddb commit 1bdaff0
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 69 deletions.
4 changes: 4 additions & 0 deletions build.config
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ DART_SRC=$HOME/dart/source/dart
DART_ARCH=x64
#DART_ARCH=ia32

# Pick the appropriate build mode (must match the Dart you build)
#DART_MODE=Debug
DART_MODE=Release

# Path to Apache apxs, leave blank if apxs or apxs2 is on the PATH
APXS=

Expand Down
15 changes: 10 additions & 5 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,28 @@ type "$HTTPD" || exit "Couldn't find httpd, edit build.config"

UNAME=`uname`
if [[ "$UNAME" == "Darwin" ]]; then
DART_LIB=$DART_SRC/runtime/xcodebuild/Debug_$DART_ARCH
DART_GEN=$DART_SRC/runtime/xcodebuild/DerivedSources/Debug_$DART_ARCH
DART_LIB=$DART_SRC/runtime/xcodebuild/${DART_MODE}_$DART_ARCH
DART_GEN=$DART_SRC/runtime/xcodebuild/DerivedSources/${DART_MODE}_$DART_ARCH
LIBRARY_GROUP_START= # not needed - mac linker 'just works' with circular dependencies
LIBRARY_GROUP_END=
else
if [[ "$UNAME" != "Linux" ]]; then
echo "Warning: Unrecognized OS $UNAME, this likely won't work"
fi
DART_LIB=$DART_SRC/runtime/out/Debug_$DART_ARCH/obj.target/runtime
DART_GEN=$DART_SRC/runtime/out/Debug_$DART_ARCH/obj/gen
DART_LIB=$DART_SRC/runtime/out/${DART_MODE}_$DART_ARCH/obj.target/runtime
DART_GEN=$DART_SRC/runtime/out/${DART_MODE}_$DART_ARCH/obj/gen
LIBRARY_GROUP_START=,--start-group # dart static libraries have circular references
LIBRARY_GROUP_END=,--end-group
fi

if [[ "$DART_MODE" == "Debug" ]]; then
COPTS="-DDEBUG"
else
COPTS="-DNDEBUG"
fi

rm src/mod_dart_gen.c; python $DART_SRC/runtime/tools/create_string_literal.py --output src/mod_dart_gen.c --include 'none' --input_cc src/mod_dart_gen.c.tmpl --var_name "mod_dart_source" src/mod_dart.dart
$APXS -S CC=g++ -c -DNDEBUG -o mod_dart.so -Wc,-Wall -Wc,-Werror -I $DART_SRC/runtime -lstdc++ -I $DART_GEN \
$APXS -S CC=g++ -c $COPTS -o mod_dart.so -Wc,-Wall -Wc,-Werror -I $DART_SRC/runtime -lstdc++ -I $DART_GEN \
-Wl,-Wl$LIBRARY_GROUP_START,$DART_LIB/libdart_export.a,$DART_LIB/libdart_builtin.a,$DART_LIB/libdart_lib_withcore.a,$DART_LIB/libdart_builtin.a,$DART_LIB/libdart_vm.a,$DART_LIB/libjscre.a,$DART_LIB/libdouble_conversion.a$LIBRARY_GROUP_END \
src/builtin.c src/mod_dart_gen.c src/apache_library.c src/mod_dart.c && \
sudo $APXS -i -a -n dart mod_dart.la && \
Expand Down
231 changes: 167 additions & 64 deletions src/mod_dart.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "http_log.h"
#include "http_protocol.h"
#include "ap_config.h"
#include "apr_hash.h"
#include "apr_strings.h"

#define AP_WARN(r, message, ...) do{\
struct timeval tv;\
Expand All @@ -29,9 +31,14 @@ typedef enum {
kYes
} NullableBool;

typedef struct dart_config {
typedef struct dart_dir_config {
NullableBool debug;
} dart_config;
} dart_dir_config;

typedef struct dart_server_config {
dart_server_config *base;
apr_hash_t *snapshots;
} dart_server_config;

extern module AP_MODULE_DECLARE_DATA dart_module;
extern "C" Dart_Handle ApacheLibraryInit(request_rec* r);
Expand Down Expand Up @@ -140,6 +147,18 @@ static Dart_Handle MasterSnapshotLibraryTagHandler(Dart_LibraryTag type, Dart_Ha
}
}

static Dart_Handle ScriptSnapshotLibraryTagHandler(Dart_LibraryTag type, Dart_Handle library, Dart_Handle url) {
if (type == kImportTag) {
const char* curl;
Dart_Handle result = Dart_StringToCString(url, &curl);
if (Dart_IsError(result)) return result;
if (!strcmp(curl, "dart:apache")) {
return ApacheLibraryLoad();
}
}
return MasterSnapshotLibraryTagHandler(type, library, url);
}

static bool dart_isolate_create(request_rec *r) {
char* error;
if (!IsolateCreate("name", "main", NULL, &error)) {
Expand All @@ -162,8 +181,17 @@ static apr_status_t dart_isolate_destroy(void* ctx) {
return OK;
}

static uint8_t *getScriptSnapshot(request_rec *r) {
dart_server_config *cfg = (dart_server_config*) ap_get_module_config(r->server->module_config, &dart_module);
while (cfg->base) cfg = cfg->base;
// printf("Looking up snapshot for %s\n", r->filename);
void* result = apr_hash_get(cfg->snapshots, r->filename, APR_HASH_KEY_STRING);
// printf("Result was %p\n", result);
return (uint8_t*) result;
}

static bool isDebug(request_rec *r) {
dart_config *cfg = (dart_config*) ap_get_module_config(r->per_dir_config, &dart_module);
dart_dir_config *cfg = (dart_dir_config*) ap_get_module_config(r->per_dir_config, &dart_module);
return cfg->debug == kYes;
}

Expand Down Expand Up @@ -196,115 +224,190 @@ static int dart_handler(request_rec *r) {
if (!dart_isolate_create(r)) return HTTP_INTERNAL_SERVER_ERROR;
apr_pool_cleanup_register(r->pool, NULL, dart_isolate_destroy, apr_pool_cleanup_null);
AP_WARN(r, "Created isolate");
Dart_Handle script = LoadFile(r->filename);
AP_WARN(r, "Loaded script file");
if (Dart_IsNull(script)) return HTTP_NOT_FOUND;
Dart_Handle library = Dart_IsError(script) ? script : Dart_LoadScript(Dart_NewString("main"), script);
uint8_t *snapshot = getScriptSnapshot(r);
Dart_Handle library;
if (snapshot) {
library = Dart_LoadScriptFromSnapshot(snapshot); // TODO did we need to load the main snapshot?
} else {
Dart_Handle script = LoadFile(r->filename);
AP_WARN(r, "Loaded script file");
if (Dart_IsNull(script)) return HTTP_NOT_FOUND;
library = Dart_IsError(script) ? script : Dart_LoadScript(Dart_NewString("main"), script);
}
AP_WARN(r, "Loaded script into VM");
if (Dart_IsError(library)) return fatal(r, "Failed to load library: %s", library);
if (Dart_IsError(library)) return fatal(r, "Failed to load script: %s", library);
Dart_Handle result = Dart_Invoke(library, Dart_NewString("main"), 0, NULL);
AP_WARN(r, "Executed script");
if (Dart_IsError(result)) return fatal(r, "Failed to execute main(): %s", result);
AP_WARN(r, "Finished");
return OK;
}

int dart_master_snapshot(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *server) {
// Modules are loaded twice, only actually create the snapshot on second load
void *data = NULL;
apr_pool_userdata_get(&data, "dart_dryrun_complete", server->process->pool);
if (!data) { // This is the dry-run
apr_pool_userdata_set((const void *)1, "dart_dryrun_complete", apr_pool_cleanup_null, server->process->pool);
printf("Dry run!\n");
return OK;
}
printf("Creating snapshot\n");
Dart_Handle create_master_snapshot(apr_pool_t *pool, uint8_t **target, const char* name) {
printf("Creating master snapshot\n");

initializeState = Dart_SetVMFlags(0, NULL) && Dart_Initialize(IsolateCreate, IsolateInterrupt);
char* error;
Dart_Isolate isolate = Dart_CreateIsolate("master", "main", NULL, NULL, &error);
if (!isolate) {
ap_log_error(APLOG_MARK, LOG_WARNING, 0, server, "CreateIsolate for master snapshot failed: %s", error);
return 1;
}
Dart_EnterScope();
Dart_SetLibraryTagHandler(MasterSnapshotLibraryTagHandler);
Dart_Handle result = Builtin::LoadLibrary(Builtin::kBuiltinLibrary);
if (Dart_IsError(result)) {
ap_log_error(APLOG_MARK, LOG_WARNING, 0, server,
"Builtin::LoadLibrary(kBuiltinLibrary) for master snapshot failed: %s", Dart_GetError(result));
Dart_ShutdownIsolate();
return 1;
}
if (Dart_IsError(result)) return result;
result = ApacheLibraryLoad();
if (Dart_IsError(result)) {
ap_log_error(APLOG_MARK, LOG_WARNING, 0, server,
"ApacheLibraryLoad for master snapshot failed: %s", Dart_GetError(result));
Dart_ShutdownIsolate();
return 1;
}
if (Dart_IsError(result)) return result;
uint8_t *buffer;
intptr_t size;
result = Dart_CreateSnapshot(&buffer, &size);
if (Dart_IsError(result)) {
ap_log_error(APLOG_MARK, LOG_WARNING, 0, server,
"Dart_CreateSnapshot for master snapshot failed: %s", Dart_GetError(result));
Dart_ShutdownIsolate();
return 1;
if (Dart_IsError(result)) return result;
*target = (uint8_t*) apr_pcalloc(pool, size); // This lives forever
if (!*target) return Dart_Error("Failed to allocate %ld bytes for master snapshot", size);
memmove(*target, buffer, size);
printf("Created master snapshot\n");
return Dart_Null();
}

Dart_Handle create_script_snapshot(apr_pool_t *pool, uint8_t **target, const char *name) {
Dart_SetLibraryTagHandler(ScriptSnapshotLibraryTagHandler);
Dart_Handle result = LoadFile(name);
printf("Loaded script file %s\n", name);
if (Dart_IsNull(result)) return Dart_Error("Script not found: %s", name);
printf("and was found\n");
if (Dart_IsError(result)) return result;
printf("And no error\n");
result = Dart_LoadScript(Dart_NewString("main"), result);
if (Dart_IsError(result)) return result;
printf("And loaded script\n");
uint8_t *buffer;
intptr_t size;
result = Dart_CreateScriptSnapshot(&buffer, &size);
if (Dart_IsError(result)) return result;
printf("and created snapshot");
*target = (uint8_t*) apr_pcalloc(pool, size); // This lives forever
if (!*target) return Dart_Error("Failed to allocate %ld bytes for snapshot of %s", size, name);
memmove(*target, buffer, size);
printf("Done with script snapshot: %s\n", name);
return Dart_Null();
}

bool create_snapshot(apr_pool_t *pool, uint8_t** target, const char* name, uint8_t *base_snapshot, Dart_Handle (*creator)(apr_pool_t *pool, uint8_t **target, const char* name), char **error) {
*error = NULL;
Dart_Isolate isolate = Dart_CreateIsolate(name, "main", base_snapshot, NULL, error);
if (!isolate) return false;
Dart_EnterScope();
Dart_Handle result = creator(pool, target, name);
if (Dart_IsError(result)) *error = apr_pstrdup(pool, Dart_GetError(result));
Dart_ExitScope();
Dart_ShutdownIsolate();
printf("Tried to create a snapshot for %s, error state=%p\n", name, *error);
return *error == NULL;
}

int dart_snapshots(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *server) {
// Modules are loaded twice, only actually create the snapshot on second load
void *data = NULL;
apr_pool_userdata_get(&data, "dart_dryrun_complete", server->process->pool);
if (!data) { // This is the dry-run
apr_pool_userdata_set((const void*) 1, "dart_dryrun_complete", apr_pool_cleanup_null, server->process->pool);
return OK;
}
master_snapshot_buffer = (uint8_t*) apr_pcalloc(server->process->pool, size); // This lives forever
if (!master_snapshot_buffer) {
ap_log_error(APLOG_MARK, LOG_WARNING, 0, server, "Failed to allocate %ld bytes for master snapshot", size);
Dart_ShutdownIsolate();
// Only create snapshots in the root server
dart_server_config *cfg = (dart_server_config*) ap_get_module_config(server->module_config, &dart_module);
if (cfg->base) return OK;
initializeState = Dart_SetVMFlags(0, NULL) && Dart_Initialize(IsolateCreate, IsolateInterrupt);

char* error;
if (!create_snapshot(server->process->pool, &master_snapshot_buffer, "master", NULL, create_master_snapshot, &error)) {
ap_log_error(APLOG_MARK, LOG_WARNING, 0, server, "Master snapshot failed: %s", error);
return 1;
}
memmove(master_snapshot_buffer, buffer, size);
Dart_ExitScope();
Dart_ShutdownIsolate();
printf("Created snapshot\n");
uint8_t *val;
const void *key;
for (apr_hash_index_t *p = apr_hash_first(ptemp, cfg->snapshots); p; p = apr_hash_next(p)) {
apr_hash_this(p, &key, NULL, NULL);
// TODO use pconf instead of server->process->pool?
if (!create_snapshot(server->process->pool, &val, (const char*) key, master_snapshot_buffer, create_script_snapshot, &error)) {
ap_log_error(APLOG_MARK, LOG_WARNING, 0, server, "Script snapshot failed for %s: %s", (const char*) key, error);
val = NULL;
}
apr_hash_set(cfg->snapshots, key, APR_HASH_KEY_STRING, (const void*) val);
}

return OK;
}

static void dart_register_hooks(apr_pool_t *p) {
ap_hook_handler(dart_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_child_init(dart_child_init, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_config(dart_master_snapshot, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_config(dart_snapshots, NULL, NULL, APR_HOOK_MIDDLE);
}

static const char *dart_set_debug(cmd_parms *cmd, void *cfg_, const char *arg) {
dart_config *cfg = (dart_config*) cfg_;
dart_dir_config *cfg = (dart_dir_config*) cfg_;
cfg->debug = strcasecmp("on", arg) ? kNo : kYes;
return NULL;
}

static const char *dart_set_snapshot(cmd_parms *cmd, void *cfg_, const char *arg) {
dart_server_config *cfg = (dart_server_config*) ap_get_module_config(cmd->server->module_config, &dart_module);
while (cfg->base) cfg = cfg->base;
printf("Adding snapshot for %s\n", arg);
apr_hash_set(cfg->snapshots, arg, APR_HASH_KEY_STRING, (void*) 1);
return NULL;
}

static const command_rec dart_directives[] = {
AP_INIT_TAKE1("DartDebug", (cmd_func) dart_set_debug, NULL, ACCESS_CONF, "Whether error messages should be sent to the browser"),
AP_INIT_TAKE1("DartDebug", (cmd_func) dart_set_debug, NULL, OR_ALL, "Whether error messages should be sent to the browser"),
AP_INIT_TAKE1("DartSnapshot", (cmd_func) dart_set_snapshot, NULL, OR_ALL, "A dart file to be snapshotted for fast loading"),
{ NULL },
};

static void *create_dir_conf(apr_pool_t* pool, char* context_) {
dart_config *cfg = (dart_config*) apr_pcalloc(pool, sizeof(dart_config));
dart_dir_config *cfg = (dart_dir_config*) apr_pcalloc(pool, sizeof(dart_dir_config));
if (cfg) {
cfg->debug = kNull;
}
return cfg;
}

static void *merge_dir_conf(apr_pool_t* pool, void* base_, void* add_) {
dart_config *base = (dart_config*) base_;
dart_config *add = (dart_config*) add_;
dart_config *cfg = (dart_config*) apr_pcalloc(pool, sizeof(dart_config));
dart_dir_config *base = (dart_dir_config*) base_;
dart_dir_config *add = (dart_dir_config*) add_;
dart_dir_config *cfg = (dart_dir_config*) apr_pcalloc(pool, sizeof(dart_dir_config));
cfg->debug = add->debug ? add->debug : base->debug;
return cfg;
}

static void *create_server_conf(apr_pool_t* pool, server_rec *server) {
printf("Creating server config\n");
dart_server_config *cfg = (dart_server_config*) apr_pcalloc(pool, sizeof(dart_server_config));
if (cfg) {
cfg->base = NULL;
cfg->snapshots = apr_hash_make(pool);
}
return cfg;
}

static void *merge_server_conf(apr_pool_t *pool, void *base_, void *add_) {
printf("Merging server configs\n");
dart_server_config *base = (dart_server_config*) base_;
dart_server_config *add = (dart_server_config*) add_;
dart_server_config *cfg = (dart_server_config*) apr_pcalloc(pool, sizeof(dart_server_config));
cfg->base = base;
cfg->snapshots = NULL;
while (base->base) base = base->base;
void *val;
const void *key;
for (apr_hash_index_t *p = apr_hash_first(pool, add->snapshots); p; p = apr_hash_next(p)) {
apr_hash_this(p, &key, NULL, &val);
printf("Copying key into base: %s\n", (char*) key);
apr_hash_set(base->snapshots, key, APR_HASH_KEY_STRING, val);
}
return cfg;
}

/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA dart_module = {
STANDARD20_MODULE_STUFF,
create_dir_conf, /* create per-dir config structures */
merge_dir_conf, /* merge per-dir config structures */
NULL, /* create per-server config structures */
NULL, /* merge per-server config structures */
dart_directives, /* table of config file commands */
dart_register_hooks /* register hooks */
create_dir_conf,
merge_dir_conf,
create_server_conf,
merge_server_conf,
dart_directives,
dart_register_hooks
};

0 comments on commit 1bdaff0

Please sign in to comment.