blob: faa5378d40c951a58b4b96401aeb3382e7ec2143 [file] [log] [blame]
/*
* Copyright (C) 2003, 2004, 2005, 2015 Filip Pizlo. All rights reserved.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY FILIP PIZLO ``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 FILIP PIZLO OR
* CONTRIBUTORS 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 "gpc_internal.h"
#include "tsf_format.h"
gpc_proto_t *gpc_proto_create(uint32_t num_args) {
gpc_proto_t *ret=malloc(sizeof(gpc_proto_t));
if (ret==NULL) {
tsf_set_errno("Could not malloc gpc_proto_t");
return NULL;
}
ret->num_args=num_args;
ret->stream=NULL;
ret->size=0;
return ret;
}
void gpc_proto_destroy(gpc_proto_t *proto) {
if (proto->stream!=NULL) {
free(proto->stream);
}
free(proto);
}
tsf_bool_t gpc_proto_reserve(gpc_proto_t *proto,
uint32_t num_slots) {
if (proto->stream==NULL) {
proto->stream=malloc(sizeof(gpc_cell_t)*num_slots);
if (proto->stream==NULL) {
tsf_set_errno("Could not malloc gpc_cell_t array");
return tsf_false;
}
} else {
gpc_cell_t *new_array=
realloc(proto->stream,
sizeof(gpc_cell_t)
* (proto->size+num_slots));
if (new_array==NULL) {
tsf_set_errno("Could not realloc gpc_cell_t array");
return tsf_false;
}
proto->stream=new_array;
}
return tsf_true;
}
tsf_bool_t gpc_proto_append(gpc_proto_t *proto,
gpc_cell_t inst,
...) {
va_list lst;
uint32_t size=gpc_instruction_static_size(inst);
va_start(lst,inst);
if (size==UINT32_MAX) {
gpc_cell_t len=
va_arg(lst,gpc_cell_t);
if (!gpc_proto_reserve(proto,2+len)) {
return tsf_false;
}
proto->stream[proto->size++]=inst;
proto->stream[proto->size++]=len;
while (len-->0) {
proto->stream[proto->size++]=
va_arg(lst,gpc_cell_t);
}
return tsf_true;
}
if (!gpc_proto_reserve(proto,size)) {
return tsf_false;
}
proto->stream[proto->size++]=inst;
while (--size>0) {
proto->stream[proto->size++]=
va_arg(lst,gpc_cell_t);
}
return tsf_true;
}
tsf_bool_t gpc_proto_append_tableset_local_to_field(gpc_proto_t *proto,
gpc_cell_t offset,
gpc_cell_t num,
const gpc_cell_t *args) {
uint32_t i;
if (!gpc_proto_reserve(proto,3+num)) {
return tsf_false;
}
proto->stream[proto->size++]=GPC_I_TABLESET_LOCAL_TO_FIELD;
proto->stream[proto->size++]=offset;
proto->stream[proto->size++]=num;
for (i=0;i<num;++i) {
proto->stream[proto->size++]=args[i];
}
return tsf_true;
}
tsf_bool_t gpc_proto_append_tableset_field_to_field(gpc_proto_t *proto,
gpc_cell_t dest_offset,
gpc_cell_t src_offset,
gpc_cell_t num,
const gpc_cell_t *args) {
uint32_t i;
if (!gpc_proto_reserve(proto,4+num)) {
return tsf_false;
}
proto->stream[proto->size++]=GPC_I_TABLESET_FIELD_TO_FIELD;
proto->stream[proto->size++]=dest_offset;
proto->stream[proto->size++]=src_offset;
proto->stream[proto->size++]=num;
for (i=0;i<num;++i) {
proto->stream[proto->size++]=args[i];
}
return tsf_true;
}
tsf_bool_t gpc_proto_append_tablejump_local(gpc_proto_t *proto,
gpc_cell_t num,
const gpc_cell_t *args) {
uint32_t i;
if (!gpc_proto_reserve(proto,2+num)) {
return tsf_false;
}
proto->stream[proto->size++]=GPC_I_TABLEJUMP_LOCAL;
proto->stream[proto->size++]=num;
for (i=0;i<num;++i) {
proto->stream[proto->size++]=args[i];
}
return tsf_true;
}
tsf_bool_t gpc_proto_append_tablejump_field(gpc_proto_t *proto,
gpc_cell_t offset,
gpc_cell_t num,
const gpc_cell_t *args) {
uint32_t i;
if (!gpc_proto_reserve(proto,3+num)) {
return tsf_false;
}
proto->stream[proto->size++]=GPC_I_TABLEJUMP_FIELD;
proto->stream[proto->size++]=offset;
proto->stream[proto->size++]=num;
for (i=0;i<num;++i) {
proto->stream[proto->size++]=args[i];
}
return tsf_true;
}
void gpc_proto_print(gpc_proto_t *proto,
FILE *out) {
uint32_t i;
for (i = 0; i < proto->size;) {
uint32_t size = gpc_instruction_size(proto->stream + i);
if (proto->stream[i] == GPC_I_LABEL) {
fprintf(out, fui64 ":", (uint64_t)proto->stream[i + 1]);
} else {
uint32_t j;
const char *name=
gpc_instruction_to_string(proto->stream[i]);
if (strlen(name) < 35) {
for (j = 0; j < 35 - strlen(name); ++j) {
fprintf(out, " ");
}
}
fprintf(out, "%s", name);
for (j = 1; j < size; ++j) {
fprintf(out, "\t" fui64, (uint64_t)proto->stream[i + j]);
}
}
fprintf(out, "\n");
i += size;
}
}