mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 05:12:33 +00:00
With these changes, it now passes all tests/general/* test cases
except those with floats.
Changes to the compiler:
- Added extra argument to test instruction (string comparisons were
being treated as integer comparisons; properly deals with different
atomic type unifications now)
- Changed bytecode stub functions
Changes to the bytecode interpreter:
- Cleaned up comments
- Forked part of mb_machine to mb_exec
- Added support for submodules
- Added support for nondet procedures
- Added support for cc_xxx procedures
- Finished higher order calls
- Added (very basic) debug interface
- Added support for type information
- Added memory corruption checking
- Changed machine state dump formatting
- Fixed bug in nested switches
- Resolved builtin__unify and builtin_compare failures
- Modified bytecode tags generation so .c & .m tag files are separate
- Header usage rationalised
Changes to test suite:
- Added test cases for the bytecode interpreter.
- More work on the bytecode interpreter.
bytecode/Mmakefile:
Modified bytecode tags generation so .c & .m tag files are separate.
mb_machine split into mb_exec.
test file renamed to simple.m (copy over tests/simple??.m to test).
bytecode/TODO:
Updated.
bytecode/mb_basetypes.h:
Removed redundant MB_WORD_BITS (use MR_WORDBITS instead).
bytecode/mb_bytecode.h:
bytecode/mpb_bytecode.c:
Formatting changes
Third test instruction argument added.
bytecode/mb_disasm.h:
bytecode/mb_disasm.c:
Formatting changes.
Third test instruction argument added.
Added MB_FMT_INTWIDE.
bytecode/mb_exec.h:
bytecode/mb_exec.c:
bytecode/mb_machine.h:
bytecode/mb_machine.c:
mb_machine* split into mb_exec* and mb_machine*.
Almost all instructions now work (see important changes above).
bytecode/mb_interface.h:
bytecode/mb_interface.c:
Added nondet stub functions.
Added functions to lookup builtin compiler procedures:
do_redo, do_fail, __unify, __compare.
Removed old debugging code.
Stack layout changed to support nondet procedures.
bytecode/mb_interface_stub.c:
bytecode/mb_interface_stub.h:
Split off bare minimum of includes for bytecode stubs.
Added nondet stubs.
bytecode/mb_machine_show.c:
Made code cleaner (added subfunctions for MB_show_state).
Added variable names to machine state dump.
bytecode/mb_mem.h:
bytecode/mb_mem.c:
Added limited memory corruption checking.
bytecode/mb_module.h:
bytecode/mb_module.c:
Swapped order of temps & vars on stack.
Fixed nested switches causing random crashes.
Added nested module support.
bytecode/test/simple??.m:
Various test files - just to check that it doesn't crash.
(Most do not output anything & must be verified by stepping through
manually).
compiler/bytecode.m:
compiler/bytecode_gen.m:
Added extra argument to test instruction (otherwise
string comparisons would be treated as integer comparisons).
compiler/code_gen.m:
Changed call structure name in bytecode stub to resolve
issues with illegal characters in C structure names.
Changed bytecode stub header file name.
255 lines
4.8 KiB
C
255 lines
4.8 KiB
C
|
|
/*
|
|
** Copyright (C) 1997,2000-2001 The University of Melbourne.
|
|
** This file may only be copied under the terms of the GNU Library General
|
|
** Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
**
|
|
*/
|
|
|
|
/* Imports */
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "mercury_tags.h"
|
|
|
|
#include "mb_mem.h"
|
|
#include "mb_util.h"
|
|
|
|
/* Exported definitions */
|
|
void *MB_malloc(size_t size);
|
|
void *MB_realloc(void* mem, size_t size);
|
|
void MB_free(void *mem);
|
|
void *MB_GC_malloc(size_t size);
|
|
void *MB_GC_malloc_atomic(size_t size);
|
|
void *MB_GC_realloc(void* mem, size_t size);
|
|
void MB_GC_free(void *mem);
|
|
|
|
/* Local declarations */
|
|
|
|
#ifdef MB_MALLOC_CHECK
|
|
void *block_get(void *mem);
|
|
void block_check(void *block);
|
|
#endif
|
|
|
|
/* Implementation */
|
|
|
|
#ifdef MB_MALLOC_CHECK
|
|
/*
|
|
** Memory block layout:
|
|
** char guardbytes[]
|
|
** size_t size
|
|
** memory passed to client
|
|
** char guardbytes[]
|
|
**
|
|
** Make sure the size of guard_bytes is a multiple of 8 to ensure we
|
|
** don't get unaligned accesses, even on 64-bit architectures.
|
|
*/
|
|
#define GRANULARITY 8 /* Alignment for block elements expect */
|
|
#define GUARD_VAL 0xa5
|
|
#define GUARD_SIZE sizeof(guard_bytes)
|
|
static const unsigned char
|
|
guard_bytes[] = { GUARD_VAL+0, GUARD_VAL+1, GUARD_VAL+2, GUARD_VAL+3,
|
|
GUARD_VAL+4, GUARD_VAL+5, GUARD_VAL+6, GUARD_VAL+7 };
|
|
|
|
/* Offset of prologue guard bytes */
|
|
#define MEMBLOCK_PREGUARD(block, i) \
|
|
(((unsigned char *) block)[i])
|
|
|
|
/* Offset of size field */
|
|
#define MEMBLOCK_SIZE(block) \
|
|
(* (size_t *) \
|
|
((unsigned char *) block \
|
|
+ MB_MULTIPLEOF(GUARD_SIZE, GRANULARITY) \
|
|
) \
|
|
)
|
|
|
|
/* Offset of memory block */
|
|
/* Offset of size field */
|
|
#define MEMBLOCK_MEM(block) \
|
|
( \
|
|
((unsigned char *) block \
|
|
+ MB_MULTIPLEOF(GUARD_SIZE, GRANULARITY) \
|
|
+ MB_MULTIPLEOF(sizeof(size_t), GRANULARITY ) \
|
|
) \
|
|
)
|
|
|
|
/* Offset of epilogue guard bytes */
|
|
#define MEMBLOCK_POSTGUARD(block, i) \
|
|
( \
|
|
(MEMBLOCK_MEM(block) \
|
|
+ MB_MULTIPLEOF(MEMBLOCK_SIZE(block), GRANULARITY) \
|
|
)[i] \
|
|
)
|
|
|
|
/* Total size of memory block */
|
|
#define MEMBLOCK_TOTALSIZE(memsize) \
|
|
( MB_MULTIPLEOF(GUARD_SIZE, GRANULARITY) \
|
|
+ MB_MULTIPLEOF(sizeof(size_t), GRANULARITY) \
|
|
+ MB_MULTIPLEOF(memsize, GRANULARITY) \
|
|
+ MB_MULTIPLEOF(GUARD_SIZE, GRANULARITY) \
|
|
)
|
|
|
|
/* Get the actual memory block start */
|
|
void *
|
|
block_get(void *mem)
|
|
{
|
|
return (unsigned char *) mem
|
|
- MB_MULTIPLEOF(GUARD_SIZE, GRANULARITY)
|
|
- MB_MULTIPLEOF(sizeof(size_t), GRANULARITY);
|
|
}
|
|
|
|
/* Checks a memory block for corruption and if not corrupt returns its size */
|
|
void
|
|
block_check(void *block)
|
|
{
|
|
int i;
|
|
|
|
/* Check prologue guard bytes */
|
|
for (i = 0; i < GUARD_SIZE; i++) {
|
|
if (MEMBLOCK_PREGUARD(block, i) != guard_bytes[i]) {
|
|
MB_fatal("mb_mem: block_check:"
|
|
" memory corruption detected");
|
|
}
|
|
}
|
|
|
|
/* Check epilogue guard bytes */
|
|
for (i = 0; i < GUARD_SIZE; i++) {
|
|
if (MEMBLOCK_POSTGUARD(block, i) != guard_bytes[i]) {
|
|
MB_fatal("mb_mem: block_check:"
|
|
" memory corruption detected");
|
|
}
|
|
}
|
|
}
|
|
|
|
void *
|
|
MB_malloc(size_t size)
|
|
{
|
|
unsigned char *block= malloc(MEMBLOCK_TOTALSIZE(size));
|
|
|
|
|
|
if (block== NULL) {
|
|
MB_fatal("MB_malloc failed");
|
|
}
|
|
|
|
MEMBLOCK_SIZE(block) = size;
|
|
memcpy(&(MEMBLOCK_PREGUARD(block, 0)), guard_bytes, GUARD_SIZE);
|
|
memcpy(&(MEMBLOCK_POSTGUARD(block, 0)), guard_bytes, GUARD_SIZE);
|
|
|
|
return MEMBLOCK_MEM(block);
|
|
}
|
|
|
|
void
|
|
MB_free(void *mem)
|
|
{
|
|
void* block = block_get(mem);
|
|
|
|
block_check(block);
|
|
|
|
/* Free the memory */
|
|
free(block);
|
|
}
|
|
|
|
void *
|
|
MB_realloc(void *mem, size_t new_size)
|
|
{
|
|
void* block = block_get(mem);
|
|
|
|
if (new_size == 0) {
|
|
MB_free(mem);
|
|
return NULL;
|
|
|
|
} else if (mem == NULL) {
|
|
return MB_malloc(new_size);
|
|
|
|
} else if (MEMBLOCK_SIZE(block) != new_size) {
|
|
block_check(block);
|
|
|
|
block = realloc(block, MEMBLOCK_TOTALSIZE(new_size));
|
|
|
|
/* Update the size */
|
|
MEMBLOCK_SIZE(block) = new_size;
|
|
|
|
/* Redo the guard bytes at the end */
|
|
memcpy(&MEMBLOCK_POSTGUARD(block, 0), guard_bytes, GUARD_SIZE);
|
|
|
|
}
|
|
|
|
block_check(block);
|
|
|
|
return MEMBLOCK_MEM(block);
|
|
}
|
|
|
|
#else /* MB_MALLOC_CHECK */
|
|
|
|
void *
|
|
MB_malloc(size_t size)
|
|
{
|
|
return malloc(size);
|
|
}
|
|
|
|
void
|
|
MB_free(void *mem)
|
|
{
|
|
return free(mem);
|
|
}
|
|
|
|
void *
|
|
MB_realloc(void *mem, size_t new_size)
|
|
{
|
|
return realloc(mem, new_size);
|
|
}
|
|
|
|
#endif /* MB_MALLOC_CHECK */
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
#ifndef MB_NO_GC
|
|
|
|
#include "gc.h"
|
|
|
|
void *
|
|
MB_GC_malloc(size_t size)
|
|
{
|
|
return GC_malloc(size);
|
|
}
|
|
|
|
void *
|
|
MB_GC_malloc_atomic(size_t size)
|
|
{
|
|
return GC_malloc_atomic(size);
|
|
}
|
|
|
|
void
|
|
MB_GC_free(void *mem)
|
|
{
|
|
GC_free(mem);
|
|
}
|
|
|
|
void *
|
|
MB_GC_realloc(void *mem, size_t size)
|
|
{
|
|
return GC_realloc(mem, size);
|
|
}
|
|
|
|
#else /* MB_NO_GC */
|
|
|
|
void *
|
|
MB_GC_malloc(size_t size, MB_Bool atomic)
|
|
{
|
|
return MB_malloc(size);
|
|
}
|
|
|
|
void
|
|
MB_GC_free(void *mem)
|
|
{
|
|
MB_free(mem);
|
|
}
|
|
|
|
void *
|
|
MB_GC_realloc(void *mem, size_t size)
|
|
{
|
|
return MB_realloc(mem, size);
|
|
}
|
|
|
|
#endif /* MB_NO_GC */
|
|
|