blob: 5e7f7fe5c0717f7644609e64b26440f48d2e46f3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_DOMAIN "vm.helpers"
#include "cxxlog.h"
#include "lil.h"
#include "lil_code_generator_utils.h"
#include "tl/memory_pool.h"
LilCguLabelAddresses::LilCguLabelAddresses(tl::MemoryPool* mem, char * init_base):
first(NULL), my_mem(mem), base(init_base) {}
void LilCguLabelAddresses::change_base(char * new_base) {
LilCguLabelAddress * cur_label_addr;
LilCguPatch * cur_patch;
for (cur_label_addr = first; cur_label_addr != NULL; cur_label_addr = cur_label_addr->next) {
if (cur_label_addr->base_relative) {
// all patch addresses are sensitive to the base address
// since label address is sensitive to the base as well
// we don't need to patch the code. just remember new addresses
cur_label_addr->addr += new_base - base;
for (cur_patch = cur_label_addr->patches; cur_patch != NULL; cur_patch = cur_patch->next) {
cur_patch->addr += new_base - base;
}
} else {
//need to patch the code
for (cur_patch = cur_label_addr->patches; cur_patch != NULL; cur_patch = cur_patch->next) {
cur_patch->addr += new_base - base;
apply_patch(cur_label_addr, cur_patch);
}
}
}
base = new_base;
}
// when base_relative is true it means that label address should be recalculated if base is changed
void LilCguLabelAddresses::define_label(LilLabel l, void * code, bool base_relative) {
LilCguLabelAddress * cur = first;
while (cur != NULL) {
if (strcmp(cur->l, l) == 0) {
if (cur->addr == NULL) {
// not defined
cur->addr = (char *)code;
cur->base_relative = base_relative;
apply_patches(cur);
}
#ifndef NDEBUG
else {
// such label has already been defined
// check that they are consistent
assert(base_relative == cur->base_relative && cur->addr == code);
}
#endif
return;
}
cur = cur->next;
}
// need to create new label address
add_new_label_adress(l, code, base_relative);
}
void LilCguLabelAddresses::add_patch_to_label(LilLabel l, void * patch_address, LilCguPatchType patch_type) {
LilCguLabelAddress * cur = first;
// try to find existing label address
while (cur != NULL && strcmp(cur->l, l) != 0) {
cur = cur->next;
}
// create new label address if not found
if (!cur) {
add_new_label_adress(l, NULL, false);
cur = first;
}
// add new patch
LilCguPatch * p = (LilCguPatch*)my_mem->alloc(sizeof(LilCguPatch));
p->addr = (char *)patch_address;
p->type = patch_type;
p->next = cur->patches;
cur->patches = p;
// apply patch if label defined
if (cur->addr != NULL) {
apply_patch(cur, p);
}
}
void LilCguLabelAddresses::apply_patches(LilCguLabelAddress * label_adress) {
for(LilCguPatch * p = label_adress->patches; p != NULL; p = p->next) {
apply_patch(label_adress, p);
}
}
void LilCguLabelAddresses::apply_patch(LilCguLabelAddress * label_adress, LilCguPatch * patch) {
int64 diff;
switch (patch->type) {
case LPT_Rel8:
diff = (int64)((char *)label_adress->addr - ((char *)patch->addr + 1));
assert(diff == (int64)(I_8)diff);
*(I_8*)patch->addr = (I_8)diff;
break;
case LPT_Rel32:
diff = (int64)((char *)label_adress->addr - (char *)((I_32 *)patch->addr + 1));
assert(diff == (int64)(I_32)diff);
*(I_32*)patch->addr = (I_32)diff;
break;
case LPT_Abs32:
assert((POINTER_SIZE_INT)label_adress->addr <= 0xFFFFffff);
*(I_32*)patch->addr = (I_32)(POINTER_SIZE_INT)label_adress->addr;
break;
default:
DIE(("Unknown patch typ"));
}
}
void LilCguLabelAddresses::add_new_label_adress(LilLabel l, void * code, bool base_relative) {
LilCguLabelAddress * cur = (LilCguLabelAddress*)my_mem->alloc(sizeof(LilCguLabelAddress));
cur->l = l;
cur->addr = (char *)code;
cur->base_relative = base_relative;
cur->patches = NULL;
cur->next = first;
first = cur;
}