/* * Stack-less Just-In-Time compiler * * Copyright Zoltan Herczeg (hzmester@freemail.hu). 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 THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``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 THE COPYRIGHT HOLDER(S) 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. */ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_has_label(struct sljit_jump *jump) { return !(jump->flags & JUMP_ADDR) && (jump->u.label != NULL); } SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_has_target(struct sljit_jump *jump) { return (jump->flags & JUMP_ADDR) != 0; } SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_jump_is_mov_addr(struct sljit_jump *jump) { return (jump->flags & JUMP_MOV_ADDR) != 0; } #define SLJIT_SERIALIZE_DEBUG ((sljit_u16)0x1) struct sljit_serialized_compiler { sljit_u32 signature; sljit_u16 version; sljit_u16 cpu_type; sljit_uw buf_segment_count; sljit_uw label_count; sljit_uw jump_count; sljit_uw const_count; sljit_s32 options; sljit_s32 scratches; sljit_s32 saveds; sljit_s32 fscratches; sljit_s32 fsaveds; sljit_s32 local_size; sljit_uw size; #if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE) sljit_s32 status_flags_state; #endif /* SLJIT_HAS_STATUS_FLAGS_STATE */ #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) sljit_s32 args_size; #endif /* SLJIT_CONFIG_X86_32 */ #if ((defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__)) \ || (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) sljit_uw args_size; #endif /* (SLJIT_CONFIG_ARM_32 && __SOFTFP__) || SLJIT_CONFIG_MIPS_32 */ #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) sljit_uw cpool_diff; sljit_uw cpool_fill; sljit_uw patches; #endif /* SLJIT_CONFIG_ARM_V6 */ #if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) sljit_s32 delay_slot; #endif /* SLJIT_CONFIG_MIPS */ }; struct sljit_serialized_debug_info { sljit_sw last_flags; sljit_s32 last_return; sljit_s32 logical_local_size; }; struct sljit_serialized_label { sljit_uw size; }; struct sljit_serialized_jump { sljit_uw addr; sljit_uw flags; sljit_uw value; }; struct sljit_serialized_const { sljit_uw addr; }; #define SLJIT_SERIALIZE_ALIGN(v) (((v) + sizeof(sljit_uw) - 1) & ~(sljit_uw)(sizeof(sljit_uw) - 1)) #if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN) #define SLJIT_SERIALIZE_SIGNATURE 0x534c4a54 #else /* !SLJIT_LITTLE_ENDIAN */ #define SLJIT_SERIALIZE_SIGNATURE 0x544a4c53 #endif /* SLJIT_LITTLE_ENDIAN */ #define SLJIT_SERIALIZE_VERSION 1 SLJIT_API_FUNC_ATTRIBUTE sljit_uw* sljit_serialize_compiler(struct sljit_compiler *compiler, sljit_s32 options, sljit_uw *size) { sljit_uw serialized_size = sizeof(struct sljit_serialized_compiler); struct sljit_memory_fragment *buf; struct sljit_label *label; struct sljit_jump *jump; struct sljit_const *const_; struct sljit_serialized_compiler *serialized_compiler; struct sljit_serialized_label *serialized_label; struct sljit_serialized_jump *serialized_jump; struct sljit_serialized_const *serialized_const; #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ || (defined SLJIT_DEBUG && SLJIT_DEBUG) struct sljit_serialized_debug_info *serialized_debug_info; #endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */ sljit_uw counter, used_size; sljit_u8 *result; sljit_u8 *ptr; SLJIT_UNUSED_ARG(options); if (size != NULL) *size = 0; PTR_FAIL_IF(compiler->error); #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ || (defined SLJIT_DEBUG && SLJIT_DEBUG) if (!(options & SLJIT_SERIALIZE_IGNORE_DEBUG)) serialized_size += sizeof(struct sljit_serialized_debug_info); #endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */ #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) serialized_size += SLJIT_SERIALIZE_ALIGN(compiler->cpool_fill * (sizeof(sljit_uw) + 1)); #endif /* SLJIT_CONFIG_ARM_V6 */ /* Compute the size of the data. */ buf = compiler->buf; while (buf != NULL) { serialized_size += sizeof(sljit_uw) + SLJIT_SERIALIZE_ALIGN(buf->used_size); buf = buf->next; } serialized_size += compiler->label_count * sizeof(struct sljit_serialized_label); jump = compiler->jumps; while (jump != NULL) { serialized_size += sizeof(struct sljit_serialized_jump); jump = jump->next; } const_ = compiler->consts; while (const_ != NULL) { serialized_size += sizeof(struct sljit_serialized_const); const_ = const_->next; } result = (sljit_u8*)SLJIT_MALLOC(serialized_size, compiler->allocator_data); PTR_FAIL_IF_NULL(result); if (size != NULL) *size = serialized_size; ptr = result; serialized_compiler = (struct sljit_serialized_compiler*)ptr; ptr += sizeof(struct sljit_serialized_compiler); serialized_compiler->signature = SLJIT_SERIALIZE_SIGNATURE; serialized_compiler->version = SLJIT_SERIALIZE_VERSION; serialized_compiler->cpu_type = 0; serialized_compiler->label_count = compiler->label_count; serialized_compiler->options = compiler->options; serialized_compiler->scratches = compiler->scratches; serialized_compiler->saveds = compiler->saveds; serialized_compiler->fscratches = compiler->fscratches; serialized_compiler->fsaveds = compiler->fsaveds; serialized_compiler->local_size = compiler->local_size; serialized_compiler->size = compiler->size; #if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE) serialized_compiler->status_flags_state = compiler->status_flags_state; #endif /* SLJIT_HAS_STATUS_FLAGS_STATE */ #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \ || ((defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__)) \ || (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) serialized_compiler->args_size = compiler->args_size; #endif /* SLJIT_CONFIG_X86_32 || (SLJIT_CONFIG_ARM_32 && __SOFTFP__) || SLJIT_CONFIG_MIPS_32 */ #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) serialized_compiler->cpool_diff = compiler->cpool_diff; serialized_compiler->cpool_fill = compiler->cpool_fill; serialized_compiler->patches = compiler->patches; SLJIT_MEMCPY(ptr, compiler->cpool, compiler->cpool_fill * sizeof(sljit_uw)); SLJIT_MEMCPY(ptr + compiler->cpool_fill * sizeof(sljit_uw), compiler->cpool_unique, compiler->cpool_fill); ptr += SLJIT_SERIALIZE_ALIGN(compiler->cpool_fill * (sizeof(sljit_uw) + 1)); #endif /* SLJIT_CONFIG_ARM_V6 */ #if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) serialized_compiler->delay_slot = compiler->delay_slot; #endif /* SLJIT_CONFIG_MIPS */ buf = compiler->buf; counter = 0; while (buf != NULL) { used_size = buf->used_size; *(sljit_uw*)ptr = used_size; ptr += sizeof(sljit_uw); SLJIT_MEMCPY(ptr, buf->memory, used_size); ptr += SLJIT_SERIALIZE_ALIGN(used_size); buf = buf->next; counter++; } serialized_compiler->buf_segment_count = counter; label = compiler->labels; while (label != NULL) { serialized_label = (struct sljit_serialized_label*)ptr; serialized_label->size = label->size; ptr += sizeof(struct sljit_serialized_label); label = label->next; } jump = compiler->jumps; counter = 0; while (jump != NULL) { serialized_jump = (struct sljit_serialized_jump*)ptr; serialized_jump->addr = jump->addr; serialized_jump->flags = jump->flags; if (jump->flags & JUMP_ADDR) serialized_jump->value = jump->u.target; else if (jump->u.label != NULL) serialized_jump->value = jump->u.label->u.index; else serialized_jump->value = SLJIT_MAX_ADDRESS; ptr += sizeof(struct sljit_serialized_jump); jump = jump->next; counter++; } serialized_compiler->jump_count = counter; const_ = compiler->consts; counter = 0; while (const_ != NULL) { serialized_const = (struct sljit_serialized_const*)ptr; serialized_const->addr = const_->addr; ptr += sizeof(struct sljit_serialized_const); const_ = const_->next; counter++; } serialized_compiler->const_count = counter; #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ || (defined SLJIT_DEBUG && SLJIT_DEBUG) if (!(options & SLJIT_SERIALIZE_IGNORE_DEBUG)) { serialized_debug_info = (struct sljit_serialized_debug_info*)ptr; serialized_debug_info->last_flags = compiler->last_flags; serialized_debug_info->last_return = compiler->last_return; serialized_debug_info->logical_local_size = compiler->logical_local_size; serialized_compiler->cpu_type |= SLJIT_SERIALIZE_DEBUG; #if (defined SLJIT_DEBUG && SLJIT_DEBUG) ptr += sizeof(struct sljit_serialized_debug_info); #endif /* SLJIT_DEBUG */ } #endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */ SLJIT_ASSERT((sljit_uw)(ptr - result) == serialized_size); return (sljit_uw*)result; } SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler *sljit_deserialize_compiler(sljit_uw* buffer, sljit_uw size, sljit_s32 options, void *allocator_data) { struct sljit_compiler *compiler; struct sljit_serialized_compiler *serialized_compiler; struct sljit_serialized_label *serialized_label; struct sljit_serialized_jump *serialized_jump; struct sljit_serialized_const *serialized_const; #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ || (defined SLJIT_DEBUG && SLJIT_DEBUG) struct sljit_serialized_debug_info *serialized_debug_info; #endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */ struct sljit_memory_fragment *buf; struct sljit_memory_fragment *last_buf; struct sljit_label *label; struct sljit_label *last_label; struct sljit_label **label_list = NULL; struct sljit_jump *jump; struct sljit_jump *last_jump; struct sljit_const *const_; struct sljit_const *last_const; sljit_u8 *ptr = (sljit_u8*)buffer; sljit_u8 *end = ptr + size; sljit_uw i, used_size, aligned_size, label_count; SLJIT_UNUSED_ARG(options); if (size < sizeof(struct sljit_serialized_compiler) || (size & (sizeof(sljit_uw) - 1)) != 0) return NULL; serialized_compiler = (struct sljit_serialized_compiler*)ptr; if (serialized_compiler->signature != SLJIT_SERIALIZE_SIGNATURE || serialized_compiler->version != SLJIT_SERIALIZE_VERSION) return NULL; compiler = sljit_create_compiler(allocator_data); PTR_FAIL_IF(compiler == NULL); compiler->label_count = serialized_compiler->label_count; compiler->options = serialized_compiler->options; compiler->scratches = serialized_compiler->scratches; compiler->saveds = serialized_compiler->saveds; compiler->fscratches = serialized_compiler->fscratches; compiler->fsaveds = serialized_compiler->fsaveds; compiler->local_size = serialized_compiler->local_size; compiler->size = serialized_compiler->size; #if (defined SLJIT_HAS_STATUS_FLAGS_STATE && SLJIT_HAS_STATUS_FLAGS_STATE) compiler->status_flags_state = serialized_compiler->status_flags_state; #endif /* SLJIT_HAS_STATUS_FLAGS_STATE */ #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \ || ((defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__)) \ || (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) compiler->args_size = serialized_compiler->args_size; #endif /* SLJIT_CONFIG_X86_32 || (SLJIT_CONFIG_ARM_32 && __SOFTFP__) || SLJIT_CONFIG_MIPS_32 */ #if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) used_size = serialized_compiler->cpool_fill; aligned_size = SLJIT_SERIALIZE_ALIGN(used_size * (sizeof(sljit_uw) + 1)); compiler->cpool_diff = serialized_compiler->cpool_diff; compiler->cpool_fill = used_size; compiler->patches = serialized_compiler->patches; if ((sljit_uw)(end - ptr) < aligned_size) goto error; SLJIT_MEMCPY(compiler->cpool, ptr, used_size * sizeof(sljit_uw)); SLJIT_MEMCPY(compiler->cpool_unique, ptr + used_size * sizeof(sljit_uw), used_size); ptr += aligned_size; #endif /* SLJIT_CONFIG_ARM_V6 */ #if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) compiler->delay_slot = serialized_compiler->delay_slot; #endif /* SLJIT_CONFIG_MIPS */ #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ || (defined SLJIT_DEBUG && SLJIT_DEBUG) if (!(serialized_compiler->cpu_type & SLJIT_SERIALIZE_DEBUG)) goto error; #endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */ ptr += sizeof(struct sljit_serialized_compiler); i = serialized_compiler->buf_segment_count; last_buf = NULL; while (i > 0) { if ((sljit_uw)(end - ptr) < sizeof(sljit_uw)) goto error; used_size = *(sljit_uw*)ptr; aligned_size = SLJIT_SERIALIZE_ALIGN(used_size); ptr += sizeof(sljit_uw); if ((sljit_uw)(end - ptr) < aligned_size) goto error; if (last_buf == NULL) { SLJIT_ASSERT(compiler->buf != NULL && compiler->buf->next == NULL); buf = compiler->buf; } else { buf = (struct sljit_memory_fragment*)SLJIT_MALLOC(BUF_SIZE, allocator_data); if (!buf) goto error; buf->next = NULL; } buf->used_size = used_size; SLJIT_MEMCPY(buf->memory, ptr, used_size); if (last_buf != NULL) last_buf->next = buf; last_buf = buf; ptr += aligned_size; i--; } last_label = NULL; label_count = serialized_compiler->label_count; if ((sljit_uw)(end - ptr) < label_count * sizeof(struct sljit_serialized_label)) goto error; label_list = (struct sljit_label **)SLJIT_MALLOC(label_count * sizeof(struct sljit_label*), allocator_data); if (label_list == NULL) goto error; for (i = 0; i < label_count; i++) { label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label)); if (label == NULL) goto error; serialized_label = (struct sljit_serialized_label*)ptr; label->next = NULL; label->u.index = i; label->size = serialized_label->size; if (last_label != NULL) last_label->next = label; else compiler->labels = label; last_label = label; label_list[i] = label; ptr += sizeof(struct sljit_serialized_label); } compiler->last_label = last_label; last_jump = NULL; i = serialized_compiler->jump_count; if ((sljit_uw)(end - ptr) < i * sizeof(struct sljit_serialized_jump)) goto error; while (i > 0) { jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); if (jump == NULL) goto error; serialized_jump = (struct sljit_serialized_jump*)ptr; jump->next = NULL; jump->addr = serialized_jump->addr; jump->flags = serialized_jump->flags; if (!(serialized_jump->flags & JUMP_ADDR)) { if (serialized_jump->value != SLJIT_MAX_ADDRESS) { if (serialized_jump->value >= label_count) goto error; jump->u.label = label_list[serialized_jump->value]; } else jump->u.label = NULL; } else jump->u.target = serialized_jump->value; if (last_jump != NULL) last_jump->next = jump; else compiler->jumps = jump; last_jump = jump; ptr += sizeof(struct sljit_serialized_jump); i--; } compiler->last_jump = last_jump; SLJIT_FREE(label_list, allocator_data); label_list = NULL; last_const = NULL; i = serialized_compiler->const_count; if ((sljit_uw)(end - ptr) < i * sizeof(struct sljit_serialized_const)) goto error; while (i > 0) { const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const)); if (const_ == NULL) goto error; serialized_const = (struct sljit_serialized_const*)ptr; const_->next = NULL; const_->addr = serialized_const->addr; if (last_const != NULL) last_const->next = const_; else compiler->consts = const_; last_const = const_; ptr += sizeof(struct sljit_serialized_const); i--; } compiler->last_const = last_const; #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \ || (defined SLJIT_DEBUG && SLJIT_DEBUG) if ((sljit_uw)(end - ptr) < sizeof(struct sljit_serialized_debug_info)) goto error; serialized_debug_info = (struct sljit_serialized_debug_info*)ptr; compiler->last_flags = (sljit_s32)serialized_debug_info->last_flags; compiler->last_return = serialized_debug_info->last_return; compiler->logical_local_size = serialized_debug_info->logical_local_size; #endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */ return compiler; error: sljit_free_compiler(compiler); if (label_list != NULL) SLJIT_FREE(label_list, allocator_data); return NULL; }