Obj* NoCloneHash_Make_Key_IMP(NoCloneHash *self, Obj *key, int32_t hash_sum) { UNUSED_VAR(self); UNUSED_VAR(hash_sum); return INCREF(key); }
bool LFLock_Request_IMP(LockFileLock *self) { LockFileLockIVARS *const ivars = LFLock_IVARS(self); bool success = false; if (Folder_Exists(ivars->folder, ivars->lock_path)) { Err_set_error((Err*)LockErr_new(Str_newf("Can't obtain lock: '%o' exists", ivars->lock_path))); return false; } // Create the "locks" subdirectory if necessary. String *lock_dir_name = (String*)SSTR_WRAP_UTF8("locks", 5); if (!Folder_Exists(ivars->folder, lock_dir_name)) { if (!Folder_MkDir(ivars->folder, lock_dir_name)) { Err *mkdir_err = (Err*)CERTIFY(Err_get_error(), ERR); LockErr *err = LockErr_new(Str_newf("Can't create 'locks' directory: %o", Err_Get_Mess(mkdir_err))); // Maybe our attempt failed because another process succeeded. if (Folder_Find_Folder(ivars->folder, lock_dir_name)) { DECREF(err); } else { // Nope, everything failed, so bail out. Err_set_error((Err*)err); return false; } } } // Prepare to write pid, lock name, and host to the lock file as JSON. Hash *file_data = Hash_new(3); Hash_Store_Utf8(file_data, "pid", 3, (Obj*)Str_newf("%i32", (int32_t)PID_getpid())); Hash_Store_Utf8(file_data, "host", 4, INCREF(ivars->host)); Hash_Store_Utf8(file_data, "name", 4, INCREF(ivars->name)); String *json = Json_to_json((Obj*)file_data); DECREF(file_data); // Write to a temporary file, then use the creation of a hard link to // ensure atomic but non-destructive creation of the lockfile with its // complete contents. OutStream *outstream = Folder_Open_Out(ivars->folder, ivars->link_path); if (!outstream) { ERR_ADD_FRAME(Err_get_error()); DECREF(json); return false; } struct lockfile_context context; context.outstream = outstream; context.json = json; Err *json_error = Err_trap(S_write_lockfile_json, &context); bool wrote_json = !json_error; DECREF(outstream); DECREF(json); if (wrote_json) { success = Folder_Hard_Link(ivars->folder, ivars->link_path, ivars->lock_path); if (!success) { Err *hard_link_err = (Err*)CERTIFY(Err_get_error(), ERR); Err_set_error((Err*)LockErr_new(Str_newf("Failed to obtain lock at '%o': %o", ivars->lock_path, Err_Get_Mess(hard_link_err)))); } } else { Err_set_error((Err*)LockErr_new(Str_newf("Failed to obtain lock at '%o': %o", ivars->lock_path, Err_Get_Mess(json_error)))); DECREF(json_error); } // Verify that our temporary file got zapped. bool deletion_failed = !Folder_Delete(ivars->folder, ivars->link_path); if (deletion_failed) { String *mess = MAKE_MESS("Failed to delete '%o'", ivars->link_path); Err_throw_mess(ERR, mess); } return success; }
static void test_open(TestBatchRunner *runner) { FSFileHandle *fh; String *test_filename = SSTR_WRAP_C("_fstest"); S_remove(test_filename); Err_set_error(NULL); fh = FSFH_open(test_filename, FH_READ_ONLY); TEST_TRUE(runner, fh == NULL, "open() with FH_READ_ONLY on non-existent file returns NULL"); TEST_TRUE(runner, Err_get_error() != NULL, "open() with FH_READ_ONLY on non-existent file sets error"); Err_set_error(NULL); fh = FSFH_open(test_filename, FH_WRITE_ONLY); TEST_TRUE(runner, fh == NULL, "open() without FH_CREATE returns NULL"); TEST_TRUE(runner, Err_get_error() != NULL, "open() without FH_CREATE sets error"); Err_set_error(NULL); fh = FSFH_open(test_filename, FH_CREATE); TEST_TRUE(runner, fh == NULL, "open() without FH_WRITE_ONLY returns NULL"); TEST_TRUE(runner, Err_get_error() != NULL, "open() without FH_WRITE_ONLY sets error"); Err_set_error(NULL); fh = FSFH_open(test_filename, FH_CREATE | FH_WRITE_ONLY | FH_EXCLUSIVE); TEST_TRUE(runner, fh && FSFH_is_a(fh, FSFILEHANDLE), "open() succeeds"); TEST_TRUE(runner, Err_get_error() == NULL, "open() no errors"); FSFH_Write(fh, "foo", 3); if (!FSFH_Close(fh)) { RETHROW(INCREF(Err_get_error())); } DECREF(fh); Err_set_error(NULL); fh = FSFH_open(test_filename, FH_CREATE | FH_WRITE_ONLY | FH_EXCLUSIVE); TEST_TRUE(runner, fh == NULL, "FH_EXCLUSIVE blocks open()"); TEST_TRUE(runner, Err_get_error() != NULL, "FH_EXCLUSIVE blocks open(), sets error"); Err_set_error(NULL); fh = FSFH_open(test_filename, FH_CREATE | FH_WRITE_ONLY); TEST_TRUE(runner, fh && FSFH_is_a(fh, FSFILEHANDLE), "open() for append"); TEST_TRUE(runner, Err_get_error() == NULL, "open() for append -- no errors"); FSFH_Write(fh, "bar", 3); if (!FSFH_Close(fh)) { RETHROW(INCREF(Err_get_error())); } DECREF(fh); Err_set_error(NULL); fh = FSFH_open(test_filename, FH_READ_ONLY); TEST_TRUE(runner, fh && FSFH_is_a(fh, FSFILEHANDLE), "open() read only"); TEST_TRUE(runner, Err_get_error() == NULL, "open() read only -- no errors"); DECREF(fh); S_remove(test_filename); }
/* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. * Returns p. */ NODE * funcode(NODE *p) { extern int gotnr; #ifdef GCC_COMPAT struct attr *ap; #endif NODE *r, *l; TWORD t = DECREF(DECREF(p->n_left->n_type)); int stcall; stcall = ISSOU(t); /* * We may have to prepend: * - Hidden arg0 for struct return (in reg or on stack). * - ebx in case of PIC code. */ /* Fix function call arguments. On x86, just add funarg */ for (r = p->n_right; r->n_op == CM; r = r->n_left) { if (r->n_right->n_op != STARG) { r->n_right = intprom(r->n_right); r->n_right = block(FUNARG, r->n_right, NIL, r->n_right->n_type, r->n_right->n_df, r->n_right->n_ap); } } if (r->n_op != STARG) { l = talloc(); *l = *r; r->n_op = FUNARG; r->n_left = l; r->n_left = intprom(r->n_left); r->n_type = r->n_left->n_type; } if (stcall) { /* Prepend a placeholder for struct address. */ /* Use BP, can never show up under normal circumstances */ l = talloc(); *l = *r; r->n_op = CM; r->n_right = l; r->n_type = INT; l = block(REG, 0, 0, INCREF(VOID), 0, 0); regno(l) = BP; l = block(FUNARG, l, 0, INCREF(VOID), 0, 0); r->n_left = l; } #ifdef GCC_COMPAT if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_REGPARM))) rparg = ap->iarg(0); else #endif rparg = 0; regcvt = 0; if (rparg) listf(p->n_right, addreg); return p; }
I32Array* PolyReader_offsets(PolyReader *self) { PolyReaderIVARS *const ivars = PolyReader_IVARS(self); return (I32Array*)INCREF(ivars->offsets); }
void PolyQuery_Add_Child_IMP(PolyQuery *self, Query *query) { CERTIFY(query, QUERY); PolyQueryIVARS *const ivars = PolyQuery_IVARS(self); Vec_Push(ivars->children, INCREF(query)); }
VArray* SegReader_seg_readers(SegReader *self) { VArray *seg_readers = VA_new(1); VA_Push(seg_readers, INCREF(self)); return seg_readers; }
static void S_discover_unused(FilePurger *self, VArray **purgables_ptr, VArray **snapshots_ptr) { Folder *folder = self->folder; DirHandle *dh = Folder_Open_Dir(folder, NULL); if (!dh) { RETHROW(INCREF(Err_get_error())); } VArray *spared = VA_new(1); VArray *snapshots = VA_new(1); CharBuf *snapfile = NULL; // Start off with the list of files in the current snapshot. if (self->snapshot) { VArray *entries = Snapshot_List(self->snapshot); VArray *referenced = S_find_all_referenced(folder, entries); VA_Push_VArray(spared, referenced); DECREF(entries); DECREF(referenced); snapfile = Snapshot_Get_Path(self->snapshot); if (snapfile) { VA_Push(spared, INCREF(snapfile)); } } CharBuf *entry = DH_Get_Entry(dh); Hash *candidates = Hash_new(64); while (DH_Next(dh)) { if (!CB_Starts_With_Str(entry, "snapshot_", 9)) { continue; } else if (!CB_Ends_With_Str(entry, ".json", 5)) { continue; } else if (snapfile && CB_Equals(entry, (Obj*)snapfile)) { continue; } else { Snapshot *snapshot = Snapshot_Read_File(Snapshot_new(), folder, entry); Lock *lock = IxManager_Make_Snapshot_Read_Lock(self->manager, entry); VArray *snap_list = Snapshot_List(snapshot); VArray *referenced = S_find_all_referenced(folder, snap_list); // DON'T obtain the lock -- only see whether another // entity holds a lock on the snapshot file. if (lock) { Lock_Clear_Stale(lock); } if (lock && Lock_Is_Locked(lock)) { // The snapshot file is locked, which means someone's using // that version of the index -- protect all of its entries. uint32_t new_size = VA_Get_Size(spared) + VA_Get_Size(referenced) + 1; VA_Grow(spared, new_size); VA_Push(spared, (Obj*)CB_Clone(entry)); VA_Push_VArray(spared, referenced); } else { // No one's using this snapshot, so all of its entries are // candidates for deletion. for (uint32_t i = 0, max = VA_Get_Size(referenced); i < max; i++) { CharBuf *file = (CharBuf*)VA_Fetch(referenced, i); Hash_Store(candidates, (Obj*)file, INCREF(&EMPTY)); } VA_Push(snapshots, INCREF(snapshot)); } DECREF(referenced); DECREF(snap_list); DECREF(snapshot); DECREF(lock); } } DECREF(dh); // Clean up after a dead segment consolidation. S_zap_dead_merge(self, candidates); // Eliminate any current files from the list of files to be purged. for (uint32_t i = 0, max = VA_Get_Size(spared); i < max; i++) { CharBuf *filename = (CharBuf*)VA_Fetch(spared, i); DECREF(Hash_Delete(candidates, (Obj*)filename)); } // Pass back purgables and Snapshots. *purgables_ptr = Hash_Keys(candidates); *snapshots_ptr = snapshots; DECREF(candidates); DECREF(spared); }
void FilePurger_purge(FilePurger *self) { Lock *deletion_lock = IxManager_Make_Deletion_Lock(self->manager); // Obtain deletion lock, purge files, release deletion lock. Lock_Clear_Stale(deletion_lock); if (Lock_Obtain(deletion_lock)) { Folder *folder = self->folder; Hash *failures = Hash_new(0); VArray *purgables; VArray *snapshots; S_discover_unused(self, &purgables, &snapshots); // Attempt to delete entries -- if failure, no big deal, just try // again later. Proceed in reverse lexical order so that directories // get deleted after they've been emptied. VA_Sort(purgables, NULL, NULL); for (uint32_t i = VA_Get_Size(purgables); i--; ) { CharBuf *entry = (CharBuf*)VA_fetch(purgables, i); if (Hash_Fetch(self->disallowed, (Obj*)entry)) { continue; } if (!Folder_Delete(folder, entry)) { if (Folder_Exists(folder, entry)) { Hash_Store(failures, (Obj*)entry, INCREF(&EMPTY)); } } } for (uint32_t i = 0, max = VA_Get_Size(snapshots); i < max; i++) { Snapshot *snapshot = (Snapshot*)VA_Fetch(snapshots, i); bool_t snapshot_has_failures = false; if (Hash_Get_Size(failures)) { // Only delete snapshot files if all of their entries were // successfully deleted. VArray *entries = Snapshot_List(snapshot); for (uint32_t j = VA_Get_Size(entries); j--; ) { CharBuf *entry = (CharBuf*)VA_Fetch(entries, j); if (Hash_Fetch(failures, (Obj*)entry)) { snapshot_has_failures = true; break; } } DECREF(entries); } if (!snapshot_has_failures) { CharBuf *snapfile = Snapshot_Get_Path(snapshot); Folder_Delete(folder, snapfile); } } DECREF(failures); DECREF(purgables); DECREF(snapshots); Lock_Release(deletion_lock); } else { WARN("Can't obtain deletion lock, skipping deletion of " "obsolete files"); } DECREF(deletion_lock); }
int main(int argc, char **argv) { extern int game_is_being_shut_down; char *p; int i = 0; struct svalue *ret; extern struct svalue catch_value; extern void init_cfuns(void); struct gdexception exception_frame; (void)setlinebuf(stdout); parse_args(argc, argv); const0.type = T_NUMBER; const0.u.number = 0; const1.type = T_NUMBER; const1.u.number = 1; constempty.type = T_FUNCTION; constempty.u.func = &funcempty; funcempty.funtype = FUN_EMPTY; catch_value = const0; /* * Check that the definition of EXTRACT_UCHAR() is correct. */ p = (char *)&i; *p = -10; if (EXTRACT_UCHAR(p) != 0x100 - 10) { (void)fprintf(stderr, "Bad definition of EXTRACT_UCHAR() in config.h.\n"); exit(1); } set_current_time(); #ifdef PROFILE_LPC set_profile_timebase(60.0); /* One minute */ #endif #if RESERVED_SIZE > 0 reserved_area = malloc(RESERVED_SIZE); #endif init_random(); init_tasks(); query_load_av(); init_num_args(); init_machine(); init_cfuns(); init_hash(); /* * Set up the signal handling. */ init_signals(); if (chdir(mudlib_path) == -1) { (void)fprintf(stderr, "Bad mudlib directory: %s\n", MUD_LIB); exit(1); } if (setjmp(exception_frame.e_context)) { clear_state(); add_message("Anomaly in the fabric of world space.\n"); } else { exception_frame.e_exception = NULL; exception_frame.e_catch = 0; exception = &exception_frame; auto_ob = 0; master_ob = 0; if ((auto_ob = load_object("secure/auto", 1, 0, 0)) != NULL) { add_ref(auto_ob, "main"); auto_ob->prog->flags |= PRAGMA_RESIDENT; } get_simul_efun(); master_ob = load_object("secure/master", 1, 0, 0); if (master_ob) { /* * Make sure master_ob is never made a dangling pointer. * Look at apply_master_ob() for more details. */ add_ref(master_ob, "main"); master_ob->prog->flags |= PRAGMA_RESIDENT; resolve_master_fkntab(); create_object(master_ob); load_parse_information(); clear_state(); } } exception = NULL; if (auto_ob == 0) { (void)fprintf(stderr, "The file secure/auto must be loadable.\n"); exit(1); } if (master_ob == 0) { (void)fprintf(stderr, "The file secure/master must be loadable.\n"); exit(1); } set_inc_list(apply_master_ob(M_DEFINE_INCLUDE_DIRS, 0)); { struct svalue* ret1; ret1 = apply_master_ob(M_PREDEF_DEFINES, 0); if (ret1 && ret1->type == T_POINTER) { int ii; for (ii = 0; ii < ret1->u.vec->size; ii++) if (ret1->u.vec->item[ii].type == T_STRING) { add_pre_define(ret1->u.vec->item[ii].u.string); } } } if (flag != NULL) { printf("Applying driver flag: %s\n", flag); push_string(flag, STRING_MSTRING); (void)apply_master_ob(M_FLAG, 1); if (game_is_being_shut_down) { (void)fprintf(stderr, "Shutdown by master object.\n"); exit(0); } } /* * See to it that the mud name is always defined in compiled files */ ret = apply_master_ob(M_GET_MUD_NAME, 0); if (ret && ret->type == T_STRING) { struct lpc_predef_s *tmp; tmp = (struct lpc_predef_s *) xalloc(sizeof(struct lpc_predef_s)); if (!tmp) fatal("xalloc failed\n"); tmp->flag = string_copy(ret->u.string); tmp->next = lpc_predefs; lpc_predefs = tmp; } ret = apply_master_ob(M_GET_VBFC_OBJECT, 0); if (ret && ret->type == T_OBJECT) { vbfc_object = ret->u.ob; INCREF(vbfc_object->ref); } else vbfc_object = 0; if (game_is_being_shut_down) exit(1); init_call_out(); preload_objects(e_flag); (void)apply_master_ob(M_FINAL_BOOT, 0); mainloop(); return 0; }
void Snapshot_add_entry(Snapshot *self, const CharBuf *entry) { Hash_Store(self->entries, (Obj*)entry, INCREF(&EMPTY)); }
/* * The start_boot() in master.c is supposed to return an array of files to load. * The array returned by apply() will be freed at next call of apply(), * which means that the ref count has to be incremented to protect against * deallocation. * * The master object is asked to do the actual loading. */ void preload_objects(int eflag) { struct gdexception exception_frame; struct vector *prefiles; struct svalue *ret = NULL; volatile int ix; set_current_time(); if (setjmp(exception_frame.e_context)) { clear_state(); (void)add_message("Error in start_boot() in master_ob.\n"); exception = NULL; return; } else { exception_frame.e_exception = NULL; exception_frame.e_catch = 0; exception = &exception_frame; push_number(eflag); ret = apply_master_ob(M_START_BOOT, 1); } if ((ret == 0) || (ret->type != T_POINTER)) return; else prefiles = ret->u.vec; if ((prefiles == 0) || (prefiles->size < 1)) return; INCREF(prefiles->ref); /* Otherwise it will be freed next sapply */ ix = -1; if (setjmp(exception_frame.e_context)) { clear_state(); (void)add_message("Anomaly in the fabric of world space.\n"); } while (++ix < prefiles->size) { set_current_time(); if (s_flag) reset_mudstatus(); eval_cost = 0; push_svalue(&(prefiles->item[ix])); (void)apply_master_ob(M_PRELOAD_BOOT, 1); if (s_flag) print_mudstatus(prefiles->item[ix].u.string, eval_cost, get_millitime(), get_processtime()); tmpclean(); } free_vector(prefiles); exception = NULL; set_current_time(); }
Indexer* Indexer_init(Indexer *self, Schema *schema, Obj *index, IndexManager *manager, int32_t flags) { bool_t create = (flags & Indexer_CREATE) ? true : false; bool_t truncate = (flags & Indexer_TRUNCATE) ? true : false; Folder *folder = S_init_folder(index, create); Lock *write_lock; CharBuf *latest_snapfile; Snapshot *latest_snapshot = Snapshot_new(); // Init. self->stock_doc = Doc_new(NULL, 0); self->truncate = false; self->optimize = false; self->prepared = false; self->needs_commit = false; self->snapfile = NULL; self->merge_lock = NULL; // Assign. self->folder = folder; self->manager = manager ? (IndexManager*)INCREF(manager) : IxManager_new(NULL, NULL); IxManager_Set_Folder(self->manager, folder); // Get a write lock for this folder. write_lock = IxManager_Make_Write_Lock(self->manager); Lock_Clear_Stale(write_lock); if (Lock_Obtain(write_lock)) { // Only assign if successful, otherwise DESTROY unlocks -- bad! self->write_lock = write_lock; } else { DECREF(write_lock); DECREF(self); RETHROW(INCREF(Err_get_error())); } // Find the latest snapshot or create a new one. latest_snapfile = IxFileNames_latest_snapshot(folder); if (latest_snapfile) { Snapshot_Read_File(latest_snapshot, folder, latest_snapfile); } // Look for an existing Schema if one wasn't supplied. if (schema) { self->schema = (Schema*)INCREF(schema); } else { if (!latest_snapfile) { THROW(ERR, "No Schema supplied, and can't find one in the index"); } else { CharBuf *schema_file = S_find_schema_file(latest_snapshot); Hash *dump = (Hash*)Json_slurp_json(folder, schema_file); if (dump) { // read file successfully self->schema = (Schema*)CERTIFY( VTable_Load_Obj(SCHEMA, (Obj*)dump), SCHEMA); schema = self->schema; DECREF(dump); schema_file = NULL; } else { THROW(ERR, "Failed to parse %o", schema_file); } } } // If we're clobbering, start with an empty Snapshot and an empty // PolyReader. Otherwise, start with the most recent Snapshot and an // up-to-date PolyReader. if (truncate) { self->snapshot = Snapshot_new(); self->polyreader = PolyReader_new(schema, folder, NULL, NULL, NULL); self->truncate = true; } else { // TODO: clone most recent snapshot rather than read it twice. self->snapshot = (Snapshot*)INCREF(latest_snapshot); self->polyreader = latest_snapfile ? PolyReader_open((Obj*)folder, NULL, NULL) : PolyReader_new(schema, folder, NULL, NULL, NULL); if (latest_snapfile) { // Make sure than any existing fields which may have been // dynamically added during past indexing sessions get added. Schema *old_schema = PolyReader_Get_Schema(self->polyreader); Schema_Eat(schema, old_schema); } } // Zap detritus from previous sessions. { // Note: we have to feed FilePurger with the most recent snapshot file // now, but with the Indexer's snapshot later. FilePurger *file_purger = FilePurger_new(folder, latest_snapshot, self->manager); FilePurger_Purge(file_purger); DECREF(file_purger); } // Create a new segment. { int64_t new_seg_num = IxManager_Highest_Seg_Num(self->manager, latest_snapshot) + 1; Lock *merge_lock = IxManager_Make_Merge_Lock(self->manager); uint32_t i, max; if (Lock_Is_Locked(merge_lock)) { // If there's a background merge process going on, stay out of its // way. Hash *merge_data = IxManager_Read_Merge_Data(self->manager); Obj *cutoff_obj = merge_data ? Hash_Fetch_Str(merge_data, "cutoff", 6) : NULL; if (!cutoff_obj) { DECREF(merge_lock); DECREF(merge_data); THROW(ERR, "Background merge detected, but can't read merge data"); } else { int64_t cutoff = Obj_To_I64(cutoff_obj); if (cutoff >= new_seg_num) { new_seg_num = cutoff + 1; } } DECREF(merge_data); } self->segment = Seg_new(new_seg_num); // Add all known fields to Segment. { VArray *fields = Schema_All_Fields(schema); for (i = 0, max = VA_Get_Size(fields); i < max; i++) { Seg_Add_Field(self->segment, (CharBuf*)VA_Fetch(fields, i)); } DECREF(fields); } DECREF(merge_lock); } // Create new SegWriter and FilePurger. self->file_purger = FilePurger_new(folder, self->snapshot, self->manager); self->seg_writer = SegWriter_new(self->schema, self->snapshot, self->segment, self->polyreader); SegWriter_Prep_Seg_Dir(self->seg_writer); // Grab a local ref to the DeletionsWriter. self->del_writer = (DeletionsWriter*)INCREF( SegWriter_Get_Del_Writer(self->seg_writer)); DECREF(latest_snapfile); DECREF(latest_snapshot); return self; }
static bool_t S_maybe_merge(Indexer *self, VArray *seg_readers) { bool_t merge_happened = false; uint32_t num_seg_readers = VA_Get_Size(seg_readers); Lock *merge_lock = IxManager_Make_Merge_Lock(self->manager); bool_t got_merge_lock = Lock_Obtain(merge_lock); int64_t cutoff; VArray *to_merge; uint32_t i, max; if (got_merge_lock) { self->merge_lock = merge_lock; cutoff = 0; } else { // If something else holds the merge lock, don't interfere. Hash *merge_data = IxManager_Read_Merge_Data(self->manager); if (merge_data) { Obj *cutoff_obj = Hash_Fetch_Str(merge_data, "cutoff", 6); if (cutoff_obj) { cutoff = Obj_To_I64(cutoff_obj); } else { cutoff = I64_MAX; } DECREF(merge_data); } else { cutoff = I64_MAX; } DECREF(merge_lock); } // Get a list of segments to recycle. Validate and confirm that there are // no dupes in the list. to_merge = IxManager_Recycle(self->manager, self->polyreader, self->del_writer, cutoff, self->optimize); { Hash *seen = Hash_new(VA_Get_Size(to_merge)); for (i = 0, max = VA_Get_Size(to_merge); i < max; i++) { SegReader *seg_reader = (SegReader*)CERTIFY( VA_Fetch(to_merge, i), SEGREADER); CharBuf *seg_name = SegReader_Get_Seg_Name(seg_reader); if (Hash_Fetch(seen, (Obj*)seg_name)) { DECREF(seen); DECREF(to_merge); THROW(ERR, "Recycle() tried to merge segment '%o' twice", seg_name); } Hash_Store(seen, (Obj*)seg_name, INCREF(&EMPTY)); } DECREF(seen); } // Consolidate segments if either sparse or optimizing forced. for (i = 0, max = VA_Get_Size(to_merge); i < max; i++) { SegReader *seg_reader = (SegReader*)VA_Fetch(to_merge, i); int64_t seg_num = SegReader_Get_Seg_Num(seg_reader); Matcher *deletions = DelWriter_Seg_Deletions(self->del_writer, seg_reader); I32Array *doc_map = DelWriter_Generate_Doc_Map(self->del_writer, deletions, SegReader_Doc_Max(seg_reader), (int32_t)Seg_Get_Count(self->segment) ); if (seg_num <= cutoff) { THROW(ERR, "Segment %o violates cutoff (%i64 <= %i64)", SegReader_Get_Seg_Name(seg_reader), seg_num, cutoff); } SegWriter_Merge_Segment(self->seg_writer, seg_reader, doc_map); merge_happened = true; DECREF(deletions); DECREF(doc_map); } // Write out new deletions. if (DelWriter_Updated(self->del_writer)) { // Only write out if they haven't all been applied. if (VA_Get_Size(to_merge) != num_seg_readers) { DelWriter_Finish(self->del_writer); } } DECREF(to_merge); return merge_happened; }
static NODE * putaddr(bigptr q, int indir) { int type, type2, funct; NODE *p, *p1, *p2; ftnint offset; bigptr offp; p = p1 = p2 = NULL; /* XXX */ type = q->vtype; type2 = types2[type]; funct = (q->vclass==CLPROC ? FTN<<TSHIFT : 0); offp = (q->b_addr.memoffset ? cpexpr(q->b_addr.memoffset) : NULL); offset = simoffset(&offp); if(offp) offp = mkconv(TYINT, offp); switch(q->vstg) { case STGAUTO: if(indir && !offp) { p = oregtree(offset, AUTOREG, type2); break; } if(!indir && !offp && !offset) { p = mklnode(REG, 0, AUTOREG, INCREF(type2)); break; } p = mklnode(REG, 0, AUTOREG, INCREF(type2)); if(offp) { p1 = putx(offp); if(offset) p2 = mklnode(ICON, offset, 0, INT); } else p1 = mklnode(ICON, offset, 0, INT); if (offp && offset) p1 = mkbinode(PLUS, p1, p2, INCREF(type2)); p = mkbinode(PLUS, p, p1, INCREF(type2)); if (indir) p = mkunode(UMUL, p, 0, type2); break; case STGARG: p = oregtree(ARGOFFSET + (ftnint)(q->b_addr.memno), ARGREG, INCREF(type2)|funct); if (offp) p1 = putx(offp); if (offset) p2 = mklnode(ICON, offset, 0, INT); if (offp && offset) p1 = mkbinode(PLUS, p1, p2, INCREF(type2)); else if (offset) p1 = p2; if (offp || offset) p = mkbinode(PLUS, p, p1, INCREF(type2)); if (indir) p = mkunode(UMUL, p, 0, type2); break; case STGLENG: if(indir) { p = oregtree(ARGOFFSET + (ftnint)(q->b_addr.memno), ARGREG, INCREF(type2)|funct); } else { fatal1("faddrnode: STGLENG: fixme!"); #if 0 p2op(P2PLUS, types2[TYLENG] | P2PTR ); p2reg(ARGREG, types2[TYLENG] | P2PTR ); p2icon( ARGOFFSET + (ftnint) (FUDGEOFFSET*p->b_addr.memno), P2INT); #endif } break; case STGBSS: case STGINIT: case STGEXT: case STGCOMMON: case STGEQUIV: case STGCONST: if(offp) { p1 = putx(offp); p2 = putmem(q, ICON, offset); p = mkbinode(PLUS, p1, p2, INCREF(type2)); if(indir) p = mkunode(UMUL, p, 0, type2); } else p = putmem(q, (indir ? NAME : ICON), offset); break; case STGREG: if(indir) p = mklnode(REG, 0, q->b_addr.memno, type2); else fatal("attempt to take address of a register"); break; default: fatal1("putaddr: invalid vstg %d", q->vstg); } frexpr(q); return p; }
CompoundFileReader* CFReader_do_open(CompoundFileReader *self, Folder *folder) { CompoundFileReaderIVARS *const ivars = CFReader_IVARS(self); String *cfmeta_file = (String*)SSTR_WRAP_UTF8("cfmeta.json", 11); Hash *metadata = (Hash*)Json_slurp_json((Folder*)folder, cfmeta_file); Err *error = NULL; Folder_init((Folder*)self, Folder_Get_Path(folder)); // Parse metadata file. if (!metadata || !Hash_Is_A(metadata, HASH)) { error = Err_new(Str_newf("Can't read '%o' in '%o'", cfmeta_file, Folder_Get_Path(folder))); } else { Obj *format = Hash_Fetch_Utf8(metadata, "format", 6); ivars->format = format ? (int32_t)Obj_To_I64(format) : 0; ivars->records = (Hash*)INCREF(Hash_Fetch_Utf8(metadata, "files", 5)); if (ivars->format < 1) { error = Err_new(Str_newf("Corrupt %o file: Missing or invalid 'format'", cfmeta_file)); } else if (ivars->format > CFWriter_current_file_format) { error = Err_new(Str_newf("Unsupported compound file format: %i32 " "(current = %i32", ivars->format, CFWriter_current_file_format)); } else if (!ivars->records) { error = Err_new(Str_newf("Corrupt %o file: missing 'files' key", cfmeta_file)); } } DECREF(metadata); if (error) { Err_set_error(error); DECREF(self); return NULL; } // Open an instream which we'll clone over and over. String *cf_file = (String*)SSTR_WRAP_UTF8("cf.dat", 6); ivars->instream = Folder_Open_In(folder, cf_file); if (!ivars->instream) { ERR_ADD_FRAME(Err_get_error()); DECREF(self); return NULL; } // Assign. ivars->real_folder = (Folder*)INCREF(folder); // Strip directory name from filepaths for old format. if (ivars->format == 1) { Vector *files = Hash_Keys(ivars->records); String *folder_name = IxFileNames_local_part(Folder_Get_Path(folder)); size_t folder_name_len = Str_Length(folder_name); for (uint32_t i = 0, max = Vec_Get_Size(files); i < max; i++) { String *orig = (String*)Vec_Fetch(files, i); if (Str_Starts_With(orig, folder_name)) { Obj *record = Hash_Delete(ivars->records, orig); size_t offset = folder_name_len + sizeof(CHY_DIR_SEP) - 1; size_t len = Str_Length(orig) - offset; String *filename = Str_SubString(orig, offset, len); Hash_Store(ivars->records, filename, (Obj*)record); DECREF(filename); } } DECREF(folder_name); DECREF(files); } return self; }
String* Bool_To_String_IMP(Boolean *self) { return (String*)INCREF(self->string); }
String* DH_Get_Entry_IMP(DirHandle *self) { String *entry = DH_IVARS(self)->entry; return (String*)INCREF(entry); }
NODE * amd64_builtin_va_arg(NODE *f, NODE *a, TWORD t) { NODE *ap, *r, *dp; ap = a->n_left; dp = a->n_right; if (dp->n_type <= ULONGLONG || ISPTR(dp->n_type) || dp->n_type == FLOAT || dp->n_type == DOUBLE) { /* type might be in general register */ if (dp->n_type == FLOAT || dp->n_type == DOUBLE) { f->n_sp = lookup(fpnext, SNORMAL); varneeds |= NEED_FPNEXT; } else { f->n_sp = lookup(gpnext, SNORMAL); varneeds |= NEED_GPNEXT; } f->n_type = f->n_sp->stype = INCREF(dp->n_type) + (FTN-PTR); f->n_ap = dp->n_ap; f->n_df = dp->n_df; f = clocal(f); r = buildtree(CALL, f, ccopy(ap)); } else if (ISSOU(dp->n_type) || dp->n_type == LDOUBLE) { /* put a reference directly to the stack */ int sz = tsize(dp->n_type, dp->n_df, dp->n_ap); int al = talign(dp->n_type, dp->n_ap); if (al < ALLONG) al = ALLONG; if (sz <= SZLONG*2 && al == ALLONG) { if (sz <= SZLONG) { f->n_sp = lookup(_1regref, SNORMAL); varneeds |= NEED_1REGREF; } else { f->n_sp = lookup(_2regref, SNORMAL); varneeds |= NEED_2REGREF; } f->n_type = f->n_sp->stype; f = clocal(f); r = buildtree(CALL, f, ccopy(ap)); r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap); r = buildtree(UMUL, r, NIL); } else { f->n_sp = lookup(memref, SNORMAL); varneeds |= NEED_MEMREF; f->n_type = f->n_sp->stype; f = clocal(f); SETOFF(sz, al); r = buildtree(CALL, f, buildtree(CM, ccopy(ap), bcon(sz/SZCHAR))); r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap); r = buildtree(UMUL, r, NIL); } } else { uerror("amd64_builtin_va_arg not supported type"); goto bad; } tfree(a); return r; bad: uerror("bad argument to __builtin_va_arg"); return bcon(0); }
void MatchDoc_set_values(MatchDoc *self, VArray *values) { DECREF(self->values); self->values = values ? (VArray*)INCREF(values) : NULL; }
HitQueue* HitQ_init(HitQueue *self, Schema *schema, SortSpec *sort_spec, uint32_t wanted) { HitQueueIVARS *const ivars = HitQ_IVARS(self); if (sort_spec) { VArray *rules = SortSpec_Get_Rules(sort_spec); uint32_t num_rules = VA_Get_Size(rules); uint32_t action_num = 0; if (!schema) { THROW(ERR, "Can't supply sort_spec without schema"); } ivars->need_values = false; ivars->num_actions = num_rules; ivars->actions = (uint8_t*)MALLOCATE(num_rules * sizeof(uint8_t)); ivars->field_types = (FieldType**)CALLOCATE(num_rules, sizeof(FieldType*)); for (uint32_t i = 0; i < num_rules; i++) { SortRule *rule = (SortRule*)VA_Fetch(rules, i); int32_t rule_type = SortRule_Get_Type(rule); bool reverse = SortRule_Get_Reverse(rule); if (rule_type == SortRule_SCORE) { ivars->actions[action_num++] = reverse ? COMPARE_BY_SCORE_REV : COMPARE_BY_SCORE; } else if (rule_type == SortRule_DOC_ID) { ivars->actions[action_num++] = reverse ? COMPARE_BY_DOC_ID_REV : COMPARE_BY_DOC_ID; } else if (rule_type == SortRule_FIELD) { String *field = SortRule_Get_Field(rule); FieldType *type = Schema_Fetch_Type(schema, field); if (type) { ivars->field_types[action_num] = (FieldType*)INCREF(type); ivars->actions[action_num++] = reverse ? COMPARE_BY_VALUE_REV : COMPARE_BY_VALUE; ivars->need_values = true; } else { // Skip over fields we don't know how to sort on. continue; } } else { THROW(ERR, "Unknown SortRule type: %i32", rule_type); } } } else { ivars->num_actions = 2; ivars->actions = (uint8_t*)MALLOCATE(ivars->num_actions * sizeof(uint8_t)); ivars->actions[0] = COMPARE_BY_SCORE; ivars->actions[1] = COMPARE_BY_DOC_ID; } return (HitQueue*)PriQ_init((PriorityQueue*)self, wanted); }
void Snapshot_add_entry(Snapshot *self, const CharBuf *filename) { Hash_Store(self->entries, filename, INCREF(&EMPTY)); }
PolyReader* PolyReader_do_open(PolyReader *self, Obj *index, Snapshot *snapshot, IndexManager *manager) { PolyReaderIVARS *const ivars = PolyReader_IVARS(self); Folder *folder = S_derive_folder(index); uint64_t last_gen = 0; PolyReader_init(self, NULL, folder, snapshot, manager, NULL); DECREF(folder); if (manager) { if (!S_obtain_deletion_lock(self)) { DECREF(self); THROW(LOCKERR, "Couldn't get deletion lock"); } } while (1) { CharBuf *target_snap_file; // If a Snapshot was supplied, use its file. if (snapshot) { target_snap_file = Snapshot_Get_Path(snapshot); if (!target_snap_file) { THROW(ERR, "Supplied snapshot objects must not be empty"); } else { CB_Inc_RefCount(target_snap_file); } } else { // Otherwise, pick the most recent snap file. target_snap_file = IxFileNames_latest_snapshot(folder); // No snap file? Looks like the index is empty. We can stop now // and return NULL. if (!target_snap_file) { break; } } // Derive "generation" of this snapshot file from its name. uint64_t gen = IxFileNames_extract_gen(target_snap_file); // Get a read lock on the most recent snapshot file if indicated. if (manager) { if (!S_obtain_read_lock(self, target_snap_file)) { DECREF(self); THROW(LOCKERR, "Couldn't get read lock for %o", target_snap_file); } } // Testing only. if (PolyReader_race_condition_debug1) { ZombieCharBuf *temp = ZCB_WRAP_STR("temp", 4); if (Folder_Exists(folder, (CharBuf*)temp)) { bool success = Folder_Rename(folder, (CharBuf*)temp, PolyReader_race_condition_debug1); if (!success) { RETHROW(INCREF(Err_get_error())); } } PolyReader_debug1_num_passes++; } // If a Snapshot object was passed in, the file has already been read. // If that's not the case, we must read the file we just picked. if (!snapshot) { struct try_read_snapshot_context context; context.snapshot = ivars->snapshot; context.folder = folder; context.path = target_snap_file; Err *error = Err_trap(S_try_read_snapshot, &context); if (error) { S_release_read_lock(self); DECREF(target_snap_file); if (last_gen < gen) { // Index updated, so try again. DECREF(error); last_gen = gen; continue; } else { // Real error. if (manager) { S_release_deletion_lock(self); } RETHROW(error); } } } /* It's possible, though unlikely, for an Indexer to delete files * out from underneath us after the snapshot file is read but before * we've got SegReaders holding open all the required files. If we * failed to open something, see if we can find a newer snapshot file. * If we can, then the exception was due to the race condition. If * not, we have a real exception, so throw an error. */ struct try_open_elements_context context; context.self = self; context.seg_readers = NULL; Err *error = Err_trap(S_try_open_elements, &context); if (error) { S_release_read_lock(self); DECREF(target_snap_file); if (last_gen < gen) { // Index updated, so try again. DECREF(error); last_gen = gen; } else { // Real error. if (manager) { S_release_deletion_lock(self); } RETHROW(error); } } else { // Succeeded. S_init_sub_readers(self, (VArray*)context.seg_readers); DECREF(context.seg_readers); DECREF(target_snap_file); break; } } if (manager) { S_release_deletion_lock(self); } return self; }
MatchPosting* MatchPost_init(MatchPosting *self, Similarity *sim) { MatchPostingIVARS *const ivars = MatchPost_IVARS(self); ivars->sim = (Similarity*)INCREF(sim); return (MatchPosting*)Post_init((Posting*)self); }
int main(int argc, char **argv) { extern int game_is_being_shut_down; int i, new_mudlib = 0; char *p; struct svalue *ret; extern struct svalue catch_value; extern void init_cfuns(void); struct gdexception exception_frame; (void)setlinebuf(stdout); const0.type = T_NUMBER; const0.u.number = 0; const1.type = T_NUMBER; const1.u.number = 1; constempty.type = T_FUNCTION; constempty.u.func = &funcempty; funcempty.funtype = FUN_EMPTY; catch_value = const0; /* * Check that the definition of EXTRACT_UCHAR() is correct. */ p = (char *)&i; *p = -10; if (EXTRACT_UCHAR(p) != 0x100 - 10) { (void)fprintf(stderr, "Bad definition of EXTRACT_UCHAR() in config.h.\n"); exit(1); } set_current_time(); #ifdef PROFILE_LPC set_profile_timebase(60.0); /* One minute */ #endif #ifdef DRAND48 srand48((long)current_time); #else #ifdef RANDOM srandom(current_time); #else #error No random generator specified!\n #endif /* RANDOM */ #endif /* DRAND48 */ #if RESERVED_SIZE > 0 reserved_area = malloc(RESERVED_SIZE); #endif init_tasks(); query_load_av(); init_num_args(); init_machine(); init_cfuns(); /* * Set up the signal handling. */ init_signals(); /* * The flags are parsed twice ! * The first time, we only search for the -m flag, which specifies * another mudlib, and the D-flags, so that they will be available * when compiling master.c. */ for (i = 1; i < argc; i++) { if (atoi(argv[i])) port_number = atoi(argv[i]); else if (argv[i][0] != '-') continue; switch(argv[i][1]) { case 'D': if (argv[i][2]) { /* Amylaar : allow flags to be passed down to the LPC preprocessor */ struct lpc_predef_s *tmp; tmp = (struct lpc_predef_s *) xalloc(sizeof(struct lpc_predef_s)); if (!tmp) fatal("xalloc failed\n"); tmp->flag = string_copy(argv[i]+2); tmp->next = lpc_predefs; lpc_predefs = tmp; continue; } (void)fprintf(stderr, "Illegal flag syntax: %s\n", argv[i]); exit(1); /* NOTREACHED */ case 'N': no_ip_demon++; continue; case 'm': if (chdir(argv[i]+2) == -1) { (void)fprintf(stderr, "Bad mudlib directory: %s\n", argv[i]+2); exit(1); } new_mudlib = 1; break; } } if (!new_mudlib && chdir(MUD_LIB) == -1) { (void)fprintf(stderr, "Bad mudlib directory: %s\n", MUD_LIB); exit(1); } if (setjmp(exception_frame.e_context)) { clear_state(); add_message("Anomaly in the fabric of world space.\n"); } else { exception_frame.e_exception = NULL; exception_frame.e_catch = 0; exception = &exception_frame; auto_ob = 0; master_ob = 0; if ((auto_ob = load_object("secure/auto", 1, 0, 0)) != NULL) { add_ref(auto_ob, "main"); auto_ob->prog->flags |= PRAGMA_RESIDENT; } get_simul_efun(); master_ob = load_object("secure/master", 1, 0, 0); if (master_ob) { /* * Make sure master_ob is never made a dangling pointer. * Look at apply_master_ob() for more details. */ add_ref(master_ob, "main"); master_ob->prog->flags |= PRAGMA_RESIDENT; resolve_master_fkntab(); create_object(master_ob); load_parse_information(); clear_state(); } } exception = NULL; if (auto_ob == 0) { (void)fprintf(stderr, "The file secure/auto must be loadable.\n"); exit(1); } if (master_ob == 0) { (void)fprintf(stderr, "The file secure/master must be loadable.\n"); exit(1); } set_inc_list(apply_master_ob(M_DEFINE_INCLUDE_DIRS, 0)); { struct svalue* ret1; ret1 = apply_master_ob(M_PREDEF_DEFINES, 0); if (ret1 && ret1->type == T_POINTER) { int ii; struct lpc_predef_s *tmp; for (ii = 0; ii < ret1->u.vec->size; ii++) if (ret1->u.vec->item[ii].type == T_STRING) { tmp = (struct lpc_predef_s *) xalloc(sizeof(struct lpc_predef_s)); tmp->flag = string_copy(ret1->u.vec->item[ii].u.string); tmp->next = lpc_predefs; lpc_predefs = tmp; } } } for (i = 1; i < argc; i++) { if (atoi(argv[i])) ; else if (argv[i][0] != '-') { (void)fprintf(stderr, "Bad argument %s\n", argv[i]); exit(1); } else { /* * Look at flags. -m has already been tested. */ switch(argv[i][1]) { case 'f': push_string(argv[i]+2, STRING_MSTRING); (void)apply_master_ob(M_FLAG, 1); if (game_is_being_shut_down) { (void)fprintf(stderr, "Shutdown by master object.\n"); exit(0); } continue; case 'e': e_flag++; continue; case 'O': warnobsoleteflag++; continue; case 'D': continue; case 'N': continue; case 'm': continue; case 'd': d_flag = atoi(argv[i] + 2); continue; case 'c': comp_flag++; continue; case 'l': unlimited++; continue; case 't': t_flag++; continue; case 'S': s_flag++; mudstatus_set(1, -1, -1); /* Statistics, default limits */ continue; case 'u': #ifdef CATCH_UDP_PORT udp_port = atoi (&argv[i][2]); #endif continue; case 'p': #ifdef SERVICE_PORT service_port = atoi (&argv[i][2]); #endif continue; case 'y': #ifdef YYDEBUG yydebug = 1; #endif continue; default: (void)fprintf(stderr, "Unknown flag: %s\n", argv[i]); exit(1); } } } /* * See to it that the mud name is always defined in compiled files */ ret = apply_master_ob(M_GET_MUD_NAME, 0); if (ret && ret->type == T_STRING) { struct lpc_predef_s *tmp; tmp = (struct lpc_predef_s *) xalloc(sizeof(struct lpc_predef_s)); if (!tmp) fatal("xalloc failed\n"); tmp->flag = string_copy(ret->u.string); tmp->next = lpc_predefs; lpc_predefs = tmp; } ret = apply_master_ob(M_GET_VBFC_OBJECT, 0); if (ret && ret->type == T_OBJECT) { vbfc_object = ret->u.ob; INCREF(vbfc_object->ref); } else vbfc_object = 0; if (game_is_being_shut_down) exit(1); if (!t_flag) init_call_out(); preload_objects(e_flag); (void)apply_master_ob(M_FINAL_BOOT, 0); mainloop(); /* backend(); */ return 0; }
SortCollector* SortColl_init(SortCollector *self, Schema *schema, SortSpec *sort_spec, uint32_t wanted) { VArray *rules = sort_spec ? (VArray*)INCREF(SortSpec_Get_Rules(sort_spec)) : S_default_sort_rules(); uint32_t num_rules = VA_Get_Size(rules); // Validate. if (sort_spec && !schema) { THROW(ERR, "Can't supply a SortSpec without a Schema."); } if (!num_rules) { THROW(ERR, "Can't supply a SortSpec with no SortRules."); } // Init. Coll_init((Collector*)self); SortCollectorIVARS *const ivars = SortColl_IVARS(self); ivars->total_hits = 0; ivars->bubble_doc = INT32_MAX; ivars->bubble_score = F32_NEGINF; ivars->seg_doc_max = 0; // Assign. ivars->wanted = wanted; // Derive. ivars->hit_q = HitQ_new(schema, sort_spec, wanted); ivars->rules = rules; // absorb refcount. ivars->num_rules = num_rules; ivars->sort_caches = (SortCache**)CALLOCATE(num_rules, sizeof(SortCache*)); ivars->ord_arrays = (void**)CALLOCATE(num_rules, sizeof(void*)); ivars->actions = (uint8_t*)CALLOCATE(num_rules, sizeof(uint8_t)); // Build up an array of "actions" which we will execute during each call // to Collect(). Determine whether we need to track scores and field // values. ivars->need_score = false; ivars->need_values = false; for (uint32_t i = 0; i < num_rules; i++) { SortRule *rule = (SortRule*)VA_Fetch(rules, i); int32_t rule_type = SortRule_Get_Type(rule); ivars->actions[i] = S_derive_action(rule, NULL); if (rule_type == SortRule_SCORE) { ivars->need_score = true; } else if (rule_type == SortRule_FIELD) { CharBuf *field = SortRule_Get_Field(rule); FieldType *type = Schema_Fetch_Type(schema, field); if (!type || !FType_Sortable(type)) { THROW(ERR, "'%o' isn't a sortable field", field); } ivars->need_values = true; } } // Perform an optimization. So long as we always collect docs in // ascending order, Collect() will favor lower doc numbers -- so we may // not need to execute a final COMPARE_BY_DOC_ID action. ivars->num_actions = num_rules; if (ivars->actions[num_rules - 1] == COMPARE_BY_DOC_ID) { ivars->num_actions--; } // Override our derived actions with an action which will be excecuted // autmatically until the queue fills up. ivars->auto_actions = (uint8_t*)MALLOCATE(1); ivars->auto_actions[0] = wanted ? AUTO_ACCEPT : AUTO_REJECT; ivars->derived_actions = ivars->actions; ivars->actions = ivars->auto_actions; // Prepare a MatchDoc-in-waiting. VArray *values = ivars->need_values ? VA_new(num_rules) : NULL; float score = ivars->need_score ? F32_NEGINF : F32_NAN; ivars->bumped = MatchDoc_new(INT32_MAX, score, values); DECREF(values); return self; }
IndexManager* IxManager_init(IndexManager *self, Folder *folder) { self->folder = (Folder*)INCREF(folder); return self; }
/* clocal() is called to do local transformations on * an expression tree preparitory to its being * written out in intermediate code. * * the major essential job is rewriting the * automatic variables and arguments in terms of * REG and OREG nodes * conversion ops which are not necessary are also clobbered here * in addition, any special features (such as rewriting * exclusive or) are easily handled here as well */ NODE * clocal(NODE *p) { register struct symtab *q; register NODE *r, *l; register int o; TWORD t; #ifdef PCC_DEBUG if (xdebug) { printf("clocal: %p\n", p); fwalk(p, eprint, 0); } #endif switch( o = p->n_op ){ case NAME: if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: case AUTO: /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; case USTATIC: case STATIC: if (kflag == 0) break; if (blevel > 0 && !statinit) p = picstatic(p); break; case EXTERN: case EXTDEF: if (kflag == 0) break; if (blevel > 0 && !statinit) p = picext(p); break; } break; case ADDROF: if (kflag == 0 || blevel == 0 || statinit) break; /* char arrays may end up here */ l = p->n_left; if (l->n_op != NAME || (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE)) break; l = p; p = picstatic(p->n_left); nfree(l); if (p->n_op != UMUL) cerror("ADDROF error"); l = p; p = p->n_left; nfree(l); break; case STASG: /* convert struct assignment to call memcpy */ l = p->n_left; if (l->n_op == NAME && ISFTN(l->n_sp->stype)) break; /* struct return, do nothing */ /* first construct arg list */ p->n_left = buildtree(ADDROF, p->n_left, 0); r = bcon(tsize(STRTY, p->n_df, p->n_ap)/SZCHAR); p->n_left = buildtree(CM, p->n_left, p->n_right); p->n_right = r; p->n_op = CM; p->n_type = INT; r = block(NAME, NIL, NIL, INT, 0, 0); r->n_sp = lookup(addname("memcpy"), SNORMAL); if (r->n_sp->sclass == SNULL) { r->n_sp->sclass = EXTERN; r->n_sp->stype = INCREF(VOID+PTR)+(FTN-PTR); } r->n_type = r->n_sp->stype; p = buildtree(CALL, r, p); break; case SCONV: l = p->n_left; if (l->n_op == ICON && ISPTR(l->n_type)) { /* Do immediate cast here */ /* Should be common code */ q = l->n_sp; l->n_sp = NULL; l->n_type = UNSIGNED; if (concast(l, p->n_type) == 0) cerror("clocal"); p = nfree(p); p->n_sp = q; } break; case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); t = p->n_type; if (ISITY(t)) t = t - (FIMAG-FLOAT); p->n_left->n_rval = RETREG(t); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal end: %p\n", p); fwalk(p, eprint, 0); } #endif return(p); }
void SegWriter_Set_Del_Writer_IMP(SegWriter *self, DeletionsWriter *del_writer) { SegWriterIVARS *const ivars = SegWriter_IVARS(self); DECREF(ivars->del_writer); ivars->del_writer = (DeletionsWriter*)INCREF(del_writer); }
/* * Do the "hard work" in assigning correct destination for arguments. * Also convert arguments < INT to inte (default argument promotions). * XXX - should be dome elsewhere. */ static NODE * argput(NODE *p) { NODE *q; TWORD ty; int typ, r, ssz; if (p->n_op == CM) { p->n_left = argput(p->n_left); p->n_right = argput(p->n_right); return p; } /* first arg may be struct return pointer */ /* XXX - check if varargs; setup al */ switch (typ = argtyp(p->n_type, p->n_df, p->n_ap)) { case INTEGER: case SSE: if (typ == SSE) r = XMM0 + nsse++; else r = argregsi[ngpr++]; if (p->n_type < INT || p->n_type == BOOL) p = cast(p, INT, 0); p = movtoreg(p, r); break; case X87: r = nrsp; nrsp += SZLDOUBLE; p = movtomem(p, r, STKREG); break; case SSEMEM: r = nrsp; nrsp += SZDOUBLE; p = movtomem(p, r, STKREG); break; case INTMEM: r = nrsp; nrsp += SZLONG; p = movtomem(p, r, STKREG); break; case STRCPX: case STRREG: /* Struct in registers */ /* Cast to long pointer and move to the registers */ /* XXX can overrun struct size */ /* XXX check carefully for SSE members */ ssz = tsize(p->n_type, p->n_df, p->n_ap); if (typ == STRCPX) { ty = DOUBLE; r = XMM0 + nsse++; } else { ty = LONG; r = argregsi[ngpr++]; } if (ssz <= SZLONG) { q = cast(p->n_left, INCREF(ty), 0); nfree(p); q = buildtree(UMUL, q, NIL); p = movtoreg(q, r); } else if (ssz <= SZLONG*2) { NODE *ql, *qr; if (!ISPTR(p->n_left->n_type)) cerror("no struct arg pointer"); p = nfree(p); p = makety(p, PTR|ty, 0, 0, 0); qr = ccopy(ql = tempnode(0, PTR|ty, 0, 0)); p = buildtree(ASSIGN, ql, p); ql = movtoreg(buildtree(UMUL, ccopy(qr), NIL), r); p = buildtree(COMOP, p, ql); ql = buildtree(UMUL, buildtree(PLUS, qr, bcon(1)), NIL); r = (typ == STRCPX ? XMM0 + nsse++ : argregsi[ngpr++]); ql = movtoreg(ql, r); p = buildtree(CM, p, ql); } else cerror("STRREG"); break; case STRMEM: { struct symtab s; NODE *l, *t; q = buildtree(UMUL, p->n_left, NIL); s.stype = p->n_type; s.squal = 0; s.sdf = p->n_df; s.sap = p->n_ap; s.soffset = nrsp; s.sclass = AUTO; nrsp += tsize(p->n_type, p->n_df, p->n_ap); l = block(REG, NIL, NIL, PTR+STRTY, 0, 0); l->n_lval = 0; regno(l) = STKREG; t = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap); t->n_sp = &s; t = stref(block(STREF, l, t, 0, 0, 0)); t = (buildtree(ASSIGN, t, q)); nfree(p); p = t->n_left; nfree(t); break; } default: cerror("argument %d", typ); } return p; }