mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-01 16:07:57 +02:00
[script] Prototypical binary translator
Hook into the scanner to write out binary version of the tokenized
objects -- note we bind executable names (i.e. check to see if is an
operator and substitute the name with an operator -- this breaks
overloading of operators by scripts).
By converting scripts to a binary form, they are more compact and
execute faster:
firefox-world-map.trace 526850146 bytes
bound.trace 275187755 bytes
[ # ] backend test min(s) median(s) stddev. count
[ 0] null bound 34.481 34.741 0.68% 3/3
[ 1] null firefox-world-map 89.635 89.716 0.19% 3/3
[ 0] drm bound 79.304 79.350 0.61% 3/3
[ 1] drm firefox-world-map 135.380 135.475 0.58% 3/3
[ 0] image bound 95.819 96.258 2.85% 3/3
[ 1] image firefox-world-map 156.889 156.935 1.36% 3/3
[ 0] xlib bound 539.130 550.220 1.40% 3/3
[ 1] xlib firefox-world-map 596.244 613.487 1.74% 3/3
This trace has a lot of complex paths and the use of binary floating point
reduces the file size by about 50%, with a commensurate reduction in scan
time and significant reduction in operator lookup overhead. Note that this
test is still IO/CPU bound on my i915 with its pitifully slow flash...
This commit is contained in:
parent
07c0c8c5c0
commit
23648e2fdf
8 changed files with 916 additions and 343 deletions
|
|
@ -1,7 +1,7 @@
|
|||
SUBDIRS = examples
|
||||
|
||||
lib_LTLIBRARIES = libcairo-script-interpreter.la
|
||||
EXTRA_PROGRAMS = csi-replay csi-exec
|
||||
EXTRA_PROGRAMS = csi-replay csi-exec csi-bind
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src
|
||||
|
||||
|
|
@ -27,5 +27,8 @@ csi_replay_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.l
|
|||
csi_exec_SOURCES = csi-exec.c
|
||||
csi_exec_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
|
||||
|
||||
csi_bind_SOURCES = csi-bind.c
|
||||
csi_bind_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
|
||||
|
||||
EXTRA_DIST = \
|
||||
COPYING
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@
|
|||
|
||||
#define CHUNK_SIZE 32768
|
||||
|
||||
#define OWN_STREAM 0x1
|
||||
|
||||
csi_status_t
|
||||
csi_file_new (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
|
|
@ -56,6 +58,7 @@ csi_file_new (csi_t *ctx,
|
|||
|
||||
file->data = NULL;
|
||||
file->type = STDIO;
|
||||
file->flags = OWN_STREAM;
|
||||
file->src = fopen (path, mode);
|
||||
if (file->src == NULL) {
|
||||
_csi_slab_free (ctx, file, sizeof (csi_file_t));
|
||||
|
|
@ -75,6 +78,42 @@ csi_file_new (csi_t *ctx,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
csi_status_t
|
||||
csi_file_new_for_stream (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
FILE *stream)
|
||||
{
|
||||
csi_file_t *file;
|
||||
|
||||
file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
|
||||
if (file == NULL)
|
||||
return _csi_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
file->base.type = CSI_OBJECT_TYPE_FILE;
|
||||
file->base.ref = 1;
|
||||
|
||||
file->data = NULL;
|
||||
file->type = STDIO;
|
||||
file->flags = 0;
|
||||
file->src = stream;
|
||||
if (file->src == NULL) {
|
||||
_csi_slab_free (ctx, file, sizeof (csi_file_t));
|
||||
return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
file->data = _csi_alloc (ctx, CHUNK_SIZE);
|
||||
if (file->data == NULL) {
|
||||
_csi_slab_free (ctx, file, sizeof (csi_file_t));
|
||||
return _csi_error (CAIRO_STATUS_NO_MEMORY);
|
||||
}
|
||||
file->bp = file->data;
|
||||
file->rem = 0;
|
||||
|
||||
obj->type = CSI_OBJECT_TYPE_FILE;
|
||||
obj->datum.file = file;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
csi_status_t
|
||||
csi_file_new_for_bytes (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
|
|
@ -727,7 +766,7 @@ csi_file_new_decrypt (csi_t *ctx, csi_object_t *src, int salt, int discard)
|
|||
csi_status_t
|
||||
_csi_file_execute (csi_t *ctx, csi_file_t *obj)
|
||||
{
|
||||
return _csi_scan_file (ctx, &ctx->scanner, obj);
|
||||
return _csi_scan_file (ctx, obj);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -917,7 +956,8 @@ csi_file_close (csi_t *ctx, csi_file_t *file)
|
|||
|
||||
switch (file->type) {
|
||||
case STDIO:
|
||||
fclose (file->src);
|
||||
if (file->flags & OWN_STREAM)
|
||||
fclose (file->src);
|
||||
break;
|
||||
case BYTES:
|
||||
if (file->src != file->data) {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) (((a)>=(b))?(a):(b))
|
||||
|
|
@ -261,10 +262,11 @@ _init_dictionaries (csi_t *ctx)
|
|||
csi_status_t status;
|
||||
csi_stack_t *stack;
|
||||
csi_object_t obj;
|
||||
csi_dictionary_t *dict;
|
||||
csi_dictionary_t *dict, *opcodes;
|
||||
const csi_operator_def_t *odef;
|
||||
const csi_integer_constant_def_t *idef;
|
||||
const csi_real_constant_def_t *rdef;
|
||||
unsigned n;
|
||||
|
||||
stack = &ctx->dstack;
|
||||
|
||||
|
|
@ -283,12 +285,37 @@ _init_dictionaries (csi_t *ctx)
|
|||
|
||||
dict = obj.datum.dictionary;
|
||||
|
||||
status = csi_dictionary_new (ctx, &obj);
|
||||
if (_csi_unlikely (status))
|
||||
return status;
|
||||
|
||||
opcodes = obj.datum.dictionary;
|
||||
|
||||
n = 0;
|
||||
csi_integer_new (&obj, n);
|
||||
status = csi_dictionary_put (ctx, opcodes, 0, &obj);
|
||||
if (_csi_unlikely (status))
|
||||
return status;
|
||||
ctx->opcode[n++] = NULL;
|
||||
|
||||
/* fill systemdict with operators */
|
||||
for (odef = _csi_operators (); odef->name != NULL; odef++) {
|
||||
status = _add_operator (ctx, dict, odef);
|
||||
if (_csi_unlikely (status))
|
||||
return status;
|
||||
|
||||
if (! csi_dictionary_has (opcodes, (csi_name_t) odef->op)) {
|
||||
csi_integer_new (&obj, n);
|
||||
status = csi_dictionary_put (ctx,
|
||||
opcodes, (csi_name_t) odef->op, &obj);
|
||||
if (_csi_unlikely (status))
|
||||
return status;
|
||||
|
||||
assert (n < sizeof (ctx->opcode) / sizeof (ctx->opcode[0]));
|
||||
ctx->opcode[n++] = odef->op;
|
||||
}
|
||||
}
|
||||
csi_dictionary_free (ctx, opcodes);
|
||||
|
||||
/* add constants */
|
||||
for (idef = _csi_integer_constants (); idef->name != NULL; idef++) {
|
||||
|
|
@ -365,6 +392,8 @@ _csi_init (csi_t *ctx)
|
|||
{
|
||||
csi_status_t status;
|
||||
|
||||
memset (ctx, 0, sizeof (*ctx));
|
||||
|
||||
ctx->status = CSI_STATUS_SUCCESS;
|
||||
ctx->ref_count = 1;
|
||||
|
||||
|
|
@ -391,7 +420,7 @@ FAIL:
|
|||
}
|
||||
|
||||
static void
|
||||
_csi_fini (csi_t *ctx)
|
||||
_csi_finish (csi_t *ctx)
|
||||
{
|
||||
_csi_stack_fini (ctx, &ctx->ostack);
|
||||
_csi_stack_fini (ctx, &ctx->dstack);
|
||||
|
|
@ -494,7 +523,7 @@ cairo_script_interpreter_create (void)
|
|||
{
|
||||
csi_t *ctx;
|
||||
|
||||
ctx = calloc (1, sizeof (csi_t));
|
||||
ctx = malloc (sizeof (csi_t));
|
||||
if (ctx == NULL)
|
||||
return (csi_t *) &_csi_nil;
|
||||
|
||||
|
|
@ -580,7 +609,7 @@ cairo_script_interpreter_finish (csi_t *ctx)
|
|||
|
||||
status = ctx->status;
|
||||
if (! ctx->finished) {
|
||||
_csi_fini (ctx);
|
||||
_csi_finish (ctx);
|
||||
ctx->finished = 1;
|
||||
} else if (status == CAIRO_STATUS_SUCCESS) {
|
||||
status = ctx->status = CSI_STATUS_INTERPRETER_FINISHED;
|
||||
|
|
@ -589,6 +618,23 @@ cairo_script_interpreter_finish (csi_t *ctx)
|
|||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
_csi_fini (csi_t *ctx)
|
||||
{
|
||||
if (! ctx->finished)
|
||||
_csi_finish (ctx);
|
||||
|
||||
if (ctx->free_array != NULL)
|
||||
csi_array_free (ctx, ctx->free_array);
|
||||
if (ctx->free_dictionary != NULL)
|
||||
csi_dictionary_free (ctx, ctx->free_dictionary);
|
||||
if (ctx->free_string != NULL)
|
||||
csi_string_free (ctx, ctx->free_string);
|
||||
|
||||
_csi_slab_fini (ctx);
|
||||
_csi_perm_fini (ctx);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_script_interpreter_destroy (csi_t *ctx)
|
||||
{
|
||||
|
|
@ -598,20 +644,33 @@ cairo_script_interpreter_destroy (csi_t *ctx)
|
|||
if (--ctx->ref_count)
|
||||
return status;
|
||||
|
||||
if (! ctx->finished)
|
||||
_csi_fini (ctx);
|
||||
|
||||
if (ctx->free_array != NULL)
|
||||
csi_array_free (ctx, ctx->free_array);
|
||||
if (ctx->free_dictionary != NULL)
|
||||
csi_dictionary_free (ctx, ctx->free_dictionary);
|
||||
if (ctx->free_string != NULL)
|
||||
csi_string_free (ctx, ctx->free_string);
|
||||
|
||||
_csi_slab_fini (ctx);
|
||||
_csi_perm_fini (ctx);
|
||||
_csi_fini (ctx);
|
||||
free (ctx);
|
||||
|
||||
return status;
|
||||
}
|
||||
slim_hidden_def (cairo_script_interpreter_destroy);
|
||||
|
||||
cairo_status_t
|
||||
cairo_script_interpreter_translate_stream (FILE *stream,
|
||||
cairo_write_func_t write_func,
|
||||
void *closure)
|
||||
{
|
||||
csi_t ctx;
|
||||
csi_object_t src;
|
||||
csi_status_t status;
|
||||
|
||||
_csi_init (&ctx);
|
||||
|
||||
status = csi_file_new_for_stream (&ctx, &src, stream);
|
||||
if (status)
|
||||
goto BAIL;
|
||||
|
||||
status = _csi_translate_file (&ctx, src.datum.file, write_func, closure);
|
||||
|
||||
BAIL:
|
||||
csi_object_free (&ctx, &src);
|
||||
_csi_fini (&ctx);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#define CAIRO_SCRIPT_INTERPRETER_H
|
||||
|
||||
#include <cairo.h>
|
||||
#include <stdio.h>
|
||||
|
||||
CAIRO_BEGIN_DECLS
|
||||
|
||||
|
|
@ -45,7 +46,8 @@ typedef struct _cairo_script_interpreter cairo_script_interpreter_t;
|
|||
/* XXX expose csi_dictionary_t and pass to hooks */
|
||||
typedef void
|
||||
(*csi_destroy_func_t) (void *closure,
|
||||
void *ptr);
|
||||
void *ptr);
|
||||
|
||||
typedef cairo_surface_t *
|
||||
(*csi_surface_create_func_t) (void *closure,
|
||||
cairo_content_t content,
|
||||
|
|
@ -100,6 +102,11 @@ cairo_script_interpreter_finish (cairo_script_interpreter_t *ctx);
|
|||
cairo_public cairo_status_t
|
||||
cairo_script_interpreter_destroy (cairo_script_interpreter_t *ctx);
|
||||
|
||||
cairo_public cairo_status_t
|
||||
cairo_script_interpreter_translate_stream (FILE *stream,
|
||||
cairo_write_func_t write_func,
|
||||
void *closure);
|
||||
|
||||
CAIRO_END_DECLS
|
||||
|
||||
#endif /*CAIRO_SCRIPT_INTERPRETER_H*/
|
||||
|
|
|
|||
|
|
@ -502,8 +502,10 @@ csi_string_new (csi_t *ctx,
|
|||
ctx->free_string = NULL;
|
||||
}
|
||||
|
||||
memcpy (string->string, str, len);
|
||||
string->string[len] = '\0';
|
||||
if (str != NULL) {
|
||||
memcpy (string->string, str, len);
|
||||
string->string[len] = '\0';
|
||||
}
|
||||
string->len = len;
|
||||
|
||||
string->base.type = CSI_OBJECT_TYPE_STRING;
|
||||
|
|
@ -555,7 +557,7 @@ _csi_string_execute (csi_t *ctx, csi_string_t *string)
|
|||
if (_csi_unlikely (status))
|
||||
return status;
|
||||
|
||||
status = _csi_scan_file (ctx, &ctx->scanner, obj.datum.file);
|
||||
status = _csi_scan_file (ctx, obj.datum.file);
|
||||
csi_object_free (ctx, &obj);
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -5440,7 +5440,7 @@ _defs[] = {
|
|||
{ "arc", _arc },
|
||||
{ "arc-negative", _arc_negative },
|
||||
{ "arc-", _arc_negative },
|
||||
//{ "arc-to", NULL },
|
||||
{ "arc-to", NULL },
|
||||
{ "array", _array },
|
||||
{ "astore", NULL },
|
||||
{ "atan", NULL },
|
||||
|
|
|
|||
|
|
@ -404,6 +404,7 @@ struct _csi_file {
|
|||
PROCEDURE,
|
||||
FILTER
|
||||
} type;
|
||||
unsigned int flags;
|
||||
void *src;
|
||||
void *data;
|
||||
uint8_t *bp;
|
||||
|
|
@ -426,14 +427,9 @@ struct _csi_scanner {
|
|||
jmp_buf jmpbuf;
|
||||
int depth;
|
||||
|
||||
enum {
|
||||
NONE,
|
||||
TOKEN,
|
||||
COMMENT,
|
||||
STRING,
|
||||
HEX,
|
||||
BASE85
|
||||
} state;
|
||||
csi_status_t (*push) (csi_t *ctx, csi_object_t *obj);
|
||||
csi_status_t (*execute) (csi_t *ctx, csi_object_t *obj);
|
||||
void *closure;
|
||||
|
||||
csi_buffer_t buffer;
|
||||
csi_stack_t procedure_stack;
|
||||
|
|
@ -478,6 +474,8 @@ struct _cairo_script_interpreter {
|
|||
csi_dictionary_t *free_dictionary;
|
||||
csi_string_t *free_string;
|
||||
|
||||
csi_operator_t opcode[256];
|
||||
|
||||
/* caches of live data */
|
||||
csi_list_t *_images;
|
||||
csi_list_t *_faces;
|
||||
|
|
@ -505,6 +503,11 @@ csi_file_new (csi_t *ctx,
|
|||
csi_object_t *obj,
|
||||
const char *path, const char *mode);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_file_new_for_stream (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
FILE *stream);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_file_new_for_bytes (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
|
|
@ -803,7 +806,13 @@ csi_private csi_status_t
|
|||
_csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_scan_file (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src);
|
||||
_csi_scan_file (csi_t *ctx, csi_file_t *src);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_translate_file (csi_t *ctx,
|
||||
csi_file_t *file,
|
||||
cairo_write_func_t write_func,
|
||||
void *closure);
|
||||
|
||||
csi_private void
|
||||
_csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue