mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-03 05:20:16 +02:00
* include/lightning/jit_private.h, lib/jit_note.c, lib/lightning.c: Store all annotation information in the mmap'ed area reserved for read only data. This adds code to not allocate memory for jit_note_t objects, and to relocate jit_line_t objects and its contents after calculating annotation information. The jit_line_t objects are relocated because it is not possible to always calculate before hand data layout because note information may be extended or redundant entries removed, as well as allowed to be added in non sequential order. A bug was also corrected in _jit_set_note, that was causing it to allocate new jit_line_t objects when not needed. It was still working correctly, but allocating way more memory than required.
407 lines
11 KiB
C
407 lines
11 KiB
C
/*
|
|
* Copyright (C) 2013 Free Software Foundation, Inc.
|
|
*
|
|
* This is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This software is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* Authors:
|
|
* Paulo Cesar Pereira de Andrade
|
|
*/
|
|
|
|
#include <lightning.h>
|
|
#include <lightning/jit_private.h>
|
|
|
|
/*
|
|
* Prototypes
|
|
*/
|
|
#define new_note(u, v) _new_note(_jit, u, v)
|
|
static jit_note_t *_new_note(jit_state_t *, jit_uint8_t*, char*);
|
|
static void new_line(jit_int32_t,jit_note_t*,char*,jit_int32_t,jit_int32_t);
|
|
#define note_search_index(u) _note_search_index(_jit, u)
|
|
static jit_int32_t _note_search_index(jit_state_t*, jit_uint8_t*);
|
|
static jit_int32_t line_insert_index(jit_note_t*,jit_int32_t);
|
|
static jit_int32_t line_search_index(jit_note_t*,jit_int32_t);
|
|
static jit_int32_t offset_insert_index(jit_line_t*,jit_int32_t);
|
|
static jit_int32_t offset_search_index(jit_line_t*,jit_int32_t);
|
|
|
|
/*
|
|
* Implementation
|
|
*/
|
|
void
|
|
jit_init_note(void)
|
|
{
|
|
}
|
|
|
|
void
|
|
jit_finish_note(void)
|
|
{
|
|
}
|
|
|
|
jit_node_t *
|
|
_jit_name(jit_state_t *_jit, char *name)
|
|
{
|
|
jit_node_t *node;
|
|
|
|
node = jit_new_node(jit_code_name);
|
|
if (name)
|
|
node->v.n = jit_data(name, strlen(name) + 1, 1);
|
|
else
|
|
node->v.p = NULL;
|
|
if (_jit->note.head == NULL)
|
|
_jit->note.head = _jit->note.tail = node;
|
|
else {
|
|
_jit->note.tail->link = node;
|
|
_jit->note.tail = node;
|
|
}
|
|
++_jit->note.length;
|
|
_jit->note.size += sizeof(jit_note_t);
|
|
/* remember previous note is invalid due to name change */
|
|
_jit->note.note = NULL;
|
|
return (_jit->note.name = node);
|
|
}
|
|
|
|
jit_node_t *
|
|
_jit_note(jit_state_t *_jit, char *name, int line)
|
|
{
|
|
jit_node_t *node;
|
|
|
|
node = jit_new_node(jit_code_note);
|
|
if (name)
|
|
node->v.n = jit_data(name, strlen(name) + 1, 1);
|
|
else
|
|
node->v.p = NULL;
|
|
node->w.w = line;
|
|
if (_jit->note.head == NULL)
|
|
_jit->note.head = _jit->note.tail = node;
|
|
else {
|
|
_jit->note.tail->link = node;
|
|
_jit->note.tail = node;
|
|
}
|
|
if (_jit->note.note == NULL ||
|
|
(name == NULL && _jit->note.note != NULL) ||
|
|
(name != NULL && _jit->note.note == NULL) ||
|
|
(name != NULL && _jit->note.note != NULL &&
|
|
strcmp(name, (char *)_jit->data.ptr + _jit->note.note->v.n->u.w)))
|
|
_jit->note.size += sizeof(jit_line_t);
|
|
_jit->note.size += sizeof(jit_int32_t) * 2;
|
|
return (_jit->note.note = node);
|
|
}
|
|
|
|
void
|
|
_jit_annotate(jit_state_t *_jit)
|
|
{
|
|
jit_node_t *node;
|
|
jit_note_t *note;
|
|
jit_line_t *line;
|
|
jit_word_t length;
|
|
jit_word_t note_offset;
|
|
jit_word_t line_offset;
|
|
|
|
/* initialize pointers in mmaped data area */
|
|
_jit->note.ptr = (jit_note_t *)_jit->note.base;
|
|
_jit->note.length = 0;
|
|
|
|
note = NULL;
|
|
for (node = _jit->note.head; node; node = node->link) {
|
|
if (node->code == jit_code_name)
|
|
note = new_note(node->u.p, node->v.p ? node->v.n->u.p : NULL);
|
|
else if (node->v.p) {
|
|
if (note == NULL)
|
|
note = new_note(node->u.p, NULL);
|
|
jit_set_note(note, node->v.n->u.p, node->w.w,
|
|
(jit_uint8_t *)node->u.p - note->code);
|
|
}
|
|
}
|
|
/* last note */
|
|
if (note)
|
|
note->size = _jit->pc.uc - note->code;
|
|
|
|
/* annotations may be very complex with conditions to extend
|
|
* or ignore redudant notes, as well as add entries to earlier
|
|
* notes, so, relocate the information to the data buffer,
|
|
* with likely over allocated reserved space */
|
|
|
|
/* relocate jit_line_t objects */
|
|
for (note_offset = 0; note_offset < _jit->note.length; note_offset++) {
|
|
note = _jit->note.ptr + note_offset;
|
|
length = sizeof(jit_line_t) * note->length;
|
|
assert(_jit->note.base + length < _jit->data.ptr + _jit->data.length);
|
|
memcpy(_jit->note.base, note->lines, length);
|
|
free(note->lines);
|
|
note->lines = (jit_line_t *)_jit->note.base;
|
|
_jit->note.base += length;
|
|
}
|
|
|
|
/* relocate offset and line number information */
|
|
for (note_offset = 0; note_offset < _jit->note.length; note_offset++) {
|
|
note = _jit->note.ptr + note_offset;
|
|
for (line_offset = 0; line_offset < note->length; line_offset++) {
|
|
line = note->lines + line_offset;
|
|
length = sizeof(jit_int32_t) * line->length;
|
|
assert(_jit->note.base + length <
|
|
_jit->data.ptr + _jit->data.length);
|
|
memcpy(_jit->note.base, line->linenos, length);
|
|
free(line->linenos);
|
|
line->linenos = (jit_int32_t *)_jit->note.base;
|
|
_jit->note.base += length;
|
|
assert(_jit->note.base + length <
|
|
_jit->data.ptr + _jit->data.length);
|
|
memcpy(_jit->note.base, line->offsets, length);
|
|
free(line->offsets);
|
|
line->offsets = (jit_int32_t *)_jit->note.base;
|
|
_jit->note.base += length;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
_jit_set_note(jit_state_t *_jit, jit_note_t *note,
|
|
char *file, int lineno, jit_int32_t offset)
|
|
{
|
|
jit_line_t *line;
|
|
jit_int32_t index;
|
|
|
|
index = line_insert_index(note, offset);
|
|
if (note->length && index == note->length &&
|
|
note->lines[index - 1].file == file)
|
|
--index;
|
|
if (index >= note->length || note->lines[index].file != file)
|
|
new_line(index, note, file, lineno, offset);
|
|
else {
|
|
line = note->lines + index;
|
|
index = offset_insert_index(line, offset);
|
|
if (line->offsets[index] == offset) {
|
|
/* common case if no code was generated for several source lines */
|
|
if (line->linenos[index] < lineno)
|
|
line->linenos[index] = lineno;
|
|
}
|
|
else if (line->linenos[index] == lineno) {
|
|
/* common case of extending entry */
|
|
if (line->offsets[index] > offset)
|
|
line->offsets[index] = offset;
|
|
}
|
|
else {
|
|
/* line or offset changed */
|
|
if ((line->length & 15) == 0) {
|
|
line->linenos = realloc(line->linenos, (line->length + 17) *
|
|
sizeof(jit_int32_t));
|
|
line->offsets = realloc(line->offsets, (line->length + 17) *
|
|
sizeof(jit_int32_t));
|
|
}
|
|
if (index < note->length) {
|
|
memmove(line->linenos + index + 1, line->linenos + index,
|
|
sizeof(jit_int32_t) * (line->length - index));
|
|
memmove(line->offsets + index + 1, line->offsets + index,
|
|
sizeof(jit_int32_t) * (line->length - index));
|
|
}
|
|
line->linenos[index] = lineno;
|
|
line->offsets[index] = offset;
|
|
++line->length;
|
|
}
|
|
}
|
|
}
|
|
|
|
jit_bool_t
|
|
_jit_get_note(jit_state_t *_jit, jit_uint8_t *code,
|
|
char **name, char **file, jit_int32_t *lineno)
|
|
{
|
|
jit_note_t *note;
|
|
jit_line_t *line;
|
|
jit_int32_t index;
|
|
jit_int32_t offset;
|
|
|
|
if ((index = note_search_index(code)) >= _jit->note.length)
|
|
return (0);
|
|
note = _jit->note.ptr + index;
|
|
if (code < note->code || code >= note->code + note->size)
|
|
return (0);
|
|
offset = code - note->code;
|
|
if ((index = line_search_index(note, offset)) >= note->length)
|
|
return (0);
|
|
if (index == 0 && offset < note->lines[0].offsets[0])
|
|
return (0);
|
|
line = note->lines + index;
|
|
if ((index = offset_search_index(line, offset)) >= line->length)
|
|
return (0);
|
|
|
|
if (name)
|
|
*name = note->name;
|
|
if (file)
|
|
*file = line->file;
|
|
if (lineno)
|
|
*lineno = line->linenos[index];
|
|
|
|
return (1);
|
|
}
|
|
|
|
static jit_note_t *
|
|
_new_note(jit_state_t *_jit, jit_uint8_t *code, char *name)
|
|
{
|
|
jit_note_t *note;
|
|
jit_note_t *prev;
|
|
|
|
if (_jit->note.length) {
|
|
prev = _jit->note.ptr + _jit->note.length - 1;
|
|
assert(code >= prev->code);
|
|
prev->size = code - prev->code;
|
|
}
|
|
note = (jit_note_t *)_jit->note.base;
|
|
_jit->note.base += sizeof(jit_note_t);
|
|
++_jit->note.length;
|
|
note->code = code;
|
|
note->name = name;
|
|
|
|
return (note);
|
|
}
|
|
|
|
static void
|
|
new_line(jit_int32_t index, jit_note_t *note,
|
|
char *file, jit_int32_t lineno, jit_int32_t offset)
|
|
{
|
|
jit_line_t *line;
|
|
|
|
if (note->lines == NULL)
|
|
note->lines = malloc(16 * sizeof(jit_line_t));
|
|
else if ((note->length & 15) == 15)
|
|
note->lines = realloc(note->lines,
|
|
(note->length + 17) * sizeof(jit_line_t));
|
|
|
|
if (index < note->length)
|
|
memmove(note->lines + index + 1, note->lines + index,
|
|
sizeof(jit_line_t) * (note->length - index));
|
|
line = note->lines + index;
|
|
++note->length;
|
|
|
|
line->file = file;
|
|
line->length = 1;
|
|
line->linenos = malloc(16 * sizeof(jit_int32_t));
|
|
line->linenos[0] = lineno;
|
|
line->offsets = malloc(16 * sizeof(jit_int32_t));
|
|
line->offsets[0] = offset;
|
|
}
|
|
|
|
static jit_int32_t
|
|
_note_search_index(jit_state_t *_jit, jit_uint8_t *code)
|
|
{
|
|
jit_int32_t bot;
|
|
jit_int32_t top;
|
|
jit_int32_t index;
|
|
jit_note_t *notes;
|
|
|
|
bot = 0;
|
|
top = _jit->note.length;
|
|
notes = _jit->note.ptr;
|
|
for (index = (bot + top) >> 1; bot < top; index = (bot + top) >> 1) {
|
|
if (code < notes[index].code)
|
|
top = index;
|
|
else if (code >= notes[index].code &&
|
|
code - notes[index].code < notes[index].size)
|
|
break;
|
|
else
|
|
bot = index + 1;
|
|
}
|
|
|
|
return (index);
|
|
}
|
|
|
|
static jit_int32_t
|
|
line_insert_index(jit_note_t *note, jit_int32_t offset)
|
|
{
|
|
jit_int32_t bot;
|
|
jit_int32_t top;
|
|
jit_int32_t index;
|
|
jit_line_t *lines;
|
|
|
|
bot = 0;
|
|
top = note->length;
|
|
if ((lines = note->lines) == NULL)
|
|
return (0);
|
|
for (index = (bot + top) >> 1; bot < top; index = (bot + top) >> 1) {
|
|
if (offset < *lines[index].offsets)
|
|
top = index;
|
|
else
|
|
bot = index + 1;
|
|
}
|
|
|
|
return ((bot + top) >> 1);
|
|
}
|
|
|
|
static jit_int32_t
|
|
line_search_index(jit_note_t *note, jit_int32_t offset)
|
|
{
|
|
jit_int32_t bot;
|
|
jit_int32_t top;
|
|
jit_int32_t index;
|
|
jit_line_t *lines;
|
|
|
|
bot = 0;
|
|
top = note->length;
|
|
if ((lines = note->lines) == NULL)
|
|
return (0);
|
|
for (index = (bot + top) >> 1; bot < top; index = (bot + top) >> 1) {
|
|
if (offset < *lines[index].offsets)
|
|
top = index;
|
|
/* offset should be already verified to be in range */
|
|
else if (index == note->length - 1 ||
|
|
(offset >= *lines[index].offsets &&
|
|
offset < *lines[index + 1].offsets))
|
|
break;
|
|
else
|
|
bot = index + 1;
|
|
}
|
|
|
|
return (index);
|
|
}
|
|
|
|
static jit_int32_t
|
|
offset_insert_index(jit_line_t *line, jit_int32_t offset)
|
|
{
|
|
jit_int32_t bot;
|
|
jit_int32_t top;
|
|
jit_int32_t index;
|
|
jit_int32_t *offsets;
|
|
|
|
bot = 0;
|
|
top = line->length;
|
|
offsets = line->offsets;
|
|
for (index = (bot + top) >> 1; bot < top; index = (bot + top) >> 1) {
|
|
if (offset < offsets[index])
|
|
top = index;
|
|
else
|
|
bot = index + 1;
|
|
}
|
|
|
|
return ((bot + top) >> 1);
|
|
}
|
|
|
|
static jit_int32_t
|
|
offset_search_index(jit_line_t *line, jit_int32_t offset)
|
|
{
|
|
jit_int32_t bot;
|
|
jit_int32_t top;
|
|
jit_int32_t index;
|
|
jit_int32_t *offsets;
|
|
|
|
bot = 0;
|
|
top = line->length;
|
|
offsets = line->offsets;
|
|
for (index = (bot + top) >> 1; bot < top; index = (bot + top) >> 1) {
|
|
if (offset < offsets[index])
|
|
top = index;
|
|
/* offset should be already verified to be in range */
|
|
else if (index == line->length - 1 ||
|
|
(offset >= offsets[index] && offset < offsets[index + 1]))
|
|
break;
|
|
else
|
|
bot = index + 1;
|
|
}
|
|
|
|
return (index);
|
|
}
|