| /* |
| * 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; |
| } |