static PageInfo* alloc_page_from_arena(Arena *arena, size_t cell_size) { void *page_data = (void*)ALIGN(arena->pos, PAGE_SIZE); if (arena->free_pages) { PageInfo* info = arena->free_pages; EJS_LIST_DETACH(info, arena->free_pages); info->cell_size = cell_size; info->num_cells = CELLS_OF_SIZE(cell_size); info->num_free_cells = info->num_cells; info->bump_ptr = info->page_start; memset (info->page_bitmap, CELL_FREE, info->num_cells * sizeof(BitmapCell)); SPEW(3, _ejs_log ("alloc_page_from_arena from free pages for cell size %zd = %p\n", info->cell_size, info)); return info; } else if (page_data < arena->end) { PageInfo* info = alloc_page_info_from_arena (arena, page_data, cell_size); int page_idx = arena->num_pages++; arena->pos = page_data + PAGE_SIZE; arena->pages[page_idx] = page_data; arena->page_infos[page_idx] = info; SPEW(3, _ejs_log ("alloc_page_from_arena from bump pointer for cell size %zd = %p\n", info->cell_size, info)); return info; } else { return NULL; } }
ejsval _ejs_invoke_closure (ejsval closure, ejsval _this, uint32_t argc, ejsval* args) { if (!EJSVAL_IS_FUNCTION(closure)) { #if DEBUG_LAST_LOOKUP extern jschar* last_lookup; if (last_lookup) { char *last_utf8 = ucs2_to_utf8(last_lookup); _ejs_log ("last property lookup was for: %s\n", last_utf8); free (last_utf8); } #endif _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "object not a function"); } #if 0 if (!EJSVAL_IS_NULL_OR_UNDEFINED(_this) && EJSVAL_IS_PRIMITIVE(_this)) { _this = ToObject(_this); } #endif EJSFunction *fun = (EJSFunction*)EJSVAL_TO_OBJECT(closure); return fun->func (fun->env, _this, argc, args); }
void _ejs_throw_nativeerror_utf8 (EJSNativeErrorType error_type, const char *message) { ejsval exc = _ejs_nativeerror_new_utf8 (error_type, message); _ejs_log ("throwing exception with message %s\n", message); _ejs_throw (exc); EJS_NOT_REACHED(); }
static ejsval _ejs_DataView_impl (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { if (EJSVAL_IS_UNDEFINED(_this)) { _ejs_log ("DataView called as a function\n"); EJS_NOT_IMPLEMENTED(); } if (argc == 0 || !EJSVAL_IS_ARRAYBUFFER(args[0])) { _ejs_log ("arg0 not an ArrayBuffer object\n"); EJS_NOT_IMPLEMENTED(); } EJSDataView* view = (EJSDataView*)EJSVAL_TO_OBJECT(_this); EJSArrayBuffer* buff = (EJSArrayBuffer*)EJSVAL_TO_OBJECT(args[0]); uint32_t offset; uint32_t len; switch (argc) { case 1: offset = 0; len = buff->size; break; case 2: offset = EJSVAL_TO_NUMBER(args[1]); len = buff->size - offset; break; default: offset = EJSVAL_TO_NUMBER(args[1]); len = EJSVAL_TO_NUMBER(args[2]); } view->buffer = args[0]; view->byteOffset = offset; view->byteLength = len; _ejs_object_define_value_property (_this, _ejs_atom_byteLength, DOUBLE_TO_EJSVAL_IMPL(view->byteLength), EJS_PROP_FLAGS_ENUMERABLE); _ejs_object_define_value_property (_this, _ejs_atom_byteOffset, DOUBLE_TO_EJSVAL_IMPL(view->byteOffset), EJS_PROP_FLAGS_ENUMERABLE); _ejs_object_define_value_property (_this, _ejs_atom_buffer, view->buffer, EJS_PROP_FLAGS_ENUMERABLE); return _this; }
static void* alloc_from_os(size_t size, size_t align) { #if defined(WIN32) void *ptr = _aligned_malloc(size, align); memset((void *)ptr, 0x00, size); return ptr; #else if (align == 0) { size = MAX(size, PAGE_SIZE); void* res = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, MAP_FD, 0); SPEW(2, _ejs_log ("mmap for 0 alignment = %p\n", res)); return res == MAP_FAILED ? NULL : res; } void* res = mmap(NULL, size*2, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, MAP_FD, 0); if (res == MAP_FAILED) { return NULL; } SPEW(2, _ejs_log ("mmap returned %p\n", res)); if (((uintptr_t)res % align) == 0) { // the memory was aligned, unmap the second half of our mapping // XXX should we just rejoice and add both halves? SPEW(2, _ejs_log ("already aligned\n")); munmap ((char *)res + size, size); } else { SPEW(2, _ejs_log ("not aligned\n")); // align res, and unmap the areas before/after the new mapping void *aligned_res = (void*)ALIGN(res, align); // the area before munmap (res, (uintptr_t)aligned_res - (uintptr_t)res); // the area after munmap ((char *)aligned_res+size, (uintptr_t)res+size*2 - (uintptr_t)((char *)aligned_res+size)); res = aligned_res; SPEW(2, _ejs_log ("aligned ptr = %p\n", res)); } return res; #endif }
void _ejs_throw_nativeerror (EJSNativeErrorType error_type, ejsval message) { ejsval exc = _ejs_nativeerror_new (error_type, message); char *message_utf8 = ucs2_to_utf8(EJSVAL_TO_FLAT_STRING(message)); _ejs_log ("throwing exception with message %s\n", message_utf8); free (message_utf8); _ejs_throw (exc); EJS_NOT_REACHED(); }
static void finalize_object(GCObjectPtr p) { GCObjectHeader* headerp = (GCObjectHeader*)p; if ((*headerp & EJS_SCAN_TYPE_OBJECT) != 0) { SPEW(2, _ejs_log ("finalizing object %p(%s)\n", p, CLASSNAME(p))); OP(p, finalize)((EJSObject*)p); } else if ((*headerp & EJS_SCAN_TYPE_CLOSUREENV) != 0) { SPEW(2, _ejs_log ("finalizing closureenv %p\n", p)); } else if ((*headerp & EJS_SCAN_TYPE_PRIMSTR) != 0) { SPEW(1, { EJSPrimString* primstr = (EJSPrimString*)p; if (EJS_PRIMSTR_GET_TYPE(primstr) == EJS_STRING_FLAT) { char* utf8 = ucs2_to_utf8(primstr->data.flat); SPEW(2, _ejs_log ("finalizing flat primitive string %p(%s)\n", p, utf8)); free (utf8); } else { SPEW(2, _ejs_log ("finalizing primitive string %p\n", p)); } });
static PageInfo* alloc_new_page(size_t cell_size) { SPEW(2, _ejs_log ("allocating new page for cell size %zd\n", cell_size)); PageInfo *rv = NULL; for (int i = 0; i < num_arenas; i ++) { rv = alloc_page_from_arena(heap_arenas[i], cell_size); if (rv) { SPEW(2, _ejs_log (" => %p", rv)); return rv; } } // need a new arena SPEW(2, _ejs_log ("unable to find page in current arenas, allocating a new one")); LOCK_ARENAS(); Arena* arena = arena_new(); UNLOCK_ARENAS(); if (arena == NULL) return NULL; rv = alloc_page_from_arena(arena, cell_size); SPEW(2, _ejs_log (" => %p", rv)); return rv; }
void _ejs_exception_throw(ejsval val) { struct ejs_exception *exc = (struct ejs_exception*)__cxa_allocate_exception(sizeof(struct ejs_exception)); exc->val = val; // need to root the exception until it's caught _ejs_gc_add_root(&exc->val); exc->tinfo = EJS_EHTYPE_ejsvalue; SPEW({ _ejs_log ("EXCEPTIONS: throwing %p\n", exc); _ejs_dump_value (val); });
static ejsval _ejs_require_impl (ejsval env, ejsval _this, uint32_t argc, ejsval *args) { if (argc < 1) { return _ejs_undefined; } ejsval arg = args[0]; if (!EJSVAL_IS_STRING(arg)) { _ejs_log ("required called with non-string\n"); return _ejs_null; } return _ejs_module_get(arg); }
_Unwind_Reason_Code EJS_PERSONALITY(int version, _Unwind_Action actions, uint64_t exceptionClass, struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context) { //SPEW(_ejs_log ("EXCEPTIONS: %s through frame [ip=%p sp=%p] " SPEW(_ejs_log ("EXCEPTIONS: through frame [ip=%p sp=%p] " "for exception %p\n", (void*)(_Unwind_GetIP(context)-1), (void*)_Unwind_GetCFA(context), exceptionObject)); // Let C++ handle the unwind itself. return CXX_PERSONALITY(version, actions, exceptionClass, exceptionObject, context); }
ejsval _ejs_invoke_closure (ejsval closure, ejsval _this, uint32_t argc, ejsval* args) { if (!EJSVAL_IS_FUNCTION(closure)) { #if DEBUG_LAST_LOOKUP extern jschar* last_lookup; if (last_lookup) { char *last_utf8 = ucs2_to_utf8(last_lookup); _ejs_log ("last property lookup was for: %s\n", last_utf8); free (last_utf8); } #endif _ejs_throw_nativeerror_utf8 (EJS_TYPE_ERROR, "object not a function"); } if (!EJSVAL_IS_NULL_OR_UNDEFINED(_this) && EJSVAL_IS_PRIMITIVE(_this)) { _this = ToObject(_this); } EJSFunction *fun = (EJSFunction*)EJSVAL_TO_OBJECT(closure); return fun->func (fun->env, _this, argc, args); #if not_anymore if (fun->bound_argc > 0) { ejsval* new_args = (ejsval*)malloc(sizeof(ejsval) * (fun->bound_argc + argc)); memmove (new_args, fun->bound_args, sizeof(ejsval) * fun->bound_argc); memmove (&new_args[fun->bound_argc], args, argc); args = new_args; argc += fun->bound_argc; } DEBUG_FUNCTION_ENTER (closure); ejsval rv = fun->func (fun->env, fun->bound_this, argc, args); DEBUG_FUNCTION_EXIT (closure); if (fun->bound_argc > 0) free (args); return rv; #endif }
ejsval _ejs_module_get (ejsval arg) { char* arg_utf8 = _ejs_string_to_utf8(EJSVAL_TO_STRING(arg)); ejsval module EJSVAL_ALIGNMENT; if (require_builtin_module (arg_utf8, &module)) { free (arg_utf8); return module; } if (require_external_module (arg_utf8, &module)) { free (arg_utf8); return module; } if (require_user_module (arg_utf8, &module)) { free (arg_utf8); return module; } _ejs_log ("require('%s') failed: module not included in build.\n", arg_utf8); free(arg_utf8); return _ejs_null; }
static Arena* arena_new() { if (num_arenas == MAX_ARENAS-1) return NULL; SPEW(1, _ejs_log ("num_arenas = %d, max = %d\n", num_arenas, MAX_ARENAS)); void* arena_start = alloc_from_os(ARENA_SIZE, ARENA_SIZE); if (arena_start == NULL) return NULL; Arena* new_arena = arena_start; memset (new_arena, 0, sizeof(Arena)); new_arena->end = arena_start + ARENA_SIZE; new_arena->pos = (void*)ALIGN(arena_start + sizeof(Arena), PAGE_SIZE); LOCK_ARENAS(); int insert_point = -1; for (int i = 0; i < num_arenas; i ++) { if (new_arena < heap_arenas[i]) { insert_point = i; break; } } if (insert_point == -1) insert_point = num_arenas; if (num_arenas-insert_point > 0) memmove (&heap_arenas[insert_point + 1], &heap_arenas[insert_point], (num_arenas-insert_point-1)*sizeof(Arena*)); heap_arenas[insert_point] = new_arena; num_arenas++; UNLOCK_ARENAS(); return new_arena; }
ejsval _ejs_regexp_replace(ejsval str, ejsval search_re, ejsval replace) { EJSRegExp* re = (EJSRegExp*)EJSVAL_TO_OBJECT(search_re); pcre16_extra extra; memset (&extra, 0, sizeof(extra)); pcre16* code = (pcre16*)re->compiled_pattern; int capture_count; pcre16_fullinfo (code, NULL, PCRE_INFO_CAPTURECOUNT, &capture_count); int ovec_count = 3 * (1 + capture_count); int* ovec = malloc(sizeof(int) * ovec_count); int cur_off = 0; do { EJSPrimString *flat_str = _ejs_string_flatten (str); jschar *chars_str = flat_str->data.flat; int rv = pcre16_exec(code, &extra, chars_str, flat_str->length, cur_off, PCRE_NO_UTF16_CHECK, ovec, ovec_count); if (rv < 0) break; ejsval replaceval; if (EJSVAL_IS_FUNCTION(replace)) { ejsval substr_match = _ejs_string_new_substring (str, ovec[0], ovec[1] - ovec[0]); ejsval capture = _ejs_string_new_substring (str, ovec[2], ovec[3] - ovec[2]); _ejs_log ("substring match is %s\n", ucs2_to_utf8(_ejs_string_flatten(substr_match)->data.flat)); _ejs_log ("capture is %s\n", ucs2_to_utf8(_ejs_string_flatten(capture)->data.flat)); int argc = 3; ejsval args[3]; args[0] = substr_match; args[1] = capture; args[2] = _ejs_undefined; replaceval = ToString(_ejs_invoke_closure (replace, _ejs_undefined, argc, args)); } else { replaceval = ToString(replace); } if (ovec[0] == 0) { // we matched from the beginning of the string, so nothing from there to prepend str = _ejs_string_concat (replaceval, _ejs_string_new_substring (str, ovec[1], flat_str->length - ovec[1])); } else { str = _ejs_string_concatv (_ejs_string_new_substring (str, 0, ovec[0]), replaceval, _ejs_string_new_substring (str, ovec[1], flat_str->length - ovec[1]), _ejs_null); } cur_off = ovec[1]; // if the RegExp object was created without a 'g' flag, only replace the first match if (!re->global) break; } while (EJS_TRUE); free (ovec); return str; }