diff options
Diffstat (limited to 'lib')
39 files changed, 7746 insertions, 7493 deletions
diff --git a/lib/ansi_c.nim b/lib/ansi_c.nim index e667822a9..6691ca4cc 100644 --- a/lib/ansi_c.nim +++ b/lib/ansi_c.nim @@ -17,9 +17,9 @@ proc c_memcpy(a, b: CString, size: cint) {.nodecl, importc: "memcpy".} proc c_strlen(a: CString): cint {.nodecl, importc: "strlen".} type - C_TextFile {.importc: "FILE", nodecl.} = record # empty record for - # data hiding - C_BinaryFile {.importc: "FILE", nodecl.} = record + C_TextFile {.importc: "FILE", nodecl, final.} = object # empty record for + # data hiding + C_BinaryFile {.importc: "FILE", nodecl, final.} = object C_TextFileStar = ptr CTextFile C_BinaryFileStar = ptr CBinaryFile diff --git a/lib/arithm.nim b/lib/arithm.nim index 5510d2f30..c8abded91 100644 --- a/lib/arithm.nim +++ b/lib/arithm.nim @@ -18,13 +18,13 @@ proc raiseDivByZero {.exportc: "raiseDivByZero".} = raise newException(EDivByZero, "divison by zero") proc addInt64(a, b: int64): int64 {.compilerProc, inline.} = - result = a + b + result = a +% b if (result xor a) >= int64(0) or (result xor b) >= int64(0): return result raiseOverflow() proc subInt64(a, b: int64): int64 {.compilerProc, inline.} = - result = a - b + result = a -% b if (result xor a) >= int64(0) or (result xor not b) >= int64(0): return result raiseOverflow() @@ -74,7 +74,7 @@ proc modInt64(a, b: int64): int64 {.compilerProc, inline.} = proc mulInt64(a, b: int64): int64 {.compilerproc.} = var resAsFloat, floatProd: float64 - result = a * b + result = a *% b floatProd = float64(a) # conversion floatProd = floatProd * float64(b) resAsFloat = float64(result) @@ -211,7 +211,7 @@ when defined(asmVersion) and not defined(gcc): """ elif defined(asmVersion) and defined(gcc): - proc addInt(a, b: int): int = + proc addInt(a, b: int): int = asm """ "addl %1,%%eax\n" "jno 1\n" "call _raiseOverflow\n" @@ -219,7 +219,7 @@ elif defined(asmVersion) and defined(gcc): :"=a"(`a`) :"a"(`a`), "r"(`b`) """ - + proc subInt(a, b: int): int = asm """ "subl %1,%%eax\n" "jno 1\n" @@ -228,7 +228,7 @@ elif defined(asmVersion) and defined(gcc): :"=a"(`a`) :"a"(`a`), "r"(`b`) """ - + proc negInt(a: int): int = asm """ "negl %%eax\n" "jno 1\n" @@ -237,7 +237,7 @@ elif defined(asmVersion) and defined(gcc): :"=a"(`a`) :"a"(`a`) """ - + proc divInt(a, b: int): int = asm """ "xorl %%edx, %%edx\n" "idivl %%ecx\n" @@ -276,13 +276,13 @@ else: # Platform independant versions of the above (slower!) proc addInt(a, b: int): int = - result = a + b + result = a +% b if (result xor a) >= 0 or (result xor b) >= 0: return result raiseOverflow() proc subInt(a, b: int): int = - result = a - b + result = a -% b if (result xor a) >= 0 or (result xor not b) >= 0: return result raiseOverflow() @@ -327,7 +327,7 @@ else: var resAsFloat, floatProd: float - result = a * b + result = a *% b floatProd = toFloat(a) * toFloat(b) resAsFloat = toFloat(result) diff --git a/lib/assign.nim b/lib/assign.nim index c8592b970..5ac475ef0 100644 --- a/lib/assign.nim +++ b/lib/assign.nim @@ -55,7 +55,8 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) = var dstseq = cast[PGenericSeq](dst) dstseq.len = seq.len dstseq.space = seq.len - of tyRecord, tyObject, tyTuple: + of tyObject, tyTuple, tyPureObject: + # we don't need to copy m_type field for tyObject, as they are equal anyway genericAssignAux(dest, src, mt.node) of tyArray, tyArrayConstr: for i in 0..(mt.size div mt.base.size)-1: @@ -75,6 +76,7 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) = copyMem(dest, src, mt.size) # copy raw bits proc genericSeqAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} = + var src = src # ugly, but I like to stress the parser sometimes :-) genericAssign(dest, addr(src), mt) proc genericAssignOpenArray(dest, src: pointer, len: int, @@ -110,7 +112,7 @@ proc objectInit(dest: Pointer, typ: PNimType) = var pint = cast[ptr PNimType](dest) pint^ = typ objectInitAux(dest, typ.node) - of tyRecord: + of tyTuple, tyPureObject: objectInitAux(dest, typ.node) of tyArray, tyArrayConstr: for i in 0..(typ.size div typ.base.size)-1: diff --git a/lib/base/cairo/cairo.nim b/lib/base/cairo/cairo.nim index c999590a2..d2a99f355 100644 --- a/lib/base/cairo/cairo.nim +++ b/lib/base/cairo/cairo.nim @@ -149,13 +149,13 @@ type cdecl.} cairo_read_func_t* = proc (closure: Pointer, data: PByte, len: int32): cairo_status_t{. cdecl.} - cairo_t* = record #OPAQUE - cairo_surface_t* = record #OPAQUE - cairo_pattern_t* = record #OPAQUE - cairo_scaled_font_t* = record #OPAQUE - cairo_font_face_t* = record #OPAQUE - cairo_font_options_t* = record #OPAQUE - cairo_matrix_t* = record + cairo_t* {.final.} = object #OPAQUE + cairo_surface_t* {.final.} = object #OPAQUE + cairo_pattern_t* {.final.} = object #OPAQUE + cairo_scaled_font_t* {.final.} = object #OPAQUE + cairo_font_face_t* {.final.} = object #OPAQUE + cairo_font_options_t* {.final.} = object #OPAQUE + cairo_matrix_t* {.final.} = object xx: float64 yx: float64 xy: float64 @@ -163,15 +163,15 @@ type x0: float64 y0: float64 - cairo_user_data_key_t* = record + cairo_user_data_key_t* {.final.} = object unused: int32 - cairo_glyph_t* = record + cairo_glyph_t* {.final.} = object index: int32 x: float64 y: float64 - cairo_text_extents_t* = record + cairo_text_extents_t* {.final.} = object x_bearing: float64 y_bearing: float64 width: float64 @@ -179,28 +179,28 @@ type x_advance: float64 y_advance: float64 - cairo_font_extents_t* = record + cairo_font_extents_t* {.final.} = object ascent: float64 descent: float64 height: float64 max_x_advance: float64 max_y_advance: float64 - cairo_path_data_t* = record #* _type : cairo_path_data_type_t; - # length : LongInt; - # end + cairo_path_data_t* {.final.} = object #* _type : cairo_path_data_type_t; + # length : LongInt; + # end x: float64 y: float64 - cairo_path_t* = record + cairo_path_t* {.final.} = object status: cairo_status_t data: Pcairo_path_data_t num_data: int32 - cairo_rectangle_t* = record + cairo_rectangle_t* {.final.} = object x, y, width, height: float64 - cairo_rectangle_list_t* = record + cairo_rectangle_list_t* {.final.} = object status: cairo_status_t rectangles: Pcairo_rectangle_t num_rectangles: int32 diff --git a/lib/base/gtk/atk.nim b/lib/base/gtk/atk.nim index 69eb7c7cc..96fde8af6 100644 --- a/lib/base/gtk/atk.nim +++ b/lib/base/gtk/atk.nim @@ -56,7 +56,7 @@ type ATK_LAYER_INVALID, ATK_LAYER_BACKGROUND, ATK_LAYER_CANVAS, ATK_LAYER_WIDGET, ATK_LAYER_MDI, ATK_LAYER_POPUP, ATK_LAYER_OVERLAY PAtkPropertyValues* = ptr TAtkPropertyValues - TAtkPropertyValues* = record + TAtkPropertyValues* {.final.} = object property_name*: cstring old_value*: TGValue new_value*: TGValue @@ -379,7 +379,7 @@ type TAtkAttributeSet* = TGSList PAtkAttribute* = ptr TAtkAttribute - TAtkAttribute* = record + TAtkAttribute* {.final.} = object name*: cstring value*: cstring @@ -453,7 +453,7 @@ type TAtkEventListenerInitProc* = proc () TAtkEventListenerInit* = proc (para1: TAtkEventListenerInitProc){.cdecl.} PAtkKeyEventStruct* = ptr TAtkKeyEventStruct - TAtkKeyEventStruct* = record + TAtkKeyEventStruct* {.final.} = object `type`*: gint state*: guint keyval*: guint diff --git a/lib/base/gtk/gdk2.nim b/lib/base/gtk/gdk2.nim index 11179525a..621a64bca 100644 --- a/lib/base/gtk/gdk2.nim +++ b/lib/base/gtk/gdk2.nim @@ -32,7 +32,7 @@ type TGdkVisualClass* = object of TGObjectClass PGdkColor* = ptr TGdkColor - TGdkColor* = record + TGdkColor* {.final.} = object pixel*: guint32 red*: guint16 green*: guint16 @@ -52,7 +52,7 @@ type TGdkFontType* = enum GDK_FONT_FONT, GDK_FONT_FONTSET PGdkFont* = ptr TGdkFont - TGdkFont* = record + TGdkFont* {.final.} = object `type`*: TGdkFontType ascent*: gint descent*: gint @@ -79,7 +79,7 @@ type PGdkGCValuesMask* = ptr TGdkGCValuesMask TGdkGCValuesMask* = int32 PGdkGCValues* = ptr TGdkGCValues - TGdkGCValues* = record + TGdkGCValues* {.final.} = object foreground*: TGdkColor background*: TGdkColor font*: PGdkFont @@ -125,7 +125,7 @@ type TGdkInputCondition* = int32 PGdkStatus* = ptr TGdkStatus TGdkStatus* = int32 - TGdkPoint* = record + TGdkPoint* {.final.} = object x*: gint y*: gint @@ -135,14 +135,14 @@ type PGdkWChar* = ptr TGdkWChar TGdkWChar* = guint32 PGdkSegment* = ptr TGdkSegment - TGdkSegment* = record + TGdkSegment* {.final.} = object x1*: gint y1*: gint x2*: gint y2*: gint PGdkRectangle* = ptr TGdkRectangle - TGdkRectangle* = record + TGdkRectangle* {.final.} = object x*: gint y*: gint width*: gint @@ -190,7 +190,7 @@ type PGdkCursorType* = ptr TGdkCursorType TGdkCursorType* = gint PGdkCursor* = ptr TGdkCursor - TGdkCursor* = record + TGdkCursor* {.final.} = object `type`*: TGdkCursorType ref_count*: guint @@ -220,14 +220,14 @@ type PGdkRegionBox* = ptr TGdkRegionBox TGdkRegionBox* = TGdkSegment PGdkRegion* = ptr TGdkRegion - TGdkRegion* = record + TGdkRegion* {.final.} = object size*: int32 numRects*: int32 rects*: PGdkRegionBox extents*: TGdkRegionBox PPOINTBLOCK* = ptr TPOINTBLOCK - TPOINTBLOCK* = record + TPOINTBLOCK* {.final.} = object pts*: array[0..(NUMPTSTOBUFFER) - 1, TGdkPoint] next*: PPOINTBLOCK @@ -336,13 +336,13 @@ type GDK_SETTING_ACTION_NEW, GDK_SETTING_ACTION_CHANGED, GDK_SETTING_ACTION_DELETED PGdkEventAny* = ptr TGdkEventAny - TGdkEventAny* = record + TGdkEventAny* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 PGdkEventExpose* = ptr TGdkEventExpose - TGdkEventExpose* = record + TGdkEventExpose* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -351,20 +351,20 @@ type count*: gint PGdkEventNoExpose* = ptr TGdkEventNoExpose - TGdkEventNoExpose* = record + TGdkEventNoExpose* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 PGdkEventVisibility* = ptr TGdkEventVisibility - TGdkEventVisibility* = record + TGdkEventVisibility* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 state*: TGdkVisibilityState PGdkEventMotion* = ptr TGdkEventMotion - TGdkEventMotion* = record + TGdkEventMotion* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -379,7 +379,7 @@ type y_root*: gdouble PGdkEventButton* = ptr TGdkEventButton - TGdkEventButton* = record + TGdkEventButton* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -394,7 +394,7 @@ type y_root*: gdouble PGdkEventScroll* = ptr TGdkEventScroll - TGdkEventScroll* = record + TGdkEventScroll* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -408,7 +408,7 @@ type y_root*: gdouble PGdkEventKey* = ptr TGdkEventKey - TGdkEventKey* = record + TGdkEventKey* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -421,7 +421,7 @@ type group*: guint8 PGdkEventCrossing* = ptr TGdkEventCrossing - TGdkEventCrossing* = record + TGdkEventCrossing* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -437,14 +437,14 @@ type state*: guint PGdkEventFocus* = ptr TGdkEventFocus - TGdkEventFocus* = record + TGdkEventFocus* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 `in`*: gint16 PGdkEventConfigure* = ptr TGdkEventConfigure - TGdkEventConfigure* = record + TGdkEventConfigure* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -454,7 +454,7 @@ type height*: gint PGdkEventProperty* = ptr TGdkEventProperty - TGdkEventProperty* = record + TGdkEventProperty* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -464,7 +464,7 @@ type TGdkNativeWindow* = pointer PGdkEventSelection* = ptr TGdkEventSelection - TGdkEventSelection* = record + TGdkEventSelection* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -475,7 +475,7 @@ type requestor*: TGdkNativeWindow PGdkEventProximity* = ptr TGdkEventProximity - TGdkEventProximity* = record + TGdkEventProximity* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -483,11 +483,11 @@ type device*: PGdkDevice PmatDUMMY* = ptr TmatDUMMY - TmatDUMMY* = record + TmatDUMMY* {.final.} = object b*: array[0..19, char] PGdkEventClient* = ptr TGdkEventClient - TGdkEventClient* = record + TGdkEventClient* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -496,7 +496,7 @@ type b*: array[0..19, char] PGdkEventSetting* = ptr TGdkEventSetting - TGdkEventSetting* = record + TGdkEventSetting* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -504,7 +504,7 @@ type name*: cstring PGdkEventWindowState* = ptr TGdkEventWindowState - TGdkEventWindowState* = record + TGdkEventWindowState* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -512,7 +512,7 @@ type new_window_state*: TGdkWindowState PGdkEventDND* = ptr TGdkEventDND - TGdkEventDND* = record + TGdkEventDND* {.final.} = object `type`*: TGdkEventType window*: PGdkWindow send_event*: gint8 @@ -521,7 +521,7 @@ type x_root*: gshort y_root*: gshort - TGdkEvent* = record + TGdkEvent* {.final.} = object data*: array[0..255, char] # union of # `type`: TGdkEventType # any: TGdkEventAny @@ -585,12 +585,12 @@ type PGdkAxisUse* = ptr TGdkAxisUse TGdkAxisUse* = int32 PGdkDeviceKey* = ptr TGdkDeviceKey - TGdkDeviceKey* = record + TGdkDeviceKey* {.final.} = object keyval*: guint modifiers*: TGdkModifierType PGdkDeviceAxis* = ptr TGdkDeviceAxis - TGdkDeviceAxis* = record + TGdkDeviceAxis* {.final.} = object use*: TGdkAxisUse min*: gdouble max*: gdouble @@ -605,12 +605,12 @@ type num_keys*: gint keys*: PGdkDeviceKey - TGdkTimeCoord* = record + TGdkTimeCoord* {.final.} = object time*: guint32 axes*: array[0..(GDK_MAX_TIMECOORD_AXES) - 1, gdouble] PGdkKeymapKey* = ptr TGdkKeymapKey - TGdkKeymapKey* = record + TGdkKeymapKey* {.final.} = object keycode*: guint group*: gint level*: gint @@ -624,12 +624,12 @@ type direction_changed*: proc (keymap: PGdkKeymap){.cdecl.} PGdkPangoAttrStipple* = ptr TGdkPangoAttrStipple - TGdkPangoAttrStipple* = record + TGdkPangoAttrStipple* {.final.} = object attr*: TPangoAttribute stipple*: PGdkBitmap PGdkPangoAttrEmbossed* = ptr TGdkPangoAttrEmbossed - TGdkPangoAttrEmbossed* = record + TGdkPangoAttrEmbossed* {.final.} = object attr*: TPangoAttribute embossed*: gboolean @@ -653,7 +653,7 @@ type GDK_OVERLAP_RECTANGLE_PART TGdkSpanFunc* = proc (span: PGdkSpan, data: gpointer){.cdecl.} PGdkRgbCmap* = ptr TGdkRgbCmap - TGdkRgbCmap* = record + TGdkRgbCmap* {.final.} = object colors*: array[0..255, guint32] n_colors*: gint info_list*: PGSList @@ -698,7 +698,7 @@ type TGdkInputFunction* = proc (data: gpointer, source: gint, condition: TGdkInputCondition){.cdecl.} TGdkDestroyNotify* = proc (data: gpointer){.cdecl.} - TGdkSpan* = record + TGdkSpan* {.final.} = object x*: gint y*: gint width*: gint @@ -731,7 +731,7 @@ type GDK_WINDOW_EDGE_SOUTH_WEST, GDK_WINDOW_EDGE_SOUTH, GDK_WINDOW_EDGE_SOUTH_EAST PGdkWindowAttr* = ptr TGdkWindowAttr - TGdkWindowAttr* = record + TGdkWindowAttr* {.final.} = object title*: cstring event_mask*: gint x*: gint @@ -748,7 +748,7 @@ type override_redirect*: gboolean PGdkGeometry* = ptr TGdkGeometry - TGdkGeometry* = record + TGdkGeometry* {.final.} = object min_width*: gint min_height*: gint max_width*: gint @@ -762,7 +762,7 @@ type win_gravity*: TGdkGravity PGdkPointerHooks* = ptr TGdkPointerHooks - TGdkPointerHooks* = record + TGdkPointerHooks* {.final.} = object get_pointer*: proc (window: PGdkWindow, x: Pgint, y: Pgint, mask: PGdkModifierType): PGdkWindow{.cdecl.} window_at_pointer*: proc (screen: PGdkScreen, win_x: Pgint, win_y: Pgint): PGdkWindow{. diff --git a/lib/base/gtk/gdk2pixbuf.nim b/lib/base/gtk/gdk2pixbuf.nim index 1dcc020d1..b9ab472c2 100644 --- a/lib/base/gtk/gdk2pixbuf.nim +++ b/lib/base/gtk/gdk2pixbuf.nim @@ -191,12 +191,12 @@ proc gdk_pixbuf_get_option*(pixbuf: PGdkPixbuf, key: cstring): cstring{.cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_get_option".} type PGdkPixbufLoader* = ptr TGdkPixbufLoader - TGdkPixbufLoader* = record + TGdkPixbufLoader* {.final.} = object parent_instance*: TGObject priv*: gpointer PGdkPixbufLoaderClass* = ptr TGdkPixbufLoaderClass - TGdkPixbufLoaderClass* = record + TGdkPixbufLoaderClass* {.final.} = object parent_class*: TGObjectClass area_prepared*: proc (loader: PGdkPixbufLoader){.cdecl.} area_updated*: proc (loader: PGdkPixbufLoader, x: int32, y: int32, diff --git a/lib/base/gtk/glib2.nim b/lib/base/gtk/glib2.nim index 4b4724c70..c84bc26eb 100644 --- a/lib/base/gtk/glib2.nim +++ b/lib/base/gtk/glib2.nim @@ -61,7 +61,7 @@ type TGHFunc* = proc (key, value, user_data: gpointer){.cdecl.} PGFreeFunc* = proc (data: gpointer){.cdecl.} PGTimeVal* = ptr TGTimeVal - TGTimeVal* = record + TGTimeVal* {.final.} = object tv_sec*: glong tv_usec*: glong @@ -88,17 +88,17 @@ type TGQuark* = guint32 PGQuark* = ptr TGQuark PGTypeCValue* = ptr TGTypeCValue - TGTypeCValue* = record + TGTypeCValue* {.final.} = object v_double*: gdouble GType* = gulong PGType* = ptr GType PGTypeClass* = ptr TGTypeClass - TGTypeClass* = record + TGTypeClass* {.final.} = object g_type*: GType PGTypeInstance* = ptr TGTypeInstance - TGTypeInstance* = record + TGTypeInstance* {.final.} = object g_class*: PGTypeClass PGTypeInterface* = ptr TGTypeInterface @@ -107,14 +107,14 @@ type g_instance_type*: GType PGTypeQuery* = ptr TGTypeQuery - TGTypeQuery* = record + TGTypeQuery* {.final.} = object theType*: GType type_name*: cstring class_size*: guint instance_size*: guint PGValue* = ptr TGValue - TGValue* = record + TGValue* {.final.} = object g_type*: GType data*: array[0..1, gdouble] @@ -122,12 +122,12 @@ type PGData* = pointer PGSList* = ptr TGSList PPGSList* = ptr PGSList - TGSList* = record + TGSList* {.final.} = object data*: gpointer next*: PGSList PGList* = ptr TGList - TGList* = record + TGList* {.final.} = object data*: gpointer next*: PGList prev*: PGList @@ -136,7 +136,7 @@ type TGParamFlags* = int32 PGParamSpec* = ptr TGParamSpec PPGParamSpec* = ptr PGParamSpec - TGParamSpec* = record + TGParamSpec* {.final.} = object g_type_instance*: TGTypeInstance name*: cstring flags*: TGParamFlags @@ -149,7 +149,7 @@ type param_id*: guint PGParamSpecClass* = ptr TGParamSpecClass - TGParamSpecClass* = record + TGParamSpecClass* {.final.} = object g_type_class*: TGTypeClass value_type*: GType finalize*: proc (pspec: PGParamSpec){.cdecl.} @@ -160,7 +160,7 @@ type dummy*: array[0..3, gpointer] PGParameter* = ptr TGParameter - TGParameter* = record + TGParameter* {.final.} = object name*: cstring value*: TGValue @@ -305,7 +305,7 @@ const type PGTypeValueTable* = ptr TGTypeValueTable - TGTypeValueTable* = record + TGTypeValueTable* {.final.} = object value_init*: proc (value: PGValue){.cdecl.} value_free*: proc (value: PGValue){.cdecl.} value_copy*: proc (src_value: PGValue, dest_value: PGValue){.cdecl.} @@ -320,7 +320,7 @@ type cdecl.} PGTypeInfo* = ptr TGTypeInfo - TGTypeInfo* = record + TGTypeInfo* {.final.} = object class_size*: guint16 base_init*: TGBaseInitFunc base_finalize*: TGBaseFinalizeFunc @@ -333,11 +333,11 @@ type value_table*: PGTypeValueTable PGTypeFundamentalInfo* = ptr TGTypeFundamentalInfo - TGTypeFundamentalInfo* = record + TGTypeFundamentalInfo* {.final.} = object type_flags*: TGTypeFundamentalFlags PGInterfaceInfo* = ptr TGInterfaceInfo - TGInterfaceInfo* = record + TGInterfaceInfo* {.final.} = object interface_init*: TGInterfaceInitFunc interface_finalize*: TGInterfaceFinalizeFunc interface_data*: gpointer @@ -449,7 +449,7 @@ const type PGValueArray* = ptr TGValueArray - TGValueArray* = record + TGValueArray* {.final.} = object n_values*: guint values*: PGValue n_prealloced*: guint @@ -628,7 +628,7 @@ proc g_value_set_param_take_ownership*(value: PGValue, param: PGParamSpec){. cdecl, dynlib: gliblib, importc: "g_value_set_param_take_ownership".} type PGParamSpecTypeInfo* = ptr TGParamSpecTypeInfo - TGParamSpecTypeInfo* = record + TGParamSpecTypeInfo* {.final.} = object instance_size*: guint16 n_preallocs*: guint16 instance_init*: proc (pspec: PGParamSpec){.cdecl.} @@ -668,7 +668,7 @@ type PGClosure* = ptr TGClosure PGClosureNotifyData* = ptr TGClosureNotifyData TGClosureNotify* = proc (data: gpointer, closure: PGClosure){.cdecl.} - TGClosure* = record + TGClosure* {.final.} = object flag0*: int32 marshal*: proc (closure: PGClosure, return_value: PGValue, n_param_values: guint, param_values: PGValue, @@ -682,7 +682,7 @@ type n_param_values: guint, param_values: PGValue, invocation_hint: gpointer, marshal_data: gpointer){. cdecl.} - TGClosureNotifyData* = record + TGClosureNotifyData* {.final.} = object data*: gpointer notify*: TGClosureNotify @@ -734,7 +734,7 @@ proc is_invalid*(a: var TGClosure): guint proc set_is_invalid*(a: var TGClosure, is_invalid: guint) type PGCClosure* = ptr TGCClosure - TGCClosure* = record + TGCClosure* {.final.} = object closure*: TGClosure callback*: gpointer @@ -797,13 +797,13 @@ type data: gpointer): gboolean{.cdecl.} PGSignalFlags* = ptr TGSignalFlags TGSignalFlags* = int32 - TGSignalInvocationHint* = record + TGSignalInvocationHint* {.final.} = object signal_id*: guint detail*: TGQuark run_type*: TGSignalFlags PGSignalQuery* = ptr TGSignalQuery - TGSignalQuery* = record + TGSignalQuery* {.final.} = object signal_id*: guint signal_name*: cstring itype*: GType @@ -952,7 +952,7 @@ type TGTypePluginCompleteInterfaceInfo* = proc (plugin: PGTypePlugin, instance_type: GType, interface_type: GType, info: PGInterfaceInfo){.cdecl.} PGTypePluginClass* = ptr TGTypePluginClass - TGTypePluginClass* = record + TGTypePluginClass* {.final.} = object base_iface*: TGTypeInterface use_plugin*: TGTypePluginUse unuse_plugin*: TGTypePluginUnuse @@ -1011,7 +1011,7 @@ type notify*: proc (anObject: PGObject, pspec: PGParamSpec){.cdecl.} pdummy*: array[0..7, gpointer] - TGObjectConstructParam* = record + TGObjectConstructParam* {.final.} = object pspec*: PGParamSpec value*: PGValue @@ -1125,27 +1125,27 @@ proc GUINT32_SWAP_LE_BE_CONSTANT*(val: guint32): guint32 type PGEnumClass* = ptr TGEnumClass PGEnumValue* = ptr TGEnumValue - TGEnumClass* = record + TGEnumClass* {.final.} = object g_type_class*: TGTypeClass minimum*: gint maximum*: gint n_values*: guint values*: PGEnumValue - TGEnumValue* = record + TGEnumValue* {.final.} = object value*: gint value_name*: cstring value_nick*: cstring PGFlagsClass* = ptr TGFlagsClass PGFlagsValue* = ptr TGFlagsValue - TGFlagsClass* = record + TGFlagsClass* {.final.} = object g_type_class*: TGTypeClass mask*: guint n_values*: guint values*: PGFlagsValue - TGFlagsValue* = record + TGFlagsValue* {.final.} = object value*: guint value_name*: cstring value_nick*: cstring @@ -1203,7 +1203,7 @@ const G_MAXUSHORT* = 2 * G_MAXSHORT + 1 G_MAXINT* = 2147483647 G_MININT* = - G_MAXINT - 1 - G_MAXUINT* = 4294967295 + G_MAXUINT* = -1 G_MINLONG* = G_MININT G_MAXLONG* = G_MAXINT G_MAXULONG* = G_MAXUINT @@ -1224,7 +1224,7 @@ const type PGSystemThread* = ptr TGSystemThread - TGSystemThread* = record + TGSystemThread* {.final.} = object data*: array[0..3, char] dummy_double*: float64 dummy_pointer*: pointer @@ -1350,7 +1350,7 @@ proc g_set_prgname*(prgname: cstring){.cdecl, dynlib: gliblib, importc: "g_set_prgname".} type PGDebugKey* = ptr TGDebugKey - TGDebugKey* = record + TGDebugKey* {.final.} = object key*: cstring value*: guint @@ -1390,7 +1390,7 @@ proc g_bit_storage*(number: gulong): guint{.cdecl, dynlib: gliblib, type PPGTrashStack* = ptr PGTrashStack PGTrashStack* = ptr TGTrashStack - TGTrashStack* = record + TGTrashStack* {.final.} = object next*: PGTrashStack @@ -1466,7 +1466,7 @@ const type PGMemVTable* = ptr TGMemVTable - TGMemVTable* = record + TGMemVTable* {.final.} = object malloc*: proc (n_bytes: gsize): gpointer{.cdecl.} realloc*: proc (mem: gpointer, n_bytes: gsize): gpointer{.cdecl.} free*: proc (mem: gpointer){.cdecl.} @@ -1679,7 +1679,7 @@ type TGCompletionStrncmpFunc* = proc (s1: cstring, s2: cstring, n: gsize): gint{. cdecl.} PGCompletion* = ptr TGCompletion - TGCompletion* = record + TGCompletion* {.final.} = object items*: PGList func*: TGCompletionFunc prefix*: cstring @@ -1809,7 +1809,7 @@ type PGDateDay* = ptr TGDateDay TGDateDay* = guint8 Ptm* = ptr Ttm - Ttm* = record + Ttm* {.final.} = object tm_sec*: gint tm_min*: gint tm_hour*: gint @@ -1872,7 +1872,7 @@ const type PGDate* = ptr TGDate - TGDate* = record + TGDate* {.final.} = object flag0*: int32 flag1*: int32 @@ -2028,7 +2028,7 @@ proc g_file_open_tmp*(tmpl: cstring, name_used: PPchar, error: pointer): int32{. cdecl, dynlib: gliblib, importc: "g_file_open_tmp".} type PGHook* = ptr TGHook - TGHook* = record + TGHook* {.final.} = object data*: gpointer next*: PGHook prev*: PGHook @@ -2047,7 +2047,7 @@ type TGHookFunc* = proc (data: gpointer){.cdecl.} TGHookCheckFunc* = proc (data: gpointer): gboolean{.cdecl.} TGHookFinalizeFunc* = proc (hook_list: PGHookList, hook: PGHook){.cdecl.} - TGHookList* = record + TGHookList* {.final.} = object seq_id*: gulong flag0*: int32 hooks*: PGHook @@ -2138,7 +2138,7 @@ proc g_hook_list_marshal_check*(hook_list: PGHookList, may_recurse: gboolean, importc: "g_hook_list_marshal_check".} type PGThreadPool* = ptr TGThreadPool - TGThreadPool* = record + TGThreadPool* {.final.} = object func*: TGFunc user_data*: gpointer exclusive*: gboolean @@ -2352,7 +2352,7 @@ proc g_utf8_collate_key*(str: cstring, len: gssize): cstring{.cdecl, dynlib: gliblib, importc: "g_utf8_collate_key".} type PGString* = ptr TGString - TGString* = record + TGString* {.final.} = object str*: cstring len*: gsize allocated_len*: gsize @@ -2468,7 +2468,7 @@ type TGIOFunc* = proc (source: PGIOChannel, condition: TGIOCondition, data: gpointer): gboolean{.cdecl.} PGIOFuncs* = ptr TGIOFuncs - TGIOFuncs* = record + TGIOFuncs* {.final.} = object io_read*: proc (channel: PGIOChannel, buf: cstring, count: gsize, bytes_read: Pgsize, err: pointer): TGIOStatus{.cdecl.} io_write*: proc (channel: PGIOChannel, buf: cstring, count: gsize, @@ -2483,7 +2483,7 @@ type cdecl.} io_get_flags*: proc (channel: PGIOChannel): TGIOFlags{.cdecl.} - TGIOChannel* = record + TGIOChannel* {.final.} = object ref_count*: guint funcs*: PGIOFuncs encoding*: cstring @@ -2699,7 +2699,7 @@ type PGMarkupParseContext* = ptr TGMarkupParseContext TGMarkupParseContext* = pointer PGMarkupParser* = ptr TGMarkupParser - TGMarkupParser* = record + TGMarkupParser* {.final.} = object start_element*: proc (context: PGMarkupParseContext, element_name: cstring, attribute_names: PPgchar, attribute_values: PPgchar, user_data: gpointer, error: pointer){.cdecl.} @@ -2733,7 +2733,7 @@ proc g_markup_escape_text*(text: cstring, length: gssize): cstring{.cdecl, dynlib: gliblib, importc: "g_markup_escape_text".} type PGNode* = ptr TGNode - TGNode* = record + TGNode* {.final.} = object data*: gpointer next*: PGNode prev*: PGNode @@ -2886,7 +2886,7 @@ proc g_qsort_with_data*(pbase: gconstpointer, total_elems: gint, size: gsize, cdecl, dynlib: gliblib, importc: "g_qsort_with_data".} type PGQueue* = ptr TGQueue - TGQueue* = record + TGQueue* {.final.} = object head*: PGList tail*: PGList length*: guint @@ -2947,7 +2947,7 @@ proc g_random_double_range*(`begin`: gdouble, `end`: gdouble): gdouble{.cdecl, dynlib: gliblib, importc: "g_random_double_range".} type PGTuples* = ptr TGTuples - TGTuples* = record + TGTuples* {.final.} = object len*: guint PGRelation* = pointer @@ -3003,12 +3003,12 @@ type PGScanner* = ptr TGScanner PGScannerConfig* = ptr TGScannerConfig PGTokenValue* = ptr TGTokenValue - TGTokenValue* = record + TGTokenValue* {.final.} = object v_float*: gdouble TGScannerMsgFunc* = proc (scanner: PGScanner, message: cstring, error: gboolean){.cdecl.} - TGScanner* = record + TGScanner* {.final.} = object user_data*: gpointer max_parse_errors*: guint parse_errors*: guint @@ -3031,7 +3031,7 @@ type scope_id*: guint msg_handler*: TGScannerMsgFunc - TGScannerConfig* = record + TGScannerConfig* {.final.} = object cset_skip_characters*: cstring cset_identifier_first*: cstring cset_identifier_nth*: cstring diff --git a/lib/base/gtk/gtk2.nim b/lib/base/gtk/gtk2.nim index 6c7a2ce9f..b7cf6e64f 100644 --- a/lib/base/gtk/gtk2.nim +++ b/lib/base/gtk/gtk2.nim @@ -155,17 +155,17 @@ type TGtkSignalFunc* = proc (para1: TGtkSignalFuncProc){.cdecl.} PGtkSignalMarshaller* = ptr TGtkSignalMarshaller TGtkSignalMarshaller* = TGSignalCMarshaller - TGtkArgSignalData* = record + TGtkArgSignalData* {.final.} = object f*: TGtkSignalFunc d*: gpointer - TGtkArg* = record + TGtkArg* {.final.} = object `type`*: TGtkType name*: cstring d*: gdouble # was a union type PGtkTypeInfo* = ptr TGtkTypeInfo - TGtkTypeInfo* = record + TGtkTypeInfo* {.final.} = object type_name*: cstring object_size*: guint class_size*: guint @@ -188,7 +188,7 @@ type TGtkAllocation* = TGdkRectangle TGtkCallback* = proc (widget: PGtkWidget, data: gpointer){.cdecl.} PGtkRequisition* = ptr TGtkRequisition - TGtkRequisition* = record + TGtkRequisition* {.final.} = object width*: gint height*: gint @@ -323,7 +323,7 @@ type gtk_reserved8*: proc (){.cdecl.} PGtkWidgetAuxInfo* = ptr TGtkWidgetAuxInfo - TGtkWidgetAuxInfo* = record + TGtkWidgetAuxInfo* {.final.} = object x*: gint y*: gint width*: gint @@ -331,7 +331,7 @@ type flag0*: guint16 PGtkWidgetShapeInfo* = ptr TGtkWidgetShapeInfo - TGtkWidgetShapeInfo* = record + TGtkWidgetShapeInfo* {.final.} = object offset_x*: gint16 offset_y*: gint16 shape_mask*: PGdkBitmap @@ -370,12 +370,12 @@ type gtk_reserved4: proc (){.cdecl.} PGtkAccelKey* = ptr TGtkAccelKey - TGtkAccelKey* = record + TGtkAccelKey* {.final.} = object accel_key*: guint accel_mods*: TGdkModifierType flag0*: guint16 - TGtkAccelGroupEntry* = record + TGtkAccelGroupEntry* {.final.} = object key*: TGtkAccelKey closure*: PGClosure accel_path_quark*: TGQuark @@ -595,7 +595,7 @@ type PGtkBindingSignal* = ptr TGtkBindingSignal PGtkBindingArg* = ptr TGtkBindingArg PGtkBindingSet* = ptr TGtkBindingSet - TGtkBindingSet* = record + TGtkBindingSet* {.final.} = object set_name*: cstring priority*: gint widget_path_pspecs*: PGSList @@ -605,7 +605,7 @@ type current*: PGtkBindingEntry flag0*: guint16 - TGtkBindingEntry* = record + TGtkBindingEntry* {.final.} = object keyval*: guint modifiers*: TGdkModifierType binding_set*: PGtkBindingSet @@ -614,13 +614,13 @@ type hash_next*: PGtkBindingEntry signals*: PGtkBindingSignal - TGtkBindingSignal* = record + TGtkBindingSignal* {.final.} = object next*: PGtkBindingSignal signal_name*: cstring n_args*: guint args*: PGtkBindingArg - TGtkBindingArg* = record + TGtkBindingArg* {.final.} = object arg_type*: TGtkType d*: gdouble @@ -634,7 +634,7 @@ type TGtkBoxClass* = object of TGtkContainerClass PGtkBoxChild* = ptr TGtkBoxChild - TGtkBoxChild* = record + TGtkBoxChild* {.final.} = object widget*: PGtkWidget padding*: guint16 flag0*: guint16 @@ -906,12 +906,12 @@ type TGtkCListCompareFunc* = proc (clist: PGtkCList, ptr1: gconstpointer, ptr2: gconstpointer): gint{.cdecl.} PGtkCListCellInfo* = ptr TGtkCListCellInfo - TGtkCListCellInfo* = record + TGtkCListCellInfo* {.final.} = object row*: gint column*: gint PGtkCListDestInfo* = ptr TGtkCListDestInfo - TGtkCListDestInfo* = record + TGtkCListDestInfo* {.final.} = object cell*: TGtkCListCellInfo insert_pos*: TGtkCListDragPos @@ -1014,7 +1014,7 @@ type PGPtrArray = pointer PGArray = pointer - TGtkCListColumn* = record + TGtkCListColumn* {.final.} = object title*: cstring area*: TGdkRectangle button*: PGtkWidget @@ -1025,7 +1025,7 @@ type justification*: TGtkJustification flag0*: guint16 - TGtkCListRow* = record + TGtkCListRow* {.final.} = object cell*: PGtkCell state*: TGtkStateType foreground*: TGdkColor @@ -1036,7 +1036,7 @@ type flag0*: guint16 PGtkCellText* = ptr TGtkCellText - TGtkCellText* = record + TGtkCellText* {.final.} = object `type`*: TGtkCellType vertical*: gint16 horizontal*: gint16 @@ -1044,7 +1044,7 @@ type text*: cstring PGtkCellPixmap* = ptr TGtkCellPixmap - TGtkCellPixmap* = record + TGtkCellPixmap* {.final.} = object `type`*: TGtkCellType vertical*: gint16 horizontal*: gint16 @@ -1053,7 +1053,7 @@ type mask*: PGdkBitmap PGtkCellPixText* = ptr TGtkCellPixText - TGtkCellPixText* = record + TGtkCellPixText* {.final.} = object `type`*: TGtkCellType vertical*: gint16 horizontal*: gint16 @@ -1064,14 +1064,14 @@ type mask*: PGdkBitmap PGtkCellWidget* = ptr TGtkCellWidget - TGtkCellWidget* = record + TGtkCellWidget* {.final.} = object `type`*: TGtkCellType vertical*: gint16 horizontal*: gint16 style*: PGtkStyle widget*: PGtkWidget - TGtkCell* = record + TGtkCell* {.final.} = object `type`*: TGtkCellType vertical*: gint16 horizontal*: gint16 @@ -1212,7 +1212,7 @@ type action: TGtkCTreeExpansionType){.cdecl.} PGtkCTreeRow* = ptr TGtkCTreeRow - TGtkCTreeRow* = record + TGtkCTreeRow* {.final.} = object row*: TGtkCListRow parent*: PGtkCTreeNode sibling*: PGtkCTreeNode @@ -1224,7 +1224,7 @@ type level*: guint16 GtkCTreeRow_flag0*: guint16 - TGtkCTreeNode* = record + TGtkCTreeNode* {.final.} = object list*: TGList PGtkDrawingArea* = ptr TGtkDrawingArea @@ -1479,7 +1479,7 @@ type TGtkFixedClass* = object of TGtkContainerClass PGtkFixedChild* = ptr TGtkFixedChild - TGtkFixedChild* = record + TGtkFixedChild* {.final.} = object widget*: PGtkWidget x*: gint y*: gint @@ -1632,7 +1632,7 @@ type gtk_reserved363: proc (){.cdecl.} gtk_reserved364: proc (){.cdecl.} - TGtkRulerMetric* = record + TGtkRulerMetric* {.final.} = object metric_name*: cstring abbrev*: cstring pixels_per_unit*: gdouble @@ -1657,7 +1657,7 @@ type TGtkSettingsClass* = object of TGObjectClass PGtkSettingsValue* = ptr TGtkSettingsValue - TGtkSettingsValue* = record + TGtkSettingsValue* {.final.} = object origin*: cstring value*: TGValue @@ -1708,7 +1708,7 @@ type GTK_RC_TOKEN_IM_MODULE_FILE, GTK_RC_TOKEN_STOCK, GTK_RC_TOKEN_LTR, GTK_RC_TOKEN_RTL, GTK_RC_TOKEN_LAST PGtkRcProperty* = ptr TGtkRcProperty - TGtkRcProperty* = record + TGtkRcProperty* {.final.} = object type_name*: TGQuark property_name*: TGQuark origin*: cstring @@ -1877,7 +1877,7 @@ type gtk_reserved3812: proc (){.cdecl.} PGtkBorder* = ptr TGtkBorder - TGtkBorder* = record + TGtkBorder* {.final.} = object left*: gint right*: gint top*: gint @@ -1978,27 +1978,27 @@ type PGtkIconSet* = pointer PGtkImagePixmapData* = ptr TGtkImagePixmapData - TGtkImagePixmapData* = record + TGtkImagePixmapData* {.final.} = object pixmap*: PGdkPixmap PGtkImageImageData* = ptr TGtkImageImageData - TGtkImageImageData* = record + TGtkImageImageData* {.final.} = object image*: PGdkImage PGtkImagePixbufData* = ptr TGtkImagePixbufData - TGtkImagePixbufData* = record + TGtkImagePixbufData* {.final.} = object pixbuf*: PGdkPixbuf PGtkImageStockData* = ptr TGtkImageStockData - TGtkImageStockData* = record + TGtkImageStockData* {.final.} = object stock_id*: cstring PGtkImageIconSetData* = ptr TGtkImageIconSetData - TGtkImageIconSetData* = record + TGtkImageIconSetData* {.final.} = object icon_set*: PGtkIconSet PGtkImageAnimationData* = ptr TGtkImageAnimationData - TGtkImageAnimationData* = record + TGtkImageAnimationData* {.final.} = object anim*: PGdkPixbufAnimation iter*: PGdkPixbufAnimationIter frame_timeout*: guint @@ -2111,7 +2111,7 @@ type gtk_reserved474: proc (){.cdecl.} PGtkItemFactoryEntry* = ptr TGtkItemFactoryEntry - TGtkItemFactoryEntry* = record + TGtkItemFactoryEntry* {.final.} = object path*: cstring accelerator*: cstring callback*: TGtkItemFactoryCallback @@ -2120,7 +2120,7 @@ type extra_data*: gconstpointer PGtkItemFactoryItem* = ptr TGtkItemFactoryItem - TGtkItemFactoryItem* = record + TGtkItemFactoryItem* {.final.} = object path*: cstring widgets*: PGSList @@ -2173,7 +2173,7 @@ type cdecl.} PGtkTreeModelFlags* = ptr TGtkTreeModelFlags TGtkTreeModelFlags* = int32 - TGtkTreeIter* = record + TGtkTreeIter* {.final.} = object stamp*: gint user_data*: gpointer user_data2*: gpointer @@ -2435,12 +2435,12 @@ type GtkPreview_flag0*: guint16 PGtkPreviewInfo* = ptr TGtkPreviewInfo - TGtkPreviewInfo* = record + TGtkPreviewInfo* {.final.} = object lookup*: Pguchar gamma*: gdouble PGtkDitherInfo* = ptr TGtkDitherInfo - TGtkDitherInfo* = record + TGtkDitherInfo* {.final.} = object c*: array[0..3, guchar] PGtkPreviewClass* = ptr TGtkPreviewClass @@ -2533,7 +2533,7 @@ type gtk_reserved603: proc (){.cdecl.} gtk_reserved604: proc (){.cdecl.} - TGtkSelectionData* = record + TGtkSelectionData* {.final.} = object selection*: TGdkAtom target*: TGdkAtom thetype*: TGdkAtom @@ -2543,18 +2543,18 @@ type display*: PGdkDisplay PGtkTargetEntry* = ptr TGtkTargetEntry - TGtkTargetEntry* = record + TGtkTargetEntry* {.final.} = object target*: cstring flags*: guint info*: guint PGtkTargetList* = ptr TGtkTargetList - TGtkTargetList* = record + TGtkTargetList* {.final.} = object list*: PGList ref_count*: guint PGtkTargetPair* = ptr TGtkTargetPair - TGtkTargetPair* = record + TGtkTargetPair* {.final.} = object target*: TGdkAtom flags*: guint info*: guint @@ -2635,7 +2635,7 @@ type gtk_reserved634: proc (){.cdecl.} PGtkStockItem* = ptr TGtkStockItem - TGtkStockItem* = record + TGtkStockItem* {.final.} = object stock_id*: cstring label*: cstring modifier*: TGdkModifierType @@ -2681,7 +2681,7 @@ type TGtkTableClass* = object of TGtkContainerClass PGtkTableChild* = ptr TGtkTableChild - TGtkTableChild* = record + TGtkTableChild* {.final.} = object widget*: PGtkWidget left_attach*: guint16 right_attach*: guint16 @@ -2691,7 +2691,7 @@ type ypadding*: guint16 GtkTableChild_flag0*: guint16 - TGtkTableRowCol* = record + TGtkTableRowCol* {.final.} = object requisition*: guint16 allocation*: guint16 spacing*: guint16 @@ -2710,7 +2710,7 @@ type PGtkTextFont* = pointer PGtkPropertyMark* = ptr TGtkPropertyMark - TGtkPropertyMark* = record + TGtkPropertyMark* {.final.} = object `property`*: PGList offset*: guint index*: guint @@ -2764,7 +2764,7 @@ type PGtkTextSearchFlags* = ptr TGtkTextSearchFlags TGtkTextSearchFlags* = int32 PGtkTextIter* = ptr TGtkTextIter - TGtkTextIter* = record + TGtkTextIter* {.final.} = object dummy1*: gpointer dummy2*: gpointer dummy3*: gint @@ -2802,7 +2802,7 @@ type gtk_reserved664: proc (){.cdecl.} PGtkTextAppearance* = ptr TGtkTextAppearance - TGtkTextAppearance* = record + TGtkTextAppearance* {.final.} = object bg_color*: TGdkColor fg_color*: TGdkColor bg_stipple*: PGdkBitmap @@ -2811,7 +2811,7 @@ type padding1*: gpointer flag0*: guint16 - TGtkTextAttributes* = record + TGtkTextAttributes* {.final.} = object refcount*: guint appearance*: TGtkTextAppearance justification*: TGtkJustification @@ -2860,7 +2860,7 @@ type gtk_reserved4: proc (){.cdecl.} PGtkTextMarkBody* = ptr TGtkTextMarkBody - TGtkTextMarkBody* = record + TGtkTextMarkBody* {.final.} = object obj*: PGtkTextMark name*: cstring tree*: PGtkTextBTree @@ -2879,11 +2879,11 @@ type gtk_reserved4: proc (){.cdecl.} PGtkTextPixbuf* = ptr TGtkTextPixbuf - TGtkTextPixbuf* = record + TGtkTextPixbuf* {.final.} = object pixbuf*: PGdkPixbuf PGtkTextChildBody* = ptr TGtkTextChildBody - TGtkTextChildBody* = record + TGtkTextChildBody* {.final.} = object obj*: PGtkTextChildAnchor widgets*: PGSList tree*: PGtkTextBTree @@ -2892,17 +2892,17 @@ type PGtkTextLineSegment* = ptr TGtkTextLineSegment PGtkTextLineSegmentClass* = ptr TGtkTextLineSegmentClass PGtkTextTagInfo* = ptr TGtkTextTagInfo - TGtkTextTagInfo* = record + TGtkTextTagInfo* {.final.} = object tag*: PGtkTextTag tag_root*: PGtkTextBTreeNode toggle_count*: gint PGtkTextToggleBody* = ptr TGtkTextToggleBody - TGtkTextToggleBody* = record + TGtkTextToggleBody* {.final.} = object info*: PGtkTextTagInfo inNodeCounts*: gboolean - TGtkTextLineSegment* = record + TGtkTextLineSegment* {.final.} = object `type`*: PGtkTextLineSegmentClass next*: PGtkTextLineSegment char_count*: int32 @@ -2919,7 +2919,7 @@ type line: PGtkTextLine){.cdecl.} TGtkTextSegCheckFunc* = proc (seg: PGtkTextLineSegment, line: PGtkTextLine){. cdecl.} - TGtkTextLineSegmentClass* = record + TGtkTextLineSegmentClass* {.final.} = object name*: cstring leftGravity*: gboolean splitFunc*: TGtkTextSegSplitFunc @@ -2929,13 +2929,13 @@ type checkFunc*: TGtkTextSegCheckFunc PGtkTextLineData* = ptr TGtkTextLineData - TGtkTextLineData* = record + TGtkTextLineData* {.final.} = object view_id*: gpointer next*: PGtkTextLineData height*: gint flag0*: int32 - TGtkTextLine* = record + TGtkTextLine* {.final.} = object parent*: PGtkTextBTreeNode next*: PGtkTextLine segments*: PGtkTextLineSegment @@ -3020,18 +3020,18 @@ type gtk_reserved4: proc (){.cdecl.} PGtkTextAttrAppearance* = ptr TGtkTextAttrAppearance - TGtkTextAttrAppearance* = record + TGtkTextAttrAppearance* {.final.} = object attr*: TPangoAttribute appearance*: TGtkTextAppearance PGtkTextCursorDisplay* = ptr TGtkTextCursorDisplay - TGtkTextCursorDisplay* = record + TGtkTextCursorDisplay* {.final.} = object x*: gint y*: gint height*: gint flag0*: guint16 - TGtkTextLineDisplay* = record + TGtkTextLineDisplay* {.final.} = object layout*: PPangoLayout cursors*: PGSList shaped_objects*: PGSList @@ -3152,7 +3152,7 @@ type PGtkTooltips* = ptr TGtkTooltips PGtkTooltipsData* = ptr TGtkTooltipsData - TGtkTooltipsData* = record + TGtkTooltipsData* {.final.} = object tooltips*: PGtkTooltips widget*: PGtkWidget tip_text*: cstring @@ -3184,7 +3184,7 @@ type TGtkToolbarSpaceStyle* = enum GTK_TOOLBAR_SPACE_EMPTY, GTK_TOOLBAR_SPACE_LINE PGtkToolbarChild* = ptr TGtkToolbarChild - TGtkToolbarChild* = record + TGtkToolbarChild* {.final.} = object `type`*: TGtkToolbarChildType widget*: PGtkWidget icon*: PGtkWidget @@ -3365,13 +3365,13 @@ type PGtkRBNode* = ptr TGtkRBNode TGtkRBTreeTraverseFunc* = proc (tree: PGtkRBTree, node: PGtkRBNode, data: gpointer){.cdecl.} - TGtkRBTree* = record + TGtkRBTree* {.final.} = object root*: PGtkRBNode `nil`*: PGtkRBNode parent_tree*: PGtkRBTree parent_node*: PGtkRBNode - TGtkRBNode* = record + TGtkRBNode* {.final.} = object flag0*: guint16 left*: PGtkRBNode right*: PGtkRBNode @@ -3386,14 +3386,14 @@ type TGtkTreeViewSearchDialogPositionFunc* = proc (tree_view: PGtkTreeView, search_dialog: PGtkWidget){.cdecl.} PGtkTreeViewColumnReorder* = ptr TGtkTreeViewColumnReorder - TGtkTreeViewColumnReorder* = record + TGtkTreeViewColumnReorder* {.final.} = object left_align*: gint right_align*: gint left_column*: PGtkTreeViewColumn right_column*: PGtkTreeViewColumn PGtkTreeViewPrivate* = ptr TGtkTreeViewPrivate - TGtkTreeViewPrivate* = record + TGtkTreeViewPrivate* {.final.} = object model*: PGtkTreeModel flags*: guint tree*: PGtkRBTree @@ -11304,96 +11304,127 @@ proc GTK_FUNDAMENTAL_TYPE*(thetype: GType): GType = result = G_TYPE_FUNDAMENTAL(thetype) proc GTK_VALUE_CHAR*(a: TGtkArg): gchar = + var a = a Result = cast[ptr gchar](addr(a.d))^ proc GTK_VALUE_UCHAR*(a: TGtkArg): guchar = + var a = a Result = cast[ptr guchar](addr(a.d))^ proc GTK_VALUE_BOOL*(a: TGtkArg): gboolean = + var a = a Result = cast[ptr gboolean](addr(a.d))^ proc GTK_VALUE_INT*(a: TGtkArg): gint = + var a = a Result = cast[ptr gint](addr(a.d))^ proc GTK_VALUE_UINT*(a: TGtkArg): guint = + var a = a Result = cast[ptr guint](addr(a.d))^ proc GTK_VALUE_LONG*(a: TGtkArg): glong = + var a = a Result = cast[ptr glong](addr(a.d))^ proc GTK_VALUE_ULONG*(a: TGtkArg): gulong = + var a = a Result = cast[ptr gulong](addr(a.d))^ proc GTK_VALUE_FLOAT*(a: TGtkArg): gfloat = + var a = a Result = cast[ptr gfloat](addr(a.d))^ proc GTK_VALUE_DOUBLE*(a: TGtkArg): gdouble = + var a = a Result = cast[ptr gdouble](addr(a.d))^ proc GTK_VALUE_STRING*(a: TGtkArg): cstring = + var a = a Result = cast[ptr cstring](addr(a.d))^ proc GTK_VALUE_ENUM*(a: TGtkArg): gint = + var a = a Result = cast[ptr gint](addr(a.d))^ proc GTK_VALUE_FLAGS*(a: TGtkArg): guint = + var a = a Result = cast[ptr guint](addr(a.d))^ proc GTK_VALUE_BOXED*(a: TGtkArg): gpointer = + var a = a Result = cast[ptr gpointer](addr(a.d))^ proc GTK_VALUE_OBJECT*(a: TGtkArg): PGtkObject = + var a = a Result = cast[ptr PGtkObject](addr(a.d))^ proc GTK_VALUE_POINTER*(a: TGtkArg): GPointer = + var a = a Result = cast[ptr gpointer](addr(a.d))^ proc GTK_VALUE_SIGNAL*(a: TGtkArg): TGtkArgSignalData = + var a = a Result = cast[ptr TGtkArgSignalData](addr(a.d))^ proc GTK_RETLOC_CHAR*(a: TGtkArg): cstring = + var a = a Result = cast[ptr cstring](addr(a.d))^ proc GTK_RETLOC_UCHAR*(a: TGtkArg): Pguchar = + var a = a Result = cast[ptr pguchar](addr(a.d))^ proc GTK_RETLOC_BOOL*(a: TGtkArg): Pgboolean = + var a = a Result = cast[ptr pgboolean](addr(a.d))^ proc GTK_RETLOC_INT*(a: TGtkArg): Pgint = + var a = a Result = cast[ptr pgint](addr(a.d))^ proc GTK_RETLOC_UINT*(a: TGtkArg): Pguint = + var a = a Result = cast[ptr pguint](addr(a.d))^ proc GTK_RETLOC_LONG*(a: TGtkArg): Pglong = + var a = a Result = cast[ptr pglong](addr(a.d))^ proc GTK_RETLOC_ULONG*(a: TGtkArg): Pgulong = + var a = a Result = cast[ptr pgulong](addr(a.d))^ proc GTK_RETLOC_FLOAT*(a: TGtkArg): Pgfloat = + var a = a Result = cast[ptr pgfloat](addr(a.d))^ proc GTK_RETLOC_DOUBLE*(a: TGtkArg): Pgdouble = + var a = a Result = cast[ptr pgdouble](addr(a.d))^ proc GTK_RETLOC_STRING*(a: TGtkArg): Ppgchar = + var a = a Result = cast[ptr Ppgchar](addr(a.d))^ proc GTK_RETLOC_ENUM*(a: TGtkArg): Pgint = + var a = a Result = cast[ptr Pgint](addr(a.d))^ proc GTK_RETLOC_FLAGS*(a: TGtkArg): Pguint = + var a = a Result = cast[ptr pguint](addr(a.d))^ proc GTK_RETLOC_BOXED*(a: TGtkArg): Pgpointer = + var a = a Result = cast[ptr pgpointer](addr(a.d))^ proc GTK_RETLOC_OBJECT*(a: TGtkArg): PPGtkObject = + var a = a Result = cast[ptr ppgtkobject](addr(a.d))^ proc GTK_RETLOC_POINTER*(a: TGtkArg): Pgpointer = + var a = a Result = cast[ptr pgpointer](addr(a.d))^ proc GTK_TYPE_WIDGET*(): GType = @@ -15108,7 +15139,7 @@ proc gtk_signal_handler_pending_by_func*(anObject: PGtkObject, signal_id: guint, G_SIGNAL_MATCH_DATA) if not may_be_blocked: t = t or cast[int](G_SIGNAL_MATCH_UNBLOCKED) - Result = g_signal_handler_find(anObject, t, signal_id, 0, nil, addr(func_), + Result = g_signal_handler_find(anObject, t, signal_id, 0, nil, func_, data) != 0 proc GTK_TYPE_SIZE_GROUP*(): GType = @@ -17045,7 +17076,7 @@ type GTK_FILE_FILTER_FILENAME = 1 shl 0, GTK_FILE_FILTER_URI = 1 shl 1, GTK_FILE_FILTER_DISPLAY_NAME = 1 shl 2, GTK_FILE_FILTER_MIME_TYPE = 1 shl 3 PGtkFileFilterInfo* = ref TGtkFileFilterInfo - TGtkFileFilterInfo* = record + TGtkFileFilterInfo* {.final.} = object contains*: TGtkFileFilterFlags filename*: cstring uri*: cstring diff --git a/lib/base/gtk/gtkhtml.nim b/lib/base/gtk/gtkhtml.nim index 5599eec2b..ca1ce883d 100644 --- a/lib/base/gtk/gtkhtml.nim +++ b/lib/base/gtk/gtkhtml.nim @@ -68,12 +68,12 @@ type exc: PDomException): PDomString{.cdecl.} PDomDocument* = ptr TDomDocument - TDomDocument* = record + TDomDocument* {.final.} = object parent*: PDomNode iterators*: PGSList PDomDocumentClass* = ptr TDomDocumentClass - TDomDocumentClass* = record + TDomDocumentClass* {.final.} = object parent_class*: PDomNodeClass PHtmlFocusIterator* = ptr THtmlFocusIterator diff --git a/lib/base/gtk/pango.nim b/lib/base/gtk/pango.nim index 4c6c48bf8..142ab4aa2 100644 --- a/lib/base/gtk/pango.nim +++ b/lib/base/gtk/pango.nim @@ -50,7 +50,7 @@ type PPangoGlyph* = ptr TPangoGlyph TPangoGlyph* = guint32 PPangoRectangle* = ptr TPangoRectangle - TPangoRectangle* = record + TPangoRectangle* {.final.} = object x*: int32 y*: int32 width*: int32 @@ -61,7 +61,7 @@ type PANGO_DIRECTION_LTR, PANGO_DIRECTION_RTL, PANGO_DIRECTION_TTB_LTR, PANGO_DIRECTION_TTB_RTL PPangoColor* = ptr TPangoColor - TPangoColor* = record + TPangoColor* {.final.} = object red*: guint16 green*: guint16 blue*: guint16 @@ -72,12 +72,12 @@ type TPangoUnderline* = int32 PPangoAttribute* = ptr TPangoAttribute PPangoAttrClass* = ptr TPangoAttrClass - TPangoAttribute* = record + TPangoAttribute* {.final.} = object klass*: PPangoAttrClass start_index*: int end_index*: int - TPangoAttrClass* = record + TPangoAttrClass* {.final.} = object `type`*: TPangoAttrType copy*: proc (attr: PPangoAttribute): PPangoAttribute{.cdecl.} destroy*: proc (attr: PPangoAttribute){.cdecl.} @@ -85,43 +85,43 @@ type cdecl.} PPangoAttrString* = ptr TPangoAttrString - TPangoAttrString* = record + TPangoAttrString* {.final.} = object attr*: TPangoAttribute value*: cstring PPangoAttrLanguage* = ptr TPangoAttrLanguage - TPangoAttrLanguage* = record + TPangoAttrLanguage* {.final.} = object attr*: TPangoAttribute value*: PPangoLanguage PPangoAttrInt* = ptr TPangoAttrInt - TPangoAttrInt* = record + TPangoAttrInt* {.final.} = object attr*: TPangoAttribute value*: int32 PPangoAttrFloat* = ptr TPangoAttrFloat - TPangoAttrFloat* = record + TPangoAttrFloat* {.final.} = object attr*: TPangoAttribute value*: gdouble PPangoAttrColor* = ptr TPangoAttrColor - TPangoAttrColor* = record + TPangoAttrColor* {.final.} = object attr*: TPangoAttribute color*: TPangoColor PPangoAttrShape* = ptr TPangoAttrShape - TPangoAttrShape* = record + TPangoAttrShape* {.final.} = object attr*: TPangoAttribute ink_rect*: TPangoRectangle logical_rect*: TPangoRectangle PPangoAttrFontDesc* = ptr TPangoAttrFontDesc - TPangoAttrFontDesc* = record + TPangoAttrFontDesc* {.final.} = object attr*: TPangoAttribute desc*: PPangoFontDescription PPangoLogAttr* = ptr TPangoLogAttr - TPangoLogAttr* = record + TPangoLogAttr* {.final.} = object flag0*: guint16 PPangoCoverageLevel* = ptr TPangoCoverageLevel @@ -129,25 +129,25 @@ type PANGO_COVERAGE_NONE, PANGO_COVERAGE_FALLBACK, PANGO_COVERAGE_APPROXIMATE, PANGO_COVERAGE_EXACT PPangoBlockInfo* = ptr TPangoBlockInfo - TPangoBlockInfo* = record + TPangoBlockInfo* {.final.} = object data*: Pguchar level*: TPangoCoverageLevel PPangoCoverage* = ptr TPangoCoverage - TPangoCoverage* = record + TPangoCoverage* {.final.} = object ref_count*: int n_blocks*: int32 data_size*: int32 blocks*: PPangoBlockInfo PPangoEngineRange* = ptr TPangoEngineRange - TPangoEngineRange* = record + TPangoEngineRange* {.final.} = object start*: int32 theEnd*: int32 langs*: cstring PPangoEngineInfo* = ptr TPangoEngineInfo - TPangoEngineInfo* = record + TPangoEngineInfo* {.final.} = object id*: cstring engine_type*: cstring render_type*: cstring @@ -155,7 +155,7 @@ type n_ranges*: gint PPangoEngine* = ptr TPangoEngine - TPangoEngine* = record + TPangoEngine* {.final.} = object id*: cstring `type`*: cstring length*: gint @@ -165,7 +165,7 @@ type attrs: PPangoLogAttr, attrs_len: int32){. cdecl.} PPangoEngineLang* = ptr TPangoEngineLang - TPangoEngineLang* = record + TPangoEngineLang* {.final.} = object engine*: TPangoEngine script_break*: TPangoEngineLangScriptBreak @@ -176,7 +176,7 @@ type language: PPangoLanguage): PPangoCoverage{. cdecl.} PPangoEngineShape* = ptr TPangoEngineShape - TPangoEngineShape* = record + TPangoEngineShape* {.final.} = object engine*: TPangoEngine script_shape*: TPangoEngineShapeScript get_coverage*: TPangoEngineShapeGetCoverage @@ -194,28 +194,28 @@ type PPangoGlyphUnit* = ptr TPangoGlyphUnit TPangoGlyphUnit* = gint32 PPangoGlyphGeometry* = ptr TPangoGlyphGeometry - TPangoGlyphGeometry* = record + TPangoGlyphGeometry* {.final.} = object width*: TPangoGlyphUnit x_offset*: TPangoGlyphUnit y_offset*: TPangoGlyphUnit PPangoGlyphVisAttr* = ptr TPangoGlyphVisAttr - TPangoGlyphVisAttr* = record + TPangoGlyphVisAttr* {.final.} = object flag0*: int16 PPangoGlyphInfo* = ptr TPangoGlyphInfo - TPangoGlyphInfo* = record + TPangoGlyphInfo* {.final.} = object glyph*: TPangoGlyph geometry*: TPangoGlyphGeometry attr*: TPangoGlyphVisAttr - TPangoGlyphString* = record + TPangoGlyphString* {.final.} = object num_glyphs*: gint glyphs*: PPangoGlyphInfo log_clusters*: Pgint space*: gint - TPangoAnalysis* = record + TPangoAnalysis* {.final.} = object shape_engine*: PPangoEngineShape lang_engine*: PPangoEngineLang font*: PPangoFont @@ -223,7 +223,7 @@ type language*: PPangoLanguage extra_attrs*: PGSList - TPangoItem* = record + TPangoItem* {.final.} = object offset*: gint length*: gint num_chars*: gint @@ -236,14 +236,14 @@ type TPangoWrapMode* = enum PANGO_WRAP_WORD, PANGO_WRAP_CHAR PPangoLayoutLine* = ptr TPangoLayoutLine - TPangoLayoutLine* = record + TPangoLayoutLine* {.final.} = object layout*: PPangoLayout start_index*: gint length*: gint runs*: PGSList PPangoLayoutRun* = ptr TPangoLayoutRun - TPangoLayoutRun* = record + TPangoLayoutRun* {.final.} = object item*: PPangoItem glyphs*: PPangoGlyphString diff --git a/lib/base/nregex.nim b/lib/base/nregex.nim index 509f77f1b..77afb8421 100644 --- a/lib/base/nregex.nim +++ b/lib/base/nregex.nim @@ -12,7 +12,7 @@ type regMN, regNewline - TRegex = record + TRegex = object of TObject case kind: TRegexKind of regChar: c: char of regSet: s: ref set[char] diff --git a/lib/base/pcre.nim b/lib/base/pcre.nim index 6a9f14123..1023f86f3 100644 --- a/lib/base/pcre.nim +++ b/lib/base/pcre.nim @@ -162,7 +162,7 @@ type # Data passed back in callouts # Const before type ignored # Pointer to character tables - Tpcre_extra* = record + Tpcre_extra* {.final.} = object flags: cuint study_data: pointer match_limit: cuint @@ -189,7 +189,7 @@ type # Offset to next item in the pattern # Length of next item in the pattern # ------------------------------------------------------------------ - TPcre_callout_block* = record + TPcre_callout_block* {.final.} = object version: cint callout_number: cint offset_vector: ptr cint diff --git a/lib/complex.nim b/lib/complex.nim index b5724e48f..6f0f568a3 100644 --- a/lib/complex.nim +++ b/lib/complex.nim @@ -19,10 +19,8 @@ import math type - TComplex* = record ## a complex number, consisting of a real and an - ## imaginary part - re*: float ## real part of the complex number - im*: float ## imarginary part of the complex number + TComplex* = tuple[re, im: float] + ## a complex number, consisting of a real and an imaginary part proc `==` *(x, y: TComplex): bool = ## Compare two complex numbers `x` and `y` for equality. diff --git a/lib/debugger.nim b/lib/debugger.nim index dca346fe0..03cbb6c0b 100644 --- a/lib/debugger.nim +++ b/lib/debugger.nim @@ -25,23 +25,24 @@ type dbQuiting, # debugger wants to quit dbBreakpoints # debugger is only interested in breakpoints - TDbgBreakpoint = record + TDbgBreakpoint {.final.} = object low, high: int # range from low to high; if disabled # both low and high are set to their negative values # this makes the check faster and safes memory filename: string name: string # name of breakpoint - TVarSlot {.compilerproc.} = record # variable slots used for debugger: + TVarSlot {.compilerproc, final.} = object # variable slots used for debugger: address: pointer typ: PNimType name: cstring # for globals this is "module.name" PExtendedFrame = ptr TExtendedFrame - TExtendedFrame = record # If the debugger is enabled the compiler provides - # an extended frame. Of course only slots that are - # needed are allocated and not 10_000, except for - # the global data description. + TExtendedFrame {.final.} = object # If the debugger is enabled the compiler + # provides an extended frame. Of course + # only slots that are + # needed are allocated and not 10_000, + # except for the global data description. f: TFrame slots: array[0..10_000, TVarSlot] @@ -69,7 +70,7 @@ proc findBreakpoint(name: string): int = return -1 proc ListBreakPoints() = - write(stdout, "*** emdb| Breakpoints:\n") + write(stdout, "*** endb| Breakpoints:\n") for i in 0 .. dbgBPlen-1: write(stdout, dbgBP[i].name & ": " & $abs(dbgBP[i].low) & ".." & $abs(dbgBP[i].high) & dbgBP[i].filename) @@ -101,13 +102,13 @@ proc writeVariable(stream: TFile, slot: TVarSlot) = writeln(stream, dbgRepr(slot.address, slot.typ)) proc ListFrame(stream: TFile, f: PExtendedFrame) = - write(stream, "*** emdb| Frame (" & $f.f.len & " slots):\n") + write(stream, "*** endb| Frame (" & $f.f.len & " slots):\n") for i in 0 .. f.f.len-1: writeVariable(stream, f.slots[i]) write(stream, "***\n") proc ListVariables(stream: TFile, f: PExtendedFrame) = - write(stream, "*** emdb| Frame (" & $f.f.len & " slots):\n") + write(stream, "*** endb| Frame (" & $f.f.len & " slots):\n") for i in 0 .. f.f.len-1: writeln(stream, f.slots[i].name) write(stream, "***\n") @@ -115,7 +116,7 @@ proc ListVariables(stream: TFile, f: PExtendedFrame) = proc debugOut(msg: cstring) = # the *** *** markers are for easy recognition of debugger # output for external frontends. - write(stdout, "*** emdb| ") + write(stdout, "*** endb| ") write(stdout, msg) write(stdout, "***\n") @@ -131,14 +132,14 @@ proc findVariable(frame: PExtendedFrame, varname: cstring): int = proc dbgShowCurrentProc(dbgFramePointer: PFrame) = if dbgFramePointer != nil: - write(stdout, "*** emdb| now in proc: ") + write(stdout, "*** endb| now in proc: ") write(stdout, dbgFramePointer.procname) write(stdout, " ***\n") else: - write(stdout, "*** emdb| (procedure name not available) ***\n") + write(stdout, "*** endb| (procedure name not available) ***\n") proc dbgShowExecutionPoint() = - write(stdout, "*** emdb| " & $framePtr.filename & "(" & $framePtr.line & + write(stdout, "*** endb| " & $framePtr.filename & "(" & $framePtr.line & ") " & $framePtr.procname & " ***\n") when defined(windows) or defined(dos) or defined(os2): @@ -219,26 +220,26 @@ h, help display this help message q, quit quit the debugger and the program <ENTER> repeat the previous debugger command EXECUTING -s, stepinto single step, stepping into routine calls -n, stepover single step, without stepping into routine calls +s, step single step, stepping into routine calls +n, next single step, without stepping into routine calls f, skipcurrent continue execution until the current routine finishes c, continue continue execution until the next breakpoint i, ignore continue execution, ignore all breakpoints BREAKPOINTS -b, setbreak <name> [fromline [toline]] [file] +b, break <name> [fromline [toline]] [file] set a new breakpoint named 'name' for line and file if line or file are omitted the current one is used breakpoints display the entire breakpoint list disable <name> disable a breakpoint enable <name> enable a breakpoint DATA DISPLAY -e, eval <exp> evaluate the expression <exp> -o, out <file> <exp> evaluate <exp> and write it to <file> +e, eval <expr> evaluate the expression <expr> +o, out <file> <expr> evaluate <expr> and write it to <file> w, where display the current execution point stackframe [file] display current stack frame [and write it to file] u, up go up in the call stack d, down go down in the call stack -callstack display the entire call stack +bt, backtrace display the entire call stack l, locals display available local variables g, globals display available global variables maxdisplay <integer> set the display's recursion maximum @@ -352,7 +353,7 @@ proc CommandPrompt() = dbgDown: int = 0 # how often we did go down while again: - write(stdout, "*** emdb| >>") + write(stdout, "*** endb| >>") var tmp = readLine(stdin) if tmp.len > 0: dbgUser = tmp # now look what we have to do: @@ -360,10 +361,10 @@ proc CommandPrompt() = var i = scanWord(dbgUser, dbgTemp, 0) case dbgTemp of "": InvalidCommand() - of "s", "stepinto": + of "s", "step": dbgState = dbStepInto again = false - of "n", "stepover": + of "n", "next": dbgState = dbStepOver dbgSkipToFrame = framePtr again = false @@ -412,9 +413,9 @@ proc CommandPrompt() = dbgShowCurrentProc(dbgFramePtr) else: debugOut("[Warning] cannot go down any further ") - of "callstack": + of "bt", "backtrace": WriteStackTrace() - of "b", "setbreak": + of "b", "break": setBreakPoint(dbgUser, i) of "breakpoints": ListBreakPoints() @@ -443,7 +444,7 @@ proc endbStep() = proc checkForBreakpoint() = var i = dbgBreakpointReached(framePtr.line) if i >= 0: - write(stdout, "*** emdb| reached ") + write(stdout, "*** endb| reached ") write(stdout, dbgBP[i].name) write(stdout, " in ") write(stdout, framePtr.filename) diff --git a/lib/dlmalloc.c b/lib/dlmalloc.c index 79fb5801b..c907da830 100644 --- a/lib/dlmalloc.c +++ b/lib/dlmalloc.c @@ -1,5071 +1,5073 @@ -#define USE_DL_PREFIX - -#define FOOTERS 1 -#define DEBUG 1 -/* -#define ABORT_ON_ASSERT_FAILURE 0 -*/ - -/* - This is a version (aka dlmalloc) of malloc/free/realloc written by - Doug Lea and released to the public domain, as explained at - http://creativecommons.org/licenses/publicdomain. Send questions, - comments, complaints, performance data, etc to dl@cs.oswego.edu - -* Version 2.8.3 Thu Sep 22 11:16:15 2005 Doug Lea (dl at gee) - - Note: There may be an updated version of this malloc obtainable at - ftp://gee.cs.oswego.edu/pub/misc/malloc.c - Check before installing! - -* Quickstart - - This library is all in one file to simplify the most common usage: - ftp it, compile it (-O3), and link it into another program. All of - the compile-time options default to reasonable values for use on - most platforms. You might later want to step through various - compile-time and dynamic tuning options. - - For convenience, an include file for code using this malloc is at: - ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.3.h - You don't really need this .h file unless you call functions not - defined in your system include files. The .h file contains only the - excerpts from this file needed for using this malloc on ANSI C/C++ - systems, so long as you haven't changed compile-time options about - naming and tuning parameters. If you do, then you can create your - own malloc.h that does include all settings by cutting at the point - indicated below. Note that you may already by default be using a C - library containing a malloc that is based on some version of this - malloc (for example in linux). You might still want to use the one - in this file to customize settings or to avoid overheads associated - with library versions. - -* Vital statistics: - - Supported pointer/size_t representation: 4 or 8 bytes - size_t MUST be an unsigned type of the same width as - pointers. (If you are using an ancient system that declares - size_t as a signed type, or need it to be a different width - than pointers, you can use a previous release of this malloc - (e.g. 2.7.2) supporting these.) - - Alignment: 8 bytes (default) - This suffices for nearly all current machines and C compilers. - However, you can define MALLOC_ALIGNMENT to be wider than this - if necessary (up to 128bytes), at the expense of using more space. - - Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes) - 8 or 16 bytes (if 8byte sizes) - Each malloced chunk has a hidden word of overhead holding size - and status information, and additional cross-check word - if FOOTERS is defined. - - Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead) - 8-byte ptrs: 32 bytes (including overhead) - - Even a request for zero bytes (i.e., malloc(0)) returns a - pointer to something of the minimum allocatable size. - The maximum overhead wastage (i.e., number of extra bytes - allocated than were requested in malloc) is less than or equal - to the minimum size, except for requests >= mmap_threshold that - are serviced via mmap(), where the worst case wastage is about - 32 bytes plus the remainder from a system page (the minimal - mmap unit); typically 4096 or 8192 bytes. - - Security: static-safe; optionally more or less - The "security" of malloc refers to the ability of malicious - code to accentuate the effects of errors (for example, freeing - space that is not currently malloc'ed or overwriting past the - ends of chunks) in code that calls malloc. This malloc - guarantees not to modify any memory locations below the base of - heap, i.e., static variables, even in the presence of usage - errors. The routines additionally detect most improper frees - and reallocs. All this holds as long as the static bookkeeping - for malloc itself is not corrupted by some other means. This - is only one aspect of security -- these checks do not, and - cannot, detect all possible programming errors. - - If FOOTERS is defined nonzero, then each allocated chunk - carries an additional check word to verify that it was malloced - from its space. These check words are the same within each - execution of a program using malloc, but differ across - executions, so externally crafted fake chunks cannot be - freed. This improves security by rejecting frees/reallocs that - could corrupt heap memory, in addition to the checks preventing - writes to statics that are always on. This may further improve - security at the expense of time and space overhead. (Note that - FOOTERS may also be worth using with MSPACES.) - - By default detected errors cause the program to abort (calling - "abort()"). You can override this to instead proceed past - errors by defining PROCEED_ON_ERROR. In this case, a bad free - has no effect, and a malloc that encounters a bad address - caused by user overwrites will ignore the bad address by - dropping pointers and indices to all known memory. This may - be appropriate for programs that should continue if at all - possible in the face of programming errors, although they may - run out of memory because dropped memory is never reclaimed. - - If you don't like either of these options, you can define - CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything - else. And if if you are sure that your program using malloc has - no errors or vulnerabilities, you can define INSECURE to 1, - which might (or might not) provide a small performance improvement. - - Thread-safety: NOT thread-safe unless USE_LOCKS defined - When USE_LOCKS is defined, each public call to malloc, free, - etc is surrounded with either a pthread mutex or a win32 - spinlock (depending on WIN32). This is not especially fast, and - can be a major bottleneck. It is designed only to provide - minimal protection in concurrent environments, and to provide a - basis for extensions. If you are using malloc in a concurrent - program, consider instead using ptmalloc, which is derived from - a version of this malloc. (See http://www.malloc.de). - - System requirements: Any combination of MORECORE and/or MMAP/MUNMAP - This malloc can use unix sbrk or any emulation (invoked using - the CALL_MORECORE macro) and/or mmap/munmap or any emulation - (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system - memory. On most unix systems, it tends to work best if both - MORECORE and MMAP are enabled. On Win32, it uses emulations - based on VirtualAlloc. It also uses common C library functions - like memset. - - Compliance: I believe it is compliant with the Single Unix Specification - (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably - others as well. - -* Overview of algorithms - - This is not the fastest, most space-conserving, most portable, or - most tunable malloc ever written. However it is among the fastest - while also being among the most space-conserving, portable and - tunable. Consistent balance across these factors results in a good - general-purpose allocator for malloc-intensive programs. - - In most ways, this malloc is a best-fit allocator. Generally, it - chooses the best-fitting existing chunk for a request, with ties - broken in approximately least-recently-used order. (This strategy - normally maintains low fragmentation.) However, for requests less - than 256bytes, it deviates from best-fit when there is not an - exactly fitting available chunk by preferring to use space adjacent - to that used for the previous small request, as well as by breaking - ties in approximately most-recently-used order. (These enhance - locality of series of small allocations.) And for very large requests - (>= 256Kb by default), it relies on system memory mapping - facilities, if supported. (This helps avoid carrying around and - possibly fragmenting memory used only for large chunks.) - - All operations (except malloc_stats and mallinfo) have execution - times that are bounded by a constant factor of the number of bits in - a size_t, not counting any clearing in calloc or copying in realloc, - or actions surrounding MORECORE and MMAP that have times - proportional to the number of non-contiguous regions returned by - system allocation routines, which is often just 1. - - The implementation is not very modular and seriously overuses - macros. Perhaps someday all C compilers will do as good a job - inlining modular code as can now be done by brute-force expansion, - but now, enough of them seem not to. - - Some compilers issue a lot of warnings about code that is - dead/unreachable only on some platforms, and also about intentional - uses of negation on unsigned types. All known cases of each can be - ignored. - - For a longer but out of date high-level description, see - http://gee.cs.oswego.edu/dl/html/malloc.html - -* MSPACES - If MSPACES is defined, then in addition to malloc, free, etc., - this file also defines mspace_malloc, mspace_free, etc. These - are versions of malloc routines that take an "mspace" argument - obtained using create_mspace, to control all internal bookkeeping. - If ONLY_MSPACES is defined, only these versions are compiled. - So if you would like to use this allocator for only some allocations, - and your system malloc for others, you can compile with - ONLY_MSPACES and then do something like... - static mspace mymspace = create_mspace(0,0); // for example - #define mymalloc(bytes) mspace_malloc(mymspace, bytes) - - (Note: If you only need one instance of an mspace, you can instead - use "USE_DL_PREFIX" to relabel the global malloc.) - - You can similarly create thread-local allocators by storing - mspaces as thread-locals. For example: - static __thread mspace tlms = 0; - void* tlmalloc(size_t bytes) { - if (tlms == 0) tlms = create_mspace(0, 0); - return mspace_malloc(tlms, bytes); - } - void tlfree(void* mem) { mspace_free(tlms, mem); } - - Unless FOOTERS is defined, each mspace is completely independent. - You cannot allocate from one and free to another (although - conformance is only weakly checked, so usage errors are not always - caught). If FOOTERS is defined, then each chunk carries around a tag - indicating its originating mspace, and frees are directed to their - originating spaces. - - ------------------------- Compile-time options --------------------------- - -Be careful in setting #define values for numerical constants of type -size_t. On some systems, literal values are not automatically extended -to size_t precision unless they are explicitly casted. - -WIN32 default: defined if _WIN32 defined - Defining WIN32 sets up defaults for MS environment and compilers. - Otherwise defaults are for unix. - -MALLOC_ALIGNMENT default: (size_t)8 - Controls the minimum alignment for malloc'ed chunks. It must be a - power of two and at least 8, even on machines for which smaller - alignments would suffice. It may be defined as larger than this - though. Note however that code and data structures are optimized for - the case of 8-byte alignment. - -MSPACES default: 0 (false) - If true, compile in support for independent allocation spaces. - This is only supported if HAVE_MMAP is true. - -ONLY_MSPACES default: 0 (false) - If true, only compile in mspace versions, not regular versions. - -USE_LOCKS default: 0 (false) - Causes each call to each public routine to be surrounded with - pthread or WIN32 mutex lock/unlock. (If set true, this can be - overridden on a per-mspace basis for mspace versions.) - -FOOTERS default: 0 - If true, provide extra checking and dispatching by placing - information in the footers of allocated chunks. This adds - space and time overhead. - -INSECURE default: 0 - If true, omit checks for usage errors and heap space overwrites. - -USE_DL_PREFIX default: NOT defined - Causes compiler to prefix all public routines with the string 'dl'. - This can be useful when you only want to use this malloc in one part - of a program, using your regular system malloc elsewhere. - -ABORT default: defined as abort() - Defines how to abort on failed checks. On most systems, a failed - check cannot die with an "assert" or even print an informative - message, because the underlying print routines in turn call malloc, - which will fail again. Generally, the best policy is to simply call - abort(). It's not very useful to do more than this because many - errors due to overwriting will show up as address faults (null, odd - addresses etc) rather than malloc-triggered checks, so will also - abort. Also, most compilers know that abort() does not return, so - can better optimize code conditionally calling it. - -PROCEED_ON_ERROR default: defined as 0 (false) - Controls whether detected bad addresses cause them to bypassed - rather than aborting. If set, detected bad arguments to free and - realloc are ignored. And all bookkeeping information is zeroed out - upon a detected overwrite of freed heap space, thus losing the - ability to ever return it from malloc again, but enabling the - application to proceed. If PROCEED_ON_ERROR is defined, the - static variable malloc_corruption_error_count is compiled in - and can be examined to see if errors have occurred. This option - generates slower code than the default abort policy. - -DEBUG default: NOT defined - The DEBUG setting is mainly intended for people trying to modify - this code or diagnose problems when porting to new platforms. - However, it may also be able to better isolate user errors than just - using runtime checks. The assertions in the check routines spell - out in more detail the assumptions and invariants underlying the - algorithms. The checking is fairly extensive, and will slow down - execution noticeably. Calling malloc_stats or mallinfo with DEBUG - set will attempt to check every non-mmapped allocated and free chunk - in the course of computing the summaries. - -ABORT_ON_ASSERT_FAILURE default: defined as 1 (true) - Debugging assertion failures can be nearly impossible if your - version of the assert macro causes malloc to be called, which will - lead to a cascade of further failures, blowing the runtime stack. - ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(), - which will usually make debugging easier. - -MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32 - The action to take before "return 0" when malloc fails to be able to - return memory because there is none available. - -HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES - True if this system supports sbrk or an emulation of it. - -MORECORE default: sbrk - The name of the sbrk-style system routine to call to obtain more - memory. See below for guidance on writing custom MORECORE - functions. The type of the argument to sbrk/MORECORE varies across - systems. It cannot be size_t, because it supports negative - arguments, so it is normally the signed type of the same width as - size_t (sometimes declared as "intptr_t"). It doesn't much matter - though. Internally, we only call it with arguments less than half - the max value of a size_t, which should work across all reasonable - possibilities, although sometimes generating compiler warnings. See - near the end of this file for guidelines for creating a custom - version of MORECORE. - -MORECORE_CONTIGUOUS default: 1 (true) - If true, take advantage of fact that consecutive calls to MORECORE - with positive arguments always return contiguous increasing - addresses. This is true of unix sbrk. It does not hurt too much to - set it true anyway, since malloc copes with non-contiguities. - Setting it false when definitely non-contiguous saves time - and possibly wasted space it would take to discover this though. - -MORECORE_CANNOT_TRIM default: NOT defined - True if MORECORE cannot release space back to the system when given - negative arguments. This is generally necessary only if you are - using a hand-crafted MORECORE function that cannot handle negative - arguments. - -HAVE_MMAP default: 1 (true) - True if this system supports mmap or an emulation of it. If so, and - HAVE_MORECORE is not true, MMAP is used for all system - allocation. If set and HAVE_MORECORE is true as well, MMAP is - primarily used to directly allocate very large blocks. It is also - used as a backup strategy in cases where MORECORE fails to provide - space from system. Note: A single call to MUNMAP is assumed to be - able to unmap memory that may have be allocated using multiple calls - to MMAP, so long as they are adjacent. - -HAVE_MREMAP default: 1 on linux, else 0 - If true realloc() uses mremap() to re-allocate large blocks and - extend or shrink allocation spaces. - -MMAP_CLEARS default: 1 on unix - True if mmap clears memory so calloc doesn't need to. This is true - for standard unix mmap using /dev/zero. - -USE_BUILTIN_FFS default: 0 (i.e., not used) - Causes malloc to use the builtin ffs() function to compute indices. - Some compilers may recognize and intrinsify ffs to be faster than the - supplied C version. Also, the case of x86 using gcc is special-cased - to an asm instruction, so is already as fast as it can be, and so - this setting has no effect. (On most x86s, the asm version is only - slightly faster than the C version.) - -malloc_getpagesize default: derive from system includes, or 4096. - The system page size. To the extent possible, this malloc manages - memory from the system in page-size units. This may be (and - usually is) a function rather than a constant. This is ignored - if WIN32, where page size is determined using getSystemInfo during - initialization. - -USE_DEV_RANDOM default: 0 (i.e., not used) - Causes malloc to use /dev/random to initialize secure magic seed for - stamping footers. Otherwise, the current time is used. - -NO_MALLINFO default: 0 - If defined, don't compile "mallinfo". This can be a simple way - of dealing with mismatches between system declarations and - those in this file. - -MALLINFO_FIELD_TYPE default: size_t - The type of the fields in the mallinfo struct. This was originally - defined as "int" in SVID etc, but is more usefully defined as - size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set - -REALLOC_ZERO_BYTES_FREES default: not defined - This should be set if a call to realloc with zero bytes should - be the same as a call to free. Some people think it should. Otherwise, - since this malloc returns a unique pointer for malloc(0), so does - realloc(p, 0). - -LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H -LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H -LACKS_STDLIB_H default: NOT defined unless on WIN32 - Define these if your system does not have these header files. - You might need to manually insert some of the declarations they provide. - -DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS, - system_info.dwAllocationGranularity in WIN32, - otherwise 64K. - Also settable using mallopt(M_GRANULARITY, x) - The unit for allocating and deallocating memory from the system. On - most systems with contiguous MORECORE, there is no reason to - make this more than a page. However, systems with MMAP tend to - either require or encourage larger granularities. You can increase - this value to prevent system allocation functions to be called so - often, especially if they are slow. The value must be at least one - page and must be a power of two. Setting to 0 causes initialization - to either page size or win32 region size. (Note: In previous - versions of malloc, the equivalent of this option was called - "TOP_PAD") - -DEFAULT_TRIM_THRESHOLD default: 2MB - Also settable using mallopt(M_TRIM_THRESHOLD, x) - The maximum amount of unused top-most memory to keep before - releasing via malloc_trim in free(). Automatic trimming is mainly - useful in long-lived programs using contiguous MORECORE. Because - trimming via sbrk can be slow on some systems, and can sometimes be - wasteful (in cases where programs immediately afterward allocate - more large chunks) the value should be high enough so that your - overall system performance would improve by releasing this much - memory. As a rough guide, you might set to a value close to the - average size of a process (program) running on your system. - Releasing this much memory would allow such a process to run in - memory. Generally, it is worth tuning trim thresholds when a - program undergoes phases where several large chunks are allocated - and released in ways that can reuse each other's storage, perhaps - mixed with phases where there are no such chunks at all. The trim - value must be greater than page size to have any useful effect. To - disable trimming completely, you can set to MAX_SIZE_T. Note that the trick - some people use of mallocing a huge space and then freeing it at - program startup, in an attempt to reserve system memory, doesn't - have the intended effect under automatic trimming, since that memory - will immediately be returned to the system. - -DEFAULT_MMAP_THRESHOLD default: 256K - Also settable using mallopt(M_MMAP_THRESHOLD, x) - The request size threshold for using MMAP to directly service a - request. Requests of at least this size that cannot be allocated - using already-existing space will be serviced via mmap. (If enough - normal freed space already exists it is used instead.) Using mmap - segregates relatively large chunks of memory so that they can be - individually obtained and released from the host system. A request - serviced through mmap is never reused by any other request (at least - not directly; the system may just so happen to remap successive - requests to the same locations). Segregating space in this way has - the benefits that: Mmapped space can always be individually released - back to the system, which helps keep the system level memory demands - of a long-lived program low. Also, mapped memory doesn't become - `locked' between other chunks, as can happen with normally allocated - chunks, which means that even trimming via malloc_trim would not - release them. However, it has the disadvantage that the space - cannot be reclaimed, consolidated, and then used to service later - requests, as happens with normal chunks. The advantages of mmap - nearly always outweigh disadvantages for "large" chunks, but the - value of "large" may vary across systems. The default is an - empirically derived value that works well in most systems. You can - disable mmap by setting to MAX_SIZE_T. - -*/ -#if defined(__WATCOMC__) || defined(_MSC_VER) -#define WIN32 1 -#endif - -#ifndef WIN32 -#ifdef _WIN32 -#define WIN32 1 -#endif /* _WIN32 */ -#endif /* WIN32 */ -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#define HAVE_MORECORE 0 -#define LACKS_UNISTD_H -#define LACKS_SYS_PARAM_H -#define LACKS_SYS_MMAN_H -#define LACKS_STRING_H -#define LACKS_STRINGS_H -#define LACKS_SYS_TYPES_H -#define LACKS_ERRNO_H -#define MALLOC_FAILURE_ACTION -#define MMAP_CLEARS 0 /* WINCE and some others apparently don't clear */ -#endif /* WIN32 */ - -#if defined(DARWIN) || defined(_DARWIN) -/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ -#ifndef HAVE_MORECORE -#define HAVE_MORECORE 0 -#define HAVE_MMAP 1 -#endif /* HAVE_MORECORE */ -#endif /* DARWIN */ - -#ifndef LACKS_SYS_TYPES_H -#include <sys/types.h> /* For size_t */ -#endif /* LACKS_SYS_TYPES_H */ - -/* The maximum possible size_t value has all bits set */ -#define MAX_SIZE_T (~(size_t)0) - -#ifndef ONLY_MSPACES -#define ONLY_MSPACES 0 -#endif /* ONLY_MSPACES */ -#ifndef MSPACES -#if ONLY_MSPACES -#define MSPACES 1 -#else /* ONLY_MSPACES */ -#define MSPACES 0 -#endif /* ONLY_MSPACES */ -#endif /* MSPACES */ -#ifndef MALLOC_ALIGNMENT -#define MALLOC_ALIGNMENT ((size_t)8U) -#endif /* MALLOC_ALIGNMENT */ -#ifndef FOOTERS -#define FOOTERS 0 -#endif /* FOOTERS */ -#ifndef ABORT -#define ABORT abort() -#endif /* ABORT */ -#ifndef ABORT_ON_ASSERT_FAILURE -#define ABORT_ON_ASSERT_FAILURE 1 -#endif /* ABORT_ON_ASSERT_FAILURE */ -#ifndef PROCEED_ON_ERROR -#define PROCEED_ON_ERROR 0 -#endif /* PROCEED_ON_ERROR */ -#ifndef USE_LOCKS -#define USE_LOCKS 0 -#endif /* USE_LOCKS */ -#ifndef INSECURE -#define INSECURE 0 -#endif /* INSECURE */ -#ifndef HAVE_MMAP -#define HAVE_MMAP 1 -#endif /* HAVE_MMAP */ -#ifndef MMAP_CLEARS -#define MMAP_CLEARS 1 -#endif /* MMAP_CLEARS */ -#ifndef HAVE_MREMAP -#ifdef linux -#define HAVE_MREMAP 1 -#else /* linux */ -#define HAVE_MREMAP 0 -#endif /* linux */ -#endif /* HAVE_MREMAP */ -#ifndef MALLOC_FAILURE_ACTION -#define MALLOC_FAILURE_ACTION errno = ENOMEM; -#endif /* MALLOC_FAILURE_ACTION */ -#ifndef HAVE_MORECORE -#if ONLY_MSPACES -#define HAVE_MORECORE 0 -#else /* ONLY_MSPACES */ -#define HAVE_MORECORE 1 -#endif /* ONLY_MSPACES */ -#endif /* HAVE_MORECORE */ -#if !HAVE_MORECORE -#define MORECORE_CONTIGUOUS 0 -#else /* !HAVE_MORECORE */ -#ifndef MORECORE -#define MORECORE sbrk -#endif /* MORECORE */ -#ifndef MORECORE_CONTIGUOUS -#define MORECORE_CONTIGUOUS 1 -#endif /* MORECORE_CONTIGUOUS */ -#endif /* HAVE_MORECORE */ -#ifndef DEFAULT_GRANULARITY -#if MORECORE_CONTIGUOUS -#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ -#else /* MORECORE_CONTIGUOUS */ -#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) -#endif /* MORECORE_CONTIGUOUS */ -#endif /* DEFAULT_GRANULARITY */ -#ifndef DEFAULT_TRIM_THRESHOLD -#ifndef MORECORE_CANNOT_TRIM -#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) -#else /* MORECORE_CANNOT_TRIM */ -#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T -#endif /* MORECORE_CANNOT_TRIM */ -#endif /* DEFAULT_TRIM_THRESHOLD */ -#ifndef DEFAULT_MMAP_THRESHOLD -#if HAVE_MMAP -#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) -#else /* HAVE_MMAP */ -#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T -#endif /* HAVE_MMAP */ -#endif /* DEFAULT_MMAP_THRESHOLD */ -#ifndef USE_BUILTIN_FFS -#define USE_BUILTIN_FFS 0 -#endif /* USE_BUILTIN_FFS */ -#ifndef USE_DEV_RANDOM -#define USE_DEV_RANDOM 0 -#endif /* USE_DEV_RANDOM */ -#ifndef NO_MALLINFO -#define NO_MALLINFO 0 -#endif /* NO_MALLINFO */ -#ifndef MALLINFO_FIELD_TYPE -#define MALLINFO_FIELD_TYPE size_t -#endif /* MALLINFO_FIELD_TYPE */ - -/* - mallopt tuning options. SVID/XPG defines four standard parameter - numbers for mallopt, normally defined in malloc.h. None of these - are used in this malloc, so setting them has no effect. But this - malloc does support the following options. -*/ - -#define M_TRIM_THRESHOLD (-1) -#define M_GRANULARITY (-2) -#define M_MMAP_THRESHOLD (-3) - -/* ------------------------ Mallinfo declarations ------------------------ */ - -#if !NO_MALLINFO -/* - This version of malloc supports the standard SVID/XPG mallinfo - routine that returns a struct containing usage properties and - statistics. It should work on any system that has a - /usr/include/malloc.h defining struct mallinfo. The main - declaration needed is the mallinfo struct that is returned (by-copy) - by mallinfo(). The malloinfo struct contains a bunch of fields that - are not even meaningful in this version of malloc. These fields are - are instead filled by mallinfo() with other numbers that might be of - interest. - - HAVE_USR_INCLUDE_MALLOC_H should be set if you have a - /usr/include/malloc.h file that includes a declaration of struct - mallinfo. If so, it is included; else a compliant version is - declared below. These must be precisely the same for mallinfo() to - work. The original SVID version of this struct, defined on most - systems with mallinfo, declares all fields as ints. But some others - define as unsigned long. If your system defines the fields using a - type of different width than listed here, you MUST #include your - system version and #define HAVE_USR_INCLUDE_MALLOC_H. -*/ - -/* #define HAVE_USR_INCLUDE_MALLOC_H */ - -#ifdef HAVE_USR_INCLUDE_MALLOC_H -#include "/usr/include/malloc.h" -#else /* HAVE_USR_INCLUDE_MALLOC_H */ - -struct mallinfo { - MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ - MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ - MALLINFO_FIELD_TYPE smblks; /* always 0 */ - MALLINFO_FIELD_TYPE hblks; /* always 0 */ - MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ - MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ - MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ - MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ - MALLINFO_FIELD_TYPE fordblks; /* total free space */ - MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ -}; - -#endif /* HAVE_USR_INCLUDE_MALLOC_H */ -#endif /* NO_MALLINFO */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#if !ONLY_MSPACES - -/* ------------------- Declarations of public routines ------------------- */ - -#ifndef USE_DL_PREFIX -#define dlcalloc calloc -#define dlfree free -#define dlmalloc malloc -#define dlmemalign memalign -#define dlrealloc realloc -#define dlvalloc valloc -#define dlpvalloc pvalloc -#define dlmallinfo mallinfo -#define dlmallopt mallopt -#define dlmalloc_trim malloc_trim -#define dlmalloc_stats malloc_stats -#define dlmalloc_usable_size malloc_usable_size -#define dlmalloc_footprint malloc_footprint -#define dlmalloc_max_footprint malloc_max_footprint -#define dlindependent_calloc independent_calloc -#define dlindependent_comalloc independent_comalloc -#endif /* USE_DL_PREFIX */ - - -/* - malloc(size_t n) - Returns a pointer to a newly allocated chunk of at least n bytes, or - null if no space is available, in which case errno is set to ENOMEM - on ANSI C systems. - - If n is zero, malloc returns a minimum-sized chunk. (The minimum - size is 16 bytes on most 32bit systems, and 32 bytes on 64bit - systems.) Note that size_t is an unsigned type, so calls with - arguments that would be negative if signed are interpreted as - requests for huge amounts of space, which will often fail. The - maximum supported value of n differs across systems, but is in all - cases less than the maximum representable value of a size_t. -*/ -void* dlmalloc(size_t); - -/* - free(void* p) - Releases the chunk of memory pointed to by p, that had been previously - allocated using malloc or a related routine such as realloc. - It has no effect if p is null. If p was not malloced or already - freed, free(p) will by default cause the current program to abort. -*/ -void dlfree(void*); - -/* - calloc(size_t n_elements, size_t element_size); - Returns a pointer to n_elements * element_size bytes, with all locations - set to zero. -*/ -void* dlcalloc(size_t, size_t); - -/* - realloc(void* p, size_t n) - Returns a pointer to a chunk of size n that contains the same data - as does chunk p up to the minimum of (n, p's size) bytes, or null - if no space is available. - - The returned pointer may or may not be the same as p. The algorithm - prefers extending p in most cases when possible, otherwise it - employs the equivalent of a malloc-copy-free sequence. - - If p is null, realloc is equivalent to malloc. - - If space is not available, realloc returns null, errno is set (if on - ANSI) and p is NOT freed. - - if n is for fewer bytes than already held by p, the newly unused - space is lopped off and freed if possible. realloc with a size - argument of zero (re)allocates a minimum-sized chunk. - - The old unix realloc convention of allowing the last-free'd chunk - to be used as an argument to realloc is not supported. -*/ - -void* dlrealloc(void*, size_t); - -/* - memalign(size_t alignment, size_t n); - Returns a pointer to a newly allocated chunk of n bytes, aligned - in accord with the alignment argument. - - The alignment argument should be a power of two. If the argument is - not a power of two, the nearest greater power is used. - 8-byte alignment is guaranteed by normal malloc calls, so don't - bother calling memalign with an argument of 8 or less. - - Overreliance on memalign is a sure way to fragment space. -*/ -void* dlmemalign(size_t, size_t); - -/* - valloc(size_t n); - Equivalent to memalign(pagesize, n), where pagesize is the page - size of the system. If the pagesize is unknown, 4096 is used. -*/ -void* dlvalloc(size_t); - -/* - mallopt(int parameter_number, int parameter_value) - Sets tunable parameters The format is to provide a - (parameter-number, parameter-value) pair. mallopt then sets the - corresponding parameter to the argument value if it can (i.e., so - long as the value is meaningful), and returns 1 if successful else - 0. SVID/XPG/ANSI defines four standard param numbers for mallopt, - normally defined in malloc.h. None of these are use in this malloc, - so setting them has no effect. But this malloc also supports other - options in mallopt. See below for details. Briefly, supported - parameters are as follows (listed defaults are for "typical" - configurations). - - Symbol param # default allowed param values - M_TRIM_THRESHOLD -1 2*1024*1024 any (MAX_SIZE_T disables) - M_GRANULARITY -2 page size any power of 2 >= page size - M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) -*/ -int dlmallopt(int, int); - -/* - malloc_footprint(); - Returns the number of bytes obtained from the system. The total - number of bytes allocated by malloc, realloc etc., is less than this - value. Unlike mallinfo, this function returns only a precomputed - result, so can be called frequently to monitor memory consumption. - Even if locks are otherwise defined, this function does not use them, - so results might not be up to date. -*/ -size_t dlmalloc_footprint(void); - -/* - malloc_max_footprint(); - Returns the maximum number of bytes obtained from the system. This - value will be greater than current footprint if deallocated space - has been reclaimed by the system. The peak number of bytes allocated - by malloc, realloc etc., is less than this value. Unlike mallinfo, - this function returns only a precomputed result, so can be called - frequently to monitor memory consumption. Even if locks are - otherwise defined, this function does not use them, so results might - not be up to date. -*/ -size_t dlmalloc_max_footprint(void); - -#if !NO_MALLINFO -/* - mallinfo() - Returns (by copy) a struct containing various summary statistics: - - arena: current total non-mmapped bytes allocated from system - ordblks: the number of free chunks - smblks: always zero. - hblks: current number of mmapped regions - hblkhd: total bytes held in mmapped regions - usmblks: the maximum total allocated space. This will be greater - than current total if trimming has occurred. - fsmblks: always zero - uordblks: current total allocated space (normal or mmapped) - fordblks: total free space - keepcost: the maximum number of bytes that could ideally be released - back to system via malloc_trim. ("ideally" means that - it ignores page restrictions etc.) - - Because these fields are ints, but internal bookkeeping may - be kept as longs, the reported values may wrap around zero and - thus be inaccurate. -*/ -struct mallinfo dlmallinfo(void); -#endif /* NO_MALLINFO */ - -/* - independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); - - independent_calloc is similar to calloc, but instead of returning a - single cleared space, it returns an array of pointers to n_elements - independent elements that can hold contents of size elem_size, each - of which starts out cleared, and can be independently freed, - realloc'ed etc. The elements are guaranteed to be adjacently - allocated (this is not guaranteed to occur with multiple callocs or - mallocs), which may also improve cache locality in some - applications. - - The "chunks" argument is optional (i.e., may be null, which is - probably the most typical usage). If it is null, the returned array - is itself dynamically allocated and should also be freed when it is - no longer needed. Otherwise, the chunks array must be of at least - n_elements in length. It is filled in with the pointers to the - chunks. - - In either case, independent_calloc returns this pointer array, or - null if the allocation failed. If n_elements is zero and "chunks" - is null, it returns a chunk representing an array with zero elements - (which should be freed if not wanted). - - Each element must be individually freed when it is no longer - needed. If you'd like to instead be able to free all at once, you - should instead use regular calloc and assign pointers into this - space to represent elements. (In this case though, you cannot - independently free elements.) - - independent_calloc simplifies and speeds up implementations of many - kinds of pools. It may also be useful when constructing large data - structures that initially have a fixed number of fixed-sized nodes, - but the number is not known at compile time, and some of the nodes - may later need to be freed. For example: - - struct Node { int item; struct Node* next; }; - - struct Node* build_list() { - struct Node** pool; - int n = read_number_of_nodes_needed(); - if (n <= 0) return 0; - pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); - if (pool == 0) die(); - // organize into a linked list... - struct Node* first = pool[0]; - for (i = 0; i < n-1; ++i) - pool[i]->next = pool[i+1]; - free(pool); // Can now free the array (or not, if it is needed later) - return first; - } -*/ -void** dlindependent_calloc(size_t, size_t, void**); - -/* - independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); - - independent_comalloc allocates, all at once, a set of n_elements - chunks with sizes indicated in the "sizes" array. It returns - an array of pointers to these elements, each of which can be - independently freed, realloc'ed etc. The elements are guaranteed to - be adjacently allocated (this is not guaranteed to occur with - multiple callocs or mallocs), which may also improve cache locality - in some applications. - - The "chunks" argument is optional (i.e., may be null). If it is null - the returned array is itself dynamically allocated and should also - be freed when it is no longer needed. Otherwise, the chunks array - must be of at least n_elements in length. It is filled in with the - pointers to the chunks. - - In either case, independent_comalloc returns this pointer array, or - null if the allocation failed. If n_elements is zero and chunks is - null, it returns a chunk representing an array with zero elements - (which should be freed if not wanted). - - Each element must be individually freed when it is no longer - needed. If you'd like to instead be able to free all at once, you - should instead use a single regular malloc, and assign pointers at - particular offsets in the aggregate space. (In this case though, you - cannot independently free elements.) - - independent_comallac differs from independent_calloc in that each - element may have a different size, and also that it does not - automatically clear elements. - - independent_comalloc can be used to speed up allocation in cases - where several structs or objects must always be allocated at the - same time. For example: - - struct Head { ... } - struct Foot { ... } - - void send_message(char* msg) { - int msglen = strlen(msg); - size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; - void* chunks[3]; - if (independent_comalloc(3, sizes, chunks) == 0) - die(); - struct Head* head = (struct Head*)(chunks[0]); - char* body = (char*)(chunks[1]); - struct Foot* foot = (struct Foot*)(chunks[2]); - // ... - } - - In general though, independent_comalloc is worth using only for - larger values of n_elements. For small values, you probably won't - detect enough difference from series of malloc calls to bother. - - Overuse of independent_comalloc can increase overall memory usage, - since it cannot reuse existing noncontiguous small chunks that - might be available for some of the elements. -*/ -void** dlindependent_comalloc(size_t, size_t*, void**); - - -/* - pvalloc(size_t n); - Equivalent to valloc(minimum-page-that-holds(n)), that is, - round up n to nearest pagesize. - */ -void* dlpvalloc(size_t); - -/* - malloc_trim(size_t pad); - - If possible, gives memory back to the system (via negative arguments - to sbrk) if there is unused memory at the `high' end of the malloc - pool or in unused MMAP segments. You can call this after freeing - large blocks of memory to potentially reduce the system-level memory - requirements of a program. However, it cannot guarantee to reduce - memory. Under some allocation patterns, some large free blocks of - memory will be locked between two used chunks, so they cannot be - given back to the system. - - The `pad' argument to malloc_trim represents the amount of free - trailing space to leave untrimmed. If this argument is zero, only - the minimum amount of memory to maintain internal data structures - will be left. Non-zero arguments can be supplied to maintain enough - trailing space to service future expected allocations without having - to re-obtain memory from the system. - - Malloc_trim returns 1 if it actually released any memory, else 0. -*/ -int dlmalloc_trim(size_t); - -/* - malloc_usable_size(void* p); - - Returns the number of bytes you can actually use in - an allocated chunk, which may be more than you requested (although - often not) due to alignment and minimum size constraints. - You can use this many bytes without worrying about - overwriting other allocated objects. This is not a particularly great - programming practice. malloc_usable_size can be more useful in - debugging and assertions, for example: - - p = malloc(n); - assert(malloc_usable_size(p) >= 256); -*/ -size_t dlmalloc_usable_size(void*); - -/* - malloc_stats(); - Prints on stderr the amount of space obtained from the system (both - via sbrk and mmap), the maximum amount (which may be more than - current if malloc_trim and/or munmap got called), and the current - number of bytes allocated via malloc (or realloc, etc) but not yet - freed. Note that this is the number of bytes allocated, not the - number requested. It will be larger than the number requested - because of alignment and bookkeeping overhead. Because it includes - alignment wastage as being in use, this figure may be greater than - zero even when no user-level chunks are allocated. - - The reported current and maximum system memory can be inaccurate if - a program makes other calls to system memory allocation functions - (normally sbrk) outside of malloc. - - malloc_stats prints only the most commonly interesting statistics. - More information can be obtained by calling mallinfo. -*/ -void dlmalloc_stats(void); - -#endif /* ONLY_MSPACES */ - -#if MSPACES - -/* - mspace is an opaque type representing an independent - region of space that supports mspace_malloc, etc. -*/ -typedef void* mspace; - -/* - create_mspace creates and returns a new independent space with the - given initial capacity, or, if 0, the default granularity size. It - returns null if there is no system memory available to create the - space. If argument locked is non-zero, the space uses a separate - lock to control access. The capacity of the space will grow - dynamically as needed to service mspace_malloc requests. You can - control the sizes of incremental increases of this space by - compiling with a different DEFAULT_GRANULARITY or dynamically - setting with mallopt(M_GRANULARITY, value). -*/ -mspace create_mspace(size_t capacity, int locked); - -/* - destroy_mspace destroys the given space, and attempts to return all - of its memory back to the system, returning the total number of - bytes freed. After destruction, the results of access to all memory - used by the space become undefined. -*/ -size_t destroy_mspace(mspace msp); - -/* - create_mspace_with_base uses the memory supplied as the initial base - of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this - space is used for bookkeeping, so the capacity must be at least this - large. (Otherwise 0 is returned.) When this initial space is - exhausted, additional memory will be obtained from the system. - Destroying this space will deallocate all additionally allocated - space (if possible) but not the initial base. -*/ -mspace create_mspace_with_base(void* base, size_t capacity, int locked); - -/* - mspace_malloc behaves as malloc, but operates within - the given space. -*/ -void* mspace_malloc(mspace msp, size_t bytes); - -/* - mspace_free behaves as free, but operates within - the given space. - - If compiled with FOOTERS==1, mspace_free is not actually needed. - free may be called instead of mspace_free because freed chunks from - any space are handled by their originating spaces. -*/ -void mspace_free(mspace msp, void* mem); - -/* - mspace_realloc behaves as realloc, but operates within - the given space. - - If compiled with FOOTERS==1, mspace_realloc is not actually - needed. realloc may be called instead of mspace_realloc because - realloced chunks from any space are handled by their originating - spaces. -*/ -void* mspace_realloc(mspace msp, void* mem, size_t newsize); - -/* - mspace_calloc behaves as calloc, but operates within - the given space. -*/ -void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); - -/* - mspace_memalign behaves as memalign, but operates within - the given space. -*/ -void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); - -/* - mspace_independent_calloc behaves as independent_calloc, but - operates within the given space. -*/ -void** mspace_independent_calloc(mspace msp, size_t n_elements, - size_t elem_size, void* chunks[]); - -/* - mspace_independent_comalloc behaves as independent_comalloc, but - operates within the given space. -*/ -void** mspace_independent_comalloc(mspace msp, size_t n_elements, - size_t sizes[], void* chunks[]); - -/* - mspace_footprint() returns the number of bytes obtained from the - system for this space. -*/ -size_t mspace_footprint(mspace msp); - -/* - mspace_max_footprint() returns the peak number of bytes obtained from the - system for this space. -*/ -size_t mspace_max_footprint(mspace msp); - - -#if !NO_MALLINFO -/* - mspace_mallinfo behaves as mallinfo, but reports properties of - the given space. -*/ -struct mallinfo mspace_mallinfo(mspace msp); -#endif /* NO_MALLINFO */ - -/* - mspace_malloc_stats behaves as malloc_stats, but reports - properties of the given space. -*/ -void mspace_malloc_stats(mspace msp); - -/* - mspace_trim behaves as malloc_trim, but - operates within the given space. -*/ -int mspace_trim(mspace msp, size_t pad); - -/* - An alias for mallopt. -*/ -int mspace_mallopt(int, int); - -#endif /* MSPACES */ - -#ifdef __cplusplus -}; /* end of extern "C" */ -#endif /* __cplusplus */ - -/* - ======================================================================== - To make a fully customizable malloc.h header file, cut everything - above this line, put into file malloc.h, edit to suit, and #include it - on the next line, as well as in programs that use this malloc. - ======================================================================== -*/ - -/* #include "malloc.h" */ - -/*------------------------------ internal #includes ---------------------- */ - -#ifdef WIN32 -#pragma warning( disable : 4146 ) /* no "unsigned" warnings */ -#endif /* WIN32 */ - -#include <stdio.h> /* for printing in malloc_stats */ - -#ifndef LACKS_ERRNO_H -#include <errno.h> /* for MALLOC_FAILURE_ACTION */ -#endif /* LACKS_ERRNO_H */ -#if FOOTERS -#include <time.h> /* for magic initialization */ -#endif /* FOOTERS */ -#ifndef LACKS_STDLIB_H -#include <stdlib.h> /* for abort() */ -#endif /* LACKS_STDLIB_H */ -#ifdef DEBUG -#if ABORT_ON_ASSERT_FAILURE -#define assert(x) if(!(x)) ABORT -#else /* ABORT_ON_ASSERT_FAILURE */ -#include <assert.h> -#endif /* ABORT_ON_ASSERT_FAILURE */ -#else /* DEBUG */ -#define assert(x) -#endif /* DEBUG */ -#ifndef LACKS_STRING_H -#include <string.h> /* for memset etc */ -#endif /* LACKS_STRING_H */ -#if USE_BUILTIN_FFS -#ifndef LACKS_STRINGS_H -#include <strings.h> /* for ffs */ -#endif /* LACKS_STRINGS_H */ -#endif /* USE_BUILTIN_FFS */ -#if HAVE_MMAP -#ifndef LACKS_SYS_MMAN_H -#include <sys/mman.h> /* for mmap */ -#endif /* LACKS_SYS_MMAN_H */ -#ifndef LACKS_FCNTL_H -#include <fcntl.h> -#endif /* LACKS_FCNTL_H */ -#endif /* HAVE_MMAP */ -#if HAVE_MORECORE -#ifndef LACKS_UNISTD_H -#include <unistd.h> /* for sbrk */ -#else /* LACKS_UNISTD_H */ -#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) -extern void* sbrk(ptrdiff_t); -#endif /* FreeBSD etc */ -#endif /* LACKS_UNISTD_H */ -#endif /* HAVE_MMAP */ - -#ifndef WIN32 -#ifndef malloc_getpagesize -# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ -# ifndef _SC_PAGE_SIZE -# define _SC_PAGE_SIZE _SC_PAGESIZE -# endif -# endif -# ifdef _SC_PAGE_SIZE -# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) -# else -# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) - extern size_t getpagesize(); -# define malloc_getpagesize getpagesize() -# else -# ifdef WIN32 /* use supplied emulation of getpagesize */ -# define malloc_getpagesize getpagesize() -# else -# ifndef LACKS_SYS_PARAM_H -# include <sys/param.h> -# endif -# ifdef EXEC_PAGESIZE -# define malloc_getpagesize EXEC_PAGESIZE -# else -# ifdef NBPG -# ifndef CLSIZE -# define malloc_getpagesize NBPG -# else -# define malloc_getpagesize (NBPG * CLSIZE) -# endif -# else -# ifdef NBPC -# define malloc_getpagesize NBPC -# else -# ifdef PAGESIZE -# define malloc_getpagesize PAGESIZE -# else /* just guess */ -# define malloc_getpagesize ((size_t)4096U) -# endif -# endif -# endif -# endif -# endif -# endif -# endif -#endif -#endif - -/* ------------------- size_t and alignment properties -------------------- */ - -/* The byte and bit size of a size_t */ -#define SIZE_T_SIZE (sizeof(size_t)) -#define SIZE_T_BITSIZE (sizeof(size_t) << 3) - -/* Some constants coerced to size_t */ -/* Annoying but necessary to avoid errors on some plaftorms */ -#define SIZE_T_ZERO ((size_t)0) -#define SIZE_T_ONE ((size_t)1) -#define SIZE_T_TWO ((size_t)2) -#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) -#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) -#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) -#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) - -/* The bit mask value corresponding to MALLOC_ALIGNMENT */ -#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) - -/* True if address a has acceptable alignment */ -#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) - -/* the number of bytes to offset an address to align it */ -#define align_offset(A)\ - ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ - ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) - -/* -------------------------- MMAP preliminaries ------------------------- */ - -/* - If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and - checks to fail so compiler optimizer can delete code rather than - using so many "#if"s. -*/ - - -/* MORECORE and MMAP must return MFAIL on failure */ -#define MFAIL ((void*)(MAX_SIZE_T)) -#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ - -#if !HAVE_MMAP -#define IS_MMAPPED_BIT (SIZE_T_ZERO) -#define USE_MMAP_BIT (SIZE_T_ZERO) -#define CALL_MMAP(s) MFAIL -#define CALL_MUNMAP(a, s) (-1) -#define DIRECT_MMAP(s) MFAIL - -#else /* HAVE_MMAP */ -#define IS_MMAPPED_BIT (SIZE_T_ONE) -#define USE_MMAP_BIT (SIZE_T_ONE) - -#ifndef WIN32 -#define CALL_MUNMAP(a, s) munmap((a), (s)) -#define MMAP_PROT (PROT_READ|PROT_WRITE) -#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) -#define MAP_ANONYMOUS MAP_ANON -#endif /* MAP_ANON */ -#ifdef MAP_ANONYMOUS -#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) -#define CALL_MMAP(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0) -#else /* MAP_ANONYMOUS */ -/* - Nearly all versions of mmap support MAP_ANONYMOUS, so the following - is unlikely to be needed, but is supplied just in case. -*/ -#define MMAP_FLAGS (MAP_PRIVATE) -static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ -#define CALL_MMAP(s) ((dev_zero_fd < 0) ? \ - (dev_zero_fd = open("/dev/zero", O_RDWR), \ - mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ - mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) -#endif /* MAP_ANONYMOUS */ - -#define DIRECT_MMAP(s) CALL_MMAP(s) -#else /* WIN32 */ - -/* Win32 MMAP via VirtualAlloc */ -static void* win32mmap(size_t size) { - void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); - return (ptr != 0)? ptr: MFAIL; -} - -/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ -static void* win32direct_mmap(size_t size) { - void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, - PAGE_READWRITE); - return (ptr != 0)? ptr: MFAIL; -} - -/* This function supports releasing coalesed segments */ -static int win32munmap(void* ptr, size_t size) { - MEMORY_BASIC_INFORMATION minfo; - char* cptr = ptr; - while (size) { - if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) - return -1; - if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || - minfo.State != MEM_COMMIT || minfo.RegionSize > size) - return -1; - if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) - return -1; - cptr += minfo.RegionSize; - size -= minfo.RegionSize; - } - return 0; -} - -#define CALL_MMAP(s) win32mmap(s) -#define CALL_MUNMAP(a, s) win32munmap((a), (s)) -#define DIRECT_MMAP(s) win32direct_mmap(s) -#endif /* WIN32 */ -#endif /* HAVE_MMAP */ - -#if HAVE_MMAP && HAVE_MREMAP -#define CALL_MREMAP(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv)) -#else /* HAVE_MMAP && HAVE_MREMAP */ -#define CALL_MREMAP(addr, osz, nsz, mv) MFAIL -#endif /* HAVE_MMAP && HAVE_MREMAP */ - -#if HAVE_MORECORE -#define CALL_MORECORE(S) MORECORE(S) -#else /* HAVE_MORECORE */ -#define CALL_MORECORE(S) MFAIL -#endif /* HAVE_MORECORE */ - -/* mstate bit set if continguous morecore disabled or failed */ -#define USE_NONCONTIGUOUS_BIT (4U) - -/* segment bit set in create_mspace_with_base */ -#define EXTERN_BIT (8U) - - -/* --------------------------- Lock preliminaries ------------------------ */ - -#if USE_LOCKS - -/* - When locks are defined, there are up to two global locks: - - * If HAVE_MORECORE, morecore_mutex protects sequences of calls to - MORECORE. In many cases sys_alloc requires two calls, that should - not be interleaved with calls by other threads. This does not - protect against direct calls to MORECORE by other threads not - using this lock, so there is still code to cope the best we can on - interference. - - * magic_init_mutex ensures that mparams.magic and other - unique mparams values are initialized only once. -*/ - -#ifndef WIN32 -/* By default use posix locks */ -#include <pthread.h> -#define MLOCK_T pthread_mutex_t -#define INITIAL_LOCK(l) pthread_mutex_init(l, NULL) -#define ACQUIRE_LOCK(l) pthread_mutex_lock(l) -#define RELEASE_LOCK(l) pthread_mutex_unlock(l) - -#if HAVE_MORECORE -static MLOCK_T morecore_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif /* HAVE_MORECORE */ - -static MLOCK_T magic_init_mutex = PTHREAD_MUTEX_INITIALIZER; - -#else /* WIN32 */ -/* - Because lock-protected regions have bounded times, and there - are no recursive lock calls, we can use simple spinlocks. -*/ - -#define MLOCK_T long -static int win32_acquire_lock (MLOCK_T *sl) { - for (;;) { -#ifdef InterlockedCompareExchangePointer - if (!InterlockedCompareExchange(sl, 1, 0)) - return 0; -#else /* Use older void* version */ - if (!InterlockedCompareExchange((void**)sl, (void*)1, (void*)0)) - return 0; -#endif /* InterlockedCompareExchangePointer */ - Sleep (0); - } -} - -static void win32_release_lock (MLOCK_T *sl) { - InterlockedExchange (sl, 0); -} - -#define INITIAL_LOCK(l) *(l)=0 -#define ACQUIRE_LOCK(l) win32_acquire_lock(l) -#define RELEASE_LOCK(l) win32_release_lock(l) -#if HAVE_MORECORE -static MLOCK_T morecore_mutex; -#endif /* HAVE_MORECORE */ -static MLOCK_T magic_init_mutex; -#endif /* WIN32 */ - -#define USE_LOCK_BIT (2U) -#else /* USE_LOCKS */ -#define USE_LOCK_BIT (0U) -#define INITIAL_LOCK(l) -#endif /* USE_LOCKS */ - -#if USE_LOCKS && HAVE_MORECORE -#define ACQUIRE_MORECORE_LOCK() ACQUIRE_LOCK(&morecore_mutex); -#define RELEASE_MORECORE_LOCK() RELEASE_LOCK(&morecore_mutex); -#else /* USE_LOCKS && HAVE_MORECORE */ -#define ACQUIRE_MORECORE_LOCK() -#define RELEASE_MORECORE_LOCK() -#endif /* USE_LOCKS && HAVE_MORECORE */ - -#if USE_LOCKS -#define ACQUIRE_MAGIC_INIT_LOCK() ACQUIRE_LOCK(&magic_init_mutex); -#define RELEASE_MAGIC_INIT_LOCK() RELEASE_LOCK(&magic_init_mutex); -#else /* USE_LOCKS */ -#define ACQUIRE_MAGIC_INIT_LOCK() -#define RELEASE_MAGIC_INIT_LOCK() -#endif /* USE_LOCKS */ - - -/* ----------------------- Chunk representations ------------------------ */ - -/* - (The following includes lightly edited explanations by Colin Plumb.) - - The malloc_chunk declaration below is misleading (but accurate and - necessary). It declares a "view" into memory allowing access to - necessary fields at known offsets from a given base. - - Chunks of memory are maintained using a `boundary tag' method as - originally described by Knuth. (See the paper by Paul Wilson - ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such - techniques.) Sizes of free chunks are stored both in the front of - each chunk and at the end. This makes consolidating fragmented - chunks into bigger chunks fast. The head fields also hold bits - representing whether chunks are free or in use. - - Here are some pictures to make it clearer. They are "exploded" to - show that the state of a chunk can be thought of as extending from - the high 31 bits of the head field of its header through the - prev_foot and PINUSE_BIT bit of the following chunk header. - - A chunk that's in use looks like: - - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of previous chunk (if P = 1) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| - | Size of this chunk 1| +-+ - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | | - +- -+ - | | - +- -+ - | : - +- size - sizeof(size_t) available payload bytes -+ - : | - chunk-> +- -+ - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| - | Size of next chunk (may or may not be in use) | +-+ - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - And if it's free, it looks like this: - - chunk-> +- -+ - | User payload (must be in use, or we would have merged!) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| - | Size of this chunk 0| +-+ - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Next pointer | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Prev pointer | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | : - +- size - sizeof(struct chunk) unused bytes -+ - : | - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of this chunk | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0| - | Size of next chunk (must be in use, or we would have merged)| +-+ - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | : - +- User payload -+ - : | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |0| - +-+ - Note that since we always merge adjacent free chunks, the chunks - adjacent to a free chunk must be in use. - - Given a pointer to a chunk (which can be derived trivially from the - payload pointer) we can, in O(1) time, find out whether the adjacent - chunks are free, and if so, unlink them from the lists that they - are on and merge them with the current chunk. - - Chunks always begin on even word boundaries, so the mem portion - (which is returned to the user) is also on an even word boundary, and - thus at least double-word aligned. - - The P (PINUSE_BIT) bit, stored in the unused low-order bit of the - chunk size (which is always a multiple of two words), is an in-use - bit for the *previous* chunk. If that bit is *clear*, then the - word before the current chunk size contains the previous chunk - size, and can be used to find the front of the previous chunk. - The very first chunk allocated always has this bit set, preventing - access to non-existent (or non-owned) memory. If pinuse is set for - any given chunk, then you CANNOT determine the size of the - previous chunk, and might even get a memory addressing fault when - trying to do so. - - The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of - the chunk size redundantly records whether the current chunk is - inuse. This redundancy enables usage checks within free and realloc, - and reduces indirection when freeing and consolidating chunks. - - Each freshly allocated chunk must have both cinuse and pinuse set. - That is, each allocated chunk borders either a previously allocated - and still in-use chunk, or the base of its memory arena. This is - ensured by making all allocations from the the `lowest' part of any - found chunk. Further, no free chunk physically borders another one, - so each free chunk is known to be preceded and followed by either - inuse chunks or the ends of memory. - - Note that the `foot' of the current chunk is actually represented - as the prev_foot of the NEXT chunk. This makes it easier to - deal with alignments etc but can be very confusing when trying - to extend or adapt this code. - - The exceptions to all this are - - 1. The special chunk `top' is the top-most available chunk (i.e., - the one bordering the end of available memory). It is treated - specially. Top is never included in any bin, is used only if - no other chunk is available, and is released back to the - system if it is very large (see M_TRIM_THRESHOLD). In effect, - the top chunk is treated as larger (and thus less well - fitting) than any other available chunk. The top chunk - doesn't update its trailing size field since there is no next - contiguous chunk that would have to index off it. However, - space is still allocated for it (TOP_FOOT_SIZE) to enable - separation or merging when space is extended. - - 3. Chunks allocated via mmap, which have the lowest-order bit - (IS_MMAPPED_BIT) set in their prev_foot fields, and do not set - PINUSE_BIT in their head fields. Because they are allocated - one-by-one, each must carry its own prev_foot field, which is - also used to hold the offset this chunk has within its mmapped - region, which is needed to preserve alignment. Each mmapped - chunk is trailed by the first two fields of a fake next-chunk - for sake of usage checks. - -*/ - -struct malloc_chunk { - size_t prev_foot; /* Size of previous chunk (if free). */ - size_t head; /* Size and inuse bits. */ - struct malloc_chunk* fd; /* double links -- used only if free. */ - struct malloc_chunk* bk; -}; - -typedef struct malloc_chunk mchunk; -typedef struct malloc_chunk* mchunkptr; -typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ -typedef unsigned int bindex_t; /* Described below */ -typedef unsigned int binmap_t; /* Described below */ -typedef unsigned int flag_t; /* The type of various bit flag sets */ - -/* ------------------- Chunks sizes and alignments ----------------------- */ - -#define MCHUNK_SIZE (sizeof(mchunk)) - -#if FOOTERS -#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) -#else /* FOOTERS */ -#define CHUNK_OVERHEAD (SIZE_T_SIZE) -#endif /* FOOTERS */ - -/* MMapped chunks need a second word of overhead ... */ -#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) -/* ... and additional padding for fake next-chunk at foot */ -#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) - -/* The smallest size we can malloc is an aligned minimal chunk */ -#define MIN_CHUNK_SIZE\ - ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) - -/* conversion from malloc headers to user pointers, and back */ -#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES)) -#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES)) -/* chunk associated with aligned address A */ -#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) - -/* Bounds on request (not chunk) sizes. */ -#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) -#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) - -/* pad request bytes into a usable size */ -#define pad_request(req) \ - (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) - -/* pad request, checking for minimum (but not maximum) */ -#define request2size(req) \ - (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req)) - - -/* ------------------ Operations on head and foot fields ----------------- */ - -/* - The head field of a chunk is or'ed with PINUSE_BIT when previous - adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in - use. If the chunk was obtained with mmap, the prev_foot field has - IS_MMAPPED_BIT set, otherwise holding the offset of the base of the - mmapped region to the base of the chunk. -*/ - -#define PINUSE_BIT (SIZE_T_ONE) -#define CINUSE_BIT (SIZE_T_TWO) -#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) - -/* Head value for fenceposts */ -#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) - -/* extraction of fields from head words */ -#define cinuse(p) ((p)->head & CINUSE_BIT) -#define pinuse(p) ((p)->head & PINUSE_BIT) -#define chunksize(p) ((p)->head & ~(INUSE_BITS)) - -#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) -#define clear_cinuse(p) ((p)->head &= ~CINUSE_BIT) - -/* Treat space at ptr +/- offset as a chunk */ -#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) -#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s))) - -/* Ptr to next or previous physical malloc_chunk. */ -#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~INUSE_BITS))) -#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) )) - -/* extract next chunk's pinuse bit */ -#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) - -/* Get/set size at footer */ -#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot) -#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s)) - -/* Set size, pinuse bit, and foot */ -#define set_size_and_pinuse_of_free_chunk(p, s)\ - ((p)->head = (s|PINUSE_BIT), set_foot(p, s)) - -/* Set size, pinuse bit, foot, and clear next pinuse */ -#define set_free_with_pinuse(p, s, n)\ - (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) - -#define is_mmapped(p)\ - (!((p)->head & PINUSE_BIT) && ((p)->prev_foot & IS_MMAPPED_BIT)) - -/* Get the internal overhead associated with chunk p */ -#define overhead_for(p)\ - (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) - -/* Return true if malloced space is not necessarily cleared */ -#if MMAP_CLEARS -#define calloc_must_clear(p) (!is_mmapped(p)) -#else /* MMAP_CLEARS */ -#define calloc_must_clear(p) (1) -#endif /* MMAP_CLEARS */ - -/* ---------------------- Overlaid data structures ----------------------- */ - -/* - When chunks are not in use, they are treated as nodes of either - lists or trees. - - "Small" chunks are stored in circular doubly-linked lists, and look - like this: - - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of previous chunk | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - `head:' | Size of chunk, in bytes |P| - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Forward pointer to next chunk in list | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Back pointer to previous chunk in list | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Unused space (may be 0 bytes long) . - . . - . | -nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - `foot:' | Size of chunk, in bytes | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Larger chunks are kept in a form of bitwise digital trees (aka - tries) keyed on chunksizes. Because malloc_tree_chunks are only for - free chunks greater than 256 bytes, their size doesn't impose any - constraints on user chunk sizes. Each node looks like: - - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of previous chunk | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - `head:' | Size of chunk, in bytes |P| - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Forward pointer to next chunk of same size | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Back pointer to previous chunk of same size | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Pointer to left child (child[0]) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Pointer to right child (child[1]) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Pointer to parent | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | bin index of this chunk | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Unused space . - . | -nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - `foot:' | Size of chunk, in bytes | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Each tree holding treenodes is a tree of unique chunk sizes. Chunks - of the same size are arranged in a circularly-linked list, with only - the oldest chunk (the next to be used, in our FIFO ordering) - actually in the tree. (Tree members are distinguished by a non-null - parent pointer.) If a chunk with the same size an an existing node - is inserted, it is linked off the existing node using pointers that - work in the same way as fd/bk pointers of small chunks. - - Each tree contains a power of 2 sized range of chunk sizes (the - smallest is 0x100 <= x < 0x180), which is is divided in half at each - tree level, with the chunks in the smaller half of the range (0x100 - <= x < 0x140 for the top nose) in the left subtree and the larger - half (0x140 <= x < 0x180) in the right subtree. This is, of course, - done by inspecting individual bits. - - Using these rules, each node's left subtree contains all smaller - sizes than its right subtree. However, the node at the root of each - subtree has no particular ordering relationship to either. (The - dividing line between the subtree sizes is based on trie relation.) - If we remove the last chunk of a given size from the interior of the - tree, we need to replace it with a leaf node. The tree ordering - rules permit a node to be replaced by any leaf below it. - - The smallest chunk in a tree (a common operation in a best-fit - allocator) can be found by walking a path to the leftmost leaf in - the tree. Unlike a usual binary tree, where we follow left child - pointers until we reach a null, here we follow the right child - pointer any time the left one is null, until we reach a leaf with - both child pointers null. The smallest chunk in the tree will be - somewhere along that path. - - The worst case number of steps to add, find, or remove a node is - bounded by the number of bits differentiating chunks within - bins. Under current bin calculations, this ranges from 6 up to 21 - (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case - is of course much better. -*/ - -struct malloc_tree_chunk { - /* The first four fields must be compatible with malloc_chunk */ - size_t prev_foot; - size_t head; - struct malloc_tree_chunk* fd; - struct malloc_tree_chunk* bk; - - struct malloc_tree_chunk* child[2]; - struct malloc_tree_chunk* parent; - bindex_t index; -}; - -typedef struct malloc_tree_chunk tchunk; -typedef struct malloc_tree_chunk* tchunkptr; -typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ - -/* A little helper macro for trees */ -#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) - -/* ----------------------------- Segments -------------------------------- */ - -/* - Each malloc space may include non-contiguous segments, held in a - list headed by an embedded malloc_segment record representing the - top-most space. Segments also include flags holding properties of - the space. Large chunks that are directly allocated by mmap are not - included in this list. They are instead independently created and - destroyed without otherwise keeping track of them. - - Segment management mainly comes into play for spaces allocated by - MMAP. Any call to MMAP might or might not return memory that is - adjacent to an existing segment. MORECORE normally contiguously - extends the current space, so this space is almost always adjacent, - which is simpler and faster to deal with. (This is why MORECORE is - used preferentially to MMAP when both are available -- see - sys_alloc.) When allocating using MMAP, we don't use any of the - hinting mechanisms (inconsistently) supported in various - implementations of unix mmap, or distinguish reserving from - committing memory. Instead, we just ask for space, and exploit - contiguity when we get it. It is probably possible to do - better than this on some systems, but no general scheme seems - to be significantly better. - - Management entails a simpler variant of the consolidation scheme - used for chunks to reduce fragmentation -- new adjacent memory is - normally prepended or appended to an existing segment. However, - there are limitations compared to chunk consolidation that mostly - reflect the fact that segment processing is relatively infrequent - (occurring only when getting memory from system) and that we - don't expect to have huge numbers of segments: - - * Segments are not indexed, so traversal requires linear scans. (It - would be possible to index these, but is not worth the extra - overhead and complexity for most programs on most platforms.) - * New segments are only appended to old ones when holding top-most - memory; if they cannot be prepended to others, they are held in - different segments. - - Except for the top-most segment of an mstate, each segment record - is kept at the tail of its segment. Segments are added by pushing - segment records onto the list headed by &mstate.seg for the - containing mstate. - - Segment flags control allocation/merge/deallocation policies: - * If EXTERN_BIT set, then we did not allocate this segment, - and so should not try to deallocate or merge with others. - (This currently holds only for the initial segment passed - into create_mspace_with_base.) - * If IS_MMAPPED_BIT set, the segment may be merged with - other surrounding mmapped segments and trimmed/de-allocated - using munmap. - * If neither bit is set, then the segment was obtained using - MORECORE so can be merged with surrounding MORECORE'd segments - and deallocated/trimmed using MORECORE with negative arguments. -*/ - -struct malloc_segment { - char* base; /* base address */ - size_t size; /* allocated size */ - struct malloc_segment* next; /* ptr to next segment */ - flag_t sflags; /* mmap and extern flag */ -}; - -#define is_mmapped_segment(S) ((S)->sflags & IS_MMAPPED_BIT) -#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) - -typedef struct malloc_segment msegment; -typedef struct malloc_segment* msegmentptr; - -/* ---------------------------- malloc_state ----------------------------- */ - -/* - A malloc_state holds all of the bookkeeping for a space. - The main fields are: - - Top - The topmost chunk of the currently active segment. Its size is - cached in topsize. The actual size of topmost space is - topsize+TOP_FOOT_SIZE, which includes space reserved for adding - fenceposts and segment records if necessary when getting more - space from the system. The size at which to autotrim top is - cached from mparams in trim_check, except that it is disabled if - an autotrim fails. - - Designated victim (dv) - This is the preferred chunk for servicing small requests that - don't have exact fits. It is normally the chunk split off most - recently to service another small request. Its size is cached in - dvsize. The link fields of this chunk are not maintained since it - is not kept in a bin. - - SmallBins - An array of bin headers for free chunks. These bins hold chunks - with sizes less than MIN_LARGE_SIZE bytes. Each bin contains - chunks of all the same size, spaced 8 bytes apart. To simplify - use in double-linked lists, each bin header acts as a malloc_chunk - pointing to the real first node, if it exists (else pointing to - itself). This avoids special-casing for headers. But to avoid - waste, we allocate only the fd/bk pointers of bins, and then use - repositioning tricks to treat these as the fields of a chunk. - - TreeBins - Treebins are pointers to the roots of trees holding a range of - sizes. There are 2 equally spaced treebins for each power of two - from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything - larger. - - Bin maps - There is one bit map for small bins ("smallmap") and one for - treebins ("treemap). Each bin sets its bit when non-empty, and - clears the bit when empty. Bit operations are then used to avoid - bin-by-bin searching -- nearly all "search" is done without ever - looking at bins that won't be selected. The bit maps - conservatively use 32 bits per map word, even if on 64bit system. - For a good description of some of the bit-based techniques used - here, see Henry S. Warren Jr's book "Hacker's Delight" (and - supplement at http://hackersdelight.org/). Many of these are - intended to reduce the branchiness of paths through malloc etc, as - well as to reduce the number of memory locations read or written. - - Segments - A list of segments headed by an embedded malloc_segment record - representing the initial space. - - Address check support - The least_addr field is the least address ever obtained from - MORECORE or MMAP. Attempted frees and reallocs of any address less - than this are trapped (unless INSECURE is defined). - - Magic tag - A cross-check field that should always hold same value as mparams.magic. - - Flags - Bits recording whether to use MMAP, locks, or contiguous MORECORE - - Statistics - Each space keeps track of current and maximum system memory - obtained via MORECORE or MMAP. - - Locking - If USE_LOCKS is defined, the "mutex" lock is acquired and released - around every public call using this mspace. -*/ - -/* Bin types, widths and sizes */ -#define NSMALLBINS (32U) -#define NTREEBINS (32U) -#define SMALLBIN_SHIFT (3U) -#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) -#define TREEBIN_SHIFT (8U) -#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) -#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) -#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) - -struct malloc_state { - binmap_t smallmap; - binmap_t treemap; - size_t dvsize; - size_t topsize; - char* least_addr; - mchunkptr dv; - mchunkptr top; - size_t trim_check; - size_t magic; - mchunkptr smallbins[(NSMALLBINS+1)*2]; - tbinptr treebins[NTREEBINS]; - size_t footprint; - size_t max_footprint; - flag_t mflags; -#if USE_LOCKS - MLOCK_T mutex; /* locate lock among fields that rarely change */ -#endif /* USE_LOCKS */ - msegment seg; -}; - -typedef struct malloc_state* mstate; - -/* ------------- Global malloc_state and malloc_params ------------------- */ - -/* - malloc_params holds global properties, including those that can be - dynamically set using mallopt. There is a single instance, mparams, - initialized in init_mparams. -*/ - -struct malloc_params { - size_t magic; - size_t page_size; - size_t granularity; - size_t mmap_threshold; - size_t trim_threshold; - flag_t default_mflags; -}; - -static struct malloc_params mparams; - -/* The global malloc_state used for all non-"mspace" calls */ -static struct malloc_state _gm_; -#define gm (&_gm_) -#define is_global(M) ((M) == &_gm_) -#define is_initialized(M) ((M)->top != 0) - -/* -------------------------- system alloc setup ------------------------- */ - -/* Operations on mflags */ - -#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) -#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) -#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) - -#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) -#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) -#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) - -#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) -#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) - -#define set_lock(M,L)\ - ((M)->mflags = (L)?\ - ((M)->mflags | USE_LOCK_BIT) :\ - ((M)->mflags & ~USE_LOCK_BIT)) - -/* page-align a size */ -#define page_align(S)\ - (((S) + (mparams.page_size)) & ~(mparams.page_size - SIZE_T_ONE)) - -/* granularity-align a size */ -#define granularity_align(S)\ - (((S) + (mparams.granularity)) & ~(mparams.granularity - SIZE_T_ONE)) - -#define is_page_aligned(S)\ - (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) -#define is_granularity_aligned(S)\ - (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) - -/* True if segment S holds address A */ -#define segment_holds(S, A)\ - ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) - -/* Return segment holding given address */ -static msegmentptr segment_holding(mstate m, char* addr) { - msegmentptr sp = &m->seg; - for (;;) { - if (addr >= sp->base && addr < sp->base + sp->size) - return sp; - if ((sp = sp->next) == 0) - return 0; - } -} - -/* Return true if segment contains a segment link */ -static int has_segment_link(mstate m, msegmentptr ss) { - msegmentptr sp = &m->seg; - for (;;) { - if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) - return 1; - if ((sp = sp->next) == 0) - return 0; - } -} - -#ifndef MORECORE_CANNOT_TRIM -#define should_trim(M,s) ((s) > (M)->trim_check) -#else /* MORECORE_CANNOT_TRIM */ -#define should_trim(M,s) (0) -#endif /* MORECORE_CANNOT_TRIM */ - -/* - TOP_FOOT_SIZE is padding at the end of a segment, including space - that may be needed to place segment records and fenceposts when new - noncontiguous segments are added. -*/ -#define TOP_FOOT_SIZE\ - (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) - - -/* ------------------------------- Hooks -------------------------------- */ - -/* - PREACTION should be defined to return 0 on success, and nonzero on - failure. If you are not using locking, you can redefine these to do - anything you like. -*/ - -#if USE_LOCKS - -/* Ensure locks are initialized */ -#define GLOBALLY_INITIALIZE() (mparams.page_size == 0 && init_mparams()) - -#define PREACTION(M) ((GLOBALLY_INITIALIZE() || use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0) -#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); } -#else /* USE_LOCKS */ - -#ifndef PREACTION -#define PREACTION(M) (0) -#endif /* PREACTION */ - -#ifndef POSTACTION -#define POSTACTION(M) -#endif /* POSTACTION */ - -#endif /* USE_LOCKS */ - -/* - CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. - USAGE_ERROR_ACTION is triggered on detected bad frees and - reallocs. The argument p is an address that might have triggered the - fault. It is ignored by the two predefined actions, but might be - useful in custom actions that try to help diagnose errors. -*/ - -#if PROCEED_ON_ERROR - -/* A count of the number of corruption errors causing resets */ -int malloc_corruption_error_count; - -/* default corruption action */ -static void reset_on_error(mstate m); - -#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) -#define USAGE_ERROR_ACTION(m, p) - -#else /* PROCEED_ON_ERROR */ - -#ifndef CORRUPTION_ERROR_ACTION -#define CORRUPTION_ERROR_ACTION(m) ABORT -#endif /* CORRUPTION_ERROR_ACTION */ - -#ifndef USAGE_ERROR_ACTION -#define USAGE_ERROR_ACTION(m,p) ABORT -#endif /* USAGE_ERROR_ACTION */ - -#endif /* PROCEED_ON_ERROR */ - -/* -------------------------- Debugging setup ---------------------------- */ - -#if ! DEBUG - -#define check_free_chunk(M,P) -#define check_inuse_chunk(M,P) -#define check_malloced_chunk(M,P,N) -#define check_mmapped_chunk(M,P) -#define check_malloc_state(M) -#define check_top_chunk(M,P) - -#else /* DEBUG */ -#define check_free_chunk(M,P) do_check_free_chunk(M,P) -#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P) -#define check_top_chunk(M,P) do_check_top_chunk(M,P) -#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N) -#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P) -#define check_malloc_state(M) do_check_malloc_state(M) - -static void do_check_any_chunk(mstate m, mchunkptr p); -static void do_check_top_chunk(mstate m, mchunkptr p); -static void do_check_mmapped_chunk(mstate m, mchunkptr p); -static void do_check_inuse_chunk(mstate m, mchunkptr p); -static void do_check_free_chunk(mstate m, mchunkptr p); -static void do_check_malloced_chunk(mstate m, void* mem, size_t s); -static void do_check_tree(mstate m, tchunkptr t); -static void do_check_treebin(mstate m, bindex_t i); -static void do_check_smallbin(mstate m, bindex_t i); -static void do_check_malloc_state(mstate m); -static int bin_find(mstate m, mchunkptr x); -static size_t traverse_and_check(mstate m); -#endif /* DEBUG */ - -/* ---------------------------- Indexing Bins ---------------------------- */ - -#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) -#define small_index(s) ((s) >> SMALLBIN_SHIFT) -#define small_index2size(i) ((i) << SMALLBIN_SHIFT) -#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) - -/* addressing by index. See above about smallbin repositioning */ -#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1]))) -#define treebin_at(M,i) (&((M)->treebins[i])) - -/* assign tree index for size S to variable I */ -#if defined(__GNUC__) && defined(i386) -#define compute_tree_index(S, I)\ -{\ - size_t X = S >> TREEBIN_SHIFT;\ - if (X == 0)\ - I = 0;\ - else if (X > 0xFFFF)\ - I = NTREEBINS-1;\ - else {\ - unsigned int K;\ - __asm__("bsrl %1,%0\n\t" : "=r" (K) : "rm" (X));\ - I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ - }\ -} -#else /* GNUC */ -#define compute_tree_index(S, I)\ -{\ - size_t X = S >> TREEBIN_SHIFT;\ - if (X == 0)\ - I = 0;\ - else if (X > 0xFFFF)\ - I = NTREEBINS-1;\ - else {\ - unsigned int Y = (unsigned int)X;\ - unsigned int N = ((Y - 0x100) >> 16) & 8;\ - unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\ - N += K;\ - N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\ - K = 14 - N + ((Y <<= K) >> 15);\ - I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\ - }\ -} -#endif /* GNUC */ - -/* Bit representing maximum resolved size in a treebin at i */ -#define bit_for_tree_index(i) \ - (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) - -/* Shift placing maximum resolved bit in a treebin at i as sign bit */ -#define leftshift_for_tree_index(i) \ - ((i == NTREEBINS-1)? 0 : \ - ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) - -/* The size of the smallest chunk held in bin with index i */ -#define minsize_for_tree_index(i) \ - ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ - (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) - - -/* ------------------------ Operations on bin maps ----------------------- */ - -/* bit corresponding to given index */ -#define idx2bit(i) ((binmap_t)(1) << (i)) - -/* Mark/Clear bits with given index */ -#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i)) -#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i)) -#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i)) - -#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i)) -#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i)) -#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i)) - -/* index corresponding to given bit */ - -#if defined(__GNUC__) && defined(i386) -#define compute_bit2idx(X, I)\ -{\ - unsigned int J;\ - __asm__("bsfl %1,%0\n\t" : "=r" (J) : "rm" (X));\ - I = (bindex_t)J;\ -} - -#else /* GNUC */ -#if USE_BUILTIN_FFS -#define compute_bit2idx(X, I) I = ffs(X)-1 - -#else /* USE_BUILTIN_FFS */ -#define compute_bit2idx(X, I)\ -{\ - unsigned int Y = X - 1;\ - unsigned int K = Y >> (16-4) & 16;\ - unsigned int N = K; Y >>= K;\ - N += K = Y >> (8-3) & 8; Y >>= K;\ - N += K = Y >> (4-2) & 4; Y >>= K;\ - N += K = Y >> (2-1) & 2; Y >>= K;\ - N += K = Y >> (1-0) & 1; Y >>= K;\ - I = (bindex_t)(N + Y);\ -} -#endif /* USE_BUILTIN_FFS */ -#endif /* GNUC */ - -/* isolate the least set bit of a bitmap */ -#define least_bit(x) ((x) & -(x)) - -/* mask with all bits to left of least bit of x on */ -#define left_bits(x) ((x<<1) | -(x<<1)) - -/* mask with all bits to left of or equal to least bit of x on */ -#define same_or_left_bits(x) ((x) | -(x)) - - -/* ----------------------- Runtime Check Support ------------------------- */ - -/* - For security, the main invariant is that malloc/free/etc never - writes to a static address other than malloc_state, unless static - malloc_state itself has been corrupted, which cannot occur via - malloc (because of these checks). In essence this means that we - believe all pointers, sizes, maps etc held in malloc_state, but - check all of those linked or offsetted from other embedded data - structures. These checks are interspersed with main code in a way - that tends to minimize their run-time cost. - - When FOOTERS is defined, in addition to range checking, we also - verify footer fields of inuse chunks, which can be used guarantee - that the mstate controlling malloc/free is intact. This is a - streamlined version of the approach described by William Robertson - et al in "Run-time Detection of Heap-based Overflows" LISA'03 - http://www.usenix.org/events/lisa03/tech/robertson.html The footer - of an inuse chunk holds the xor of its mstate and a random seed, - that is checked upon calls to free() and realloc(). This is - (probablistically) unguessable from outside the program, but can be - computed by any code successfully malloc'ing any chunk, so does not - itself provide protection against code that has already broken - security through some other means. Unlike Robertson et al, we - always dynamically check addresses of all offset chunks (previous, - next, etc). This turns out to be cheaper than relying on hashes. -*/ - -#if !INSECURE -/* Check if address a is at least as high as any from MORECORE or MMAP */ -#define ok_address(M, a) ((char*)(a) >= (M)->least_addr) -/* Check if address of next chunk n is higher than base chunk p */ -#define ok_next(p, n) ((char*)(p) < (char*)(n)) -/* Check if p has its cinuse bit on */ -#define ok_cinuse(p) cinuse(p) -/* Check if p has its pinuse bit on */ -#define ok_pinuse(p) pinuse(p) - -#else /* !INSECURE */ -#define ok_address(M, a) (1) -#define ok_next(b, n) (1) -#define ok_cinuse(p) (1) -#define ok_pinuse(p) (1) -#endif /* !INSECURE */ - -#if (FOOTERS && !INSECURE) -/* Check if (alleged) mstate m has expected magic field */ -#define ok_magic(M) ((M)->magic == mparams.magic) -#else /* (FOOTERS && !INSECURE) */ -#define ok_magic(M) (1) -#endif /* (FOOTERS && !INSECURE) */ - - -/* In gcc, use __builtin_expect to minimize impact of checks */ -#if !INSECURE -#if defined(__GNUC__) && __GNUC__ >= 3 -#define RTCHECK(e) __builtin_expect(e, 1) -#else /* GNUC */ -#define RTCHECK(e) (e) -#endif /* GNUC */ -#else /* !INSECURE */ -#define RTCHECK(e) (1) -#endif /* !INSECURE */ - -/* macros to set up inuse chunks with or without footers */ - -#if !FOOTERS - -#define mark_inuse_foot(M,p,s) - -/* Set cinuse bit and pinuse bit of next chunk */ -#define set_inuse(M,p,s)\ - ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ - ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) - -/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ -#define set_inuse_and_pinuse(M,p,s)\ - ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ - ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) - -/* Set size, cinuse and pinuse bit of this chunk */ -#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ - ((p)->head = (s|PINUSE_BIT|CINUSE_BIT)) - -#else /* FOOTERS */ - -/* Set foot of inuse chunk to be xor of mstate and seed */ -#define mark_inuse_foot(M,p,s)\ - (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) - -#define get_mstate_for(p)\ - ((mstate)(((mchunkptr)((char*)(p) +\ - (chunksize(p))))->prev_foot ^ mparams.magic)) - -#define set_inuse(M,p,s)\ - ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ - (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ - mark_inuse_foot(M,p,s)) - -#define set_inuse_and_pinuse(M,p,s)\ - ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ - (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\ - mark_inuse_foot(M,p,s)) - -#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ - ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ - mark_inuse_foot(M, p, s)) - -#endif /* !FOOTERS */ - -/* ---------------------------- setting mparams -------------------------- */ - -/* Initialize mparams */ -static int init_mparams(void) { - if (mparams.page_size == 0) { - size_t s; - - mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; - mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; -#if MORECORE_CONTIGUOUS - mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT; -#else /* MORECORE_CONTIGUOUS */ - mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT; -#endif /* MORECORE_CONTIGUOUS */ - -#if (FOOTERS && !INSECURE) - { -#if USE_DEV_RANDOM - int fd; - unsigned char buf[sizeof(size_t)]; - /* Try to use /dev/urandom, else fall back on using time */ - if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && - read(fd, buf, sizeof(buf)) == sizeof(buf)) { - s = *((size_t *) buf); - close(fd); - } - else -#endif /* USE_DEV_RANDOM */ - s = (size_t)(time(0) ^ (size_t)0x55555555U); - - s |= (size_t)8U; /* ensure nonzero */ - s &= ~(size_t)7U; /* improve chances of fault for bad values */ - - } -#else /* (FOOTERS && !INSECURE) */ - s = (size_t)0x58585858U; -#endif /* (FOOTERS && !INSECURE) */ - ACQUIRE_MAGIC_INIT_LOCK(); - if (mparams.magic == 0) { - mparams.magic = s; - /* Set up lock for main malloc area */ - INITIAL_LOCK(&gm->mutex); - gm->mflags = mparams.default_mflags; - } - RELEASE_MAGIC_INIT_LOCK(); - -#ifndef WIN32 - mparams.page_size = malloc_getpagesize; - mparams.granularity = ((DEFAULT_GRANULARITY != 0)? - DEFAULT_GRANULARITY : mparams.page_size); -#else /* WIN32 */ - { - SYSTEM_INFO system_info; - GetSystemInfo(&system_info); - mparams.page_size = system_info.dwPageSize; - mparams.granularity = system_info.dwAllocationGranularity; - } -#endif /* WIN32 */ - - /* Sanity-check configuration: - size_t must be unsigned and as wide as pointer type. - ints must be at least 4 bytes. - alignment must be at least 8. - Alignment, min chunk size, and page size must all be powers of 2. - */ - if ((sizeof(size_t) != sizeof(char*)) || - (MAX_SIZE_T < MIN_CHUNK_SIZE) || - (sizeof(int) < 4) || - (MALLOC_ALIGNMENT < (size_t)8U) || - ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) || - ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) || - ((mparams.granularity & (mparams.granularity-SIZE_T_ONE)) != 0) || - ((mparams.page_size & (mparams.page_size-SIZE_T_ONE)) != 0)) - ABORT; - } - return 0; -} - -/* support for mallopt */ -static int change_mparam(int param_number, int value) { - size_t val = (size_t)value; - init_mparams(); - switch(param_number) { - case M_TRIM_THRESHOLD: - mparams.trim_threshold = val; - return 1; - case M_GRANULARITY: - if (val >= mparams.page_size && ((val & (val-1)) == 0)) { - mparams.granularity = val; - return 1; - } - else - return 0; - case M_MMAP_THRESHOLD: - mparams.mmap_threshold = val; - return 1; - default: - return 0; - } -} - -#if DEBUG -/* ------------------------- Debugging Support --------------------------- */ - -/* Check properties of any chunk, whether free, inuse, mmapped etc */ -static void do_check_any_chunk(mstate m, mchunkptr p) { - assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); - assert(ok_address(m, p)); -} - -/* Check properties of top chunk */ -static void do_check_top_chunk(mstate m, mchunkptr p) { - msegmentptr sp = segment_holding(m, (char*)p); - size_t sz = chunksize(p); - assert(sp != 0); - assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); - assert(ok_address(m, p)); - assert(sz == m->topsize); - assert(sz > 0); - assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE); - assert(pinuse(p)); - assert(!next_pinuse(p)); -} - -/* Check properties of (inuse) mmapped chunks */ -static void do_check_mmapped_chunk(mstate m, mchunkptr p) { - size_t sz = chunksize(p); - size_t len = (sz + (p->prev_foot & ~IS_MMAPPED_BIT) + MMAP_FOOT_PAD); - assert(is_mmapped(p)); - assert(use_mmap(m)); - assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); - assert(ok_address(m, p)); - assert(!is_small(sz)); - assert((len & (mparams.page_size-SIZE_T_ONE)) == 0); - assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); - assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0); -} - -/* Check properties of inuse chunks */ -static void do_check_inuse_chunk(mstate m, mchunkptr p) { - do_check_any_chunk(m, p); - assert(cinuse(p)); - assert(next_pinuse(p)); - /* If not pinuse and not mmapped, previous chunk has OK offset */ - assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p); - if (is_mmapped(p)) - do_check_mmapped_chunk(m, p); -} - -/* Check properties of free chunks */ -static void do_check_free_chunk(mstate m, mchunkptr p) { - size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT); - mchunkptr next = chunk_plus_offset(p, sz); - do_check_any_chunk(m, p); - assert(!cinuse(p)); - assert(!next_pinuse(p)); - assert (!is_mmapped(p)); - if (p != m->dv && p != m->top) { - if (sz >= MIN_CHUNK_SIZE) { - assert((sz & CHUNK_ALIGN_MASK) == 0); - assert(is_aligned(chunk2mem(p))); - assert(next->prev_foot == sz); - assert(pinuse(p)); - assert (next == m->top || cinuse(next)); - assert(p->fd->bk == p); - assert(p->bk->fd == p); - } - else /* markers are always of size SIZE_T_SIZE */ - assert(sz == SIZE_T_SIZE); - } -} - -/* Check properties of malloced chunks at the point they are malloced */ -static void do_check_malloced_chunk(mstate m, void* mem, size_t s) { - if (mem != 0) { - mchunkptr p = mem2chunk(mem); - size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT); - do_check_inuse_chunk(m, p); - assert((sz & CHUNK_ALIGN_MASK) == 0); - assert(sz >= MIN_CHUNK_SIZE); - assert(sz >= s); - /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ - assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE)); - } -} - -/* Check a tree and its subtrees. */ -static void do_check_tree(mstate m, tchunkptr t) { - tchunkptr head = 0; - tchunkptr u = t; - bindex_t tindex = t->index; - size_t tsize = chunksize(t); - bindex_t idx; - compute_tree_index(tsize, idx); - assert(tindex == idx); - assert(tsize >= MIN_LARGE_SIZE); - assert(tsize >= minsize_for_tree_index(idx)); - assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1)))); - - do { /* traverse through chain of same-sized nodes */ - do_check_any_chunk(m, ((mchunkptr)u)); - assert(u->index == tindex); - assert(chunksize(u) == tsize); - assert(!cinuse(u)); - assert(!next_pinuse(u)); - assert(u->fd->bk == u); - assert(u->bk->fd == u); - if (u->parent == 0) { - assert(u->child[0] == 0); - assert(u->child[1] == 0); - } - else { - assert(head == 0); /* only one node on chain has parent */ - head = u; - assert(u->parent != u); - assert (u->parent->child[0] == u || - u->parent->child[1] == u || - *((tbinptr*)(u->parent)) == u); - if (u->child[0] != 0) { - assert(u->child[0]->parent == u); - assert(u->child[0] != u); - do_check_tree(m, u->child[0]); - } - if (u->child[1] != 0) { - assert(u->child[1]->parent == u); - assert(u->child[1] != u); - do_check_tree(m, u->child[1]); - } - if (u->child[0] != 0 && u->child[1] != 0) { - assert(chunksize(u->child[0]) < chunksize(u->child[1])); - } - } - u = u->fd; - } while (u != t); - assert(head != 0); -} - -/* Check all the chunks in a treebin. */ -static void do_check_treebin(mstate m, bindex_t i) { - tbinptr* tb = treebin_at(m, i); - tchunkptr t = *tb; - int empty = (m->treemap & (1U << i)) == 0; - if (t == 0) - assert(empty); - if (!empty) - do_check_tree(m, t); -} - -/* Check all the chunks in a smallbin. */ -static void do_check_smallbin(mstate m, bindex_t i) { - sbinptr b = smallbin_at(m, i); - mchunkptr p = b->bk; - unsigned int empty = (m->smallmap & (1U << i)) == 0; - if (p == b) - assert(empty); - if (!empty) { - for (; p != b; p = p->bk) { - size_t size = chunksize(p); - mchunkptr q; - /* each chunk claims to be free */ - do_check_free_chunk(m, p); - /* chunk belongs in bin */ - assert(small_index(size) == i); - assert(p->bk == b || chunksize(p->bk) == chunksize(p)); - /* chunk is followed by an inuse chunk */ - q = next_chunk(p); - if (q->head != FENCEPOST_HEAD) - do_check_inuse_chunk(m, q); - } - } -} - -/* Find x in a bin. Used in other check functions. */ -static int bin_find(mstate m, mchunkptr x) { - size_t size = chunksize(x); - if (is_small(size)) { - bindex_t sidx = small_index(size); - sbinptr b = smallbin_at(m, sidx); - if (smallmap_is_marked(m, sidx)) { - mchunkptr p = b; - do { - if (p == x) - return 1; - } while ((p = p->fd) != b); - } - } - else { - bindex_t tidx; - compute_tree_index(size, tidx); - if (treemap_is_marked(m, tidx)) { - tchunkptr t = *treebin_at(m, tidx); - size_t sizebits = size << leftshift_for_tree_index(tidx); - while (t != 0 && chunksize(t) != size) { - t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; - sizebits <<= 1; - } - if (t != 0) { - tchunkptr u = t; - do { - if (u == (tchunkptr)x) - return 1; - } while ((u = u->fd) != t); - } - } - } - return 0; -} - -/* Traverse each chunk and check it; return total */ -static size_t traverse_and_check(mstate m) { - size_t sum = 0; - if (is_initialized(m)) { - msegmentptr s = &m->seg; - sum += m->topsize + TOP_FOOT_SIZE; - while (s != 0) { - mchunkptr q = align_as_chunk(s->base); - mchunkptr lastq = 0; - assert(pinuse(q)); - while (segment_holds(s, q) && - q != m->top && q->head != FENCEPOST_HEAD) { - sum += chunksize(q); - if (cinuse(q)) { - assert(!bin_find(m, q)); - do_check_inuse_chunk(m, q); - } - else { - assert(q == m->dv || bin_find(m, q)); - assert(lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */ - do_check_free_chunk(m, q); - } - lastq = q; - q = next_chunk(q); - } - s = s->next; - } - } - return sum; -} - -/* Check all properties of malloc_state. */ -static void do_check_malloc_state(mstate m) { - bindex_t i; - size_t total; - /* check bins */ - for (i = 0; i < NSMALLBINS; ++i) - do_check_smallbin(m, i); - for (i = 0; i < NTREEBINS; ++i) - do_check_treebin(m, i); - - if (m->dvsize != 0) { /* check dv chunk */ - do_check_any_chunk(m, m->dv); - assert(m->dvsize == chunksize(m->dv)); - assert(m->dvsize >= MIN_CHUNK_SIZE); - assert(bin_find(m, m->dv) == 0); - } - - if (m->top != 0) { /* check top chunk */ - do_check_top_chunk(m, m->top); - assert(m->topsize == chunksize(m->top)); - assert(m->topsize > 0); - assert(bin_find(m, m->top) == 0); - } - - total = traverse_and_check(m); - assert(total <= m->footprint); - assert(m->footprint <= m->max_footprint); -} -#endif /* DEBUG */ - -/* ----------------------------- statistics ------------------------------ */ - -#if !NO_MALLINFO -static struct mallinfo internal_mallinfo(mstate m) { - struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - if (!PREACTION(m)) { - check_malloc_state(m); - if (is_initialized(m)) { - size_t nfree = SIZE_T_ONE; /* top always free */ - size_t mfree = m->topsize + TOP_FOOT_SIZE; - size_t sum = mfree; - msegmentptr s = &m->seg; - while (s != 0) { - mchunkptr q = align_as_chunk(s->base); - while (segment_holds(s, q) && - q != m->top && q->head != FENCEPOST_HEAD) { - size_t sz = chunksize(q); - sum += sz; - if (!cinuse(q)) { - mfree += sz; - ++nfree; - } - q = next_chunk(q); - } - s = s->next; - } - - nm.arena = sum; - nm.ordblks = nfree; - nm.hblkhd = m->footprint - sum; - nm.usmblks = m->max_footprint; - nm.uordblks = m->footprint - mfree; - nm.fordblks = mfree; - nm.keepcost = m->topsize; - } - - POSTACTION(m); - } - return nm; -} -#endif /* !NO_MALLINFO */ - -static void internal_malloc_stats(mstate m) { - if (!PREACTION(m)) { - size_t maxfp = 0; - size_t fp = 0; - size_t used = 0; - check_malloc_state(m); - if (is_initialized(m)) { - msegmentptr s = &m->seg; - maxfp = m->max_footprint; - fp = m->footprint; - used = fp - (m->topsize + TOP_FOOT_SIZE); - - while (s != 0) { - mchunkptr q = align_as_chunk(s->base); - while (segment_holds(s, q) && - q != m->top && q->head != FENCEPOST_HEAD) { - if (!cinuse(q)) - used -= chunksize(q); - q = next_chunk(q); - } - s = s->next; - } - } - - fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp)); - fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp)); - fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used)); - - POSTACTION(m); - } -} - -/* ----------------------- Operations on smallbins ----------------------- */ - -/* - Various forms of linking and unlinking are defined as macros. Even - the ones for trees, which are very long but have very short typical - paths. This is ugly but reduces reliance on inlining support of - compilers. -*/ - -/* Link a free chunk into a smallbin */ -#define insert_small_chunk(M, P, S) {\ - bindex_t I = small_index(S);\ - mchunkptr B = smallbin_at(M, I);\ - mchunkptr F = B;\ - assert(S >= MIN_CHUNK_SIZE);\ - if (!smallmap_is_marked(M, I))\ - mark_smallmap(M, I);\ - else if (RTCHECK(ok_address(M, B->fd)))\ - F = B->fd;\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - }\ - B->fd = P;\ - F->bk = P;\ - P->fd = F;\ - P->bk = B;\ -} - -/* Unlink a chunk from a smallbin */ -#define unlink_small_chunk(M, P, S) {\ - mchunkptr F = P->fd;\ - mchunkptr B = P->bk;\ - bindex_t I = small_index(S);\ - assert(P != B);\ - assert(P != F);\ - assert(chunksize(P) == small_index2size(I));\ - if (F == B)\ - clear_smallmap(M, I);\ - else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\ - (B == smallbin_at(M,I) || ok_address(M, B)))) {\ - F->bk = B;\ - B->fd = F;\ - }\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - }\ -} - -/* Unlink the first chunk from a smallbin */ -#define unlink_first_small_chunk(M, B, P, I) {\ - mchunkptr F = P->fd;\ - assert(P != B);\ - assert(P != F);\ - assert(chunksize(P) == small_index2size(I));\ - if (B == F)\ - clear_smallmap(M, I);\ - else if (RTCHECK(ok_address(M, F))) {\ - B->fd = F;\ - F->bk = B;\ - }\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - }\ -} - -/* Replace dv node, binning the old one */ -/* Used only when dvsize known to be small */ -#define replace_dv(M, P, S) {\ - size_t DVS = M->dvsize;\ - if (DVS != 0) {\ - mchunkptr DV = M->dv;\ - assert(is_small(DVS));\ - insert_small_chunk(M, DV, DVS);\ - }\ - M->dvsize = S;\ - M->dv = P;\ -} - -/* ------------------------- Operations on trees ------------------------- */ - -/* Insert chunk into tree */ -#define insert_large_chunk(M, X, S) {\ - tbinptr* H;\ - bindex_t I;\ - compute_tree_index(S, I);\ - H = treebin_at(M, I);\ - X->index = I;\ - X->child[0] = X->child[1] = 0;\ - if (!treemap_is_marked(M, I)) {\ - mark_treemap(M, I);\ - *H = X;\ - X->parent = (tchunkptr)H;\ - X->fd = X->bk = X;\ - }\ - else {\ - tchunkptr T = *H;\ - size_t K = S << leftshift_for_tree_index(I);\ - for (;;) {\ - if (chunksize(T) != S) {\ - tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\ - K <<= 1;\ - if (*C != 0)\ - T = *C;\ - else if (RTCHECK(ok_address(M, C))) {\ - *C = X;\ - X->parent = T;\ - X->fd = X->bk = X;\ - break;\ - }\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - break;\ - }\ - }\ - else {\ - tchunkptr F = T->fd;\ - if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\ - T->fd = F->bk = X;\ - X->fd = F;\ - X->bk = T;\ - X->parent = 0;\ - break;\ - }\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - break;\ - }\ - }\ - }\ - }\ -} - -/* - Unlink steps: - - 1. If x is a chained node, unlink it from its same-sized fd/bk links - and choose its bk node as its replacement. - 2. If x was the last node of its size, but not a leaf node, it must - be replaced with a leaf node (not merely one with an open left or - right), to make sure that lefts and rights of descendents - correspond properly to bit masks. We use the rightmost descendent - of x. We could use any other leaf, but this is easy to locate and - tends to counteract removal of leftmosts elsewhere, and so keeps - paths shorter than minimally guaranteed. This doesn't loop much - because on average a node in a tree is near the bottom. - 3. If x is the base of a chain (i.e., has parent links) relink - x's parent and children to x's replacement (or null if none). -*/ - -#define unlink_large_chunk(M, X) {\ - tchunkptr XP = X->parent;\ - tchunkptr R;\ - if (X->bk != X) {\ - tchunkptr F = X->fd;\ - R = X->bk;\ - if (RTCHECK(ok_address(M, F))) {\ - F->bk = R;\ - R->fd = F;\ - }\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - }\ - }\ - else {\ - tchunkptr* RP;\ - if (((R = *(RP = &(X->child[1]))) != 0) ||\ - ((R = *(RP = &(X->child[0]))) != 0)) {\ - tchunkptr* CP;\ - while ((*(CP = &(R->child[1])) != 0) ||\ - (*(CP = &(R->child[0])) != 0)) {\ - R = *(RP = CP);\ - }\ - if (RTCHECK(ok_address(M, RP)))\ - *RP = 0;\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - }\ - }\ - }\ - if (XP != 0) {\ - tbinptr* H = treebin_at(M, X->index);\ - if (X == *H) {\ - if ((*H = R) == 0) \ - clear_treemap(M, X->index);\ - }\ - else if (RTCHECK(ok_address(M, XP))) {\ - if (XP->child[0] == X) \ - XP->child[0] = R;\ - else \ - XP->child[1] = R;\ - }\ - else\ - CORRUPTION_ERROR_ACTION(M);\ - if (R != 0) {\ - if (RTCHECK(ok_address(M, R))) {\ - tchunkptr C0, C1;\ - R->parent = XP;\ - if ((C0 = X->child[0]) != 0) {\ - if (RTCHECK(ok_address(M, C0))) {\ - R->child[0] = C0;\ - C0->parent = R;\ - }\ - else\ - CORRUPTION_ERROR_ACTION(M);\ - }\ - if ((C1 = X->child[1]) != 0) {\ - if (RTCHECK(ok_address(M, C1))) {\ - R->child[1] = C1;\ - C1->parent = R;\ - }\ - else\ - CORRUPTION_ERROR_ACTION(M);\ - }\ - }\ - else\ - CORRUPTION_ERROR_ACTION(M);\ - }\ - }\ -} - -/* Relays to large vs small bin operations */ - -#define insert_chunk(M, P, S)\ - if (is_small(S)) insert_small_chunk(M, P, S)\ - else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } - -#define unlink_chunk(M, P, S)\ - if (is_small(S)) unlink_small_chunk(M, P, S)\ - else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } - - -/* Relays to internal calls to malloc/free from realloc, memalign etc */ - -#if ONLY_MSPACES -#define internal_malloc(m, b) mspace_malloc(m, b) -#define internal_free(m, mem) mspace_free(m,mem); -#else /* ONLY_MSPACES */ -#if MSPACES -#define internal_malloc(m, b)\ - (m == gm)? dlmalloc(b) : mspace_malloc(m, b) -#define internal_free(m, mem)\ - if (m == gm) dlfree(mem); else mspace_free(m,mem); -#else /* MSPACES */ -#define internal_malloc(m, b) dlmalloc(b) -#define internal_free(m, mem) dlfree(mem) -#endif /* MSPACES */ -#endif /* ONLY_MSPACES */ - -/* ----------------------- Direct-mmapping chunks ----------------------- */ - -/* - Directly mmapped chunks are set up with an offset to the start of - the mmapped region stored in the prev_foot field of the chunk. This - allows reconstruction of the required argument to MUNMAP when freed, - and also allows adjustment of the returned chunk to meet alignment - requirements (especially in memalign). There is also enough space - allocated to hold a fake next chunk of size SIZE_T_SIZE to maintain - the PINUSE bit so frees can be checked. -*/ - -/* Malloc using mmap */ -static void* mmap_alloc(mstate m, size_t nb) { - size_t mmsize = granularity_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - if (mmsize > nb) { /* Check for wrap around 0 */ - char* mm = (char*)(DIRECT_MMAP(mmsize)); - if (mm != CMFAIL) { - size_t offset = align_offset(chunk2mem(mm)); - size_t psize = mmsize - offset - MMAP_FOOT_PAD; - mchunkptr p = (mchunkptr)(mm + offset); - p->prev_foot = offset | IS_MMAPPED_BIT; - (p)->head = (psize|CINUSE_BIT); - mark_inuse_foot(m, p, psize); - chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; - chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0; - - if (mm < m->least_addr) - m->least_addr = mm; - if ((m->footprint += mmsize) > m->max_footprint) - m->max_footprint = m->footprint; - assert(is_aligned(chunk2mem(p))); - check_mmapped_chunk(m, p); - return chunk2mem(p); - } - } - return 0; -} - -/* Realloc using mmap */ -static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) { - size_t oldsize = chunksize(oldp); - if (is_small(nb)) /* Can't shrink mmap regions below small size */ - return 0; - /* Keep old chunk if big enough but not too big */ - if (oldsize >= nb + SIZE_T_SIZE && - (oldsize - nb) <= (mparams.granularity << 1)) - return oldp; - else { - size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT; - size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; - size_t newmmsize = granularity_align(nb + SIX_SIZE_T_SIZES + - CHUNK_ALIGN_MASK); - char* cp = (char*)CALL_MREMAP((char*)oldp - offset, - oldmmsize, newmmsize, 1); - if (cp != CMFAIL) { - mchunkptr newp = (mchunkptr)(cp + offset); - size_t psize = newmmsize - offset - MMAP_FOOT_PAD; - newp->head = (psize|CINUSE_BIT); - mark_inuse_foot(m, newp, psize); - chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; - chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0; - - if (cp < m->least_addr) - m->least_addr = cp; - if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) - m->max_footprint = m->footprint; - check_mmapped_chunk(m, newp); - return newp; - } - } - return 0; -} - -/* -------------------------- mspace management -------------------------- */ - -/* Initialize top chunk and its size */ -static void init_top(mstate m, mchunkptr p, size_t psize) { - /* Ensure alignment */ - size_t offset = align_offset(chunk2mem(p)); - p = (mchunkptr)((char*)p + offset); - psize -= offset; - - m->top = p; - m->topsize = psize; - p->head = psize | PINUSE_BIT; - /* set size of fake trailing chunk holding overhead space only once */ - chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; - m->trim_check = mparams.trim_threshold; /* reset on each update */ -} - -/* Initialize bins for a new mstate that is otherwise zeroed out */ -static void init_bins(mstate m) { - /* Establish circular links for smallbins */ - bindex_t i; - for (i = 0; i < NSMALLBINS; ++i) { - sbinptr bin = smallbin_at(m,i); - bin->fd = bin->bk = bin; - } -} - -#if PROCEED_ON_ERROR - -/* default corruption action */ -static void reset_on_error(mstate m) { - int i; - ++malloc_corruption_error_count; - /* Reinitialize fields to forget about all memory */ - m->smallbins = m->treebins = 0; - m->dvsize = m->topsize = 0; - m->seg.base = 0; - m->seg.size = 0; - m->seg.next = 0; - m->top = m->dv = 0; - for (i = 0; i < NTREEBINS; ++i) - *treebin_at(m, i) = 0; - init_bins(m); -} -#endif /* PROCEED_ON_ERROR */ - -/* Allocate chunk and prepend remainder with chunk in successor base. */ -static void* prepend_alloc(mstate m, char* newbase, char* oldbase, - size_t nb) { - mchunkptr p = align_as_chunk(newbase); - mchunkptr oldfirst = align_as_chunk(oldbase); - size_t psize = (char*)oldfirst - (char*)p; - mchunkptr q = chunk_plus_offset(p, nb); - size_t qsize = psize - nb; - set_size_and_pinuse_of_inuse_chunk(m, p, nb); - - assert((char*)oldfirst > (char*)q); - assert(pinuse(oldfirst)); - assert(qsize >= MIN_CHUNK_SIZE); - - /* consolidate remainder with first chunk of old base */ - if (oldfirst == m->top) { - size_t tsize = m->topsize += qsize; - m->top = q; - q->head = tsize | PINUSE_BIT; - check_top_chunk(m, q); - } - else if (oldfirst == m->dv) { - size_t dsize = m->dvsize += qsize; - m->dv = q; - set_size_and_pinuse_of_free_chunk(q, dsize); - } - else { - if (!cinuse(oldfirst)) { - size_t nsize = chunksize(oldfirst); - unlink_chunk(m, oldfirst, nsize); - oldfirst = chunk_plus_offset(oldfirst, nsize); - qsize += nsize; - } - set_free_with_pinuse(q, qsize, oldfirst); - insert_chunk(m, q, qsize); - check_free_chunk(m, q); - } - - check_malloced_chunk(m, chunk2mem(p), nb); - return chunk2mem(p); -} - - -/* Add a segment to hold a new noncontiguous region */ -static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { - /* Determine locations and sizes of segment, fenceposts, old top */ - char* old_top = (char*)m->top; - msegmentptr oldsp = segment_holding(m, old_top); - char* old_end = oldsp->base + oldsp->size; - size_t ssize = pad_request(sizeof(struct malloc_segment)); - char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - size_t offset = align_offset(chunk2mem(rawsp)); - char* asp = rawsp + offset; - char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp; - mchunkptr sp = (mchunkptr)csp; - msegmentptr ss = (msegmentptr)(chunk2mem(sp)); - mchunkptr tnext = chunk_plus_offset(sp, ssize); - mchunkptr p = tnext; - int nfences = 0; - - /* reset top to new space */ - init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); - - /* Set up segment record */ - assert(is_aligned(ss)); - set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); - *ss = m->seg; /* Push current record */ - m->seg.base = tbase; - m->seg.size = tsize; - m->seg.sflags = mmapped; - m->seg.next = ss; - - /* Insert trailing fenceposts */ - for (;;) { - mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); - p->head = FENCEPOST_HEAD; - ++nfences; - if ((char*)(&(nextp->head)) < old_end) - p = nextp; - else - break; - } - assert(nfences >= 2); - - /* Insert the rest of old top into a bin as an ordinary free chunk */ - if (csp != old_top) { - mchunkptr q = (mchunkptr)old_top; - size_t psize = csp - old_top; - mchunkptr tn = chunk_plus_offset(q, psize); - set_free_with_pinuse(q, psize, tn); - insert_chunk(m, q, psize); - } - - check_top_chunk(m, m->top); -} - -/* -------------------------- System allocation -------------------------- */ - -/* Get memory from system using MORECORE or MMAP */ -static void* sys_alloc(mstate m, size_t nb) { - char* tbase = CMFAIL; - size_t tsize = 0; - flag_t mmap_flag = 0; - - init_mparams(); - - /* Directly map large chunks */ - if (use_mmap(m) && nb >= mparams.mmap_threshold) { - void* mem = mmap_alloc(m, nb); - if (mem != 0) - return mem; - } - - /* - Try getting memory in any of three ways (in most-preferred to - least-preferred order): - 1. A call to MORECORE that can normally contiguously extend memory. - (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or - or main space is mmapped or a previous contiguous call failed) - 2. A call to MMAP new space (disabled if not HAVE_MMAP). - Note that under the default settings, if MORECORE is unable to - fulfill a request, and HAVE_MMAP is true, then mmap is - used as a noncontiguous system allocator. This is a useful backup - strategy for systems with holes in address spaces -- in this case - sbrk cannot contiguously expand the heap, but mmap may be able to - find space. - 3. A call to MORECORE that cannot usually contiguously extend memory. - (disabled if not HAVE_MORECORE) - */ - - if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) { - char* br = CMFAIL; - msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top); - size_t asize = 0; - ACQUIRE_MORECORE_LOCK(); - - if (ss == 0) { /* First time through or recovery */ - char* base = (char*)CALL_MORECORE(0); - if (base != CMFAIL) { - asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE); - /* Adjust to end on a page boundary */ - if (!is_page_aligned(base)) - asize += (page_align((size_t)base) - (size_t)base); - /* Can't call MORECORE if size is negative when treated as signed */ - if (asize < HALF_MAX_SIZE_T && - (br = (char*)(CALL_MORECORE(asize))) == base) { - tbase = base; - tsize = asize; - } - } - } - else { - /* Subtract out existing available top space from MORECORE request. */ - asize = granularity_align(nb - m->topsize + TOP_FOOT_SIZE + SIZE_T_ONE); - /* Use mem here only if it did continuously extend old space */ - if (asize < HALF_MAX_SIZE_T && - (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) { - tbase = br; - tsize = asize; - } - } - - if (tbase == CMFAIL) { /* Cope with partial failure */ - if (br != CMFAIL) { /* Try to use/extend the space we did get */ - if (asize < HALF_MAX_SIZE_T && - asize < nb + TOP_FOOT_SIZE + SIZE_T_ONE) { - size_t esize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE - asize); - if (esize < HALF_MAX_SIZE_T) { - char* end = (char*)CALL_MORECORE(esize); - if (end != CMFAIL) - asize += esize; - else { /* Can't use; try to release */ - CALL_MORECORE(-asize); - br = CMFAIL; - } - } - } - } - if (br != CMFAIL) { /* Use the space we did get */ - tbase = br; - tsize = asize; - } - else - disable_contiguous(m); /* Don't try contiguous path in the future */ - } - - RELEASE_MORECORE_LOCK(); - } - - if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */ - size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE; - size_t rsize = granularity_align(req); - if (rsize > nb) { /* Fail if wraps around zero */ - char* mp = (char*)(CALL_MMAP(rsize)); - if (mp != CMFAIL) { - tbase = mp; - tsize = rsize; - mmap_flag = IS_MMAPPED_BIT; - } - } - } - - if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */ - size_t asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE); - if (asize < HALF_MAX_SIZE_T) { - char* br = CMFAIL; - char* end = CMFAIL; - ACQUIRE_MORECORE_LOCK(); - br = (char*)(CALL_MORECORE(asize)); - end = (char*)(CALL_MORECORE(0)); - RELEASE_MORECORE_LOCK(); - if (br != CMFAIL && end != CMFAIL && br < end) { - size_t ssize = end - br; - if (ssize > nb + TOP_FOOT_SIZE) { - tbase = br; - tsize = ssize; - } - } - } - } - - if (tbase != CMFAIL) { - - if ((m->footprint += tsize) > m->max_footprint) - m->max_footprint = m->footprint; - - if (!is_initialized(m)) { /* first-time initialization */ - m->seg.base = m->least_addr = tbase; - m->seg.size = tsize; - m->seg.sflags = mmap_flag; - m->magic = mparams.magic; - init_bins(m); - if (is_global(m)) - init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); - else { - /* Offset top by embedded malloc_state */ - mchunkptr mn = next_chunk(mem2chunk(m)); - init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE); - } - } - - else { - /* Try to merge with an existing segment */ - msegmentptr sp = &m->seg; - while (sp != 0 && tbase != sp->base + sp->size) - sp = sp->next; - if (sp != 0 && - !is_extern_segment(sp) && - (sp->sflags & IS_MMAPPED_BIT) == mmap_flag && - segment_holds(sp, m->top)) { /* append */ - sp->size += tsize; - init_top(m, m->top, m->topsize + tsize); - } - else { - if (tbase < m->least_addr) - m->least_addr = tbase; - sp = &m->seg; - while (sp != 0 && sp->base != tbase + tsize) - sp = sp->next; - if (sp != 0 && - !is_extern_segment(sp) && - (sp->sflags & IS_MMAPPED_BIT) == mmap_flag) { - char* oldbase = sp->base; - sp->base = tbase; - sp->size += tsize; - return prepend_alloc(m, tbase, oldbase, nb); - } - else - add_segment(m, tbase, tsize, mmap_flag); - } - } - - if (nb < m->topsize) { /* Allocate from new or extended top space */ - size_t rsize = m->topsize -= nb; - mchunkptr p = m->top; - mchunkptr r = m->top = chunk_plus_offset(p, nb); - r->head = rsize | PINUSE_BIT; - set_size_and_pinuse_of_inuse_chunk(m, p, nb); - check_top_chunk(m, m->top); - check_malloced_chunk(m, chunk2mem(p), nb); - return chunk2mem(p); - } - } - - MALLOC_FAILURE_ACTION; - return 0; -} - -/* ----------------------- system deallocation -------------------------- */ - -/* Unmap and unlink any mmapped segments that don't contain used chunks */ -static size_t release_unused_segments(mstate m) { - size_t released = 0; - msegmentptr pred = &m->seg; - msegmentptr sp = pred->next; - while (sp != 0) { - char* base = sp->base; - size_t size = sp->size; - msegmentptr next = sp->next; - if (is_mmapped_segment(sp) && !is_extern_segment(sp)) { - mchunkptr p = align_as_chunk(base); - size_t psize = chunksize(p); - /* Can unmap if first chunk holds entire segment and not pinned */ - if (!cinuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) { - tchunkptr tp = (tchunkptr)p; - assert(segment_holds(sp, (char*)sp)); - if (p == m->dv) { - m->dv = 0; - m->dvsize = 0; - } - else { - unlink_large_chunk(m, tp); - } - if (CALL_MUNMAP(base, size) == 0) { - released += size; - m->footprint -= size; - /* unlink obsoleted record */ - sp = pred; - sp->next = next; - } - else { /* back out if cannot unmap */ - insert_large_chunk(m, tp, psize); - } - } - } - pred = sp; - sp = next; - } - return released; -} - -static int sys_trim(mstate m, size_t pad) { - size_t released = 0; - if (pad < MAX_REQUEST && is_initialized(m)) { - pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ - - if (m->topsize > pad) { - /* Shrink top space in granularity-size units, keeping at least one */ - size_t unit = mparams.granularity; - size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - - SIZE_T_ONE) * unit; - msegmentptr sp = segment_holding(m, (char*)m->top); - - if (!is_extern_segment(sp)) { - if (is_mmapped_segment(sp)) { - if (HAVE_MMAP && - sp->size >= extra && - !has_segment_link(m, sp)) { /* can't shrink if pinned */ - size_t newsize = sp->size - extra; - /* Prefer mremap, fall back to munmap */ - if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || - (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { - released = extra; - } - } - } - else if (HAVE_MORECORE) { - if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ - extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; - ACQUIRE_MORECORE_LOCK(); - { - /* Make sure end of memory is where we last set it. */ - char* old_br = (char*)(CALL_MORECORE(0)); - if (old_br == sp->base + sp->size) { - char* rel_br = (char*)(CALL_MORECORE(-extra)); - char* new_br = (char*)(CALL_MORECORE(0)); - if (rel_br != CMFAIL && new_br < old_br) - released = old_br - new_br; - } - } - RELEASE_MORECORE_LOCK(); - } - } - - if (released != 0) { - sp->size -= released; - m->footprint -= released; - init_top(m, m->top, m->topsize - released); - check_top_chunk(m, m->top); - } - } - - /* Unmap any unused mmapped segments */ - if (HAVE_MMAP) - released += release_unused_segments(m); - - /* On failure, disable autotrim to avoid repeated failed future calls */ - if (released == 0) - m->trim_check = MAX_SIZE_T; - } - - return (released != 0)? 1 : 0; -} - -/* ---------------------------- malloc support --------------------------- */ - -/* allocate a large request from the best fitting chunk in a treebin */ -static void* tmalloc_large(mstate m, size_t nb) { - tchunkptr v = 0; - size_t rsize = -nb; /* Unsigned negation */ - tchunkptr t; - bindex_t idx; - compute_tree_index(nb, idx); - - if ((t = *treebin_at(m, idx)) != 0) { - /* Traverse tree for this bin looking for node with size == nb */ - size_t sizebits = nb << leftshift_for_tree_index(idx); - tchunkptr rst = 0; /* The deepest untaken right subtree */ - for (;;) { - tchunkptr rt; - size_t trem = chunksize(t) - nb; - if (trem < rsize) { - v = t; - if ((rsize = trem) == 0) - break; - } - rt = t->child[1]; - t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; - if (rt != 0 && rt != t) - rst = rt; - if (t == 0) { - t = rst; /* set t to least subtree holding sizes > nb */ - break; - } - sizebits <<= 1; - } - } - - if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */ - binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; - if (leftbits != 0) { - bindex_t i; - binmap_t leastbit = least_bit(leftbits); - compute_bit2idx(leastbit, i); - t = *treebin_at(m, i); - } - } - - while (t != 0) { /* find smallest of tree or subtree */ - size_t trem = chunksize(t) - nb; - if (trem < rsize) { - rsize = trem; - v = t; - } - t = leftmost_child(t); - } - - /* If dv is a better fit, return 0 so malloc will use it */ - if (v != 0 && rsize < (size_t)(m->dvsize - nb)) { - if (RTCHECK(ok_address(m, v))) { /* split */ - mchunkptr r = chunk_plus_offset(v, nb); - assert(chunksize(v) == rsize + nb); - if (RTCHECK(ok_next(v, r))) { - unlink_large_chunk(m, v); - if (rsize < MIN_CHUNK_SIZE) - set_inuse_and_pinuse(m, v, (rsize + nb)); - else { - set_size_and_pinuse_of_inuse_chunk(m, v, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - insert_chunk(m, r, rsize); - } - return chunk2mem(v); - } - } - CORRUPTION_ERROR_ACTION(m); - } - return 0; -} - -/* allocate a small request from the best fitting chunk in a treebin */ -static void* tmalloc_small(mstate m, size_t nb) { - tchunkptr t, v; - size_t rsize; - bindex_t i; - binmap_t leastbit = least_bit(m->treemap); - compute_bit2idx(leastbit, i); - - v = t = *treebin_at(m, i); - rsize = chunksize(t) - nb; - - while ((t = leftmost_child(t)) != 0) { - size_t trem = chunksize(t) - nb; - if (trem < rsize) { - rsize = trem; - v = t; - } - } - - if (RTCHECK(ok_address(m, v))) { - mchunkptr r = chunk_plus_offset(v, nb); - assert(chunksize(v) == rsize + nb); - if (RTCHECK(ok_next(v, r))) { - unlink_large_chunk(m, v); - if (rsize < MIN_CHUNK_SIZE) - set_inuse_and_pinuse(m, v, (rsize + nb)); - else { - set_size_and_pinuse_of_inuse_chunk(m, v, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - replace_dv(m, r, rsize); - } - return chunk2mem(v); - } - } - - CORRUPTION_ERROR_ACTION(m); - return 0; -} - -/* --------------------------- realloc support --------------------------- */ - -static void* internal_realloc(mstate m, void* oldmem, size_t bytes) { - if (bytes >= MAX_REQUEST) { - MALLOC_FAILURE_ACTION; - return 0; - } - if (!PREACTION(m)) { - mchunkptr oldp = mem2chunk(oldmem); - size_t oldsize = chunksize(oldp); - mchunkptr next = chunk_plus_offset(oldp, oldsize); - mchunkptr newp = 0; - void* extra = 0; - - /* Try to either shrink or extend into top. Else malloc-copy-free */ - - if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) && - ok_next(oldp, next) && ok_pinuse(next))) { - size_t nb = request2size(bytes); - if (is_mmapped(oldp)) - newp = mmap_resize(m, oldp, nb); - else if (oldsize >= nb) { /* already big enough */ - size_t rsize = oldsize - nb; - newp = oldp; - if (rsize >= MIN_CHUNK_SIZE) { - mchunkptr remainder = chunk_plus_offset(newp, nb); - set_inuse(m, newp, nb); - set_inuse(m, remainder, rsize); - extra = chunk2mem(remainder); - } - } - else if (next == m->top && oldsize + m->topsize > nb) { - /* Expand into top */ - size_t newsize = oldsize + m->topsize; - size_t newtopsize = newsize - nb; - mchunkptr newtop = chunk_plus_offset(oldp, nb); - set_inuse(m, oldp, nb); - newtop->head = newtopsize |PINUSE_BIT; - m->top = newtop; - m->topsize = newtopsize; - newp = oldp; - } - } - else { - USAGE_ERROR_ACTION(m, oldmem); - POSTACTION(m); - return 0; - } - - POSTACTION(m); - - if (newp != 0) { - if (extra != 0) { - internal_free(m, extra); - } - check_inuse_chunk(m, newp); - return chunk2mem(newp); - } - else { - void* newmem = internal_malloc(m, bytes); - if (newmem != 0) { - size_t oc = oldsize - overhead_for(oldp); - memcpy(newmem, oldmem, (oc < bytes)? oc : bytes); - internal_free(m, oldmem); - } - return newmem; - } - } - return 0; -} - -/* --------------------------- memalign support -------------------------- */ - -static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { - if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */ - return internal_malloc(m, bytes); - if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ - alignment = MIN_CHUNK_SIZE; - if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */ - size_t a = MALLOC_ALIGNMENT << 1; - while (a < alignment) a <<= 1; - alignment = a; - } - - if (bytes >= MAX_REQUEST - alignment) { - if (m != 0) { /* Test isn't needed but avoids compiler warning */ - MALLOC_FAILURE_ACTION; - } - } - else { - size_t nb = request2size(bytes); - size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; - char* mem = (char*)internal_malloc(m, req); - if (mem != 0) { - void* leader = 0; - void* trailer = 0; - mchunkptr p = mem2chunk(mem); - - if (PREACTION(m)) return 0; - if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */ - /* - Find an aligned spot inside chunk. Since we need to give - back leading space in a chunk of at least MIN_CHUNK_SIZE, if - the first calculation places us at a spot with less than - MIN_CHUNK_SIZE leader, we can move to the next aligned spot. - We've allocated enough total room so that this is always - possible. - */ - char* br = (char*)mem2chunk((size_t)(((size_t)(mem + - alignment - - SIZE_T_ONE)) & - -alignment)); - char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)? - br : br+alignment; - mchunkptr newp = (mchunkptr)pos; - size_t leadsize = pos - (char*)(p); - size_t newsize = chunksize(p) - leadsize; - - if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */ - newp->prev_foot = p->prev_foot + leadsize; - newp->head = (newsize|CINUSE_BIT); - } - else { /* Otherwise, give back leader, use the rest */ - set_inuse(m, newp, newsize); - set_inuse(m, p, leadsize); - leader = chunk2mem(p); - } - p = newp; - } - - /* Give back spare room at the end */ - if (!is_mmapped(p)) { - size_t size = chunksize(p); - if (size > nb + MIN_CHUNK_SIZE) { - size_t remainder_size = size - nb; - mchunkptr remainder = chunk_plus_offset(p, nb); - set_inuse(m, p, nb); - set_inuse(m, remainder, remainder_size); - trailer = chunk2mem(remainder); - } - } - - assert (chunksize(p) >= nb); - assert((((size_t)(chunk2mem(p))) % alignment) == 0); - check_inuse_chunk(m, p); - POSTACTION(m); - if (leader != 0) { - internal_free(m, leader); - } - if (trailer != 0) { - internal_free(m, trailer); - } - return chunk2mem(p); - } - } - return 0; -} - -/* ------------------------ comalloc/coalloc support --------------------- */ - -static void** ialloc(mstate m, - size_t n_elements, - size_t* sizes, - int opts, - void* chunks[]) { - /* - This provides common support for independent_X routines, handling - all of the combinations that can result. - - The opts arg has: - bit 0 set if all elements are same size (using sizes[0]) - bit 1 set if elements should be zeroed - */ - - size_t element_size; /* chunksize of each element, if all same */ - size_t contents_size; /* total size of elements */ - size_t array_size; /* request size of pointer array */ - void* mem; /* malloced aggregate space */ - mchunkptr p; /* corresponding chunk */ - size_t remainder_size; /* remaining bytes while splitting */ - void** marray; /* either "chunks" or malloced ptr array */ - mchunkptr array_chunk; /* chunk for malloced ptr array */ - flag_t was_enabled; /* to disable mmap */ - size_t size; - size_t i; - - /* compute array length, if needed */ - if (chunks != 0) { - if (n_elements == 0) - return chunks; /* nothing to do */ - marray = chunks; - array_size = 0; - } - else { - /* if empty req, must still return chunk representing empty array */ - if (n_elements == 0) - return (void**)internal_malloc(m, 0); - marray = 0; - array_size = request2size(n_elements * (sizeof(void*))); - } - - /* compute total element size */ - if (opts & 0x1) { /* all-same-size */ - element_size = request2size(*sizes); - contents_size = n_elements * element_size; - } - else { /* add up all the sizes */ - element_size = 0; - contents_size = 0; - for (i = 0; i != n_elements; ++i) - contents_size += request2size(sizes[i]); - } - - size = contents_size + array_size; - - /* - Allocate the aggregate chunk. First disable direct-mmapping so - malloc won't use it, since we would not be able to later - free/realloc space internal to a segregated mmap region. - */ - was_enabled = use_mmap(m); - disable_mmap(m); - mem = internal_malloc(m, size - CHUNK_OVERHEAD); - if (was_enabled) - enable_mmap(m); - if (mem == 0) - return 0; - - if (PREACTION(m)) return 0; - p = mem2chunk(mem); - remainder_size = chunksize(p); - - assert(!is_mmapped(p)); - - if (opts & 0x2) { /* optionally clear the elements */ - memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size); - } - - /* If not provided, allocate the pointer array as final part of chunk */ - if (marray == 0) { - size_t array_chunk_size; - array_chunk = chunk_plus_offset(p, contents_size); - array_chunk_size = remainder_size - contents_size; - marray = (void**) (chunk2mem(array_chunk)); - set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size); - remainder_size = contents_size; - } - - /* split out elements */ - for (i = 0; ; ++i) { - marray[i] = chunk2mem(p); - if (i != n_elements-1) { - if (element_size != 0) - size = element_size; - else - size = request2size(sizes[i]); - remainder_size -= size; - set_size_and_pinuse_of_inuse_chunk(m, p, size); - p = chunk_plus_offset(p, size); - } - else { /* the final element absorbs any overallocation slop */ - set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); - break; - } - } - -#if DEBUG - if (marray != chunks) { - /* final element must have exactly exhausted chunk */ - if (element_size != 0) { - assert(remainder_size == element_size); - } - else { - assert(remainder_size == request2size(sizes[i])); - } - check_inuse_chunk(m, mem2chunk(marray)); - } - for (i = 0; i != n_elements; ++i) - check_inuse_chunk(m, mem2chunk(marray[i])); - -#endif /* DEBUG */ - - POSTACTION(m); - return marray; -} - - -/* -------------------------- public routines ---------------------------- */ - -#if !ONLY_MSPACES - -void* dlmalloc(size_t bytes) { - /* - Basic algorithm: - If a small request (< 256 bytes minus per-chunk overhead): - 1. If one exists, use a remainderless chunk in associated smallbin. - (Remainderless means that there are too few excess bytes to - represent as a chunk.) - 2. If it is big enough, use the dv chunk, which is normally the - chunk adjacent to the one used for the most recent small request. - 3. If one exists, split the smallest available chunk in a bin, - saving remainder in dv. - 4. If it is big enough, use the top chunk. - 5. If available, get memory from system and use it - Otherwise, for a large request: - 1. Find the smallest available binned chunk that fits, and use it - if it is better fitting than dv chunk, splitting if necessary. - 2. If better fitting than any binned chunk, use the dv chunk. - 3. If it is big enough, use the top chunk. - 4. If request size >= mmap threshold, try to directly mmap this chunk. - 5. If available, get memory from system and use it - - The ugly goto's here ensure that postaction occurs along all paths. - */ - - if (!PREACTION(gm)) { - void* mem; - size_t nb; - if (bytes <= MAX_SMALL_REQUEST) { - bindex_t idx; - binmap_t smallbits; - nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); - idx = small_index(nb); - smallbits = gm->smallmap >> idx; - - if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ - mchunkptr b, p; - idx += ~smallbits & 1; /* Uses next bin if idx empty */ - b = smallbin_at(gm, idx); - p = b->fd; - assert(chunksize(p) == small_index2size(idx)); - unlink_first_small_chunk(gm, b, p, idx); - set_inuse_and_pinuse(gm, p, small_index2size(idx)); - mem = chunk2mem(p); - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - - else if (nb > gm->dvsize) { - if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ - mchunkptr b, p, r; - size_t rsize; - bindex_t i; - binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); - binmap_t leastbit = least_bit(leftbits); - compute_bit2idx(leastbit, i); - b = smallbin_at(gm, i); - p = b->fd; - assert(chunksize(p) == small_index2size(i)); - unlink_first_small_chunk(gm, b, p, i); - rsize = small_index2size(i) - nb; - /* Fit here cannot be remainderless if 4byte sizes */ - if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) - set_inuse_and_pinuse(gm, p, small_index2size(i)); - else { - set_size_and_pinuse_of_inuse_chunk(gm, p, nb); - r = chunk_plus_offset(p, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - replace_dv(gm, r, rsize); - } - mem = chunk2mem(p); - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - - else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) { - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - } - } - else if (bytes >= MAX_REQUEST) - nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ - else { - nb = pad_request(bytes); - if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) { - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - } - - if (nb <= gm->dvsize) { - size_t rsize = gm->dvsize - nb; - mchunkptr p = gm->dv; - if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ - mchunkptr r = gm->dv = chunk_plus_offset(p, nb); - gm->dvsize = rsize; - set_size_and_pinuse_of_free_chunk(r, rsize); - set_size_and_pinuse_of_inuse_chunk(gm, p, nb); - } - else { /* exhaust dv */ - size_t dvs = gm->dvsize; - gm->dvsize = 0; - gm->dv = 0; - set_inuse_and_pinuse(gm, p, dvs); - } - mem = chunk2mem(p); - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - - else if (nb < gm->topsize) { /* Split top */ - size_t rsize = gm->topsize -= nb; - mchunkptr p = gm->top; - mchunkptr r = gm->top = chunk_plus_offset(p, nb); - r->head = rsize | PINUSE_BIT; - set_size_and_pinuse_of_inuse_chunk(gm, p, nb); - mem = chunk2mem(p); - check_top_chunk(gm, gm->top); - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - - mem = sys_alloc(gm, nb); - - postaction: - POSTACTION(gm); - return mem; - } - - return 0; -} - -void dlfree(void* mem) { - /* - Consolidate freed chunks with preceeding or succeeding bordering - free chunks, if they exist, and then place in a bin. Intermixed - with special cases for top, dv, mmapped chunks, and usage errors. - */ - - if (mem != 0) { - mchunkptr p = mem2chunk(mem); -#if FOOTERS - mstate fm = get_mstate_for(p); - if (!ok_magic(fm)) { - USAGE_ERROR_ACTION(fm, p); - return; - } -#else /* FOOTERS */ -#define fm gm -#endif /* FOOTERS */ - if (!PREACTION(fm)) { - check_inuse_chunk(fm, p); - if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { - size_t psize = chunksize(p); - mchunkptr next = chunk_plus_offset(p, psize); - if (!pinuse(p)) { - size_t prevsize = p->prev_foot; - if ((prevsize & IS_MMAPPED_BIT) != 0) { - prevsize &= ~IS_MMAPPED_BIT; - psize += prevsize + MMAP_FOOT_PAD; - if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) - fm->footprint -= psize; - goto postaction; - } - else { - mchunkptr prev = chunk_minus_offset(p, prevsize); - psize += prevsize; - p = prev; - if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ - if (p != fm->dv) { - unlink_chunk(fm, p, prevsize); - } - else if ((next->head & INUSE_BITS) == INUSE_BITS) { - fm->dvsize = psize; - set_free_with_pinuse(p, psize, next); - goto postaction; - } - } - else - goto erroraction; - } - } - - if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { - if (!cinuse(next)) { /* consolidate forward */ - if (next == fm->top) { - size_t tsize = fm->topsize += psize; - fm->top = p; - p->head = tsize | PINUSE_BIT; - if (p == fm->dv) { - fm->dv = 0; - fm->dvsize = 0; - } - if (should_trim(fm, tsize)) - sys_trim(fm, 0); - goto postaction; - } - else if (next == fm->dv) { - size_t dsize = fm->dvsize += psize; - fm->dv = p; - set_size_and_pinuse_of_free_chunk(p, dsize); - goto postaction; - } - else { - size_t nsize = chunksize(next); - psize += nsize; - unlink_chunk(fm, next, nsize); - set_size_and_pinuse_of_free_chunk(p, psize); - if (p == fm->dv) { - fm->dvsize = psize; - goto postaction; - } - } - } - else - set_free_with_pinuse(p, psize, next); - insert_chunk(fm, p, psize); - check_free_chunk(fm, p); - goto postaction; - } - } - erroraction: - USAGE_ERROR_ACTION(fm, p); - postaction: - POSTACTION(fm); - } - } -#if !FOOTERS -#undef fm -#endif /* FOOTERS */ -} - -void* dlcalloc(size_t n_elements, size_t elem_size) { - void* mem; - size_t req = 0; - if (n_elements != 0) { - req = n_elements * elem_size; - if (((n_elements | elem_size) & ~(size_t)0xffff) && - (req / n_elements != elem_size)) - req = MAX_SIZE_T; /* force downstream failure on overflow */ - } - mem = dlmalloc(req); - if (mem != 0 && calloc_must_clear(mem2chunk(mem))) - memset(mem, 0, req); - return mem; -} - -void* dlrealloc(void* oldmem, size_t bytes) { - if (oldmem == 0) - return dlmalloc(bytes); -#ifdef REALLOC_ZERO_BYTES_FREES - if (bytes == 0) { - dlfree(oldmem); - return 0; - } -#endif /* REALLOC_ZERO_BYTES_FREES */ - else { -#if ! FOOTERS - mstate m = gm; -#else /* FOOTERS */ - mstate m = get_mstate_for(mem2chunk(oldmem)); - if (!ok_magic(m)) { - USAGE_ERROR_ACTION(m, oldmem); - return 0; - } -#endif /* FOOTERS */ - return internal_realloc(m, oldmem, bytes); - } -} - -void* dlmemalign(size_t alignment, size_t bytes) { - return internal_memalign(gm, alignment, bytes); -} - -void** dlindependent_calloc(size_t n_elements, size_t elem_size, - void* chunks[]) { - size_t sz = elem_size; /* serves as 1-element array */ - return ialloc(gm, n_elements, &sz, 3, chunks); -} - -void** dlindependent_comalloc(size_t n_elements, size_t sizes[], - void* chunks[]) { - return ialloc(gm, n_elements, sizes, 0, chunks); -} - -void* dlvalloc(size_t bytes) { - size_t pagesz; - init_mparams(); - pagesz = mparams.page_size; - return dlmemalign(pagesz, bytes); -} - -void* dlpvalloc(size_t bytes) { - size_t pagesz; - init_mparams(); - pagesz = mparams.page_size; - return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); -} - -int dlmalloc_trim(size_t pad) { - int result = 0; - if (!PREACTION(gm)) { - result = sys_trim(gm, pad); - POSTACTION(gm); - } - return result; -} - -size_t dlmalloc_footprint(void) { - return gm->footprint; -} - -size_t dlmalloc_max_footprint(void) { - return gm->max_footprint; -} - -#if !NO_MALLINFO -struct mallinfo dlmallinfo(void) { - return internal_mallinfo(gm); -} -#endif /* NO_MALLINFO */ - -void dlmalloc_stats() { - internal_malloc_stats(gm); -} - -size_t dlmalloc_usable_size(void* mem) { - if (mem != 0) { - mchunkptr p = mem2chunk(mem); - if (cinuse(p)) - return chunksize(p) - overhead_for(p); - } - return 0; -} - -int dlmallopt(int param_number, int value) { - return change_mparam(param_number, value); -} - -#endif /* !ONLY_MSPACES */ - -/* ----------------------------- user mspaces ---------------------------- */ - -#if MSPACES - -static mstate init_user_mstate(char* tbase, size_t tsize) { - size_t msize = pad_request(sizeof(struct malloc_state)); - mchunkptr mn; - mchunkptr msp = align_as_chunk(tbase); - mstate m = (mstate)(chunk2mem(msp)); - memset(m, 0, msize); - INITIAL_LOCK(&m->mutex); - msp->head = (msize|PINUSE_BIT|CINUSE_BIT); - m->seg.base = m->least_addr = tbase; - m->seg.size = m->footprint = m->max_footprint = tsize; - m->magic = mparams.magic; - m->mflags = mparams.default_mflags; - disable_contiguous(m); - init_bins(m); - mn = next_chunk(mem2chunk(m)); - init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE); - check_top_chunk(m, m->top); - return m; -} - -mspace create_mspace(size_t capacity, int locked) { - mstate m = 0; - size_t msize = pad_request(sizeof(struct malloc_state)); - init_mparams(); /* Ensure pagesize etc initialized */ - - if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { - size_t rs = ((capacity == 0)? mparams.granularity : - (capacity + TOP_FOOT_SIZE + msize)); - size_t tsize = granularity_align(rs); - char* tbase = (char*)(CALL_MMAP(tsize)); - if (tbase != CMFAIL) { - m = init_user_mstate(tbase, tsize); - m->seg.sflags = IS_MMAPPED_BIT; - set_lock(m, locked); - } - } - return (mspace)m; -} - -mspace create_mspace_with_base(void* base, size_t capacity, int locked) { - mstate m = 0; - size_t msize = pad_request(sizeof(struct malloc_state)); - init_mparams(); /* Ensure pagesize etc initialized */ - - if (capacity > msize + TOP_FOOT_SIZE && - capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { - m = init_user_mstate((char*)base, capacity); - m->seg.sflags = EXTERN_BIT; - set_lock(m, locked); - } - return (mspace)m; -} - -size_t destroy_mspace(mspace msp) { - size_t freed = 0; - mstate ms = (mstate)msp; - if (ok_magic(ms)) { - msegmentptr sp = &ms->seg; - while (sp != 0) { - char* base = sp->base; - size_t size = sp->size; - flag_t flag = sp->sflags; - sp = sp->next; - if ((flag & IS_MMAPPED_BIT) && !(flag & EXTERN_BIT) && - CALL_MUNMAP(base, size) == 0) - freed += size; - } - } - else { - USAGE_ERROR_ACTION(ms,ms); - } - return freed; -} - -/* - mspace versions of routines are near-clones of the global - versions. This is not so nice but better than the alternatives. -*/ - - -void* mspace_malloc(mspace msp, size_t bytes) { - mstate ms = (mstate)msp; - if (!ok_magic(ms)) { - USAGE_ERROR_ACTION(ms,ms); - return 0; - } - if (!PREACTION(ms)) { - void* mem; - size_t nb; - if (bytes <= MAX_SMALL_REQUEST) { - bindex_t idx; - binmap_t smallbits; - nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); - idx = small_index(nb); - smallbits = ms->smallmap >> idx; - - if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ - mchunkptr b, p; - idx += ~smallbits & 1; /* Uses next bin if idx empty */ - b = smallbin_at(ms, idx); - p = b->fd; - assert(chunksize(p) == small_index2size(idx)); - unlink_first_small_chunk(ms, b, p, idx); - set_inuse_and_pinuse(ms, p, small_index2size(idx)); - mem = chunk2mem(p); - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - - else if (nb > ms->dvsize) { - if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ - mchunkptr b, p, r; - size_t rsize; - bindex_t i; - binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); - binmap_t leastbit = least_bit(leftbits); - compute_bit2idx(leastbit, i); - b = smallbin_at(ms, i); - p = b->fd; - assert(chunksize(p) == small_index2size(i)); - unlink_first_small_chunk(ms, b, p, i); - rsize = small_index2size(i) - nb; - /* Fit here cannot be remainderless if 4byte sizes */ - if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) - set_inuse_and_pinuse(ms, p, small_index2size(i)); - else { - set_size_and_pinuse_of_inuse_chunk(ms, p, nb); - r = chunk_plus_offset(p, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - replace_dv(ms, r, rsize); - } - mem = chunk2mem(p); - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - - else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) { - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - } - } - else if (bytes >= MAX_REQUEST) - nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ - else { - nb = pad_request(bytes); - if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) { - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - } - - if (nb <= ms->dvsize) { - size_t rsize = ms->dvsize - nb; - mchunkptr p = ms->dv; - if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ - mchunkptr r = ms->dv = chunk_plus_offset(p, nb); - ms->dvsize = rsize; - set_size_and_pinuse_of_free_chunk(r, rsize); - set_size_and_pinuse_of_inuse_chunk(ms, p, nb); - } - else { /* exhaust dv */ - size_t dvs = ms->dvsize; - ms->dvsize = 0; - ms->dv = 0; - set_inuse_and_pinuse(ms, p, dvs); - } - mem = chunk2mem(p); - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - - else if (nb < ms->topsize) { /* Split top */ - size_t rsize = ms->topsize -= nb; - mchunkptr p = ms->top; - mchunkptr r = ms->top = chunk_plus_offset(p, nb); - r->head = rsize | PINUSE_BIT; - set_size_and_pinuse_of_inuse_chunk(ms, p, nb); - mem = chunk2mem(p); - check_top_chunk(ms, ms->top); - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - - mem = sys_alloc(ms, nb); - - postaction: - POSTACTION(ms); - return mem; - } - - return 0; -} - -void mspace_free(mspace msp, void* mem) { - if (mem != 0) { - mchunkptr p = mem2chunk(mem); -#if FOOTERS - mstate fm = get_mstate_for(p); -#else /* FOOTERS */ - mstate fm = (mstate)msp; -#endif /* FOOTERS */ - if (!ok_magic(fm)) { - USAGE_ERROR_ACTION(fm, p); - return; - } - if (!PREACTION(fm)) { - check_inuse_chunk(fm, p); - if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { - size_t psize = chunksize(p); - mchunkptr next = chunk_plus_offset(p, psize); - if (!pinuse(p)) { - size_t prevsize = p->prev_foot; - if ((prevsize & IS_MMAPPED_BIT) != 0) { - prevsize &= ~IS_MMAPPED_BIT; - psize += prevsize + MMAP_FOOT_PAD; - if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) - fm->footprint -= psize; - goto postaction; - } - else { - mchunkptr prev = chunk_minus_offset(p, prevsize); - psize += prevsize; - p = prev; - if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ - if (p != fm->dv) { - unlink_chunk(fm, p, prevsize); - } - else if ((next->head & INUSE_BITS) == INUSE_BITS) { - fm->dvsize = psize; - set_free_with_pinuse(p, psize, next); - goto postaction; - } - } - else - goto erroraction; - } - } - - if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { - if (!cinuse(next)) { /* consolidate forward */ - if (next == fm->top) { - size_t tsize = fm->topsize += psize; - fm->top = p; - p->head = tsize | PINUSE_BIT; - if (p == fm->dv) { - fm->dv = 0; - fm->dvsize = 0; - } - if (should_trim(fm, tsize)) - sys_trim(fm, 0); - goto postaction; - } - else if (next == fm->dv) { - size_t dsize = fm->dvsize += psize; - fm->dv = p; - set_size_and_pinuse_of_free_chunk(p, dsize); - goto postaction; - } - else { - size_t nsize = chunksize(next); - psize += nsize; - unlink_chunk(fm, next, nsize); - set_size_and_pinuse_of_free_chunk(p, psize); - if (p == fm->dv) { - fm->dvsize = psize; - goto postaction; - } - } - } - else - set_free_with_pinuse(p, psize, next); - insert_chunk(fm, p, psize); - check_free_chunk(fm, p); - goto postaction; - } - } - erroraction: - USAGE_ERROR_ACTION(fm, p); - postaction: - POSTACTION(fm); - } - } -} - -void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) { - void* mem; - size_t req = 0; - mstate ms = (mstate)msp; - if (!ok_magic(ms)) { - USAGE_ERROR_ACTION(ms,ms); - return 0; - } - if (n_elements != 0) { - req = n_elements * elem_size; - if (((n_elements | elem_size) & ~(size_t)0xffff) && - (req / n_elements != elem_size)) - req = MAX_SIZE_T; /* force downstream failure on overflow */ - } - mem = internal_malloc(ms, req); - if (mem != 0 && calloc_must_clear(mem2chunk(mem))) - memset(mem, 0, req); - return mem; -} - -void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) { - if (oldmem == 0) - return mspace_malloc(msp, bytes); -#ifdef REALLOC_ZERO_BYTES_FREES - if (bytes == 0) { - mspace_free(msp, oldmem); - return 0; - } -#endif /* REALLOC_ZERO_BYTES_FREES */ - else { -#if FOOTERS - mchunkptr p = mem2chunk(oldmem); - mstate ms = get_mstate_for(p); -#else /* FOOTERS */ - mstate ms = (mstate)msp; -#endif /* FOOTERS */ - if (!ok_magic(ms)) { - USAGE_ERROR_ACTION(ms,ms); - return 0; - } - return internal_realloc(ms, oldmem, bytes); - } -} - -void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) { - mstate ms = (mstate)msp; - if (!ok_magic(ms)) { - USAGE_ERROR_ACTION(ms,ms); - return 0; - } - return internal_memalign(ms, alignment, bytes); -} - -void** mspace_independent_calloc(mspace msp, size_t n_elements, - size_t elem_size, void* chunks[]) { - size_t sz = elem_size; /* serves as 1-element array */ - mstate ms = (mstate)msp; - if (!ok_magic(ms)) { - USAGE_ERROR_ACTION(ms,ms); - return 0; - } - return ialloc(ms, n_elements, &sz, 3, chunks); -} - -void** mspace_independent_comalloc(mspace msp, size_t n_elements, - size_t sizes[], void* chunks[]) { - mstate ms = (mstate)msp; - if (!ok_magic(ms)) { - USAGE_ERROR_ACTION(ms,ms); - return 0; - } - return ialloc(ms, n_elements, sizes, 0, chunks); -} - -int mspace_trim(mspace msp, size_t pad) { - int result = 0; - mstate ms = (mstate)msp; - if (ok_magic(ms)) { - if (!PREACTION(ms)) { - result = sys_trim(ms, pad); - POSTACTION(ms); - } - } - else { - USAGE_ERROR_ACTION(ms,ms); - } - return result; -} - -void mspace_malloc_stats(mspace msp) { - mstate ms = (mstate)msp; - if (ok_magic(ms)) { - internal_malloc_stats(ms); - } - else { - USAGE_ERROR_ACTION(ms,ms); - } -} - -size_t mspace_footprint(mspace msp) { - size_t result; - mstate ms = (mstate)msp; - if (ok_magic(ms)) { - result = ms->footprint; - } - USAGE_ERROR_ACTION(ms,ms); - return result; -} - - -size_t mspace_max_footprint(mspace msp) { - size_t result; - mstate ms = (mstate)msp; - if (ok_magic(ms)) { - result = ms->max_footprint; - } - USAGE_ERROR_ACTION(ms,ms); - return result; -} - - -#if !NO_MALLINFO -struct mallinfo mspace_mallinfo(mspace msp) { - mstate ms = (mstate)msp; - if (!ok_magic(ms)) { - USAGE_ERROR_ACTION(ms,ms); - } - return internal_mallinfo(ms); -} -#endif /* NO_MALLINFO */ - -int mspace_mallopt(int param_number, int value) { - return change_mparam(param_number, value); -} - -#endif /* MSPACES */ - -/* -------------------- Alternative MORECORE functions ------------------- */ - -/* - Guidelines for creating a custom version of MORECORE: - - * For best performance, MORECORE should allocate in multiples of pagesize. - * MORECORE may allocate more memory than requested. (Or even less, - but this will usually result in a malloc failure.) - * MORECORE must not allocate memory when given argument zero, but - instead return one past the end address of memory from previous - nonzero call. - * For best performance, consecutive calls to MORECORE with positive - arguments should return increasing addresses, indicating that - space has been contiguously extended. - * Even though consecutive calls to MORECORE need not return contiguous - addresses, it must be OK for malloc'ed chunks to span multiple - regions in those cases where they do happen to be contiguous. - * MORECORE need not handle negative arguments -- it may instead - just return MFAIL when given negative arguments. - Negative arguments are always multiples of pagesize. MORECORE - must not misinterpret negative args as large positive unsigned - args. You can suppress all such calls from even occurring by defining - MORECORE_CANNOT_TRIM, - - As an example alternative MORECORE, here is a custom allocator - kindly contributed for pre-OSX macOS. It uses virtually but not - necessarily physically contiguous non-paged memory (locked in, - present and won't get swapped out). You can use it by uncommenting - this section, adding some #includes, and setting up the appropriate - defines above: - - #define MORECORE osMoreCore - - There is also a shutdown routine that should somehow be called for - cleanup upon program exit. - - #define MAX_POOL_ENTRIES 100 - #define MINIMUM_MORECORE_SIZE (64 * 1024U) - static int next_os_pool; - void *our_os_pools[MAX_POOL_ENTRIES]; - - void *osMoreCore(int size) - { - void *ptr = 0; - static void *sbrk_top = 0; - - if (size > 0) - { - if (size < MINIMUM_MORECORE_SIZE) - size = MINIMUM_MORECORE_SIZE; - if (CurrentExecutionLevel() == kTaskLevel) - ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); - if (ptr == 0) - { - return (void *) MFAIL; - } - // save ptrs so they can be freed during cleanup - our_os_pools[next_os_pool] = ptr; - next_os_pool++; - ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); - sbrk_top = (char *) ptr + size; - return ptr; - } - else if (size < 0) - { - // we don't currently support shrink behavior - return (void *) MFAIL; - } - else - { - return sbrk_top; - } - } - - // cleanup any allocated memory pools - // called as last thing before shutting down driver - - void osCleanupMem(void) - { - void **ptr; - - for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) - if (*ptr) - { - PoolDeallocate(*ptr); - *ptr = 0; - } - } - -*/ - - -/* ----------------------------------------------------------------------- -History: - V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee) - * Add max_footprint functions - * Ensure all appropriate literals are size_t - * Fix conditional compilation problem for some #define settings - * Avoid concatenating segments with the one provided - in create_mspace_with_base - * Rename some variables to avoid compiler shadowing warnings - * Use explicit lock initialization. - * Better handling of sbrk interference. - * Simplify and fix segment insertion, trimming and mspace_destroy - * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x - * Thanks especially to Dennis Flanagan for help on these. - - V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee) - * Fix memalign brace error. - - V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee) - * Fix improper #endif nesting in C++ - * Add explicit casts needed for C++ - - V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee) - * Use trees for large bins - * Support mspaces - * Use segments to unify sbrk-based and mmap-based system allocation, - removing need for emulation on most platforms without sbrk. - * Default safety checks - * Optional footer checks. Thanks to William Robertson for the idea. - * Internal code refactoring - * Incorporate suggestions and platform-specific changes. - Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas, - Aaron Bachmann, Emery Berger, and others. - * Speed up non-fastbin processing enough to remove fastbins. - * Remove useless cfree() to avoid conflicts with other apps. - * Remove internal memcpy, memset. Compilers handle builtins better. - * Remove some options that no one ever used and rename others. - - V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) - * Fix malloc_state bitmap array misdeclaration - - V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee) - * Allow tuning of FIRST_SORTED_BIN_SIZE - * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte. - * Better detection and support for non-contiguousness of MORECORE. - Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger - * Bypass most of malloc if no frees. Thanks To Emery Berger. - * Fix freeing of old top non-contiguous chunk im sysmalloc. - * Raised default trim and map thresholds to 256K. - * Fix mmap-related #defines. Thanks to Lubos Lunak. - * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield. - * Branch-free bin calculation - * Default trim and mmap thresholds now 256K. - - V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) - * Introduce independent_comalloc and independent_calloc. - Thanks to Michael Pachos for motivation and help. - * Make optional .h file available - * Allow > 2GB requests on 32bit systems. - * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>. - Thanks also to Andreas Mueller <a.mueller at paradatec.de>, - and Anonymous. - * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for - helping test this.) - * memalign: check alignment arg - * realloc: don't try to shift chunks backwards, since this - leads to more fragmentation in some programs and doesn't - seem to help in any others. - * Collect all cases in malloc requiring system memory into sysmalloc - * Use mmap as backup to sbrk - * Place all internal state in malloc_state - * Introduce fastbins (although similar to 2.5.1) - * Many minor tunings and cosmetic improvements - * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK - * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS - Thanks to Tony E. Bennett <tbennett@nvidia.com> and others. - * Include errno.h to support default failure action. - - V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) - * return null for negative arguments - * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com> - * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' - (e.g. WIN32 platforms) - * Cleanup header file inclusion for WIN32 platforms - * Cleanup code to avoid Microsoft Visual C++ compiler complaints - * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing - memory allocation routines - * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) - * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to - usage of 'assert' in non-WIN32 code - * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to - avoid infinite loop - * Always call 'fREe()' rather than 'free()' - - V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) - * Fixed ordering problem with boundary-stamping - - V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) - * Added pvalloc, as recommended by H.J. Liu - * Added 64bit pointer support mainly from Wolfram Gloger - * Added anonymously donated WIN32 sbrk emulation - * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen - * malloc_extend_top: fix mask error that caused wastage after - foreign sbrks - * Add linux mremap support code from HJ Liu - - V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) - * Integrated most documentation with the code. - * Add support for mmap, with help from - Wolfram Gloger (Gloger@lrz.uni-muenchen.de). - * Use last_remainder in more cases. - * Pack bins using idea from colin@nyx10.cs.du.edu - * Use ordered bins instead of best-fit threshhold - * Eliminate block-local decls to simplify tracing and debugging. - * Support another case of realloc via move into top - * Fix error occuring when initial sbrk_base not word-aligned. - * Rely on page size for units instead of SBRK_UNIT to - avoid surprises about sbrk alignment conventions. - * Add mallinfo, mallopt. Thanks to Raymond Nijssen - (raymond@es.ele.tue.nl) for the suggestion. - * Add `pad' argument to malloc_trim and top_pad mallopt parameter. - * More precautions for cases where other routines call sbrk, - courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). - * Added macros etc., allowing use in linux libc from - H.J. Lu (hjl@gnu.ai.mit.edu) - * Inverted this history list - - V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) - * Re-tuned and fixed to behave more nicely with V2.6.0 changes. - * Removed all preallocation code since under current scheme - the work required to undo bad preallocations exceeds - the work saved in good cases for most test programs. - * No longer use return list or unconsolidated bins since - no scheme using them consistently outperforms those that don't - given above changes. - * Use best fit for very large chunks to prevent some worst-cases. - * Added some support for debugging - - V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) - * Removed footers when chunks are in use. Thanks to - Paul Wilson (wilson@cs.texas.edu) for the suggestion. - - V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) - * Added malloc_trim, with help from Wolfram Gloger - (wmglo@Dent.MED.Uni-Muenchen.DE). - - V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) - - V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) - * realloc: try to expand in both directions - * malloc: swap order of clean-bin strategy; - * realloc: only conditionally expand backwards - * Try not to scavenge used bins - * Use bin counts as a guide to preallocation - * Occasionally bin return list chunks in first scan - * Add a few optimizations from colin@nyx10.cs.du.edu - - V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) - * faster bin computation & slightly different binning - * merged all consolidations to one part of malloc proper - (eliminating old malloc_find_space & malloc_clean_bin) - * Scan 2 returns chunks (not just 1) - * Propagate failure in realloc if malloc returns 0 - * Add stuff to allow compilation on non-ANSI compilers - from kpv@research.att.com - - V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) - * removed potential for odd address access in prev_chunk - * removed dependency on getpagesize.h - * misc cosmetics and a bit more internal documentation - * anticosmetics: mangled names in macros to evade debugger strangeness - * tested on sparc, hp-700, dec-mips, rs6000 - with gcc & native cc (hp, dec only) allowing - Detlefs & Zorn comparison study (in SIGPLAN Notices.) - - Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) - * Based loosely on libg++-1.2X malloc. (It retains some of the overall - structure of old version, but most details differ.) - -*/ +#define USE_DL_PREFIX + +#define FOOTERS 1 +#define DEBUG 1 +/* +#define ABORT_ON_ASSERT_FAILURE 0 +*/ + +#define ABORT do { printf("abort was called\n"); abort(); } while (0) + +/* + This is a version (aka dlmalloc) of malloc/free/realloc written by + Doug Lea and released to the public domain, as explained at + http://creativecommons.org/licenses/publicdomain. Send questions, + comments, complaints, performance data, etc to dl@cs.oswego.edu + +* Version 2.8.3 Thu Sep 22 11:16:15 2005 Doug Lea (dl at gee) + + Note: There may be an updated version of this malloc obtainable at + ftp://gee.cs.oswego.edu/pub/misc/malloc.c + Check before installing! + +* Quickstart + + This library is all in one file to simplify the most common usage: + ftp it, compile it (-O3), and link it into another program. All of + the compile-time options default to reasonable values for use on + most platforms. You might later want to step through various + compile-time and dynamic tuning options. + + For convenience, an include file for code using this malloc is at: + ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.3.h + You don't really need this .h file unless you call functions not + defined in your system include files. The .h file contains only the + excerpts from this file needed for using this malloc on ANSI C/C++ + systems, so long as you haven't changed compile-time options about + naming and tuning parameters. If you do, then you can create your + own malloc.h that does include all settings by cutting at the point + indicated below. Note that you may already by default be using a C + library containing a malloc that is based on some version of this + malloc (for example in linux). You might still want to use the one + in this file to customize settings or to avoid overheads associated + with library versions. + +* Vital statistics: + + Supported pointer/size_t representation: 4 or 8 bytes + size_t MUST be an unsigned type of the same width as + pointers. (If you are using an ancient system that declares + size_t as a signed type, or need it to be a different width + than pointers, you can use a previous release of this malloc + (e.g. 2.7.2) supporting these.) + + Alignment: 8 bytes (default) + This suffices for nearly all current machines and C compilers. + However, you can define MALLOC_ALIGNMENT to be wider than this + if necessary (up to 128bytes), at the expense of using more space. + + Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes) + 8 or 16 bytes (if 8byte sizes) + Each malloced chunk has a hidden word of overhead holding size + and status information, and additional cross-check word + if FOOTERS is defined. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead) + 8-byte ptrs: 32 bytes (including overhead) + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + The maximum overhead wastage (i.e., number of extra bytes + allocated than were requested in malloc) is less than or equal + to the minimum size, except for requests >= mmap_threshold that + are serviced via mmap(), where the worst case wastage is about + 32 bytes plus the remainder from a system page (the minimal + mmap unit); typically 4096 or 8192 bytes. + + Security: static-safe; optionally more or less + The "security" of malloc refers to the ability of malicious + code to accentuate the effects of errors (for example, freeing + space that is not currently malloc'ed or overwriting past the + ends of chunks) in code that calls malloc. This malloc + guarantees not to modify any memory locations below the base of + heap, i.e., static variables, even in the presence of usage + errors. The routines additionally detect most improper frees + and reallocs. All this holds as long as the static bookkeeping + for malloc itself is not corrupted by some other means. This + is only one aspect of security -- these checks do not, and + cannot, detect all possible programming errors. + + If FOOTERS is defined nonzero, then each allocated chunk + carries an additional check word to verify that it was malloced + from its space. These check words are the same within each + execution of a program using malloc, but differ across + executions, so externally crafted fake chunks cannot be + freed. This improves security by rejecting frees/reallocs that + could corrupt heap memory, in addition to the checks preventing + writes to statics that are always on. This may further improve + security at the expense of time and space overhead. (Note that + FOOTERS may also be worth using with MSPACES.) + + By default detected errors cause the program to abort (calling + "abort()"). You can override this to instead proceed past + errors by defining PROCEED_ON_ERROR. In this case, a bad free + has no effect, and a malloc that encounters a bad address + caused by user overwrites will ignore the bad address by + dropping pointers and indices to all known memory. This may + be appropriate for programs that should continue if at all + possible in the face of programming errors, although they may + run out of memory because dropped memory is never reclaimed. + + If you don't like either of these options, you can define + CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything + else. And if if you are sure that your program using malloc has + no errors or vulnerabilities, you can define INSECURE to 1, + which might (or might not) provide a small performance improvement. + + Thread-safety: NOT thread-safe unless USE_LOCKS defined + When USE_LOCKS is defined, each public call to malloc, free, + etc is surrounded with either a pthread mutex or a win32 + spinlock (depending on WIN32). This is not especially fast, and + can be a major bottleneck. It is designed only to provide + minimal protection in concurrent environments, and to provide a + basis for extensions. If you are using malloc in a concurrent + program, consider instead using ptmalloc, which is derived from + a version of this malloc. (See http://www.malloc.de). + + System requirements: Any combination of MORECORE and/or MMAP/MUNMAP + This malloc can use unix sbrk or any emulation (invoked using + the CALL_MORECORE macro) and/or mmap/munmap or any emulation + (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system + memory. On most unix systems, it tends to work best if both + MORECORE and MMAP are enabled. On Win32, it uses emulations + based on VirtualAlloc. It also uses common C library functions + like memset. + + Compliance: I believe it is compliant with the Single Unix Specification + (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably + others as well. + +* Overview of algorithms + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and + tunable. Consistent balance across these factors results in a good + general-purpose allocator for malloc-intensive programs. + + In most ways, this malloc is a best-fit allocator. Generally, it + chooses the best-fitting existing chunk for a request, with ties + broken in approximately least-recently-used order. (This strategy + normally maintains low fragmentation.) However, for requests less + than 256bytes, it deviates from best-fit when there is not an + exactly fitting available chunk by preferring to use space adjacent + to that used for the previous small request, as well as by breaking + ties in approximately most-recently-used order. (These enhance + locality of series of small allocations.) And for very large requests + (>= 256Kb by default), it relies on system memory mapping + facilities, if supported. (This helps avoid carrying around and + possibly fragmenting memory used only for large chunks.) + + All operations (except malloc_stats and mallinfo) have execution + times that are bounded by a constant factor of the number of bits in + a size_t, not counting any clearing in calloc or copying in realloc, + or actions surrounding MORECORE and MMAP that have times + proportional to the number of non-contiguous regions returned by + system allocation routines, which is often just 1. + + The implementation is not very modular and seriously overuses + macros. Perhaps someday all C compilers will do as good a job + inlining modular code as can now be done by brute-force expansion, + but now, enough of them seem not to. + + Some compilers issue a lot of warnings about code that is + dead/unreachable only on some platforms, and also about intentional + uses of negation on unsigned types. All known cases of each can be + ignored. + + For a longer but out of date high-level description, see + http://gee.cs.oswego.edu/dl/html/malloc.html + +* MSPACES + If MSPACES is defined, then in addition to malloc, free, etc., + this file also defines mspace_malloc, mspace_free, etc. These + are versions of malloc routines that take an "mspace" argument + obtained using create_mspace, to control all internal bookkeeping. + If ONLY_MSPACES is defined, only these versions are compiled. + So if you would like to use this allocator for only some allocations, + and your system malloc for others, you can compile with + ONLY_MSPACES and then do something like... + static mspace mymspace = create_mspace(0,0); // for example + #define mymalloc(bytes) mspace_malloc(mymspace, bytes) + + (Note: If you only need one instance of an mspace, you can instead + use "USE_DL_PREFIX" to relabel the global malloc.) + + You can similarly create thread-local allocators by storing + mspaces as thread-locals. For example: + static __thread mspace tlms = 0; + void* tlmalloc(size_t bytes) { + if (tlms == 0) tlms = create_mspace(0, 0); + return mspace_malloc(tlms, bytes); + } + void tlfree(void* mem) { mspace_free(tlms, mem); } + + Unless FOOTERS is defined, each mspace is completely independent. + You cannot allocate from one and free to another (although + conformance is only weakly checked, so usage errors are not always + caught). If FOOTERS is defined, then each chunk carries around a tag + indicating its originating mspace, and frees are directed to their + originating spaces. + + ------------------------- Compile-time options --------------------------- + +Be careful in setting #define values for numerical constants of type +size_t. On some systems, literal values are not automatically extended +to size_t precision unless they are explicitly casted. + +WIN32 default: defined if _WIN32 defined + Defining WIN32 sets up defaults for MS environment and compilers. + Otherwise defaults are for unix. + +MALLOC_ALIGNMENT default: (size_t)8 + Controls the minimum alignment for malloc'ed chunks. It must be a + power of two and at least 8, even on machines for which smaller + alignments would suffice. It may be defined as larger than this + though. Note however that code and data structures are optimized for + the case of 8-byte alignment. + +MSPACES default: 0 (false) + If true, compile in support for independent allocation spaces. + This is only supported if HAVE_MMAP is true. + +ONLY_MSPACES default: 0 (false) + If true, only compile in mspace versions, not regular versions. + +USE_LOCKS default: 0 (false) + Causes each call to each public routine to be surrounded with + pthread or WIN32 mutex lock/unlock. (If set true, this can be + overridden on a per-mspace basis for mspace versions.) + +FOOTERS default: 0 + If true, provide extra checking and dispatching by placing + information in the footers of allocated chunks. This adds + space and time overhead. + +INSECURE default: 0 + If true, omit checks for usage errors and heap space overwrites. + +USE_DL_PREFIX default: NOT defined + Causes compiler to prefix all public routines with the string 'dl'. + This can be useful when you only want to use this malloc in one part + of a program, using your regular system malloc elsewhere. + +ABORT default: defined as abort() + Defines how to abort on failed checks. On most systems, a failed + check cannot die with an "assert" or even print an informative + message, because the underlying print routines in turn call malloc, + which will fail again. Generally, the best policy is to simply call + abort(). It's not very useful to do more than this because many + errors due to overwriting will show up as address faults (null, odd + addresses etc) rather than malloc-triggered checks, so will also + abort. Also, most compilers know that abort() does not return, so + can better optimize code conditionally calling it. + +PROCEED_ON_ERROR default: defined as 0 (false) + Controls whether detected bad addresses cause them to bypassed + rather than aborting. If set, detected bad arguments to free and + realloc are ignored. And all bookkeeping information is zeroed out + upon a detected overwrite of freed heap space, thus losing the + ability to ever return it from malloc again, but enabling the + application to proceed. If PROCEED_ON_ERROR is defined, the + static variable malloc_corruption_error_count is compiled in + and can be examined to see if errors have occurred. This option + generates slower code than the default abort policy. + +DEBUG default: NOT defined + The DEBUG setting is mainly intended for people trying to modify + this code or diagnose problems when porting to new platforms. + However, it may also be able to better isolate user errors than just + using runtime checks. The assertions in the check routines spell + out in more detail the assumptions and invariants underlying the + algorithms. The checking is fairly extensive, and will slow down + execution noticeably. Calling malloc_stats or mallinfo with DEBUG + set will attempt to check every non-mmapped allocated and free chunk + in the course of computing the summaries. + +ABORT_ON_ASSERT_FAILURE default: defined as 1 (true) + Debugging assertion failures can be nearly impossible if your + version of the assert macro causes malloc to be called, which will + lead to a cascade of further failures, blowing the runtime stack. + ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(), + which will usually make debugging easier. + +MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32 + The action to take before "return 0" when malloc fails to be able to + return memory because there is none available. + +HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES + True if this system supports sbrk or an emulation of it. + +MORECORE default: sbrk + The name of the sbrk-style system routine to call to obtain more + memory. See below for guidance on writing custom MORECORE + functions. The type of the argument to sbrk/MORECORE varies across + systems. It cannot be size_t, because it supports negative + arguments, so it is normally the signed type of the same width as + size_t (sometimes declared as "intptr_t"). It doesn't much matter + though. Internally, we only call it with arguments less than half + the max value of a size_t, which should work across all reasonable + possibilities, although sometimes generating compiler warnings. See + near the end of this file for guidelines for creating a custom + version of MORECORE. + +MORECORE_CONTIGUOUS default: 1 (true) + If true, take advantage of fact that consecutive calls to MORECORE + with positive arguments always return contiguous increasing + addresses. This is true of unix sbrk. It does not hurt too much to + set it true anyway, since malloc copes with non-contiguities. + Setting it false when definitely non-contiguous saves time + and possibly wasted space it would take to discover this though. + +MORECORE_CANNOT_TRIM default: NOT defined + True if MORECORE cannot release space back to the system when given + negative arguments. This is generally necessary only if you are + using a hand-crafted MORECORE function that cannot handle negative + arguments. + +HAVE_MMAP default: 1 (true) + True if this system supports mmap or an emulation of it. If so, and + HAVE_MORECORE is not true, MMAP is used for all system + allocation. If set and HAVE_MORECORE is true as well, MMAP is + primarily used to directly allocate very large blocks. It is also + used as a backup strategy in cases where MORECORE fails to provide + space from system. Note: A single call to MUNMAP is assumed to be + able to unmap memory that may have be allocated using multiple calls + to MMAP, so long as they are adjacent. + +HAVE_MREMAP default: 1 on linux, else 0 + If true realloc() uses mremap() to re-allocate large blocks and + extend or shrink allocation spaces. + +MMAP_CLEARS default: 1 on unix + True if mmap clears memory so calloc doesn't need to. This is true + for standard unix mmap using /dev/zero. + +USE_BUILTIN_FFS default: 0 (i.e., not used) + Causes malloc to use the builtin ffs() function to compute indices. + Some compilers may recognize and intrinsify ffs to be faster than the + supplied C version. Also, the case of x86 using gcc is special-cased + to an asm instruction, so is already as fast as it can be, and so + this setting has no effect. (On most x86s, the asm version is only + slightly faster than the C version.) + +malloc_getpagesize default: derive from system includes, or 4096. + The system page size. To the extent possible, this malloc manages + memory from the system in page-size units. This may be (and + usually is) a function rather than a constant. This is ignored + if WIN32, where page size is determined using getSystemInfo during + initialization. + +USE_DEV_RANDOM default: 0 (i.e., not used) + Causes malloc to use /dev/random to initialize secure magic seed for + stamping footers. Otherwise, the current time is used. + +NO_MALLINFO default: 0 + If defined, don't compile "mallinfo". This can be a simple way + of dealing with mismatches between system declarations and + those in this file. + +MALLINFO_FIELD_TYPE default: size_t + The type of the fields in the mallinfo struct. This was originally + defined as "int" in SVID etc, but is more usefully defined as + size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set + +REALLOC_ZERO_BYTES_FREES default: not defined + This should be set if a call to realloc with zero bytes should + be the same as a call to free. Some people think it should. Otherwise, + since this malloc returns a unique pointer for malloc(0), so does + realloc(p, 0). + +LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H +LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H +LACKS_STDLIB_H default: NOT defined unless on WIN32 + Define these if your system does not have these header files. + You might need to manually insert some of the declarations they provide. + +DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS, + system_info.dwAllocationGranularity in WIN32, + otherwise 64K. + Also settable using mallopt(M_GRANULARITY, x) + The unit for allocating and deallocating memory from the system. On + most systems with contiguous MORECORE, there is no reason to + make this more than a page. However, systems with MMAP tend to + either require or encourage larger granularities. You can increase + this value to prevent system allocation functions to be called so + often, especially if they are slow. The value must be at least one + page and must be a power of two. Setting to 0 causes initialization + to either page size or win32 region size. (Note: In previous + versions of malloc, the equivalent of this option was called + "TOP_PAD") + +DEFAULT_TRIM_THRESHOLD default: 2MB + Also settable using mallopt(M_TRIM_THRESHOLD, x) + The maximum amount of unused top-most memory to keep before + releasing via malloc_trim in free(). Automatic trimming is mainly + useful in long-lived programs using contiguous MORECORE. Because + trimming via sbrk can be slow on some systems, and can sometimes be + wasteful (in cases where programs immediately afterward allocate + more large chunks) the value should be high enough so that your + overall system performance would improve by releasing this much + memory. As a rough guide, you might set to a value close to the + average size of a process (program) running on your system. + Releasing this much memory would allow such a process to run in + memory. Generally, it is worth tuning trim thresholds when a + program undergoes phases where several large chunks are allocated + and released in ways that can reuse each other's storage, perhaps + mixed with phases where there are no such chunks at all. The trim + value must be greater than page size to have any useful effect. To + disable trimming completely, you can set to MAX_SIZE_T. Note that the trick + some people use of mallocing a huge space and then freeing it at + program startup, in an attempt to reserve system memory, doesn't + have the intended effect under automatic trimming, since that memory + will immediately be returned to the system. + +DEFAULT_MMAP_THRESHOLD default: 256K + Also settable using mallopt(M_MMAP_THRESHOLD, x) + The request size threshold for using MMAP to directly service a + request. Requests of at least this size that cannot be allocated + using already-existing space will be serviced via mmap. (If enough + normal freed space already exists it is used instead.) Using mmap + segregates relatively large chunks of memory so that they can be + individually obtained and released from the host system. A request + serviced through mmap is never reused by any other request (at least + not directly; the system may just so happen to remap successive + requests to the same locations). Segregating space in this way has + the benefits that: Mmapped space can always be individually released + back to the system, which helps keep the system level memory demands + of a long-lived program low. Also, mapped memory doesn't become + `locked' between other chunks, as can happen with normally allocated + chunks, which means that even trimming via malloc_trim would not + release them. However, it has the disadvantage that the space + cannot be reclaimed, consolidated, and then used to service later + requests, as happens with normal chunks. The advantages of mmap + nearly always outweigh disadvantages for "large" chunks, but the + value of "large" may vary across systems. The default is an + empirically derived value that works well in most systems. You can + disable mmap by setting to MAX_SIZE_T. + +*/ +#if defined(__WATCOMC__) || defined(_MSC_VER) +#define WIN32 1 +#endif + +#ifndef WIN32 +#ifdef _WIN32 +#define WIN32 1 +#endif /* _WIN32 */ +#endif /* WIN32 */ +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#define HAVE_MORECORE 0 +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H +#define LACKS_SYS_MMAN_H +#define LACKS_STRING_H +#define LACKS_STRINGS_H +#define LACKS_SYS_TYPES_H +#define LACKS_ERRNO_H +#define MALLOC_FAILURE_ACTION +#define MMAP_CLEARS 0 /* WINCE and some others apparently don't clear */ +#endif /* WIN32 */ + +#if defined(DARWIN) || defined(_DARWIN) +/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ +#ifndef HAVE_MORECORE +#define HAVE_MORECORE 0 +#define HAVE_MMAP 1 +#endif /* HAVE_MORECORE */ +#endif /* DARWIN */ + +#ifndef LACKS_SYS_TYPES_H +#include <sys/types.h> /* For size_t */ +#endif /* LACKS_SYS_TYPES_H */ + +/* The maximum possible size_t value has all bits set */ +#define MAX_SIZE_T (~(size_t)0) + +#ifndef ONLY_MSPACES +#define ONLY_MSPACES 0 +#endif /* ONLY_MSPACES */ +#ifndef MSPACES +#if ONLY_MSPACES +#define MSPACES 1 +#else /* ONLY_MSPACES */ +#define MSPACES 0 +#endif /* ONLY_MSPACES */ +#endif /* MSPACES */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)8U) +#endif /* MALLOC_ALIGNMENT */ +#ifndef FOOTERS +#define FOOTERS 0 +#endif /* FOOTERS */ +#ifndef ABORT +#define ABORT abort() +#endif /* ABORT */ +#ifndef ABORT_ON_ASSERT_FAILURE +#define ABORT_ON_ASSERT_FAILURE 1 +#endif /* ABORT_ON_ASSERT_FAILURE */ +#ifndef PROCEED_ON_ERROR +#define PROCEED_ON_ERROR 0 +#endif /* PROCEED_ON_ERROR */ +#ifndef USE_LOCKS +#define USE_LOCKS 0 +#endif /* USE_LOCKS */ +#ifndef INSECURE +#define INSECURE 0 +#endif /* INSECURE */ +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 +#endif /* HAVE_MMAP */ +#ifndef MMAP_CLEARS +#define MMAP_CLEARS 1 +#endif /* MMAP_CLEARS */ +#ifndef HAVE_MREMAP +#ifdef linux +#define HAVE_MREMAP 1 +#else /* linux */ +#define HAVE_MREMAP 0 +#endif /* linux */ +#endif /* HAVE_MREMAP */ +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION errno = ENOMEM; +#endif /* MALLOC_FAILURE_ACTION */ +#ifndef HAVE_MORECORE +#if ONLY_MSPACES +#define HAVE_MORECORE 0 +#else /* ONLY_MSPACES */ +#define HAVE_MORECORE 1 +#endif /* ONLY_MSPACES */ +#endif /* HAVE_MORECORE */ +#if !HAVE_MORECORE +#define MORECORE_CONTIGUOUS 0 +#else /* !HAVE_MORECORE */ +#ifndef MORECORE +#define MORECORE sbrk +#endif /* MORECORE */ +#ifndef MORECORE_CONTIGUOUS +#define MORECORE_CONTIGUOUS 1 +#endif /* MORECORE_CONTIGUOUS */ +#endif /* HAVE_MORECORE */ +#ifndef DEFAULT_GRANULARITY +#if MORECORE_CONTIGUOUS +#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ +#else /* MORECORE_CONTIGUOUS */ +#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) +#endif /* MORECORE_CONTIGUOUS */ +#endif /* DEFAULT_GRANULARITY */ +#ifndef DEFAULT_TRIM_THRESHOLD +#ifndef MORECORE_CANNOT_TRIM +#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) +#else /* MORECORE_CANNOT_TRIM */ +#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T +#endif /* MORECORE_CANNOT_TRIM */ +#endif /* DEFAULT_TRIM_THRESHOLD */ +#ifndef DEFAULT_MMAP_THRESHOLD +#if HAVE_MMAP +#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) +#else /* HAVE_MMAP */ +#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* DEFAULT_MMAP_THRESHOLD */ +#ifndef USE_BUILTIN_FFS +#define USE_BUILTIN_FFS 0 +#endif /* USE_BUILTIN_FFS */ +#ifndef USE_DEV_RANDOM +#define USE_DEV_RANDOM 0 +#endif /* USE_DEV_RANDOM */ +#ifndef NO_MALLINFO +#define NO_MALLINFO 0 +#endif /* NO_MALLINFO */ +#ifndef MALLINFO_FIELD_TYPE +#define MALLINFO_FIELD_TYPE size_t +#endif /* MALLINFO_FIELD_TYPE */ + +/* + mallopt tuning options. SVID/XPG defines four standard parameter + numbers for mallopt, normally defined in malloc.h. None of these + are used in this malloc, so setting them has no effect. But this + malloc does support the following options. +*/ + +#define M_TRIM_THRESHOLD (-1) +#define M_GRANULARITY (-2) +#define M_MMAP_THRESHOLD (-3) + +/* ------------------------ Mallinfo declarations ------------------------ */ + +#if !NO_MALLINFO +/* + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing usage properties and + statistics. It should work on any system that has a + /usr/include/malloc.h defining struct mallinfo. The main + declaration needed is the mallinfo struct that is returned (by-copy) + by mallinfo(). The malloinfo struct contains a bunch of fields that + are not even meaningful in this version of malloc. These fields are + are instead filled by mallinfo() with other numbers that might be of + interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else a compliant version is + declared below. These must be precisely the same for mallinfo() to + work. The original SVID version of this struct, defined on most + systems with mallinfo, declares all fields as ints. But some others + define as unsigned long. If your system defines the fields using a + type of different width than listed here, you MUST #include your + system version and #define HAVE_USR_INCLUDE_MALLOC_H. +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#ifdef HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else /* HAVE_USR_INCLUDE_MALLOC_H */ + +struct mallinfo { + MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ + MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ + MALLINFO_FIELD_TYPE smblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ + MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ + MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ + MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ + MALLINFO_FIELD_TYPE fordblks; /* total free space */ + MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ +}; + +#endif /* HAVE_USR_INCLUDE_MALLOC_H */ +#endif /* NO_MALLINFO */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if !ONLY_MSPACES + +/* ------------------- Declarations of public routines ------------------- */ + +#ifndef USE_DL_PREFIX +#define dlcalloc calloc +#define dlfree free +#define dlmalloc malloc +#define dlmemalign memalign +#define dlrealloc realloc +#define dlvalloc valloc +#define dlpvalloc pvalloc +#define dlmallinfo mallinfo +#define dlmallopt mallopt +#define dlmalloc_trim malloc_trim +#define dlmalloc_stats malloc_stats +#define dlmalloc_usable_size malloc_usable_size +#define dlmalloc_footprint malloc_footprint +#define dlmalloc_max_footprint malloc_max_footprint +#define dlindependent_calloc independent_calloc +#define dlindependent_comalloc independent_comalloc +#endif /* USE_DL_PREFIX */ + + +/* + malloc(size_t n) + Returns a pointer to a newly allocated chunk of at least n bytes, or + null if no space is available, in which case errno is set to ENOMEM + on ANSI C systems. + + If n is zero, malloc returns a minimum-sized chunk. (The minimum + size is 16 bytes on most 32bit systems, and 32 bytes on 64bit + systems.) Note that size_t is an unsigned type, so calls with + arguments that would be negative if signed are interpreted as + requests for huge amounts of space, which will often fail. The + maximum supported value of n differs across systems, but is in all + cases less than the maximum representable value of a size_t. +*/ +void* dlmalloc(size_t); + +/* + free(void* p) + Releases the chunk of memory pointed to by p, that had been previously + allocated using malloc or a related routine such as realloc. + It has no effect if p is null. If p was not malloced or already + freed, free(p) will by default cause the current program to abort. +*/ +void dlfree(void*); + +/* + calloc(size_t n_elements, size_t element_size); + Returns a pointer to n_elements * element_size bytes, with all locations + set to zero. +*/ +void* dlcalloc(size_t, size_t); + +/* + realloc(void* p, size_t n) + Returns a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. + + The returned pointer may or may not be the same as p. The algorithm + prefers extending p in most cases when possible, otherwise it + employs the equivalent of a malloc-copy-free sequence. + + If p is null, realloc is equivalent to malloc. + + If space is not available, realloc returns null, errno is set (if on + ANSI) and p is NOT freed. + + if n is for fewer bytes than already held by p, the newly unused + space is lopped off and freed if possible. realloc with a size + argument of zero (re)allocates a minimum-sized chunk. + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is not supported. +*/ + +void* dlrealloc(void*, size_t); + +/* + memalign(size_t alignment, size_t n); + Returns a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument. + + The alignment argument should be a power of two. If the argument is + not a power of two, the nearest greater power is used. + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. +*/ +void* dlmemalign(size_t, size_t); + +/* + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system. If the pagesize is unknown, 4096 is used. +*/ +void* dlvalloc(size_t); + +/* + mallopt(int parameter_number, int parameter_value) + Sets tunable parameters The format is to provide a + (parameter-number, parameter-value) pair. mallopt then sets the + corresponding parameter to the argument value if it can (i.e., so + long as the value is meaningful), and returns 1 if successful else + 0. SVID/XPG/ANSI defines four standard param numbers for mallopt, + normally defined in malloc.h. None of these are use in this malloc, + so setting them has no effect. But this malloc also supports other + options in mallopt. See below for details. Briefly, supported + parameters are as follows (listed defaults are for "typical" + configurations). + + Symbol param # default allowed param values + M_TRIM_THRESHOLD -1 2*1024*1024 any (MAX_SIZE_T disables) + M_GRANULARITY -2 page size any power of 2 >= page size + M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) +*/ +int dlmallopt(int, int); + +/* + malloc_footprint(); + Returns the number of bytes obtained from the system. The total + number of bytes allocated by malloc, realloc etc., is less than this + value. Unlike mallinfo, this function returns only a precomputed + result, so can be called frequently to monitor memory consumption. + Even if locks are otherwise defined, this function does not use them, + so results might not be up to date. +*/ +size_t dlmalloc_footprint(void); + +/* + malloc_max_footprint(); + Returns the maximum number of bytes obtained from the system. This + value will be greater than current footprint if deallocated space + has been reclaimed by the system. The peak number of bytes allocated + by malloc, realloc etc., is less than this value. Unlike mallinfo, + this function returns only a precomputed result, so can be called + frequently to monitor memory consumption. Even if locks are + otherwise defined, this function does not use them, so results might + not be up to date. +*/ +size_t dlmalloc_max_footprint(void); + +#if !NO_MALLINFO +/* + mallinfo() + Returns (by copy) a struct containing various summary statistics: + + arena: current total non-mmapped bytes allocated from system + ordblks: the number of free chunks + smblks: always zero. + hblks: current number of mmapped regions + hblkhd: total bytes held in mmapped regions + usmblks: the maximum total allocated space. This will be greater + than current total if trimming has occurred. + fsmblks: always zero + uordblks: current total allocated space (normal or mmapped) + fordblks: total free space + keepcost: the maximum number of bytes that could ideally be released + back to system via malloc_trim. ("ideally" means that + it ignores page restrictions etc.) + + Because these fields are ints, but internal bookkeeping may + be kept as longs, the reported values may wrap around zero and + thus be inaccurate. +*/ +struct mallinfo dlmallinfo(void); +#endif /* NO_MALLINFO */ + +/* + independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); + + independent_calloc is similar to calloc, but instead of returning a + single cleared space, it returns an array of pointers to n_elements + independent elements that can hold contents of size elem_size, each + of which starts out cleared, and can be independently freed, + realloc'ed etc. The elements are guaranteed to be adjacently + allocated (this is not guaranteed to occur with multiple callocs or + mallocs), which may also improve cache locality in some + applications. + + The "chunks" argument is optional (i.e., may be null, which is + probably the most typical usage). If it is null, the returned array + is itself dynamically allocated and should also be freed when it is + no longer needed. Otherwise, the chunks array must be of at least + n_elements in length. It is filled in with the pointers to the + chunks. + + In either case, independent_calloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and "chunks" + is null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use regular calloc and assign pointers into this + space to represent elements. (In this case though, you cannot + independently free elements.) + + independent_calloc simplifies and speeds up implementations of many + kinds of pools. It may also be useful when constructing large data + structures that initially have a fixed number of fixed-sized nodes, + but the number is not known at compile time, and some of the nodes + may later need to be freed. For example: + + struct Node { int item; struct Node* next; }; + + struct Node* build_list() { + struct Node** pool; + int n = read_number_of_nodes_needed(); + if (n <= 0) return 0; + pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); + if (pool == 0) die(); + // organize into a linked list... + struct Node* first = pool[0]; + for (i = 0; i < n-1; ++i) + pool[i]->next = pool[i+1]; + free(pool); // Can now free the array (or not, if it is needed later) + return first; + } +*/ +void** dlindependent_calloc(size_t, size_t, void**); + +/* + independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); + + independent_comalloc allocates, all at once, a set of n_elements + chunks with sizes indicated in the "sizes" array. It returns + an array of pointers to these elements, each of which can be + independently freed, realloc'ed etc. The elements are guaranteed to + be adjacently allocated (this is not guaranteed to occur with + multiple callocs or mallocs), which may also improve cache locality + in some applications. + + The "chunks" argument is optional (i.e., may be null). If it is null + the returned array is itself dynamically allocated and should also + be freed when it is no longer needed. Otherwise, the chunks array + must be of at least n_elements in length. It is filled in with the + pointers to the chunks. + + In either case, independent_comalloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and chunks is + null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use a single regular malloc, and assign pointers at + particular offsets in the aggregate space. (In this case though, you + cannot independently free elements.) + + independent_comallac differs from independent_calloc in that each + element may have a different size, and also that it does not + automatically clear elements. + + independent_comalloc can be used to speed up allocation in cases + where several structs or objects must always be allocated at the + same time. For example: + + struct Head { ... } + struct Foot { ... } + + void send_message(char* msg) { + int msglen = strlen(msg); + size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; + void* chunks[3]; + if (independent_comalloc(3, sizes, chunks) == 0) + die(); + struct Head* head = (struct Head*)(chunks[0]); + char* body = (char*)(chunks[1]); + struct Foot* foot = (struct Foot*)(chunks[2]); + // ... + } + + In general though, independent_comalloc is worth using only for + larger values of n_elements. For small values, you probably won't + detect enough difference from series of malloc calls to bother. + + Overuse of independent_comalloc can increase overall memory usage, + since it cannot reuse existing noncontiguous small chunks that + might be available for some of the elements. +*/ +void** dlindependent_comalloc(size_t, size_t*, void**); + + +/* + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + */ +void* dlpvalloc(size_t); + +/* + malloc_trim(size_t pad); + + If possible, gives memory back to the system (via negative arguments + to sbrk) if there is unused memory at the `high' end of the malloc + pool or in unused MMAP segments. You can call this after freeing + large blocks of memory to potentially reduce the system-level memory + requirements of a program. However, it cannot guarantee to reduce + memory. Under some allocation patterns, some large free blocks of + memory will be locked between two used chunks, so they cannot be + given back to the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, only + the minimum amount of memory to maintain internal data structures + will be left. Non-zero arguments can be supplied to maintain enough + trailing space to service future expected allocations without having + to re-obtain memory from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. +*/ +int dlmalloc_trim(size_t); + +/* + malloc_usable_size(void* p); + + Returns the number of bytes you can actually use in + an allocated chunk, which may be more than you requested (although + often not) due to alignment and minimum size constraints. + You can use this many bytes without worrying about + overwriting other allocated objects. This is not a particularly great + programming practice. malloc_usable_size can be more useful in + debugging and assertions, for example: + + p = malloc(n); + assert(malloc_usable_size(p) >= 256); +*/ +size_t dlmalloc_usable_size(void*); + +/* + malloc_stats(); + Prints on stderr the amount of space obtained from the system (both + via sbrk and mmap), the maximum amount (which may be more than + current if malloc_trim and/or munmap got called), and the current + number of bytes allocated via malloc (or realloc, etc) but not yet + freed. Note that this is the number of bytes allocated, not the + number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead. Because it includes + alignment wastage as being in use, this figure may be greater than + zero even when no user-level chunks are allocated. + + The reported current and maximum system memory can be inaccurate if + a program makes other calls to system memory allocation functions + (normally sbrk) outside of malloc. + + malloc_stats prints only the most commonly interesting statistics. + More information can be obtained by calling mallinfo. +*/ +void dlmalloc_stats(void); + +#endif /* ONLY_MSPACES */ + +#if MSPACES + +/* + mspace is an opaque type representing an independent + region of space that supports mspace_malloc, etc. +*/ +typedef void* mspace; + +/* + create_mspace creates and returns a new independent space with the + given initial capacity, or, if 0, the default granularity size. It + returns null if there is no system memory available to create the + space. If argument locked is non-zero, the space uses a separate + lock to control access. The capacity of the space will grow + dynamically as needed to service mspace_malloc requests. You can + control the sizes of incremental increases of this space by + compiling with a different DEFAULT_GRANULARITY or dynamically + setting with mallopt(M_GRANULARITY, value). +*/ +mspace create_mspace(size_t capacity, int locked); + +/* + destroy_mspace destroys the given space, and attempts to return all + of its memory back to the system, returning the total number of + bytes freed. After destruction, the results of access to all memory + used by the space become undefined. +*/ +size_t destroy_mspace(mspace msp); + +/* + create_mspace_with_base uses the memory supplied as the initial base + of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this + space is used for bookkeeping, so the capacity must be at least this + large. (Otherwise 0 is returned.) When this initial space is + exhausted, additional memory will be obtained from the system. + Destroying this space will deallocate all additionally allocated + space (if possible) but not the initial base. +*/ +mspace create_mspace_with_base(void* base, size_t capacity, int locked); + +/* + mspace_malloc behaves as malloc, but operates within + the given space. +*/ +void* mspace_malloc(mspace msp, size_t bytes); + +/* + mspace_free behaves as free, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_free is not actually needed. + free may be called instead of mspace_free because freed chunks from + any space are handled by their originating spaces. +*/ +void mspace_free(mspace msp, void* mem); + +/* + mspace_realloc behaves as realloc, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_realloc is not actually + needed. realloc may be called instead of mspace_realloc because + realloced chunks from any space are handled by their originating + spaces. +*/ +void* mspace_realloc(mspace msp, void* mem, size_t newsize); + +/* + mspace_calloc behaves as calloc, but operates within + the given space. +*/ +void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); + +/* + mspace_memalign behaves as memalign, but operates within + the given space. +*/ +void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); + +/* + mspace_independent_calloc behaves as independent_calloc, but + operates within the given space. +*/ +void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]); + +/* + mspace_independent_comalloc behaves as independent_comalloc, but + operates within the given space. +*/ +void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]); + +/* + mspace_footprint() returns the number of bytes obtained from the + system for this space. +*/ +size_t mspace_footprint(mspace msp); + +/* + mspace_max_footprint() returns the peak number of bytes obtained from the + system for this space. +*/ +size_t mspace_max_footprint(mspace msp); + + +#if !NO_MALLINFO +/* + mspace_mallinfo behaves as mallinfo, but reports properties of + the given space. +*/ +struct mallinfo mspace_mallinfo(mspace msp); +#endif /* NO_MALLINFO */ + +/* + mspace_malloc_stats behaves as malloc_stats, but reports + properties of the given space. +*/ +void mspace_malloc_stats(mspace msp); + +/* + mspace_trim behaves as malloc_trim, but + operates within the given space. +*/ +int mspace_trim(mspace msp, size_t pad); + +/* + An alias for mallopt. +*/ +int mspace_mallopt(int, int); + +#endif /* MSPACES */ + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif /* __cplusplus */ + +/* + ======================================================================== + To make a fully customizable malloc.h header file, cut everything + above this line, put into file malloc.h, edit to suit, and #include it + on the next line, as well as in programs that use this malloc. + ======================================================================== +*/ + +/* #include "malloc.h" */ + +/*------------------------------ internal #includes ---------------------- */ + +#ifdef WIN32 +#pragma warning( disable : 4146 ) /* no "unsigned" warnings */ +#endif /* WIN32 */ + +#include <stdio.h> /* for printing in malloc_stats */ + +#ifndef LACKS_ERRNO_H +#include <errno.h> /* for MALLOC_FAILURE_ACTION */ +#endif /* LACKS_ERRNO_H */ +#if FOOTERS +#include <time.h> /* for magic initialization */ +#endif /* FOOTERS */ +#ifndef LACKS_STDLIB_H +#include <stdlib.h> /* for abort() */ +#endif /* LACKS_STDLIB_H */ +#ifdef DEBUG +#if ABORT_ON_ASSERT_FAILURE +#define assert(x) if(!(x)) ABORT +#else /* ABORT_ON_ASSERT_FAILURE */ +#include <assert.h> +#endif /* ABORT_ON_ASSERT_FAILURE */ +#else /* DEBUG */ +#define assert(x) +#endif /* DEBUG */ +#ifndef LACKS_STRING_H +#include <string.h> /* for memset etc */ +#endif /* LACKS_STRING_H */ +#if USE_BUILTIN_FFS +#ifndef LACKS_STRINGS_H +#include <strings.h> /* for ffs */ +#endif /* LACKS_STRINGS_H */ +#endif /* USE_BUILTIN_FFS */ +#if HAVE_MMAP +#ifndef LACKS_SYS_MMAN_H +#include <sys/mman.h> /* for mmap */ +#endif /* LACKS_SYS_MMAN_H */ +#ifndef LACKS_FCNTL_H +#include <fcntl.h> +#endif /* LACKS_FCNTL_H */ +#endif /* HAVE_MMAP */ +#if HAVE_MORECORE +#ifndef LACKS_UNISTD_H +#include <unistd.h> /* for sbrk */ +#else /* LACKS_UNISTD_H */ +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) +extern void* sbrk(ptrdiff_t); +#endif /* FreeBSD etc */ +#endif /* LACKS_UNISTD_H */ +#endif /* HAVE_MMAP */ + +#ifndef WIN32 +#ifndef malloc_getpagesize +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# ifdef WIN32 /* use supplied emulation of getpagesize */ +# define malloc_getpagesize getpagesize() +# else +# ifndef LACKS_SYS_PARAM_H +# include <sys/param.h> +# endif +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else /* just guess */ +# define malloc_getpagesize ((size_t)4096U) +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif +#endif + +/* ------------------- size_t and alignment properties -------------------- */ + +/* The byte and bit size of a size_t */ +#define SIZE_T_SIZE (sizeof(size_t)) +#define SIZE_T_BITSIZE (sizeof(size_t) << 3) + +/* Some constants coerced to size_t */ +/* Annoying but necessary to avoid errors on some plaftorms */ +#define SIZE_T_ZERO ((size_t)0) +#define SIZE_T_ONE ((size_t)1) +#define SIZE_T_TWO ((size_t)2) +#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) +#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) +#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) +#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) + +/* The bit mask value corresponding to MALLOC_ALIGNMENT */ +#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) + +/* True if address a has acceptable alignment */ +#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) + +/* the number of bytes to offset an address to align it */ +#define align_offset(A)\ + ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ + ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) + +/* -------------------------- MMAP preliminaries ------------------------- */ + +/* + If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and + checks to fail so compiler optimizer can delete code rather than + using so many "#if"s. +*/ + + +/* MORECORE and MMAP must return MFAIL on failure */ +#define MFAIL ((void*)(MAX_SIZE_T)) +#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ + +#if !HAVE_MMAP +#define IS_MMAPPED_BIT (SIZE_T_ZERO) +#define USE_MMAP_BIT (SIZE_T_ZERO) +#define CALL_MMAP(s) MFAIL +#define CALL_MUNMAP(a, s) (-1) +#define DIRECT_MMAP(s) MFAIL + +#else /* HAVE_MMAP */ +#define IS_MMAPPED_BIT (SIZE_T_ONE) +#define USE_MMAP_BIT (SIZE_T_ONE) + +#ifndef WIN32 +#define CALL_MUNMAP(a, s) munmap((a), (s)) +#define MMAP_PROT (PROT_READ|PROT_WRITE) +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif /* MAP_ANON */ +#ifdef MAP_ANONYMOUS +#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) +#define CALL_MMAP(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0) +#else /* MAP_ANONYMOUS */ +/* + Nearly all versions of mmap support MAP_ANONYMOUS, so the following + is unlikely to be needed, but is supplied just in case. +*/ +#define MMAP_FLAGS (MAP_PRIVATE) +static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ +#define CALL_MMAP(s) ((dev_zero_fd < 0) ? \ + (dev_zero_fd = open("/dev/zero", O_RDWR), \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) +#endif /* MAP_ANONYMOUS */ + +#define DIRECT_MMAP(s) CALL_MMAP(s) +#else /* WIN32 */ + +/* Win32 MMAP via VirtualAlloc */ +static void* win32mmap(size_t size) { + void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); + return (ptr != 0)? ptr: MFAIL; +} + +/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ +static void* win32direct_mmap(size_t size) { + void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, + PAGE_READWRITE); + return (ptr != 0)? ptr: MFAIL; +} + +/* This function supports releasing coalesed segments */ +static int win32munmap(void* ptr, size_t size) { + MEMORY_BASIC_INFORMATION minfo; + char* cptr = ptr; + while (size) { + if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) + return -1; + if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || + minfo.State != MEM_COMMIT || minfo.RegionSize > size) + return -1; + if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) + return -1; + cptr += minfo.RegionSize; + size -= minfo.RegionSize; + } + return 0; +} + +#define CALL_MMAP(s) win32mmap(s) +#define CALL_MUNMAP(a, s) win32munmap((a), (s)) +#define DIRECT_MMAP(s) win32direct_mmap(s) +#endif /* WIN32 */ +#endif /* HAVE_MMAP */ + +#if HAVE_MMAP && HAVE_MREMAP +#define CALL_MREMAP(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv)) +#else /* HAVE_MMAP && HAVE_MREMAP */ +#define CALL_MREMAP(addr, osz, nsz, mv) MFAIL +#endif /* HAVE_MMAP && HAVE_MREMAP */ + +#if HAVE_MORECORE +#define CALL_MORECORE(S) MORECORE(S) +#else /* HAVE_MORECORE */ +#define CALL_MORECORE(S) MFAIL +#endif /* HAVE_MORECORE */ + +/* mstate bit set if continguous morecore disabled or failed */ +#define USE_NONCONTIGUOUS_BIT (4U) + +/* segment bit set in create_mspace_with_base */ +#define EXTERN_BIT (8U) + + +/* --------------------------- Lock preliminaries ------------------------ */ + +#if USE_LOCKS + +/* + When locks are defined, there are up to two global locks: + + * If HAVE_MORECORE, morecore_mutex protects sequences of calls to + MORECORE. In many cases sys_alloc requires two calls, that should + not be interleaved with calls by other threads. This does not + protect against direct calls to MORECORE by other threads not + using this lock, so there is still code to cope the best we can on + interference. + + * magic_init_mutex ensures that mparams.magic and other + unique mparams values are initialized only once. +*/ + +#ifndef WIN32 +/* By default use posix locks */ +#include <pthread.h> +#define MLOCK_T pthread_mutex_t +#define INITIAL_LOCK(l) pthread_mutex_init(l, NULL) +#define ACQUIRE_LOCK(l) pthread_mutex_lock(l) +#define RELEASE_LOCK(l) pthread_mutex_unlock(l) + +#if HAVE_MORECORE +static MLOCK_T morecore_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif /* HAVE_MORECORE */ + +static MLOCK_T magic_init_mutex = PTHREAD_MUTEX_INITIALIZER; + +#else /* WIN32 */ +/* + Because lock-protected regions have bounded times, and there + are no recursive lock calls, we can use simple spinlocks. +*/ + +#define MLOCK_T long +static int win32_acquire_lock (MLOCK_T *sl) { + for (;;) { +#ifdef InterlockedCompareExchangePointer + if (!InterlockedCompareExchange(sl, 1, 0)) + return 0; +#else /* Use older void* version */ + if (!InterlockedCompareExchange((void**)sl, (void*)1, (void*)0)) + return 0; +#endif /* InterlockedCompareExchangePointer */ + Sleep (0); + } +} + +static void win32_release_lock (MLOCK_T *sl) { + InterlockedExchange (sl, 0); +} + +#define INITIAL_LOCK(l) *(l)=0 +#define ACQUIRE_LOCK(l) win32_acquire_lock(l) +#define RELEASE_LOCK(l) win32_release_lock(l) +#if HAVE_MORECORE +static MLOCK_T morecore_mutex; +#endif /* HAVE_MORECORE */ +static MLOCK_T magic_init_mutex; +#endif /* WIN32 */ + +#define USE_LOCK_BIT (2U) +#else /* USE_LOCKS */ +#define USE_LOCK_BIT (0U) +#define INITIAL_LOCK(l) +#endif /* USE_LOCKS */ + +#if USE_LOCKS && HAVE_MORECORE +#define ACQUIRE_MORECORE_LOCK() ACQUIRE_LOCK(&morecore_mutex); +#define RELEASE_MORECORE_LOCK() RELEASE_LOCK(&morecore_mutex); +#else /* USE_LOCKS && HAVE_MORECORE */ +#define ACQUIRE_MORECORE_LOCK() +#define RELEASE_MORECORE_LOCK() +#endif /* USE_LOCKS && HAVE_MORECORE */ + +#if USE_LOCKS +#define ACQUIRE_MAGIC_INIT_LOCK() ACQUIRE_LOCK(&magic_init_mutex); +#define RELEASE_MAGIC_INIT_LOCK() RELEASE_LOCK(&magic_init_mutex); +#else /* USE_LOCKS */ +#define ACQUIRE_MAGIC_INIT_LOCK() +#define RELEASE_MAGIC_INIT_LOCK() +#endif /* USE_LOCKS */ + + +/* ----------------------- Chunk representations ------------------------ */ + +/* + (The following includes lightly edited explanations by Colin Plumb.) + + The malloc_chunk declaration below is misleading (but accurate and + necessary). It declares a "view" into memory allowing access to + necessary fields at known offsets from a given base. + + Chunks of memory are maintained using a `boundary tag' method as + originally described by Knuth. (See the paper by Paul Wilson + ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such + techniques.) Sizes of free chunks are stored both in the front of + each chunk and at the end. This makes consolidating fragmented + chunks into bigger chunks fast. The head fields also hold bits + representing whether chunks are free or in use. + + Here are some pictures to make it clearer. They are "exploded" to + show that the state of a chunk can be thought of as extending from + the high 31 bits of the head field of its header through the + prev_foot and PINUSE_BIT bit of the following chunk header. + + A chunk that's in use looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk (if P = 1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 1| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +- -+ + | | + +- -+ + | : + +- size - sizeof(size_t) available payload bytes -+ + : | + chunk-> +- -+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| + | Size of next chunk (may or may not be in use) | +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + And if it's free, it looks like this: + + chunk-> +- -+ + | User payload (must be in use, or we would have merged!) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 0| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Next pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Prev pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- size - sizeof(struct chunk) unused bytes -+ + : | + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0| + | Size of next chunk (must be in use, or we would have merged)| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- User payload -+ + : | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0| + +-+ + Note that since we always merge adjacent free chunks, the chunks + adjacent to a free chunk must be in use. + + Given a pointer to a chunk (which can be derived trivially from the + payload pointer) we can, in O(1) time, find out whether the adjacent + chunks are free, and if so, unlink them from the lists that they + are on and merge them with the current chunk. + + Chunks always begin on even word boundaries, so the mem portion + (which is returned to the user) is also on an even word boundary, and + thus at least double-word aligned. + + The P (PINUSE_BIT) bit, stored in the unused low-order bit of the + chunk size (which is always a multiple of two words), is an in-use + bit for the *previous* chunk. If that bit is *clear*, then the + word before the current chunk size contains the previous chunk + size, and can be used to find the front of the previous chunk. + The very first chunk allocated always has this bit set, preventing + access to non-existent (or non-owned) memory. If pinuse is set for + any given chunk, then you CANNOT determine the size of the + previous chunk, and might even get a memory addressing fault when + trying to do so. + + The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of + the chunk size redundantly records whether the current chunk is + inuse. This redundancy enables usage checks within free and realloc, + and reduces indirection when freeing and consolidating chunks. + + Each freshly allocated chunk must have both cinuse and pinuse set. + That is, each allocated chunk borders either a previously allocated + and still in-use chunk, or the base of its memory arena. This is + ensured by making all allocations from the the `lowest' part of any + found chunk. Further, no free chunk physically borders another one, + so each free chunk is known to be preceded and followed by either + inuse chunks or the ends of memory. + + Note that the `foot' of the current chunk is actually represented + as the prev_foot of the NEXT chunk. This makes it easier to + deal with alignments etc but can be very confusing when trying + to extend or adapt this code. + + The exceptions to all this are + + 1. The special chunk `top' is the top-most available chunk (i.e., + the one bordering the end of available memory). It is treated + specially. Top is never included in any bin, is used only if + no other chunk is available, and is released back to the + system if it is very large (see M_TRIM_THRESHOLD). In effect, + the top chunk is treated as larger (and thus less well + fitting) than any other available chunk. The top chunk + doesn't update its trailing size field since there is no next + contiguous chunk that would have to index off it. However, + space is still allocated for it (TOP_FOOT_SIZE) to enable + separation or merging when space is extended. + + 3. Chunks allocated via mmap, which have the lowest-order bit + (IS_MMAPPED_BIT) set in their prev_foot fields, and do not set + PINUSE_BIT in their head fields. Because they are allocated + one-by-one, each must carry its own prev_foot field, which is + also used to hold the offset this chunk has within its mmapped + region, which is needed to preserve alignment. Each mmapped + chunk is trailed by the first two fields of a fake next-chunk + for sake of usage checks. + +*/ + +struct malloc_chunk { + size_t prev_foot; /* Size of previous chunk (if free). */ + size_t head; /* Size and inuse bits. */ + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; +}; + +typedef struct malloc_chunk mchunk; +typedef struct malloc_chunk* mchunkptr; +typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ +typedef unsigned int bindex_t; /* Described below */ +typedef unsigned int binmap_t; /* Described below */ +typedef unsigned int flag_t; /* The type of various bit flag sets */ + +/* ------------------- Chunks sizes and alignments ----------------------- */ + +#define MCHUNK_SIZE (sizeof(mchunk)) + +#if FOOTERS +#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +#else /* FOOTERS */ +#define CHUNK_OVERHEAD (SIZE_T_SIZE) +#endif /* FOOTERS */ + +/* MMapped chunks need a second word of overhead ... */ +#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +/* ... and additional padding for fake next-chunk at foot */ +#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) + +/* The smallest size we can malloc is an aligned minimal chunk */ +#define MIN_CHUNK_SIZE\ + ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* conversion from malloc headers to user pointers, and back */ +#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES)) +/* chunk associated with aligned address A */ +#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) + +/* Bounds on request (not chunk) sizes. */ +#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) +#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) + +/* pad request bytes into a usable size */ +#define pad_request(req) \ + (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* pad request, checking for minimum (but not maximum) */ +#define request2size(req) \ + (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req)) + + +/* ------------------ Operations on head and foot fields ----------------- */ + +/* + The head field of a chunk is or'ed with PINUSE_BIT when previous + adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in + use. If the chunk was obtained with mmap, the prev_foot field has + IS_MMAPPED_BIT set, otherwise holding the offset of the base of the + mmapped region to the base of the chunk. +*/ + +#define PINUSE_BIT (SIZE_T_ONE) +#define CINUSE_BIT (SIZE_T_TWO) +#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) + +/* Head value for fenceposts */ +#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) + +/* extraction of fields from head words */ +#define cinuse(p) ((p)->head & CINUSE_BIT) +#define pinuse(p) ((p)->head & PINUSE_BIT) +#define chunksize(p) ((p)->head & ~(INUSE_BITS)) + +#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) +#define clear_cinuse(p) ((p)->head &= ~CINUSE_BIT) + +/* Treat space at ptr +/- offset as a chunk */ +#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) +#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s))) + +/* Ptr to next or previous physical malloc_chunk. */ +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~INUSE_BITS))) +#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) )) + +/* extract next chunk's pinuse bit */ +#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) + +/* Get/set size at footer */ +#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot) +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s)) + +/* Set size, pinuse bit, and foot */ +#define set_size_and_pinuse_of_free_chunk(p, s)\ + ((p)->head = (s|PINUSE_BIT), set_foot(p, s)) + +/* Set size, pinuse bit, foot, and clear next pinuse */ +#define set_free_with_pinuse(p, s, n)\ + (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) + +#define is_mmapped(p)\ + (!((p)->head & PINUSE_BIT) && ((p)->prev_foot & IS_MMAPPED_BIT)) + +/* Get the internal overhead associated with chunk p */ +#define overhead_for(p)\ + (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) + +/* Return true if malloced space is not necessarily cleared */ +#if MMAP_CLEARS +#define calloc_must_clear(p) (!is_mmapped(p)) +#else /* MMAP_CLEARS */ +#define calloc_must_clear(p) (1) +#endif /* MMAP_CLEARS */ + +/* ---------------------- Overlaid data structures ----------------------- */ + +/* + When chunks are not in use, they are treated as nodes of either + lists or trees. + + "Small" chunks are stored in circular doubly-linked lists, and look + like this: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space (may be 0 bytes long) . + . . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Larger chunks are kept in a form of bitwise digital trees (aka + tries) keyed on chunksizes. Because malloc_tree_chunks are only for + free chunks greater than 256 bytes, their size doesn't impose any + constraints on user chunk sizes. Each node looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to left child (child[0]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to right child (child[1]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to parent | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | bin index of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Each tree holding treenodes is a tree of unique chunk sizes. Chunks + of the same size are arranged in a circularly-linked list, with only + the oldest chunk (the next to be used, in our FIFO ordering) + actually in the tree. (Tree members are distinguished by a non-null + parent pointer.) If a chunk with the same size an an existing node + is inserted, it is linked off the existing node using pointers that + work in the same way as fd/bk pointers of small chunks. + + Each tree contains a power of 2 sized range of chunk sizes (the + smallest is 0x100 <= x < 0x180), which is is divided in half at each + tree level, with the chunks in the smaller half of the range (0x100 + <= x < 0x140 for the top nose) in the left subtree and the larger + half (0x140 <= x < 0x180) in the right subtree. This is, of course, + done by inspecting individual bits. + + Using these rules, each node's left subtree contains all smaller + sizes than its right subtree. However, the node at the root of each + subtree has no particular ordering relationship to either. (The + dividing line between the subtree sizes is based on trie relation.) + If we remove the last chunk of a given size from the interior of the + tree, we need to replace it with a leaf node. The tree ordering + rules permit a node to be replaced by any leaf below it. + + The smallest chunk in a tree (a common operation in a best-fit + allocator) can be found by walking a path to the leftmost leaf in + the tree. Unlike a usual binary tree, where we follow left child + pointers until we reach a null, here we follow the right child + pointer any time the left one is null, until we reach a leaf with + both child pointers null. The smallest chunk in the tree will be + somewhere along that path. + + The worst case number of steps to add, find, or remove a node is + bounded by the number of bits differentiating chunks within + bins. Under current bin calculations, this ranges from 6 up to 21 + (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case + is of course much better. +*/ + +struct malloc_tree_chunk { + /* The first four fields must be compatible with malloc_chunk */ + size_t prev_foot; + size_t head; + struct malloc_tree_chunk* fd; + struct malloc_tree_chunk* bk; + + struct malloc_tree_chunk* child[2]; + struct malloc_tree_chunk* parent; + bindex_t index; +}; + +typedef struct malloc_tree_chunk tchunk; +typedef struct malloc_tree_chunk* tchunkptr; +typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ + +/* A little helper macro for trees */ +#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) + +/* ----------------------------- Segments -------------------------------- */ + +/* + Each malloc space may include non-contiguous segments, held in a + list headed by an embedded malloc_segment record representing the + top-most space. Segments also include flags holding properties of + the space. Large chunks that are directly allocated by mmap are not + included in this list. They are instead independently created and + destroyed without otherwise keeping track of them. + + Segment management mainly comes into play for spaces allocated by + MMAP. Any call to MMAP might or might not return memory that is + adjacent to an existing segment. MORECORE normally contiguously + extends the current space, so this space is almost always adjacent, + which is simpler and faster to deal with. (This is why MORECORE is + used preferentially to MMAP when both are available -- see + sys_alloc.) When allocating using MMAP, we don't use any of the + hinting mechanisms (inconsistently) supported in various + implementations of unix mmap, or distinguish reserving from + committing memory. Instead, we just ask for space, and exploit + contiguity when we get it. It is probably possible to do + better than this on some systems, but no general scheme seems + to be significantly better. + + Management entails a simpler variant of the consolidation scheme + used for chunks to reduce fragmentation -- new adjacent memory is + normally prepended or appended to an existing segment. However, + there are limitations compared to chunk consolidation that mostly + reflect the fact that segment processing is relatively infrequent + (occurring only when getting memory from system) and that we + don't expect to have huge numbers of segments: + + * Segments are not indexed, so traversal requires linear scans. (It + would be possible to index these, but is not worth the extra + overhead and complexity for most programs on most platforms.) + * New segments are only appended to old ones when holding top-most + memory; if they cannot be prepended to others, they are held in + different segments. + + Except for the top-most segment of an mstate, each segment record + is kept at the tail of its segment. Segments are added by pushing + segment records onto the list headed by &mstate.seg for the + containing mstate. + + Segment flags control allocation/merge/deallocation policies: + * If EXTERN_BIT set, then we did not allocate this segment, + and so should not try to deallocate or merge with others. + (This currently holds only for the initial segment passed + into create_mspace_with_base.) + * If IS_MMAPPED_BIT set, the segment may be merged with + other surrounding mmapped segments and trimmed/de-allocated + using munmap. + * If neither bit is set, then the segment was obtained using + MORECORE so can be merged with surrounding MORECORE'd segments + and deallocated/trimmed using MORECORE with negative arguments. +*/ + +struct malloc_segment { + char* base; /* base address */ + size_t size; /* allocated size */ + struct malloc_segment* next; /* ptr to next segment */ + flag_t sflags; /* mmap and extern flag */ +}; + +#define is_mmapped_segment(S) ((S)->sflags & IS_MMAPPED_BIT) +#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) + +typedef struct malloc_segment msegment; +typedef struct malloc_segment* msegmentptr; + +/* ---------------------------- malloc_state ----------------------------- */ + +/* + A malloc_state holds all of the bookkeeping for a space. + The main fields are: + + Top + The topmost chunk of the currently active segment. Its size is + cached in topsize. The actual size of topmost space is + topsize+TOP_FOOT_SIZE, which includes space reserved for adding + fenceposts and segment records if necessary when getting more + space from the system. The size at which to autotrim top is + cached from mparams in trim_check, except that it is disabled if + an autotrim fails. + + Designated victim (dv) + This is the preferred chunk for servicing small requests that + don't have exact fits. It is normally the chunk split off most + recently to service another small request. Its size is cached in + dvsize. The link fields of this chunk are not maintained since it + is not kept in a bin. + + SmallBins + An array of bin headers for free chunks. These bins hold chunks + with sizes less than MIN_LARGE_SIZE bytes. Each bin contains + chunks of all the same size, spaced 8 bytes apart. To simplify + use in double-linked lists, each bin header acts as a malloc_chunk + pointing to the real first node, if it exists (else pointing to + itself). This avoids special-casing for headers. But to avoid + waste, we allocate only the fd/bk pointers of bins, and then use + repositioning tricks to treat these as the fields of a chunk. + + TreeBins + Treebins are pointers to the roots of trees holding a range of + sizes. There are 2 equally spaced treebins for each power of two + from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything + larger. + + Bin maps + There is one bit map for small bins ("smallmap") and one for + treebins ("treemap). Each bin sets its bit when non-empty, and + clears the bit when empty. Bit operations are then used to avoid + bin-by-bin searching -- nearly all "search" is done without ever + looking at bins that won't be selected. The bit maps + conservatively use 32 bits per map word, even if on 64bit system. + For a good description of some of the bit-based techniques used + here, see Henry S. Warren Jr's book "Hacker's Delight" (and + supplement at http://hackersdelight.org/). Many of these are + intended to reduce the branchiness of paths through malloc etc, as + well as to reduce the number of memory locations read or written. + + Segments + A list of segments headed by an embedded malloc_segment record + representing the initial space. + + Address check support + The least_addr field is the least address ever obtained from + MORECORE or MMAP. Attempted frees and reallocs of any address less + than this are trapped (unless INSECURE is defined). + + Magic tag + A cross-check field that should always hold same value as mparams.magic. + + Flags + Bits recording whether to use MMAP, locks, or contiguous MORECORE + + Statistics + Each space keeps track of current and maximum system memory + obtained via MORECORE or MMAP. + + Locking + If USE_LOCKS is defined, the "mutex" lock is acquired and released + around every public call using this mspace. +*/ + +/* Bin types, widths and sizes */ +#define NSMALLBINS (32U) +#define NTREEBINS (32U) +#define SMALLBIN_SHIFT (3U) +#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) +#define TREEBIN_SHIFT (8U) +#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) +#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) +#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) + +struct malloc_state { + binmap_t smallmap; + binmap_t treemap; + size_t dvsize; + size_t topsize; + char* least_addr; + mchunkptr dv; + mchunkptr top; + size_t trim_check; + size_t magic; + mchunkptr smallbins[(NSMALLBINS+1)*2]; + tbinptr treebins[NTREEBINS]; + size_t footprint; + size_t max_footprint; + flag_t mflags; +#if USE_LOCKS + MLOCK_T mutex; /* locate lock among fields that rarely change */ +#endif /* USE_LOCKS */ + msegment seg; +}; + +typedef struct malloc_state* mstate; + +/* ------------- Global malloc_state and malloc_params ------------------- */ + +/* + malloc_params holds global properties, including those that can be + dynamically set using mallopt. There is a single instance, mparams, + initialized in init_mparams. +*/ + +struct malloc_params { + size_t magic; + size_t page_size; + size_t granularity; + size_t mmap_threshold; + size_t trim_threshold; + flag_t default_mflags; +}; + +static struct malloc_params mparams; + +/* The global malloc_state used for all non-"mspace" calls */ +static struct malloc_state _gm_; +#define gm (&_gm_) +#define is_global(M) ((M) == &_gm_) +#define is_initialized(M) ((M)->top != 0) + +/* -------------------------- system alloc setup ------------------------- */ + +/* Operations on mflags */ + +#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) +#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) +#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) + +#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) +#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) +#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) + +#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) +#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) + +#define set_lock(M,L)\ + ((M)->mflags = (L)?\ + ((M)->mflags | USE_LOCK_BIT) :\ + ((M)->mflags & ~USE_LOCK_BIT)) + +/* page-align a size */ +#define page_align(S)\ + (((S) + (mparams.page_size)) & ~(mparams.page_size - SIZE_T_ONE)) + +/* granularity-align a size */ +#define granularity_align(S)\ + (((S) + (mparams.granularity)) & ~(mparams.granularity - SIZE_T_ONE)) + +#define is_page_aligned(S)\ + (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) +#define is_granularity_aligned(S)\ + (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) + +/* True if segment S holds address A */ +#define segment_holds(S, A)\ + ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) + +/* Return segment holding given address */ +static msegmentptr segment_holding(mstate m, char* addr) { + msegmentptr sp = &m->seg; + for (;;) { + if (addr >= sp->base && addr < sp->base + sp->size) + return sp; + if ((sp = sp->next) == 0) + return 0; + } +} + +/* Return true if segment contains a segment link */ +static int has_segment_link(mstate m, msegmentptr ss) { + msegmentptr sp = &m->seg; + for (;;) { + if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) + return 1; + if ((sp = sp->next) == 0) + return 0; + } +} + +#ifndef MORECORE_CANNOT_TRIM +#define should_trim(M,s) ((s) > (M)->trim_check) +#else /* MORECORE_CANNOT_TRIM */ +#define should_trim(M,s) (0) +#endif /* MORECORE_CANNOT_TRIM */ + +/* + TOP_FOOT_SIZE is padding at the end of a segment, including space + that may be needed to place segment records and fenceposts when new + noncontiguous segments are added. +*/ +#define TOP_FOOT_SIZE\ + (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) + + +/* ------------------------------- Hooks -------------------------------- */ + +/* + PREACTION should be defined to return 0 on success, and nonzero on + failure. If you are not using locking, you can redefine these to do + anything you like. +*/ + +#if USE_LOCKS + +/* Ensure locks are initialized */ +#define GLOBALLY_INITIALIZE() (mparams.page_size == 0 && init_mparams()) + +#define PREACTION(M) ((GLOBALLY_INITIALIZE() || use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0) +#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); } +#else /* USE_LOCKS */ + +#ifndef PREACTION +#define PREACTION(M) (0) +#endif /* PREACTION */ + +#ifndef POSTACTION +#define POSTACTION(M) +#endif /* POSTACTION */ + +#endif /* USE_LOCKS */ + +/* + CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. + USAGE_ERROR_ACTION is triggered on detected bad frees and + reallocs. The argument p is an address that might have triggered the + fault. It is ignored by the two predefined actions, but might be + useful in custom actions that try to help diagnose errors. +*/ + +#if PROCEED_ON_ERROR + +/* A count of the number of corruption errors causing resets */ +int malloc_corruption_error_count; + +/* default corruption action */ +static void reset_on_error(mstate m); + +#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) +#define USAGE_ERROR_ACTION(m, p) + +#else /* PROCEED_ON_ERROR */ + +#ifndef CORRUPTION_ERROR_ACTION +#define CORRUPTION_ERROR_ACTION(m) ABORT +#endif /* CORRUPTION_ERROR_ACTION */ + +#ifndef USAGE_ERROR_ACTION +#define USAGE_ERROR_ACTION(m,p) ABORT +#endif /* USAGE_ERROR_ACTION */ + +#endif /* PROCEED_ON_ERROR */ + +/* -------------------------- Debugging setup ---------------------------- */ + +#if ! DEBUG + +#define check_free_chunk(M,P) +#define check_inuse_chunk(M,P) +#define check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) +#define check_malloc_state(M) +#define check_top_chunk(M,P) + +#else /* DEBUG */ +#define check_free_chunk(M,P) do_check_free_chunk(M,P) +#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P) +#define check_top_chunk(M,P) do_check_top_chunk(M,P) +#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P) +#define check_malloc_state(M) do_check_malloc_state(M) + +static void do_check_any_chunk(mstate m, mchunkptr p); +static void do_check_top_chunk(mstate m, mchunkptr p); +static void do_check_mmapped_chunk(mstate m, mchunkptr p); +static void do_check_inuse_chunk(mstate m, mchunkptr p); +static void do_check_free_chunk(mstate m, mchunkptr p); +static void do_check_malloced_chunk(mstate m, void* mem, size_t s); +static void do_check_tree(mstate m, tchunkptr t); +static void do_check_treebin(mstate m, bindex_t i); +static void do_check_smallbin(mstate m, bindex_t i); +static void do_check_malloc_state(mstate m); +static int bin_find(mstate m, mchunkptr x); +static size_t traverse_and_check(mstate m); +#endif /* DEBUG */ + +/* ---------------------------- Indexing Bins ---------------------------- */ + +#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) +#define small_index(s) ((s) >> SMALLBIN_SHIFT) +#define small_index2size(i) ((i) << SMALLBIN_SHIFT) +#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) + +/* addressing by index. See above about smallbin repositioning */ +#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1]))) +#define treebin_at(M,i) (&((M)->treebins[i])) + +/* assign tree index for size S to variable I */ +#if defined(__GNUC__) && defined(i386) +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K;\ + __asm__("bsrl %1,%0\n\t" : "=r" (K) : "rm" (X));\ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} +#else /* GNUC */ +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int Y = (unsigned int)X;\ + unsigned int N = ((Y - 0x100) >> 16) & 8;\ + unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\ + N += K;\ + N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\ + K = 14 - N + ((Y <<= K) >> 15);\ + I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\ + }\ +} +#endif /* GNUC */ + +/* Bit representing maximum resolved size in a treebin at i */ +#define bit_for_tree_index(i) \ + (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) + +/* Shift placing maximum resolved bit in a treebin at i as sign bit */ +#define leftshift_for_tree_index(i) \ + ((i == NTREEBINS-1)? 0 : \ + ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) + +/* The size of the smallest chunk held in bin with index i */ +#define minsize_for_tree_index(i) \ + ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ + (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) + + +/* ------------------------ Operations on bin maps ----------------------- */ + +/* bit corresponding to given index */ +#define idx2bit(i) ((binmap_t)(1) << (i)) + +/* Mark/Clear bits with given index */ +#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i)) +#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i)) +#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i)) + +#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i)) +#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i)) +#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i)) + +/* index corresponding to given bit */ + +#if defined(__GNUC__) && defined(i386) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + __asm__("bsfl %1,%0\n\t" : "=r" (J) : "rm" (X));\ + I = (bindex_t)J;\ +} + +#else /* GNUC */ +#if USE_BUILTIN_FFS +#define compute_bit2idx(X, I) I = ffs(X)-1 + +#else /* USE_BUILTIN_FFS */ +#define compute_bit2idx(X, I)\ +{\ + unsigned int Y = X - 1;\ + unsigned int K = Y >> (16-4) & 16;\ + unsigned int N = K; Y >>= K;\ + N += K = Y >> (8-3) & 8; Y >>= K;\ + N += K = Y >> (4-2) & 4; Y >>= K;\ + N += K = Y >> (2-1) & 2; Y >>= K;\ + N += K = Y >> (1-0) & 1; Y >>= K;\ + I = (bindex_t)(N + Y);\ +} +#endif /* USE_BUILTIN_FFS */ +#endif /* GNUC */ + +/* isolate the least set bit of a bitmap */ +#define least_bit(x) ((x) & -(x)) + +/* mask with all bits to left of least bit of x on */ +#define left_bits(x) ((x<<1) | -(x<<1)) + +/* mask with all bits to left of or equal to least bit of x on */ +#define same_or_left_bits(x) ((x) | -(x)) + + +/* ----------------------- Runtime Check Support ------------------------- */ + +/* + For security, the main invariant is that malloc/free/etc never + writes to a static address other than malloc_state, unless static + malloc_state itself has been corrupted, which cannot occur via + malloc (because of these checks). In essence this means that we + believe all pointers, sizes, maps etc held in malloc_state, but + check all of those linked or offsetted from other embedded data + structures. These checks are interspersed with main code in a way + that tends to minimize their run-time cost. + + When FOOTERS is defined, in addition to range checking, we also + verify footer fields of inuse chunks, which can be used guarantee + that the mstate controlling malloc/free is intact. This is a + streamlined version of the approach described by William Robertson + et al in "Run-time Detection of Heap-based Overflows" LISA'03 + http://www.usenix.org/events/lisa03/tech/robertson.html The footer + of an inuse chunk holds the xor of its mstate and a random seed, + that is checked upon calls to free() and realloc(). This is + (probablistically) unguessable from outside the program, but can be + computed by any code successfully malloc'ing any chunk, so does not + itself provide protection against code that has already broken + security through some other means. Unlike Robertson et al, we + always dynamically check addresses of all offset chunks (previous, + next, etc). This turns out to be cheaper than relying on hashes. +*/ + +#if !INSECURE +/* Check if address a is at least as high as any from MORECORE or MMAP */ +#define ok_address(M, a) ((char*)(a) >= (M)->least_addr) +/* Check if address of next chunk n is higher than base chunk p */ +#define ok_next(p, n) ((char*)(p) < (char*)(n)) +/* Check if p has its cinuse bit on */ +#define ok_cinuse(p) cinuse(p) +/* Check if p has its pinuse bit on */ +#define ok_pinuse(p) pinuse(p) + +#else /* !INSECURE */ +#define ok_address(M, a) (1) +#define ok_next(b, n) (1) +#define ok_cinuse(p) (1) +#define ok_pinuse(p) (1) +#endif /* !INSECURE */ + +#if (FOOTERS && !INSECURE) +/* Check if (alleged) mstate m has expected magic field */ +#define ok_magic(M) ((M)->magic == mparams.magic) +#else /* (FOOTERS && !INSECURE) */ +#define ok_magic(M) (1) +#endif /* (FOOTERS && !INSECURE) */ + + +/* In gcc, use __builtin_expect to minimize impact of checks */ +#if !INSECURE +#if defined(__GNUC__) && __GNUC__ >= 3 +#define RTCHECK(e) __builtin_expect(e, 1) +#else /* GNUC */ +#define RTCHECK(e) (e) +#endif /* GNUC */ +#else /* !INSECURE */ +#define RTCHECK(e) (1) +#endif /* !INSECURE */ + +/* macros to set up inuse chunks with or without footers */ + +#if !FOOTERS + +#define mark_inuse_foot(M,p,s) + +/* Set cinuse bit and pinuse bit of next chunk */ +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set size, cinuse and pinuse bit of this chunk */ +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT)) + +#else /* FOOTERS */ + +/* Set foot of inuse chunk to be xor of mstate and seed */ +#define mark_inuse_foot(M,p,s)\ + (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) + +#define get_mstate_for(p)\ + ((mstate)(((mchunkptr)((char*)(p) +\ + (chunksize(p))))->prev_foot ^ mparams.magic)) + +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ + mark_inuse_foot(M,p,s)) + +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\ + mark_inuse_foot(M,p,s)) + +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + mark_inuse_foot(M, p, s)) + +#endif /* !FOOTERS */ + +/* ---------------------------- setting mparams -------------------------- */ + +/* Initialize mparams */ +static int init_mparams(void) { + if (mparams.page_size == 0) { + size_t s; + + mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; + mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; +#if MORECORE_CONTIGUOUS + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT; +#else /* MORECORE_CONTIGUOUS */ + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT; +#endif /* MORECORE_CONTIGUOUS */ + +#if (FOOTERS && !INSECURE) + { +#if USE_DEV_RANDOM + int fd; + unsigned char buf[sizeof(size_t)]; + /* Try to use /dev/urandom, else fall back on using time */ + if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && + read(fd, buf, sizeof(buf)) == sizeof(buf)) { + s = *((size_t *) buf); + close(fd); + } + else +#endif /* USE_DEV_RANDOM */ + s = (size_t)(time(0) ^ (size_t)0x55555555U); + + s |= (size_t)8U; /* ensure nonzero */ + s &= ~(size_t)7U; /* improve chances of fault for bad values */ + + } +#else /* (FOOTERS && !INSECURE) */ + s = (size_t)0x58585858U; +#endif /* (FOOTERS && !INSECURE) */ + ACQUIRE_MAGIC_INIT_LOCK(); + if (mparams.magic == 0) { + mparams.magic = s; + /* Set up lock for main malloc area */ + INITIAL_LOCK(&gm->mutex); + gm->mflags = mparams.default_mflags; + } + RELEASE_MAGIC_INIT_LOCK(); + +#ifndef WIN32 + mparams.page_size = malloc_getpagesize; + mparams.granularity = ((DEFAULT_GRANULARITY != 0)? + DEFAULT_GRANULARITY : mparams.page_size); +#else /* WIN32 */ + { + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + mparams.page_size = system_info.dwPageSize; + mparams.granularity = system_info.dwAllocationGranularity; + } +#endif /* WIN32 */ + + /* Sanity-check configuration: + size_t must be unsigned and as wide as pointer type. + ints must be at least 4 bytes. + alignment must be at least 8. + Alignment, min chunk size, and page size must all be powers of 2. + */ + if ((sizeof(size_t) != sizeof(char*)) || + (MAX_SIZE_T < MIN_CHUNK_SIZE) || + (sizeof(int) < 4) || + (MALLOC_ALIGNMENT < (size_t)8U) || + ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) || + ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) || + ((mparams.granularity & (mparams.granularity-SIZE_T_ONE)) != 0) || + ((mparams.page_size & (mparams.page_size-SIZE_T_ONE)) != 0)) + ABORT; + } + return 0; +} + +/* support for mallopt */ +static int change_mparam(int param_number, int value) { + size_t val = (size_t)value; + init_mparams(); + switch(param_number) { + case M_TRIM_THRESHOLD: + mparams.trim_threshold = val; + return 1; + case M_GRANULARITY: + if (val >= mparams.page_size && ((val & (val-1)) == 0)) { + mparams.granularity = val; + return 1; + } + else + return 0; + case M_MMAP_THRESHOLD: + mparams.mmap_threshold = val; + return 1; + default: + return 0; + } +} + +#if DEBUG +/* ------------------------- Debugging Support --------------------------- */ + +/* Check properties of any chunk, whether free, inuse, mmapped etc */ +static void do_check_any_chunk(mstate m, mchunkptr p) { + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); +} + +/* Check properties of top chunk */ +static void do_check_top_chunk(mstate m, mchunkptr p) { + msegmentptr sp = segment_holding(m, (char*)p); + size_t sz = chunksize(p); + assert(sp != 0); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(sz == m->topsize); + assert(sz > 0); + assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE); + assert(pinuse(p)); + assert(!next_pinuse(p)); +} + +/* Check properties of (inuse) mmapped chunks */ +static void do_check_mmapped_chunk(mstate m, mchunkptr p) { + size_t sz = chunksize(p); + size_t len = (sz + (p->prev_foot & ~IS_MMAPPED_BIT) + MMAP_FOOT_PAD); + assert(is_mmapped(p)); + assert(use_mmap(m)); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(!is_small(sz)); + assert((len & (mparams.page_size-SIZE_T_ONE)) == 0); + assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); + assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0); +} + +/* Check properties of inuse chunks */ +static void do_check_inuse_chunk(mstate m, mchunkptr p) { + do_check_any_chunk(m, p); + assert(cinuse(p)); + assert(next_pinuse(p)); + /* If not pinuse and not mmapped, previous chunk has OK offset */ + assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p); + if (is_mmapped(p)) + do_check_mmapped_chunk(m, p); +} + +/* Check properties of free chunks */ +static void do_check_free_chunk(mstate m, mchunkptr p) { + size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT); + mchunkptr next = chunk_plus_offset(p, sz); + do_check_any_chunk(m, p); + assert(!cinuse(p)); + assert(!next_pinuse(p)); + assert (!is_mmapped(p)); + if (p != m->dv && p != m->top) { + if (sz >= MIN_CHUNK_SIZE) { + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(is_aligned(chunk2mem(p))); + assert(next->prev_foot == sz); + assert(pinuse(p)); + assert (next == m->top || cinuse(next)); + assert(p->fd->bk == p); + assert(p->bk->fd == p); + } + else /* markers are always of size SIZE_T_SIZE */ + assert(sz == SIZE_T_SIZE); + } +} + +/* Check properties of malloced chunks at the point they are malloced */ +static void do_check_malloced_chunk(mstate m, void* mem, size_t s) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT); + do_check_inuse_chunk(m, p); + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(sz >= MIN_CHUNK_SIZE); + assert(sz >= s); + /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ + assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE)); + } +} + +/* Check a tree and its subtrees. */ +static void do_check_tree(mstate m, tchunkptr t) { + tchunkptr head = 0; + tchunkptr u = t; + bindex_t tindex = t->index; + size_t tsize = chunksize(t); + bindex_t idx; + compute_tree_index(tsize, idx); + assert(tindex == idx); + assert(tsize >= MIN_LARGE_SIZE); + assert(tsize >= minsize_for_tree_index(idx)); + assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1)))); + + do { /* traverse through chain of same-sized nodes */ + do_check_any_chunk(m, ((mchunkptr)u)); + assert(u->index == tindex); + assert(chunksize(u) == tsize); + assert(!cinuse(u)); + assert(!next_pinuse(u)); + assert(u->fd->bk == u); + assert(u->bk->fd == u); + if (u->parent == 0) { + assert(u->child[0] == 0); + assert(u->child[1] == 0); + } + else { + assert(head == 0); /* only one node on chain has parent */ + head = u; + assert(u->parent != u); + assert (u->parent->child[0] == u || + u->parent->child[1] == u || + *((tbinptr*)(u->parent)) == u); + if (u->child[0] != 0) { + assert(u->child[0]->parent == u); + assert(u->child[0] != u); + do_check_tree(m, u->child[0]); + } + if (u->child[1] != 0) { + assert(u->child[1]->parent == u); + assert(u->child[1] != u); + do_check_tree(m, u->child[1]); + } + if (u->child[0] != 0 && u->child[1] != 0) { + assert(chunksize(u->child[0]) < chunksize(u->child[1])); + } + } + u = u->fd; + } while (u != t); + assert(head != 0); +} + +/* Check all the chunks in a treebin. */ +static void do_check_treebin(mstate m, bindex_t i) { + tbinptr* tb = treebin_at(m, i); + tchunkptr t = *tb; + int empty = (m->treemap & (1U << i)) == 0; + if (t == 0) + assert(empty); + if (!empty) + do_check_tree(m, t); +} + +/* Check all the chunks in a smallbin. */ +static void do_check_smallbin(mstate m, bindex_t i) { + sbinptr b = smallbin_at(m, i); + mchunkptr p = b->bk; + unsigned int empty = (m->smallmap & (1U << i)) == 0; + if (p == b) + assert(empty); + if (!empty) { + for (; p != b; p = p->bk) { + size_t size = chunksize(p); + mchunkptr q; + /* each chunk claims to be free */ + do_check_free_chunk(m, p); + /* chunk belongs in bin */ + assert(small_index(size) == i); + assert(p->bk == b || chunksize(p->bk) == chunksize(p)); + /* chunk is followed by an inuse chunk */ + q = next_chunk(p); + if (q->head != FENCEPOST_HEAD) + do_check_inuse_chunk(m, q); + } + } +} + +/* Find x in a bin. Used in other check functions. */ +static int bin_find(mstate m, mchunkptr x) { + size_t size = chunksize(x); + if (is_small(size)) { + bindex_t sidx = small_index(size); + sbinptr b = smallbin_at(m, sidx); + if (smallmap_is_marked(m, sidx)) { + mchunkptr p = b; + do { + if (p == x) + return 1; + } while ((p = p->fd) != b); + } + } + else { + bindex_t tidx; + compute_tree_index(size, tidx); + if (treemap_is_marked(m, tidx)) { + tchunkptr t = *treebin_at(m, tidx); + size_t sizebits = size << leftshift_for_tree_index(tidx); + while (t != 0 && chunksize(t) != size) { + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + sizebits <<= 1; + } + if (t != 0) { + tchunkptr u = t; + do { + if (u == (tchunkptr)x) + return 1; + } while ((u = u->fd) != t); + } + } + } + return 0; +} + +/* Traverse each chunk and check it; return total */ +static size_t traverse_and_check(mstate m) { + size_t sum = 0; + if (is_initialized(m)) { + msegmentptr s = &m->seg; + sum += m->topsize + TOP_FOOT_SIZE; + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + mchunkptr lastq = 0; + assert(pinuse(q)); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + sum += chunksize(q); + if (cinuse(q)) { + assert(!bin_find(m, q)); + do_check_inuse_chunk(m, q); + } + else { + assert(q == m->dv || bin_find(m, q)); + assert(lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */ + do_check_free_chunk(m, q); + } + lastq = q; + q = next_chunk(q); + } + s = s->next; + } + } + return sum; +} + +/* Check all properties of malloc_state. */ +static void do_check_malloc_state(mstate m) { + bindex_t i; + size_t total; + /* check bins */ + for (i = 0; i < NSMALLBINS; ++i) + do_check_smallbin(m, i); + for (i = 0; i < NTREEBINS; ++i) + do_check_treebin(m, i); + + if (m->dvsize != 0) { /* check dv chunk */ + do_check_any_chunk(m, m->dv); + assert(m->dvsize == chunksize(m->dv)); + assert(m->dvsize >= MIN_CHUNK_SIZE); + assert(bin_find(m, m->dv) == 0); + } + + if (m->top != 0) { /* check top chunk */ + do_check_top_chunk(m, m->top); + assert(m->topsize == chunksize(m->top)); + assert(m->topsize > 0); + assert(bin_find(m, m->top) == 0); + } + + total = traverse_and_check(m); + assert(total <= m->footprint); + assert(m->footprint <= m->max_footprint); +} +#endif /* DEBUG */ + +/* ----------------------------- statistics ------------------------------ */ + +#if !NO_MALLINFO +static struct mallinfo internal_mallinfo(mstate m) { + struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + if (!PREACTION(m)) { + check_malloc_state(m); + if (is_initialized(m)) { + size_t nfree = SIZE_T_ONE; /* top always free */ + size_t mfree = m->topsize + TOP_FOOT_SIZE; + size_t sum = mfree; + msegmentptr s = &m->seg; + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + size_t sz = chunksize(q); + sum += sz; + if (!cinuse(q)) { + mfree += sz; + ++nfree; + } + q = next_chunk(q); + } + s = s->next; + } + + nm.arena = sum; + nm.ordblks = nfree; + nm.hblkhd = m->footprint - sum; + nm.usmblks = m->max_footprint; + nm.uordblks = m->footprint - mfree; + nm.fordblks = mfree; + nm.keepcost = m->topsize; + } + + POSTACTION(m); + } + return nm; +} +#endif /* !NO_MALLINFO */ + +static void internal_malloc_stats(mstate m) { + if (!PREACTION(m)) { + size_t maxfp = 0; + size_t fp = 0; + size_t used = 0; + check_malloc_state(m); + if (is_initialized(m)) { + msegmentptr s = &m->seg; + maxfp = m->max_footprint; + fp = m->footprint; + used = fp - (m->topsize + TOP_FOOT_SIZE); + + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + if (!cinuse(q)) + used -= chunksize(q); + q = next_chunk(q); + } + s = s->next; + } + } + + fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp)); + fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp)); + fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used)); + + POSTACTION(m); + } +} + +/* ----------------------- Operations on smallbins ----------------------- */ + +/* + Various forms of linking and unlinking are defined as macros. Even + the ones for trees, which are very long but have very short typical + paths. This is ugly but reduces reliance on inlining support of + compilers. +*/ + +/* Link a free chunk into a smallbin */ +#define insert_small_chunk(M, P, S) {\ + bindex_t I = small_index(S);\ + mchunkptr B = smallbin_at(M, I);\ + mchunkptr F = B;\ + assert(S >= MIN_CHUNK_SIZE);\ + if (!smallmap_is_marked(M, I))\ + mark_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, B->fd)))\ + F = B->fd;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + B->fd = P;\ + F->bk = P;\ + P->fd = F;\ + P->bk = B;\ +} + +/* Unlink a chunk from a smallbin */ +#define unlink_small_chunk(M, P, S) {\ + mchunkptr F = P->fd;\ + mchunkptr B = P->bk;\ + bindex_t I = small_index(S);\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (F == B)\ + clear_smallmap(M, I);\ + else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\ + (B == smallbin_at(M,I) || ok_address(M, B)))) {\ + F->bk = B;\ + B->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Unlink the first chunk from a smallbin */ +#define unlink_first_small_chunk(M, B, P, I) {\ + mchunkptr F = P->fd;\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (B == F)\ + clear_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, F))) {\ + B->fd = F;\ + F->bk = B;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Replace dv node, binning the old one */ +/* Used only when dvsize known to be small */ +#define replace_dv(M, P, S) {\ + size_t DVS = M->dvsize;\ + if (DVS != 0) {\ + mchunkptr DV = M->dv;\ + assert(is_small(DVS));\ + insert_small_chunk(M, DV, DVS);\ + }\ + M->dvsize = S;\ + M->dv = P;\ +} + +/* ------------------------- Operations on trees ------------------------- */ + +/* Insert chunk into tree */ +#define insert_large_chunk(M, X, S) {\ + tbinptr* H;\ + bindex_t I;\ + compute_tree_index(S, I);\ + H = treebin_at(M, I);\ + X->index = I;\ + X->child[0] = X->child[1] = 0;\ + if (!treemap_is_marked(M, I)) {\ + mark_treemap(M, I);\ + *H = X;\ + X->parent = (tchunkptr)H;\ + X->fd = X->bk = X;\ + }\ + else {\ + tchunkptr T = *H;\ + size_t K = S << leftshift_for_tree_index(I);\ + for (;;) {\ + if (chunksize(T) != S) {\ + tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\ + K <<= 1;\ + if (*C != 0)\ + T = *C;\ + else if (RTCHECK(ok_address(M, C))) {\ + *C = X;\ + X->parent = T;\ + X->fd = X->bk = X;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + else {\ + tchunkptr F = T->fd;\ + if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\ + T->fd = F->bk = X;\ + X->fd = F;\ + X->bk = T;\ + X->parent = 0;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + }\ + }\ +} + +/* + Unlink steps: + + 1. If x is a chained node, unlink it from its same-sized fd/bk links + and choose its bk node as its replacement. + 2. If x was the last node of its size, but not a leaf node, it must + be replaced with a leaf node (not merely one with an open left or + right), to make sure that lefts and rights of descendents + correspond properly to bit masks. We use the rightmost descendent + of x. We could use any other leaf, but this is easy to locate and + tends to counteract removal of leftmosts elsewhere, and so keeps + paths shorter than minimally guaranteed. This doesn't loop much + because on average a node in a tree is near the bottom. + 3. If x is the base of a chain (i.e., has parent links) relink + x's parent and children to x's replacement (or null if none). +*/ + +#define unlink_large_chunk(M, X) {\ + tchunkptr XP = X->parent;\ + tchunkptr R;\ + if (X->bk != X) {\ + tchunkptr F = X->fd;\ + R = X->bk;\ + if (RTCHECK(ok_address(M, F))) {\ + F->bk = R;\ + R->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else {\ + tchunkptr* RP;\ + if (((R = *(RP = &(X->child[1]))) != 0) ||\ + ((R = *(RP = &(X->child[0]))) != 0)) {\ + tchunkptr* CP;\ + while ((*(CP = &(R->child[1])) != 0) ||\ + (*(CP = &(R->child[0])) != 0)) {\ + R = *(RP = CP);\ + }\ + if (RTCHECK(ok_address(M, RP)))\ + *RP = 0;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + }\ + if (XP != 0) {\ + tbinptr* H = treebin_at(M, X->index);\ + if (X == *H) {\ + if ((*H = R) == 0) \ + clear_treemap(M, X->index);\ + }\ + else if (RTCHECK(ok_address(M, XP))) {\ + if (XP->child[0] == X) \ + XP->child[0] = R;\ + else \ + XP->child[1] = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + if (R != 0) {\ + if (RTCHECK(ok_address(M, R))) {\ + tchunkptr C0, C1;\ + R->parent = XP;\ + if ((C0 = X->child[0]) != 0) {\ + if (RTCHECK(ok_address(M, C0))) {\ + R->child[0] = C0;\ + C0->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + if ((C1 = X->child[1]) != 0) {\ + if (RTCHECK(ok_address(M, C1))) {\ + R->child[1] = C1;\ + C1->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ +} + +/* Relays to large vs small bin operations */ + +#define insert_chunk(M, P, S)\ + if (is_small(S)) insert_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } + +#define unlink_chunk(M, P, S)\ + if (is_small(S)) unlink_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } + + +/* Relays to internal calls to malloc/free from realloc, memalign etc */ + +#if ONLY_MSPACES +#define internal_malloc(m, b) mspace_malloc(m, b) +#define internal_free(m, mem) mspace_free(m,mem); +#else /* ONLY_MSPACES */ +#if MSPACES +#define internal_malloc(m, b)\ + (m == gm)? dlmalloc(b) : mspace_malloc(m, b) +#define internal_free(m, mem)\ + if (m == gm) dlfree(mem); else mspace_free(m,mem); +#else /* MSPACES */ +#define internal_malloc(m, b) dlmalloc(b) +#define internal_free(m, mem) dlfree(mem) +#endif /* MSPACES */ +#endif /* ONLY_MSPACES */ + +/* ----------------------- Direct-mmapping chunks ----------------------- */ + +/* + Directly mmapped chunks are set up with an offset to the start of + the mmapped region stored in the prev_foot field of the chunk. This + allows reconstruction of the required argument to MUNMAP when freed, + and also allows adjustment of the returned chunk to meet alignment + requirements (especially in memalign). There is also enough space + allocated to hold a fake next chunk of size SIZE_T_SIZE to maintain + the PINUSE bit so frees can be checked. +*/ + +/* Malloc using mmap */ +static void* mmap_alloc(mstate m, size_t nb) { + size_t mmsize = granularity_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + if (mmsize > nb) { /* Check for wrap around 0 */ + char* mm = (char*)(DIRECT_MMAP(mmsize)); + if (mm != CMFAIL) { + size_t offset = align_offset(chunk2mem(mm)); + size_t psize = mmsize - offset - MMAP_FOOT_PAD; + mchunkptr p = (mchunkptr)(mm + offset); + p->prev_foot = offset | IS_MMAPPED_BIT; + (p)->head = (psize|CINUSE_BIT); + mark_inuse_foot(m, p, psize); + chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0; + + if (mm < m->least_addr) + m->least_addr = mm; + if ((m->footprint += mmsize) > m->max_footprint) + m->max_footprint = m->footprint; + assert(is_aligned(chunk2mem(p))); + check_mmapped_chunk(m, p); + return chunk2mem(p); + } + } + return 0; +} + +/* Realloc using mmap */ +static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) { + size_t oldsize = chunksize(oldp); + if (is_small(nb)) /* Can't shrink mmap regions below small size */ + return 0; + /* Keep old chunk if big enough but not too big */ + if (oldsize >= nb + SIZE_T_SIZE && + (oldsize - nb) <= (mparams.granularity << 1)) + return oldp; + else { + size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT; + size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; + size_t newmmsize = granularity_align(nb + SIX_SIZE_T_SIZES + + CHUNK_ALIGN_MASK); + char* cp = (char*)CALL_MREMAP((char*)oldp - offset, + oldmmsize, newmmsize, 1); + if (cp != CMFAIL) { + mchunkptr newp = (mchunkptr)(cp + offset); + size_t psize = newmmsize - offset - MMAP_FOOT_PAD; + newp->head = (psize|CINUSE_BIT); + mark_inuse_foot(m, newp, psize); + chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0; + + if (cp < m->least_addr) + m->least_addr = cp; + if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) + m->max_footprint = m->footprint; + check_mmapped_chunk(m, newp); + return newp; + } + } + return 0; +} + +/* -------------------------- mspace management -------------------------- */ + +/* Initialize top chunk and its size */ +static void init_top(mstate m, mchunkptr p, size_t psize) { + /* Ensure alignment */ + size_t offset = align_offset(chunk2mem(p)); + p = (mchunkptr)((char*)p + offset); + psize -= offset; + + m->top = p; + m->topsize = psize; + p->head = psize | PINUSE_BIT; + /* set size of fake trailing chunk holding overhead space only once */ + chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; + m->trim_check = mparams.trim_threshold; /* reset on each update */ +} + +/* Initialize bins for a new mstate that is otherwise zeroed out */ +static void init_bins(mstate m) { + /* Establish circular links for smallbins */ + bindex_t i; + for (i = 0; i < NSMALLBINS; ++i) { + sbinptr bin = smallbin_at(m,i); + bin->fd = bin->bk = bin; + } +} + +#if PROCEED_ON_ERROR + +/* default corruption action */ +static void reset_on_error(mstate m) { + int i; + ++malloc_corruption_error_count; + /* Reinitialize fields to forget about all memory */ + m->smallbins = m->treebins = 0; + m->dvsize = m->topsize = 0; + m->seg.base = 0; + m->seg.size = 0; + m->seg.next = 0; + m->top = m->dv = 0; + for (i = 0; i < NTREEBINS; ++i) + *treebin_at(m, i) = 0; + init_bins(m); +} +#endif /* PROCEED_ON_ERROR */ + +/* Allocate chunk and prepend remainder with chunk in successor base. */ +static void* prepend_alloc(mstate m, char* newbase, char* oldbase, + size_t nb) { + mchunkptr p = align_as_chunk(newbase); + mchunkptr oldfirst = align_as_chunk(oldbase); + size_t psize = (char*)oldfirst - (char*)p; + mchunkptr q = chunk_plus_offset(p, nb); + size_t qsize = psize - nb; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + + assert((char*)oldfirst > (char*)q); + assert(pinuse(oldfirst)); + assert(qsize >= MIN_CHUNK_SIZE); + + /* consolidate remainder with first chunk of old base */ + if (oldfirst == m->top) { + size_t tsize = m->topsize += qsize; + m->top = q; + q->head = tsize | PINUSE_BIT; + check_top_chunk(m, q); + } + else if (oldfirst == m->dv) { + size_t dsize = m->dvsize += qsize; + m->dv = q; + set_size_and_pinuse_of_free_chunk(q, dsize); + } + else { + if (!cinuse(oldfirst)) { + size_t nsize = chunksize(oldfirst); + unlink_chunk(m, oldfirst, nsize); + oldfirst = chunk_plus_offset(oldfirst, nsize); + qsize += nsize; + } + set_free_with_pinuse(q, qsize, oldfirst); + insert_chunk(m, q, qsize); + check_free_chunk(m, q); + } + + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); +} + + +/* Add a segment to hold a new noncontiguous region */ +static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { + /* Determine locations and sizes of segment, fenceposts, old top */ + char* old_top = (char*)m->top; + msegmentptr oldsp = segment_holding(m, old_top); + char* old_end = oldsp->base + oldsp->size; + size_t ssize = pad_request(sizeof(struct malloc_segment)); + char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + size_t offset = align_offset(chunk2mem(rawsp)); + char* asp = rawsp + offset; + char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp; + mchunkptr sp = (mchunkptr)csp; + msegmentptr ss = (msegmentptr)(chunk2mem(sp)); + mchunkptr tnext = chunk_plus_offset(sp, ssize); + mchunkptr p = tnext; + int nfences = 0; + + /* reset top to new space */ + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + + /* Set up segment record */ + assert(is_aligned(ss)); + set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); + *ss = m->seg; /* Push current record */ + m->seg.base = tbase; + m->seg.size = tsize; + m->seg.sflags = mmapped; + m->seg.next = ss; + + /* Insert trailing fenceposts */ + for (;;) { + mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); + p->head = FENCEPOST_HEAD; + ++nfences; + if ((char*)(&(nextp->head)) < old_end) + p = nextp; + else + break; + } + assert(nfences >= 2); + + /* Insert the rest of old top into a bin as an ordinary free chunk */ + if (csp != old_top) { + mchunkptr q = (mchunkptr)old_top; + size_t psize = csp - old_top; + mchunkptr tn = chunk_plus_offset(q, psize); + set_free_with_pinuse(q, psize, tn); + insert_chunk(m, q, psize); + } + + check_top_chunk(m, m->top); +} + +/* -------------------------- System allocation -------------------------- */ + +/* Get memory from system using MORECORE or MMAP */ +static void* sys_alloc(mstate m, size_t nb) { + char* tbase = CMFAIL; + size_t tsize = 0; + flag_t mmap_flag = 0; + + init_mparams(); + + /* Directly map large chunks */ + if (use_mmap(m) && nb >= mparams.mmap_threshold) { + void* mem = mmap_alloc(m, nb); + if (mem != 0) + return mem; + } + + /* + Try getting memory in any of three ways (in most-preferred to + least-preferred order): + 1. A call to MORECORE that can normally contiguously extend memory. + (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or + or main space is mmapped or a previous contiguous call failed) + 2. A call to MMAP new space (disabled if not HAVE_MMAP). + Note that under the default settings, if MORECORE is unable to + fulfill a request, and HAVE_MMAP is true, then mmap is + used as a noncontiguous system allocator. This is a useful backup + strategy for systems with holes in address spaces -- in this case + sbrk cannot contiguously expand the heap, but mmap may be able to + find space. + 3. A call to MORECORE that cannot usually contiguously extend memory. + (disabled if not HAVE_MORECORE) + */ + + if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) { + char* br = CMFAIL; + msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top); + size_t asize = 0; + ACQUIRE_MORECORE_LOCK(); + + if (ss == 0) { /* First time through or recovery */ + char* base = (char*)CALL_MORECORE(0); + if (base != CMFAIL) { + asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE); + /* Adjust to end on a page boundary */ + if (!is_page_aligned(base)) + asize += (page_align((size_t)base) - (size_t)base); + /* Can't call MORECORE if size is negative when treated as signed */ + if (asize < HALF_MAX_SIZE_T && + (br = (char*)(CALL_MORECORE(asize))) == base) { + tbase = base; + tsize = asize; + } + } + } + else { + /* Subtract out existing available top space from MORECORE request. */ + asize = granularity_align(nb - m->topsize + TOP_FOOT_SIZE + SIZE_T_ONE); + /* Use mem here only if it did continuously extend old space */ + if (asize < HALF_MAX_SIZE_T && + (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) { + tbase = br; + tsize = asize; + } + } + + if (tbase == CMFAIL) { /* Cope with partial failure */ + if (br != CMFAIL) { /* Try to use/extend the space we did get */ + if (asize < HALF_MAX_SIZE_T && + asize < nb + TOP_FOOT_SIZE + SIZE_T_ONE) { + size_t esize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE - asize); + if (esize < HALF_MAX_SIZE_T) { + char* end = (char*)CALL_MORECORE(esize); + if (end != CMFAIL) + asize += esize; + else { /* Can't use; try to release */ + CALL_MORECORE(-asize); + br = CMFAIL; + } + } + } + } + if (br != CMFAIL) { /* Use the space we did get */ + tbase = br; + tsize = asize; + } + else + disable_contiguous(m); /* Don't try contiguous path in the future */ + } + + RELEASE_MORECORE_LOCK(); + } + + if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */ + size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE; + size_t rsize = granularity_align(req); + if (rsize > nb) { /* Fail if wraps around zero */ + char* mp = (char*)(CALL_MMAP(rsize)); + if (mp != CMFAIL) { + tbase = mp; + tsize = rsize; + mmap_flag = IS_MMAPPED_BIT; + } + } + } + + if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */ + size_t asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE); + if (asize < HALF_MAX_SIZE_T) { + char* br = CMFAIL; + char* end = CMFAIL; + ACQUIRE_MORECORE_LOCK(); + br = (char*)(CALL_MORECORE(asize)); + end = (char*)(CALL_MORECORE(0)); + RELEASE_MORECORE_LOCK(); + if (br != CMFAIL && end != CMFAIL && br < end) { + size_t ssize = end - br; + if (ssize > nb + TOP_FOOT_SIZE) { + tbase = br; + tsize = ssize; + } + } + } + } + + if (tbase != CMFAIL) { + + if ((m->footprint += tsize) > m->max_footprint) + m->max_footprint = m->footprint; + + if (!is_initialized(m)) { /* first-time initialization */ + m->seg.base = m->least_addr = tbase; + m->seg.size = tsize; + m->seg.sflags = mmap_flag; + m->magic = mparams.magic; + init_bins(m); + if (is_global(m)) + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + else { + /* Offset top by embedded malloc_state */ + mchunkptr mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE); + } + } + + else { + /* Try to merge with an existing segment */ + msegmentptr sp = &m->seg; + while (sp != 0 && tbase != sp->base + sp->size) + sp = sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & IS_MMAPPED_BIT) == mmap_flag && + segment_holds(sp, m->top)) { /* append */ + sp->size += tsize; + init_top(m, m->top, m->topsize + tsize); + } + else { + if (tbase < m->least_addr) + m->least_addr = tbase; + sp = &m->seg; + while (sp != 0 && sp->base != tbase + tsize) + sp = sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & IS_MMAPPED_BIT) == mmap_flag) { + char* oldbase = sp->base; + sp->base = tbase; + sp->size += tsize; + return prepend_alloc(m, tbase, oldbase, nb); + } + else + add_segment(m, tbase, tsize, mmap_flag); + } + } + + if (nb < m->topsize) { /* Allocate from new or extended top space */ + size_t rsize = m->topsize -= nb; + mchunkptr p = m->top; + mchunkptr r = m->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + check_top_chunk(m, m->top); + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); + } + } + + MALLOC_FAILURE_ACTION; + return 0; +} + +/* ----------------------- system deallocation -------------------------- */ + +/* Unmap and unlink any mmapped segments that don't contain used chunks */ +static size_t release_unused_segments(mstate m) { + size_t released = 0; + msegmentptr pred = &m->seg; + msegmentptr sp = pred->next; + while (sp != 0) { + char* base = sp->base; + size_t size = sp->size; + msegmentptr next = sp->next; + if (is_mmapped_segment(sp) && !is_extern_segment(sp)) { + mchunkptr p = align_as_chunk(base); + size_t psize = chunksize(p); + /* Can unmap if first chunk holds entire segment and not pinned */ + if (!cinuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) { + tchunkptr tp = (tchunkptr)p; + assert(segment_holds(sp, (char*)sp)); + if (p == m->dv) { + m->dv = 0; + m->dvsize = 0; + } + else { + unlink_large_chunk(m, tp); + } + if (CALL_MUNMAP(base, size) == 0) { + released += size; + m->footprint -= size; + /* unlink obsoleted record */ + sp = pred; + sp->next = next; + } + else { /* back out if cannot unmap */ + insert_large_chunk(m, tp, psize); + } + } + } + pred = sp; + sp = next; + } + return released; +} + +static int sys_trim(mstate m, size_t pad) { + size_t released = 0; + if (pad < MAX_REQUEST && is_initialized(m)) { + pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ + + if (m->topsize > pad) { + /* Shrink top space in granularity-size units, keeping at least one */ + size_t unit = mparams.granularity; + size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - + SIZE_T_ONE) * unit; + msegmentptr sp = segment_holding(m, (char*)m->top); + + if (!is_extern_segment(sp)) { + if (is_mmapped_segment(sp)) { + if (HAVE_MMAP && + sp->size >= extra && + !has_segment_link(m, sp)) { /* can't shrink if pinned */ + size_t newsize = sp->size - extra; + /* Prefer mremap, fall back to munmap */ + if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || + (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { + released = extra; + } + } + } + else if (HAVE_MORECORE) { + if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ + extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; + ACQUIRE_MORECORE_LOCK(); + { + /* Make sure end of memory is where we last set it. */ + char* old_br = (char*)(CALL_MORECORE(0)); + if (old_br == sp->base + sp->size) { + char* rel_br = (char*)(CALL_MORECORE(-extra)); + char* new_br = (char*)(CALL_MORECORE(0)); + if (rel_br != CMFAIL && new_br < old_br) + released = old_br - new_br; + } + } + RELEASE_MORECORE_LOCK(); + } + } + + if (released != 0) { + sp->size -= released; + m->footprint -= released; + init_top(m, m->top, m->topsize - released); + check_top_chunk(m, m->top); + } + } + + /* Unmap any unused mmapped segments */ + if (HAVE_MMAP) + released += release_unused_segments(m); + + /* On failure, disable autotrim to avoid repeated failed future calls */ + if (released == 0) + m->trim_check = MAX_SIZE_T; + } + + return (released != 0)? 1 : 0; +} + +/* ---------------------------- malloc support --------------------------- */ + +/* allocate a large request from the best fitting chunk in a treebin */ +static void* tmalloc_large(mstate m, size_t nb) { + tchunkptr v = 0; + size_t rsize = -nb; /* Unsigned negation */ + tchunkptr t; + bindex_t idx; + compute_tree_index(nb, idx); + + if ((t = *treebin_at(m, idx)) != 0) { + /* Traverse tree for this bin looking for node with size == nb */ + size_t sizebits = nb << leftshift_for_tree_index(idx); + tchunkptr rst = 0; /* The deepest untaken right subtree */ + for (;;) { + tchunkptr rt; + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + v = t; + if ((rsize = trem) == 0) + break; + } + rt = t->child[1]; + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + if (rt != 0 && rt != t) + rst = rt; + if (t == 0) { + t = rst; /* set t to least subtree holding sizes > nb */ + break; + } + sizebits <<= 1; + } + } + + if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */ + binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; + if (leftbits != 0) { + bindex_t i; + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + t = *treebin_at(m, i); + } + } + + while (t != 0) { /* find smallest of tree or subtree */ + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + t = leftmost_child(t); + } + + /* If dv is a better fit, return 0 so malloc will use it */ + if (v != 0 && rsize < (size_t)(m->dvsize - nb)) { + if (RTCHECK(ok_address(m, v))) { /* split */ + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + insert_chunk(m, r, rsize); + } + return chunk2mem(v); + } + } + CORRUPTION_ERROR_ACTION(m); + } + return 0; +} + +/* allocate a small request from the best fitting chunk in a treebin */ +static void* tmalloc_small(mstate m, size_t nb) { + tchunkptr t, v; + size_t rsize; + bindex_t i; + binmap_t leastbit = least_bit(m->treemap); + compute_bit2idx(leastbit, i); + + v = t = *treebin_at(m, i); + rsize = chunksize(t) - nb; + + while ((t = leftmost_child(t)) != 0) { + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + } + + if (RTCHECK(ok_address(m, v))) { + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(m, r, rsize); + } + return chunk2mem(v); + } + } + + CORRUPTION_ERROR_ACTION(m); + return 0; +} + +/* --------------------------- realloc support --------------------------- */ + +static void* internal_realloc(mstate m, void* oldmem, size_t bytes) { + if (bytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + return 0; + } + if (!PREACTION(m)) { + mchunkptr oldp = mem2chunk(oldmem); + size_t oldsize = chunksize(oldp); + mchunkptr next = chunk_plus_offset(oldp, oldsize); + mchunkptr newp = 0; + void* extra = 0; + + /* Try to either shrink or extend into top. Else malloc-copy-free */ + + if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) && + ok_next(oldp, next) && ok_pinuse(next))) { + size_t nb = request2size(bytes); + if (is_mmapped(oldp)) + newp = mmap_resize(m, oldp, nb); + else if (oldsize >= nb) { /* already big enough */ + size_t rsize = oldsize - nb; + newp = oldp; + if (rsize >= MIN_CHUNK_SIZE) { + mchunkptr remainder = chunk_plus_offset(newp, nb); + set_inuse(m, newp, nb); + set_inuse(m, remainder, rsize); + extra = chunk2mem(remainder); + } + } + else if (next == m->top && oldsize + m->topsize > nb) { + /* Expand into top */ + size_t newsize = oldsize + m->topsize; + size_t newtopsize = newsize - nb; + mchunkptr newtop = chunk_plus_offset(oldp, nb); + set_inuse(m, oldp, nb); + newtop->head = newtopsize |PINUSE_BIT; + m->top = newtop; + m->topsize = newtopsize; + newp = oldp; + } + } + else { + USAGE_ERROR_ACTION(m, oldmem); + POSTACTION(m); + return 0; + } + + POSTACTION(m); + + if (newp != 0) { + if (extra != 0) { + internal_free(m, extra); + } + check_inuse_chunk(m, newp); + return chunk2mem(newp); + } + else { + void* newmem = internal_malloc(m, bytes); + if (newmem != 0) { + size_t oc = oldsize - overhead_for(oldp); + memcpy(newmem, oldmem, (oc < bytes)? oc : bytes); + internal_free(m, oldmem); + } + return newmem; + } + } + return 0; +} + +/* --------------------------- memalign support -------------------------- */ + +static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { + if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */ + return internal_malloc(m, bytes); + if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ + alignment = MIN_CHUNK_SIZE; + if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */ + size_t a = MALLOC_ALIGNMENT << 1; + while (a < alignment) a <<= 1; + alignment = a; + } + + if (bytes >= MAX_REQUEST - alignment) { + if (m != 0) { /* Test isn't needed but avoids compiler warning */ + MALLOC_FAILURE_ACTION; + } + } + else { + size_t nb = request2size(bytes); + size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; + char* mem = (char*)internal_malloc(m, req); + if (mem != 0) { + void* leader = 0; + void* trailer = 0; + mchunkptr p = mem2chunk(mem); + + if (PREACTION(m)) return 0; + if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */ + /* + Find an aligned spot inside chunk. Since we need to give + back leading space in a chunk of at least MIN_CHUNK_SIZE, if + the first calculation places us at a spot with less than + MIN_CHUNK_SIZE leader, we can move to the next aligned spot. + We've allocated enough total room so that this is always + possible. + */ + char* br = (char*)mem2chunk((size_t)(((size_t)(mem + + alignment - + SIZE_T_ONE)) & + -alignment)); + char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)? + br : br+alignment; + mchunkptr newp = (mchunkptr)pos; + size_t leadsize = pos - (char*)(p); + size_t newsize = chunksize(p) - leadsize; + + if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */ + newp->prev_foot = p->prev_foot + leadsize; + newp->head = (newsize|CINUSE_BIT); + } + else { /* Otherwise, give back leader, use the rest */ + set_inuse(m, newp, newsize); + set_inuse(m, p, leadsize); + leader = chunk2mem(p); + } + p = newp; + } + + /* Give back spare room at the end */ + if (!is_mmapped(p)) { + size_t size = chunksize(p); + if (size > nb + MIN_CHUNK_SIZE) { + size_t remainder_size = size - nb; + mchunkptr remainder = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, remainder, remainder_size); + trailer = chunk2mem(remainder); + } + } + + assert (chunksize(p) >= nb); + assert((((size_t)(chunk2mem(p))) % alignment) == 0); + check_inuse_chunk(m, p); + POSTACTION(m); + if (leader != 0) { + internal_free(m, leader); + } + if (trailer != 0) { + internal_free(m, trailer); + } + return chunk2mem(p); + } + } + return 0; +} + +/* ------------------------ comalloc/coalloc support --------------------- */ + +static void** ialloc(mstate m, + size_t n_elements, + size_t* sizes, + int opts, + void* chunks[]) { + /* + This provides common support for independent_X routines, handling + all of the combinations that can result. + + The opts arg has: + bit 0 set if all elements are same size (using sizes[0]) + bit 1 set if elements should be zeroed + */ + + size_t element_size; /* chunksize of each element, if all same */ + size_t contents_size; /* total size of elements */ + size_t array_size; /* request size of pointer array */ + void* mem; /* malloced aggregate space */ + mchunkptr p; /* corresponding chunk */ + size_t remainder_size; /* remaining bytes while splitting */ + void** marray; /* either "chunks" or malloced ptr array */ + mchunkptr array_chunk; /* chunk for malloced ptr array */ + flag_t was_enabled; /* to disable mmap */ + size_t size; + size_t i; + + /* compute array length, if needed */ + if (chunks != 0) { + if (n_elements == 0) + return chunks; /* nothing to do */ + marray = chunks; + array_size = 0; + } + else { + /* if empty req, must still return chunk representing empty array */ + if (n_elements == 0) + return (void**)internal_malloc(m, 0); + marray = 0; + array_size = request2size(n_elements * (sizeof(void*))); + } + + /* compute total element size */ + if (opts & 0x1) { /* all-same-size */ + element_size = request2size(*sizes); + contents_size = n_elements * element_size; + } + else { /* add up all the sizes */ + element_size = 0; + contents_size = 0; + for (i = 0; i != n_elements; ++i) + contents_size += request2size(sizes[i]); + } + + size = contents_size + array_size; + + /* + Allocate the aggregate chunk. First disable direct-mmapping so + malloc won't use it, since we would not be able to later + free/realloc space internal to a segregated mmap region. + */ + was_enabled = use_mmap(m); + disable_mmap(m); + mem = internal_malloc(m, size - CHUNK_OVERHEAD); + if (was_enabled) + enable_mmap(m); + if (mem == 0) + return 0; + + if (PREACTION(m)) return 0; + p = mem2chunk(mem); + remainder_size = chunksize(p); + + assert(!is_mmapped(p)); + + if (opts & 0x2) { /* optionally clear the elements */ + memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size); + } + + /* If not provided, allocate the pointer array as final part of chunk */ + if (marray == 0) { + size_t array_chunk_size; + array_chunk = chunk_plus_offset(p, contents_size); + array_chunk_size = remainder_size - contents_size; + marray = (void**) (chunk2mem(array_chunk)); + set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size); + remainder_size = contents_size; + } + + /* split out elements */ + for (i = 0; ; ++i) { + marray[i] = chunk2mem(p); + if (i != n_elements-1) { + if (element_size != 0) + size = element_size; + else + size = request2size(sizes[i]); + remainder_size -= size; + set_size_and_pinuse_of_inuse_chunk(m, p, size); + p = chunk_plus_offset(p, size); + } + else { /* the final element absorbs any overallocation slop */ + set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); + break; + } + } + +#if DEBUG + if (marray != chunks) { + /* final element must have exactly exhausted chunk */ + if (element_size != 0) { + assert(remainder_size == element_size); + } + else { + assert(remainder_size == request2size(sizes[i])); + } + check_inuse_chunk(m, mem2chunk(marray)); + } + for (i = 0; i != n_elements; ++i) + check_inuse_chunk(m, mem2chunk(marray[i])); + +#endif /* DEBUG */ + + POSTACTION(m); + return marray; +} + + +/* -------------------------- public routines ---------------------------- */ + +#if !ONLY_MSPACES + +void* dlmalloc(size_t bytes) { + /* + Basic algorithm: + If a small request (< 256 bytes minus per-chunk overhead): + 1. If one exists, use a remainderless chunk in associated smallbin. + (Remainderless means that there are too few excess bytes to + represent as a chunk.) + 2. If it is big enough, use the dv chunk, which is normally the + chunk adjacent to the one used for the most recent small request. + 3. If one exists, split the smallest available chunk in a bin, + saving remainder in dv. + 4. If it is big enough, use the top chunk. + 5. If available, get memory from system and use it + Otherwise, for a large request: + 1. Find the smallest available binned chunk that fits, and use it + if it is better fitting than dv chunk, splitting if necessary. + 2. If better fitting than any binned chunk, use the dv chunk. + 3. If it is big enough, use the top chunk. + 4. If request size >= mmap threshold, try to directly mmap this chunk. + 5. If available, get memory from system and use it + + The ugly goto's here ensure that postaction occurs along all paths. + */ + + if (!PREACTION(gm)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = gm->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(gm, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(gm, b, p, idx); + set_inuse_and_pinuse(gm, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb > gm->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(gm, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(gm, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(gm, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(gm, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + + if (nb <= gm->dvsize) { + size_t rsize = gm->dvsize - nb; + mchunkptr p = gm->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = gm->dv = chunk_plus_offset(p, nb); + gm->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + } + else { /* exhaust dv */ + size_t dvs = gm->dvsize; + gm->dvsize = 0; + gm->dv = 0; + set_inuse_and_pinuse(gm, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb < gm->topsize) { /* Split top */ + size_t rsize = gm->topsize -= nb; + mchunkptr p = gm->top; + mchunkptr r = gm->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + mem = chunk2mem(p); + check_top_chunk(gm, gm->top); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + mem = sys_alloc(gm, nb); + + postaction: + POSTACTION(gm); + return mem; + } + + return 0; +} + +void dlfree(void* mem) { + /* + Consolidate freed chunks with preceeding or succeeding bordering + free chunks, if they exist, and then place in a bin. Intermixed + with special cases for top, dv, mmapped chunks, and usage errors. + */ + + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } +#else /* FOOTERS */ +#define fm gm +#endif /* FOOTERS */ + if (!PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if ((prevsize & IS_MMAPPED_BIT) != 0) { + prevsize &= ~IS_MMAPPED_BIT; + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + insert_chunk(fm, p, psize); + check_free_chunk(fm, p); + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + POSTACTION(fm); + } + } +#if !FOOTERS +#undef fm +#endif /* FOOTERS */ +} + +void* dlcalloc(size_t n_elements, size_t elem_size) { + void* mem; + size_t req = 0; + if (n_elements != 0) { + req = n_elements * elem_size; + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + mem = dlmalloc(req); + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + memset(mem, 0, req); + return mem; +} + +void* dlrealloc(void* oldmem, size_t bytes) { + if (oldmem == 0) + return dlmalloc(bytes); +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { + dlfree(oldmem); + return 0; + } +#endif /* REALLOC_ZERO_BYTES_FREES */ + else { +#if ! FOOTERS + mstate m = gm; +#else /* FOOTERS */ + mstate m = get_mstate_for(mem2chunk(oldmem)); + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + return internal_realloc(m, oldmem, bytes); + } +} + +void* dlmemalign(size_t alignment, size_t bytes) { + return internal_memalign(gm, alignment, bytes); +} + +void** dlindependent_calloc(size_t n_elements, size_t elem_size, + void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ + return ialloc(gm, n_elements, &sz, 3, chunks); +} + +void** dlindependent_comalloc(size_t n_elements, size_t sizes[], + void* chunks[]) { + return ialloc(gm, n_elements, sizes, 0, chunks); +} + +void* dlvalloc(size_t bytes) { + size_t pagesz; + init_mparams(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, bytes); +} + +void* dlpvalloc(size_t bytes) { + size_t pagesz; + init_mparams(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); +} + +int dlmalloc_trim(size_t pad) { + int result = 0; + if (!PREACTION(gm)) { + result = sys_trim(gm, pad); + POSTACTION(gm); + } + return result; +} + +size_t dlmalloc_footprint(void) { + return gm->footprint; +} + +size_t dlmalloc_max_footprint(void) { + return gm->max_footprint; +} + +#if !NO_MALLINFO +struct mallinfo dlmallinfo(void) { + return internal_mallinfo(gm); +} +#endif /* NO_MALLINFO */ + +void dlmalloc_stats() { + internal_malloc_stats(gm); +} + +size_t dlmalloc_usable_size(void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (cinuse(p)) + return chunksize(p) - overhead_for(p); + } + return 0; +} + +int dlmallopt(int param_number, int value) { + return change_mparam(param_number, value); +} + +#endif /* !ONLY_MSPACES */ + +/* ----------------------------- user mspaces ---------------------------- */ + +#if MSPACES + +static mstate init_user_mstate(char* tbase, size_t tsize) { + size_t msize = pad_request(sizeof(struct malloc_state)); + mchunkptr mn; + mchunkptr msp = align_as_chunk(tbase); + mstate m = (mstate)(chunk2mem(msp)); + memset(m, 0, msize); + INITIAL_LOCK(&m->mutex); + msp->head = (msize|PINUSE_BIT|CINUSE_BIT); + m->seg.base = m->least_addr = tbase; + m->seg.size = m->footprint = m->max_footprint = tsize; + m->magic = mparams.magic; + m->mflags = mparams.default_mflags; + disable_contiguous(m); + init_bins(m); + mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE); + check_top_chunk(m, m->top); + return m; +} + +mspace create_mspace(size_t capacity, int locked) { + mstate m = 0; + size_t msize = pad_request(sizeof(struct malloc_state)); + init_mparams(); /* Ensure pagesize etc initialized */ + + if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + size_t rs = ((capacity == 0)? mparams.granularity : + (capacity + TOP_FOOT_SIZE + msize)); + size_t tsize = granularity_align(rs); + char* tbase = (char*)(CALL_MMAP(tsize)); + if (tbase != CMFAIL) { + m = init_user_mstate(tbase, tsize); + m->seg.sflags = IS_MMAPPED_BIT; + set_lock(m, locked); + } + } + return (mspace)m; +} + +mspace create_mspace_with_base(void* base, size_t capacity, int locked) { + mstate m = 0; + size_t msize = pad_request(sizeof(struct malloc_state)); + init_mparams(); /* Ensure pagesize etc initialized */ + + if (capacity > msize + TOP_FOOT_SIZE && + capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + m = init_user_mstate((char*)base, capacity); + m->seg.sflags = EXTERN_BIT; + set_lock(m, locked); + } + return (mspace)m; +} + +size_t destroy_mspace(mspace msp) { + size_t freed = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + msegmentptr sp = &ms->seg; + while (sp != 0) { + char* base = sp->base; + size_t size = sp->size; + flag_t flag = sp->sflags; + sp = sp->next; + if ((flag & IS_MMAPPED_BIT) && !(flag & EXTERN_BIT) && + CALL_MUNMAP(base, size) == 0) + freed += size; + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return freed; +} + +/* + mspace versions of routines are near-clones of the global + versions. This is not so nice but better than the alternatives. +*/ + + +void* mspace_malloc(mspace msp, size_t bytes) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (!PREACTION(ms)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = ms->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(ms, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(ms, b, p, idx); + set_inuse_and_pinuse(ms, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb > ms->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(ms, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(ms, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(ms, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(ms, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + + if (nb <= ms->dvsize) { + size_t rsize = ms->dvsize - nb; + mchunkptr p = ms->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = ms->dv = chunk_plus_offset(p, nb); + ms->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + } + else { /* exhaust dv */ + size_t dvs = ms->dvsize; + ms->dvsize = 0; + ms->dv = 0; + set_inuse_and_pinuse(ms, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb < ms->topsize) { /* Split top */ + size_t rsize = ms->topsize -= nb; + mchunkptr p = ms->top; + mchunkptr r = ms->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + mem = chunk2mem(p); + check_top_chunk(ms, ms->top); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + mem = sys_alloc(ms, nb); + + postaction: + POSTACTION(ms); + return mem; + } + + return 0; +} + +void mspace_free(mspace msp, void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); +#else /* FOOTERS */ + mstate fm = (mstate)msp; +#endif /* FOOTERS */ + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } + if (!PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if ((prevsize & IS_MMAPPED_BIT) != 0) { + prevsize &= ~IS_MMAPPED_BIT; + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + insert_chunk(fm, p, psize); + check_free_chunk(fm, p); + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + POSTACTION(fm); + } + } +} + +void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) { + void* mem; + size_t req = 0; + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (n_elements != 0) { + req = n_elements * elem_size; + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + mem = internal_malloc(ms, req); + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + memset(mem, 0, req); + return mem; +} + +void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) { + if (oldmem == 0) + return mspace_malloc(msp, bytes); +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { + mspace_free(msp, oldmem); + return 0; + } +#endif /* REALLOC_ZERO_BYTES_FREES */ + else { +#if FOOTERS + mchunkptr p = mem2chunk(oldmem); + mstate ms = get_mstate_for(p); +#else /* FOOTERS */ + mstate ms = (mstate)msp; +#endif /* FOOTERS */ + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return internal_realloc(ms, oldmem, bytes); + } +} + +void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return internal_memalign(ms, alignment, bytes); +} + +void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return ialloc(ms, n_elements, &sz, 3, chunks); +} + +void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return ialloc(ms, n_elements, sizes, 0, chunks); +} + +int mspace_trim(mspace msp, size_t pad) { + int result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + if (!PREACTION(ms)) { + result = sys_trim(ms, pad); + POSTACTION(ms); + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +void mspace_malloc_stats(mspace msp) { + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + internal_malloc_stats(ms); + } + else { + USAGE_ERROR_ACTION(ms,ms); + } +} + +size_t mspace_footprint(mspace msp) { + size_t result; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + result = ms->footprint; + } + USAGE_ERROR_ACTION(ms,ms); + return result; +} + + +size_t mspace_max_footprint(mspace msp) { + size_t result; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + result = ms->max_footprint; + } + USAGE_ERROR_ACTION(ms,ms); + return result; +} + + +#if !NO_MALLINFO +struct mallinfo mspace_mallinfo(mspace msp) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + } + return internal_mallinfo(ms); +} +#endif /* NO_MALLINFO */ + +int mspace_mallopt(int param_number, int value) { + return change_mparam(param_number, value); +} + +#endif /* MSPACES */ + +/* -------------------- Alternative MORECORE functions ------------------- */ + +/* + Guidelines for creating a custom version of MORECORE: + + * For best performance, MORECORE should allocate in multiples of pagesize. + * MORECORE may allocate more memory than requested. (Or even less, + but this will usually result in a malloc failure.) + * MORECORE must not allocate memory when given argument zero, but + instead return one past the end address of memory from previous + nonzero call. + * For best performance, consecutive calls to MORECORE with positive + arguments should return increasing addresses, indicating that + space has been contiguously extended. + * Even though consecutive calls to MORECORE need not return contiguous + addresses, it must be OK for malloc'ed chunks to span multiple + regions in those cases where they do happen to be contiguous. + * MORECORE need not handle negative arguments -- it may instead + just return MFAIL when given negative arguments. + Negative arguments are always multiples of pagesize. MORECORE + must not misinterpret negative args as large positive unsigned + args. You can suppress all such calls from even occurring by defining + MORECORE_CANNOT_TRIM, + + As an example alternative MORECORE, here is a custom allocator + kindly contributed for pre-OSX macOS. It uses virtually but not + necessarily physically contiguous non-paged memory (locked in, + present and won't get swapped out). You can use it by uncommenting + this section, adding some #includes, and setting up the appropriate + defines above: + + #define MORECORE osMoreCore + + There is also a shutdown routine that should somehow be called for + cleanup upon program exit. + + #define MAX_POOL_ENTRIES 100 + #define MINIMUM_MORECORE_SIZE (64 * 1024U) + static int next_os_pool; + void *our_os_pools[MAX_POOL_ENTRIES]; + + void *osMoreCore(int size) + { + void *ptr = 0; + static void *sbrk_top = 0; + + if (size > 0) + { + if (size < MINIMUM_MORECORE_SIZE) + size = MINIMUM_MORECORE_SIZE; + if (CurrentExecutionLevel() == kTaskLevel) + ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); + if (ptr == 0) + { + return (void *) MFAIL; + } + // save ptrs so they can be freed during cleanup + our_os_pools[next_os_pool] = ptr; + next_os_pool++; + ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); + sbrk_top = (char *) ptr + size; + return ptr; + } + else if (size < 0) + { + // we don't currently support shrink behavior + return (void *) MFAIL; + } + else + { + return sbrk_top; + } + } + + // cleanup any allocated memory pools + // called as last thing before shutting down driver + + void osCleanupMem(void) + { + void **ptr; + + for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) + if (*ptr) + { + PoolDeallocate(*ptr); + *ptr = 0; + } + } + +*/ + + +/* ----------------------------------------------------------------------- +History: + V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee) + * Add max_footprint functions + * Ensure all appropriate literals are size_t + * Fix conditional compilation problem for some #define settings + * Avoid concatenating segments with the one provided + in create_mspace_with_base + * Rename some variables to avoid compiler shadowing warnings + * Use explicit lock initialization. + * Better handling of sbrk interference. + * Simplify and fix segment insertion, trimming and mspace_destroy + * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x + * Thanks especially to Dennis Flanagan for help on these. + + V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee) + * Fix memalign brace error. + + V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee) + * Fix improper #endif nesting in C++ + * Add explicit casts needed for C++ + + V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee) + * Use trees for large bins + * Support mspaces + * Use segments to unify sbrk-based and mmap-based system allocation, + removing need for emulation on most platforms without sbrk. + * Default safety checks + * Optional footer checks. Thanks to William Robertson for the idea. + * Internal code refactoring + * Incorporate suggestions and platform-specific changes. + Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas, + Aaron Bachmann, Emery Berger, and others. + * Speed up non-fastbin processing enough to remove fastbins. + * Remove useless cfree() to avoid conflicts with other apps. + * Remove internal memcpy, memset. Compilers handle builtins better. + * Remove some options that no one ever used and rename others. + + V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) + * Fix malloc_state bitmap array misdeclaration + + V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee) + * Allow tuning of FIRST_SORTED_BIN_SIZE + * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte. + * Better detection and support for non-contiguousness of MORECORE. + Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger + * Bypass most of malloc if no frees. Thanks To Emery Berger. + * Fix freeing of old top non-contiguous chunk im sysmalloc. + * Raised default trim and map thresholds to 256K. + * Fix mmap-related #defines. Thanks to Lubos Lunak. + * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield. + * Branch-free bin calculation + * Default trim and mmap thresholds now 256K. + + V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) + * Introduce independent_comalloc and independent_calloc. + Thanks to Michael Pachos for motivation and help. + * Make optional .h file available + * Allow > 2GB requests on 32bit systems. + * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>. + Thanks also to Andreas Mueller <a.mueller at paradatec.de>, + and Anonymous. + * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for + helping test this.) + * memalign: check alignment arg + * realloc: don't try to shift chunks backwards, since this + leads to more fragmentation in some programs and doesn't + seem to help in any others. + * Collect all cases in malloc requiring system memory into sysmalloc + * Use mmap as backup to sbrk + * Place all internal state in malloc_state + * Introduce fastbins (although similar to 2.5.1) + * Many minor tunings and cosmetic improvements + * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK + * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS + Thanks to Tony E. Bennett <tbennett@nvidia.com> and others. + * Include errno.h to support default failure action. + + V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) + * return null for negative arguments + * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com> + * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' + (e.g. WIN32 platforms) + * Cleanup header file inclusion for WIN32 platforms + * Cleanup code to avoid Microsoft Visual C++ compiler complaints + * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing + memory allocation routines + * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) + * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to + usage of 'assert' in non-WIN32 code + * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to + avoid infinite loop + * Always call 'fREe()' rather than 'free()' + + V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) + * Fixed ordering problem with boundary-stamping + + V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) + * Added pvalloc, as recommended by H.J. Liu + * Added 64bit pointer support mainly from Wolfram Gloger + * Added anonymously donated WIN32 sbrk emulation + * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen + * malloc_extend_top: fix mask error that caused wastage after + foreign sbrks + * Add linux mremap support code from HJ Liu + + V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) + * Integrated most documentation with the code. + * Add support for mmap, with help from + Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Use last_remainder in more cases. + * Pack bins using idea from colin@nyx10.cs.du.edu + * Use ordered bins instead of best-fit threshhold + * Eliminate block-local decls to simplify tracing and debugging. + * Support another case of realloc via move into top + * Fix error occuring when initial sbrk_base not word-aligned. + * Rely on page size for units instead of SBRK_UNIT to + avoid surprises about sbrk alignment conventions. + * Add mallinfo, mallopt. Thanks to Raymond Nijssen + (raymond@es.ele.tue.nl) for the suggestion. + * Add `pad' argument to malloc_trim and top_pad mallopt parameter. + * More precautions for cases where other routines call sbrk, + courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Added macros etc., allowing use in linux libc from + H.J. Lu (hjl@gnu.ai.mit.edu) + * Inverted this history list + + V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) + * Re-tuned and fixed to behave more nicely with V2.6.0 changes. + * Removed all preallocation code since under current scheme + the work required to undo bad preallocations exceeds + the work saved in good cases for most test programs. + * No longer use return list or unconsolidated bins since + no scheme using them consistently outperforms those that don't + given above changes. + * Use best fit for very large chunks to prevent some worst-cases. + * Added some support for debugging + + V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) + * Removed footers when chunks are in use. Thanks to + Paul Wilson (wilson@cs.texas.edu) for the suggestion. + + V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) + * Added malloc_trim, with help from Wolfram Gloger + (wmglo@Dent.MED.Uni-Muenchen.DE). + + V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) + + V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) + * realloc: try to expand in both directions + * malloc: swap order of clean-bin strategy; + * realloc: only conditionally expand backwards + * Try not to scavenge used bins + * Use bin counts as a guide to preallocation + * Occasionally bin return list chunks in first scan + * Add a few optimizations from colin@nyx10.cs.du.edu + + V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) + * faster bin computation & slightly different binning + * merged all consolidations to one part of malloc proper + (eliminating old malloc_find_space & malloc_clean_bin) + * Scan 2 returns chunks (not just 1) + * Propagate failure in realloc if malloc returns 0 + * Add stuff to allow compilation on non-ANSI compilers + from kpv@research.att.com + + V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) + * removed potential for odd address access in prev_chunk + * removed dependency on getpagesize.h + * misc cosmetics and a bit more internal documentation + * anticosmetics: mangled names in macros to evade debugger strangeness + * tested on sparc, hp-700, dec-mips, rs6000 + with gcc & native cc (hp, dec only) allowing + Detlefs & Zorn comparison study (in SIGPLAN Notices.) + + Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) + * Based loosely on libg++-1.2X malloc. (It retains some of the overall + structure of old version, but most details differ.) + +*/ diff --git a/lib/excpt.nim b/lib/excpt.nim index ae057cc97..8adb3d5a9 100644 --- a/lib/excpt.nim +++ b/lib/excpt.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2006 Andreas Rumpf +# (c) Copyright 2008 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -35,35 +35,34 @@ proc chckNil(p: pointer) {.inline, compilerproc.} type PSafePoint = ptr TSafePoint - TSafePoint {.compilerproc.} = record + TSafePoint {.compilerproc, final.} = object prev: PSafePoint # points to next safe point ON THE STACK exc: ref E_Base status: int context: C_JmpBuf var - excHandler {.compilerproc, volatile.}: PSafePoint = nil + excHandler {.compilerproc.}: PSafePoint = nil # list of exception handlers # a global variable for the root of all try blocks proc reraiseException() = - if excHandler != nil: + if excHandler == nil: raise newException(ENoExceptionToReraise, "no exception to reraise") else: c_longjmp(excHandler.context, 1) type PFrame = ptr TFrame - TFrame {.importc, nodecl.} = record + TFrame {.importc, nodecl, final.} = object prev: PFrame procname: CString line: int # current line number filename: CString len: int # length of slots (when not debugging always zero) - TTempFrame = record # used for recursion elimination in WriteStackTrace - procname: CString - line: int + TTempFrame = tuple[ # used for recursion elimination in WriteStackTrace + procname: CString, line: int] var buf: string # cannot be allocated on the stack! @@ -71,7 +70,7 @@ var # assert, as it raises an exception and # exception handler needs the buffer too - framePtr {.exportc, volatile.}: PFrame + framePtr {.exportc.}: PFrame tempFrames: array [0..255, TTempFrame] # cannot be allocated # on the stack! @@ -82,8 +81,7 @@ proc auxWriteStackTrace(f: PFrame, s: var string) = i = 0 total = 0 while it != nil and i <= high(tempFrames): - tempFrames[i].procname = it.procname - tempFrames[i].line = it.line + tempFrames[i] = (it.procname, it.line) inc(i) inc(total) it = it.prev @@ -110,10 +108,10 @@ proc rawWriteStackTrace(s: var string) = auxWriteStackTrace(framePtr, s) proc quitOrDebug() {.inline.} = - when not defined(emdb): + when not defined(endb): quit(1) else: - emdbStep() # call the debugger + endbStep() # call the debugger proc raiseException(e: ref E_Base, ename: CString) = GC_disable() # a bad thing is an error in the GC while raising an exception @@ -122,7 +120,7 @@ proc raiseException(e: ref E_Base, ename: CString) = excHandler.exc = e c_longjmp(excHandler.context, 1) else: - if cast[pointer](buf) != nil: + if not isNil(buf): setLen(buf, 0) rawWriteStackTrace(buf) if e.msg != nil and e.msg[0] != '\0': @@ -135,9 +133,7 @@ proc raiseException(e: ref E_Base, ename: CString) = add(buf, "]\n") writeToStdErr(buf) else: - writeToStdErr("*** FATAL ERROR *** ") writeToStdErr(ename) - writeToStdErr("\n") quitOrDebug() GC_enable() @@ -147,7 +143,8 @@ var proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} = if not cond: GC_disable() # BUGFIX: `$` allocates a new string object! - if cast[pointer](assertBuf) != nil: # BUGFIX: when debugging the GC, assertBuf may be nil + if not isNil(assertBuf): + # BUGFIX: when debugging the GC, assertBuf may be nil setLen(assertBuf, 0) add(assertBuf, "[Assertion failure] file: ") add(assertBuf, file) @@ -164,6 +161,11 @@ proc WriteStackTrace() = rawWriteStackTrace(s) writeToStdErr(s) +#proc stackTraceWrapper {.noconv.} = +# writeStackTrace() + +#addQuitProc(stackTraceWrapper) + var dbgAborting: bool # whether the debugger wants to abort @@ -171,6 +173,7 @@ proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} = # print stack trace and quit var s = int(sig) + GC_disable() setLen(buf, 0) rawWriteStackTrace(buf) @@ -185,6 +188,7 @@ proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} = else: add(buf, "unknown signal\n") writeToStdErr(buf) dbgAborting = True # play safe here... + GC_enable() quit(1) # always quit when SIGABRT proc registerSignalHandler() = @@ -195,8 +199,8 @@ proc registerSignalHandler() = c_signal(SIGILL, signalHandler) c_signal(SIGBUS, signalHandler) -registerSignalHandler() # call it in initialization section -# for easier debugging of the GC, this memory is only allocated after the +registerSignalHandler() # call it in initialization section +# for easier debugging of the GC, this memory is only allocated after the # signal handlers have been registered new(gAssertionFailed) buf = newString(2048) @@ -204,12 +208,15 @@ assertBuf = newString(2048) setLen(buf, 0) setLen(assertBuf, 0) -proc raiseRangeError() {.compilerproc, noreturn.} = - raise newException(EOutOfRange, "value out of range") +proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn.} = + raise newException(EOutOfRange, "value " & $val & " out of range") proc raiseIndexError() {.compilerproc, noreturn.} = raise newException(EInvalidIndex, "index out of bounds") +proc raiseFieldError(f: string) {.compilerproc, noreturn.} = + raise newException(EInvalidField, f & " is not accessible") + proc chckIndx(i, a, b: int): int = if i >= a and i <= b: return i @@ -220,19 +227,19 @@ proc chckRange(i, a, b: int): int = if i >= a and i <= b: return i else: - raiseRangeError() + raiseRangeError(i) proc chckRange64(i, a, b: int64): int64 {.compilerproc.} = if i >= a and i <= b: return i else: - raiseRangeError() + raiseRangeError(i) proc chckRangeF(x, a, b: float): float = if x >= a and x <= b: return x else: - raiseRangeError() + raise newException(EOutOfRange, "value " & $x & " out of range") proc chckNil(p: pointer) = if p == nil: c_raise(SIGSEGV) diff --git a/lib/gc.nim b/lib/gc.nim index 570c484e6..72a287064 100644 --- a/lib/gc.nim +++ b/lib/gc.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2006 Andreas Rumpf +# (c) Copyright 2008 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -13,33 +13,39 @@ # For a description of the algorithms used here see: # intern.html -#{.define: debugGC.} # we wish to debug the GC... +{.define: debugGC.} # we wish to debug the GC... #when defined(debugGC): # {.define: logGC.} # define if the GC should log some of its activities {.define: cycleGC.} +const + traceGC = false # extensive debugging + reallyDealloc = true # for debugging purposes this can be set to false + # Guess the page size of the system; if it is the # wrong value, performance may be worse (this is not # for sure though), but GC still works; must be a power of two! const - PageSize = 1024 * sizeof(int) - RC_Increase = 7 * PageSize # is an additive increase + PageShift = if sizeof(pointer) == 4: 12 else: 13 + PageSize = 1 shl PageShift # on 32 bit systems 4096 CycleIncrease = 2 # is a multiplicative increase + InitialCycleThreshold = 8*1024*1024 # X MB because cycle checking is slow + ZctThreshold = 512 # we collect garbage if the ZCT's size + # reaches this threshold + # this needs benchmarking... + when defined(debugGC): - const InitialThreshold = 64*1024 - const stressGC = True # GC is debugged; no need to stress it + const stressGC = False else: const stressGC = False - const InitialThreshold = RC_Increase - # this may need benchmarking... # things the System module thinks should be available: when defined(useDL) or defined(nativeDL): type - TMallocInfo {.importc: "struct mallinfo", nodecl.} = record + TMallocInfo {.importc: "struct mallinfo", nodecl, final.} = object arena: cint # non-mmapped space allocated from system ordblks: cint # number of free chunks smblks: cint # number of fastbin blocks @@ -68,8 +74,7 @@ else: # not available: proc getTotalMem(): int = return -1 var - rcThreshold: int = InitialThreshold - cycleThreshold: int = InitialThreshold + cycleThreshold: int = InitialCycleThreshold memUsed: int = 0 # we have to keep track how much we have allocated @@ -113,11 +118,12 @@ type waNone, waRelease, waZctDecRef, waCycleDecRef, waCycleIncRef, waDebugIncRef TCollectorData = int - TCell = record + TCell {.final.} = object refcount: TCollectorData # the refcount and bit flags typ: PNimType - stackcount: int # stack counter for debugging - drefc: int # real reference counter for debugging + when stressGC: + stackcount: int # stack counter for debugging + drefc: int # real reference counter for debugging PCell = ptr TCell @@ -145,6 +151,7 @@ proc extGetCellType(c: pointer): PNimType {.compilerproc.} = proc internRefcount(p: pointer): int {.exportc: "getRefcount".} = result = int(usrToCell(p).refcount) + if result < 0: result = 0 proc gcAlloc(size: int): pointer = result = alloc0(size) @@ -162,7 +169,7 @@ proc GC_setStrategy(strategy: TGC_Strategy) = of gcOptimizeTime: nil proc GC_enableMarkAndSweep() = - cycleThreshold = InitialThreshold + cycleThreshold = InitialCycleThreshold proc GC_disableMarkAndSweep() = cycleThreshold = high(cycleThreshold)-1 @@ -174,7 +181,7 @@ proc nextTry(h, maxHash: int): int {.inline.} = # generates each int in range(maxHash) exactly once (see any text on # random-number generation for proof). -# ------------------ Zero count table (ZCT) and any table (AT) ------------- +# ------------------ Any table (AT) ------------- # these values are for DL-malloc known for sure (and other allocators # can only be worse): @@ -200,8 +207,7 @@ when BitsPerPage mod BitsPerUnit != 0: # ------------------- cell set handling ------------------------------ # A cellset consists of a hash table of page descriptors. A page -# descriptor has a bit for -# every Memalignment'th byte in the page. +# descriptor has a bit for every Memalignment'th byte in the page. # However, only bits corresponding to addresses that start memory blocks # are set. # Page descriptors are also linked to a list; the list @@ -217,17 +223,59 @@ type TBitIndex = range[0..UnitsPerPage-1] - TPageDesc = record + TPageDesc {.final.} = object next: PPageDesc # all nodes are connected with this pointer key: TAddress # start address at bit 0 bits: array[TBitIndex, int] # a bit vector PPageDescArray = ptr array[0..1000_000, PPageDesc] - TCellSet = record + TCellSet {.final.} = object counter, max: int head: PPageDesc data: PPageDescArray + PCellArray = ptr array[0..100_000_000, PCell] + TCellSeq {.final.} = object + len, cap: int + d: PCellArray + + TSlowSet {.final.} = object # used for debugging purposes only + L: int # current length + cap: int # capacity + d: PCellArray + + TGcHeap {.final.} = object # this contains the zero count and + # non-zero count table + mask: TAddress # mask for fast pointer detection + zct: TCellSeq # the zero count table + at: TCellSet # a table that contains all references + newAT: TCellSet + stackCells: TCellSeq # cells that need to be decremented because they + # are in the hardware stack; a cell may occur + # several times in this data structure + +var + stackBottom: pointer + gch: TGcHeap + +proc add(s: var TCellSeq, c: PCell) {.inline.} = + if s.len >= s.cap: + s.cap = s.cap * 3 div 2 + s.d = cast[PCellArray](realloc(s.d, s.cap * sizeof(PCell))) + if s.d == nil: raiseOutOfMem() + s.d[s.len] = c + inc(s.len) + +proc inOperator(s: TCellSeq, c: PCell): bool {.inline.} = + for i in 0 .. s.len-1: + if s.d[i] == c: return True + return False + +proc init(s: var TCellSeq, cap: int = 1024) = + s.len = 0 + s.cap = cap + s.d = cast[PCellArray](gcAlloc(cap * sizeof(PCell))) + const InitCellSetSize = 1024 # must be a power of two! @@ -284,7 +332,8 @@ proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc = if x.key == key: return x h = nextTry(h, t.max) - if (t.max+1) * 2 < t.counter * 3: CellSetEnlarge(t) + if ((t.max+1)*2 < t.counter*3) or ((t.max+1)-t.counter < 4): + CellSetEnlarge(t) inc(t.counter) h = cast[int](key) and t.max while t.data[h] != nil: h = nextTry(h, t.max) @@ -303,7 +352,7 @@ proc in_Operator(s: TCellSet, cell: PCell): bool = u: TAddress t: PPageDesc u = cast[TAddress](cell) - t = CellSetGet(s, u /% PageSize) + t = CellSetGet(s, u shr PageShift) if t != nil: u = (u %% PageSize) /% MemAlignment result = (t.bits[u /% BitsPerUnit] and (1 shl (u %% BitsPerUnit))) != 0 @@ -315,7 +364,7 @@ proc incl(s: var TCellSet, cell: PCell) = u: TAddress t: PPageDesc u = cast[TAddress](cell) - t = CellSetPut(s, u /% PageSize) + t = CellSetPut(s, u shr PageShift) u = (u %% PageSize) /% MemAlignment t.bits[u /% BitsPerUnit] = t.bits[u /% BitsPerUnit] or (1 shl (u %% BitsPerUnit)) @@ -325,7 +374,7 @@ proc excl(s: var TCellSet, cell: PCell) = u: TAddress t: PPageDesc u = cast[TAddress](cell) - t = CellSetGet(s, u /% PageSize) + t = CellSetGet(s, u shr PageShift) if t != nil: u = (u %% PageSize) /% MemAlignment t.bits[u /% BitsPerUnit] = (t.bits[u /% BitsPerUnit] and @@ -342,7 +391,7 @@ iterator elements(t: TCellSet): PCell {.inline.} = var j = 0 while w != 0: # test all remaining bits for zero if (w and 1) != 0: # the bit is set! - yield cast[PCell]((r.key *% PageSize) +% + yield cast[PCell]((r.key shl PageShift) or # +% (i*%BitsPerUnit+%j) *% MemAlignment) inc(j) w = w shr 1 @@ -354,68 +403,121 @@ iterator elements(t: TCellSet): PCell {.inline.} = proc testPageDescs() = var root: TCellSet CellSetInit(root) - var u = 10_000 - while u <= 20_000: - incl(root, cast[PCell](u)) - inc(u, 8) + #var u = 10_000 + #while u <= 20_000: + # incl(root, cast[PCell](u)) + # inc(u, 8) + + incl(root, cast[PCell](0x81cdfb8)) for cell in elements(root): - c_fprintf(c_stdout, "%ld\n", cast[int](cell)) + c_fprintf(c_stdout, "%p\n", cast[int](cell)) -# testPageDescs() +#testPageDescs() when defined(debugGC): proc writeCell(msg: CString, c: PCell) = - c_fprintf(c_stdout, "%s: %p\n", msg, c) + if c.typ != nil: + if c.typ.kind == tyString: + c_fprintf(c_stdout, "%s\n", cast[TAddress](cellToUsr(c)) + sizeof(int)*2) + c_fprintf(c_stdout, "%s: %p %d\n", msg, c, c.typ.kind) + else: c_fprintf(c_stdout, "%s: %p (nil type)\n", msg, c) proc writePtr(msg: CString, p: Pointer) = c_fprintf(c_stdout, "%s: %p\n", msg, p) -# ------------------------------------------------------------------------- -type - PStackCells = ptr array[0..1000_0000, PCell] - TCountTables = record # this contains the zero count and - # non-zero count table - mask: TAddress # mask for fast pointer detection - zct: TCellSet # the zero count table - at: TCellSet # a table that contains all references - newAT: TCellSet - newZCT: TCellSet - stackCells: PStackCells # cells that need to be decremented because they - # are in the hardware stack; a cell may occur - # several times in this data structure - stackLen, stackMax: int # for managing the stack cells - -proc addStackCell(ct: var TCountTables, cell: PCell) = - if ct.stackLen >= ct.stackMax: - ct.stackMax = ct.stackMax * 3 div 2 - ct.stackCells = cast[PStackCells](realloc(ct.stackCells, ct.stackMax * - sizeof(PCell))) - if ct.stackCells == nil: raiseOutOfMem() - ct.stackCells[ct.stackLen] = cell - inc(ct.stackLen) +when traceGC: + # traceGC is a special switch to enable extensive debugging + type + TCellState = enum + csAllocated, csZctFreed, csCycFreed + + proc cellSetInit(s: var TSlowSet) = + s.L = 0 + s.cap = 4096 + s.d = cast[PCellArray](gcAlloc(s.cap * sizeof(PCell))) + + proc cellSetDeinit(s: var TSlowSet) = + s.L = 0 + s.cap = 0 + dealloc(s.d) + + proc incl(s: var TSlowSet, c: PCell) = + if s.L >= s.cap: + s.cap = s.cap * 3 div 2 + s.d = cast[PCellArray](realloc(s.d, s.cap * sizeof(PCell))) + if s.d == nil: raiseOutOfMem() + s.d[s.L] = c + inc(s.L) + + proc excl(s: var TSlowSet, c: PCell) = + var i = 0 + while i < s.L: + if s.d[i] == c: + s.d[i] = s.d[s.L-1] + dec(s.L) + break + inc(i) -var - stackBottom: pointer - ct: TCountTables + proc inOperator(s: TSlowSet, c: PCell): bool = + var i = 0 + while i < s.L: + if s.d[i] == c: return true + inc(i) -proc GC_invariant(): bool = - result = True - when stressGC: - if recGcLock == 0: - GC_disable() - for cell in elements(ct.at): - var t = cell.typ # getCellType(cell) - if t == nil or t.kind notin {tySequence, tyString, tyRef}: - writeCell("corrupt cell?", cell) - result = false - GC_enable() + iterator elements(s: TSlowSet): PCell = + var i = 0 + while i < s.L: + yield s.d[i] + inc(i) -when stressGC: - proc GCdebugHook() = - if not GC_invariant(): - assert(false) + var + states: array[TCellState, TSlowSet] # TCellSet] + + proc traceCell(c: PCell, state: TCellState) = + case state + of csAllocated: + if c in states[csAllocated]: + writeCell("attempt to alloc a already allocated cell", c) + assert(false) + excl(states[csCycFreed], c) + excl(states[csZctFreed], c) + of csZctFreed: + if c notin states[csAllocated]: + writeCell("attempt to free a not allocated cell", c) + assert(false) + if c in states[csZctFreed]: + writeCell("attempt to free zct cell twice", c) + assert(false) + if c in states[csCycFreed]: + writeCell("attempt to free with zct, but already freed with cyc", c) + assert(false) + excl(states[csAllocated], c) + of csCycFreed: + if c notin states[csAllocated]: + writeCell("attempt to free a not allocated cell", c) + assert(false) + if c in states[csCycFreed]: + writeCell("attempt to free cyc cell twice", c) + assert(false) + if c in states[csZctFreed]: + writeCell("attempt to free with cyc, but already freed with zct", c) + assert(false) + excl(states[csAllocated], c) + incl(states[state], c) + +template gcTrace(cell, state: expr): stmt = + when traceGC: traceCell(cell, state) - dbgLineHook = GCdebugHook +# ------------------------------------------------------------------------- + +# forward declarations: +proc collectCT(gch: var TGcHeap) +proc IsOnStack(p: pointer): bool +proc forAllChildren(cell: PCell, op: TWalkOp) +proc collectCycles(gch: var TGcHeap) + +proc reprAny(p: pointer, typ: PNimType): string {.compilerproc.} +# we need the prototype here for debugging purposes proc prepareDealloc(cell: PCell) = if cell.typ.finalizer != nil: @@ -433,79 +535,95 @@ proc prepareDealloc(cell: PCell) = else: memUsed = memUsed - cell.typ.size -proc setStackBottom(theStackBottom: pointer) {.compilerproc.} = - stackBottom = theStackBottom - -proc initGC() = - # init the rt - CellSetInit(ct.zct) - CellSetInit(ct.at) - ct.stackLen = 0 - ct.stackMax = 255 - ct.stackCells = cast[PStackCells](gcAlloc((ct.stackMax+1) * sizeof(PCell))) - ct.mask = 0 - new(gOutOfMem) # reserve space for the EOutOfMemory exception here! - assert(GC_invariant()) - -# forward declarations: -proc collectCT(ct: var TCountTables) -proc IsOnStack(p: pointer): bool -proc forAllChildren(cell: PCell, op: TWalkOp) -proc collectCycles() - -proc reprAny(p: pointer, typ: PNimType): string {.compilerproc.} -# we need the prototype here for debugging purposes - -proc outputCell(c: PCell) = +proc checkZCT(): bool = + if recGcLock >= 1: return true # prevent endless recursion inc(recGcLock) - write(stdout, reprAny(cellToUsr(c), c.typ)) + result = true + for i in 0..gch.zct.len-1: + var c = gch.zct.d[i] + if c.refcount > 0: # should be in the ZCT! + writeCell("wrong ZCT entry", c) + result = false + elif gch.zct.d[-c.refcount] != c: + writeCell("wrong ZCT position", c) + result = false dec(recGcLock) -proc writeGraph() = - {.checkpoint.} - block: - inc(recGcLock) - for c in elements(ct.AT): outputCell(c) - dec(recGcLock) - -proc checkRefc(): bool = +proc GC_invariant(): bool = if recGcLock >= 1: return true # prevent endless recursion inc(recGcLock) result = True - # set counters back to zero: - for c in elements(ct.AT): - c.drefc = 0 - for c in elements(ct.AT): - forAllChildren(c, waDebugIncRef) - for c in elements(ct.AT): - if c.drefc > c.refcount - c.stackcount: - result = false # failed - c_fprintf(c_stdout, - "broken cell: %p, refc: %ld, stack: %ld, real: %ld\n", - c, c.refcount, c.stackcount, c.drefc) + block checks: + if not checkZCT(): + result = false + break checks + # set counters back to zero: + for c in elements(gch.AT): + var t = c.typ + if t == nil or t.kind notin {tySequence, tyString, tyRef}: + writeCell("corrupt cell?", c) + result = false + break checks + when stressGC: c.drefc = 0 + for c in elements(gch.AT): + forAllChildren(c, waDebugIncRef) + when stressGC: + for c in elements(gch.AT): + var rc = c.refcount + if rc < 0: rc = 0 + if c.drefc > rc + c.stackcount: + result = false # failed + c_fprintf(c_stdout, + "broken cell: %p, refc: %ld, stack: %ld, real: %ld\n", + c, c.refcount, c.stackcount, c.drefc) + break checks dec(recGcLock) -proc seqCheck(cell: PCell): bool = - assert(cell.typ != nil) - if cell.typ.kind in {tySequence, tyString}: - result = cell.refcount - cell.stackcount <= 1 - else: - result = true +when stressGC: + proc GCdebugHook() = + if not GC_invariant(): + assert(false) + + dbgLineHook = GCdebugHook + +proc setStackBottom(theStackBottom: pointer) {.compilerproc.} = + stackBottom = theStackBottom + +proc initGC() = + when traceGC: + for i in low(TCellState)..high(TCellState): CellSetInit(states[i]) + # init the rt + init(gch.zct) + CellSetInit(gch.at) + init(gch.stackCells) + gch.mask = 0 + new(gOutOfMem) # reserve space for the EOutOfMemory exception here! + assert(GC_invariant()) proc decRef(cell: PCell) {.inline.} = - assert(cell in ct.AT) - when defined(debugGC): - if cell.refcount == 0: - writePtr("decref broken", cellToUsr(cell)) assert(cell.refcount > 0) # this should be the case! - assert(seqCheck(cell)) + when stressGC: assert(cell in gch.AT) dec(cell.refcount) if cell.refcount == 0: - incl(ct.zct, cell) + cell.refcount = -gch.zct.len + when stressGC: assert(cell notin gch.zct) + add(gch.zct, cell) + when stressGC: assert(checkZCT()) proc incRef(cell: PCell) {.inline.} = - assert(seqCheck(cell)) - inc(cell.refcount) + var rc = cell.refcount + if rc <= 0: + # remove from zero count table: + when stressGC: assert(gch.zct.len > -rc) + when stressGC: assert(gch.zct.d[-rc] == cell) + gch.zct.d[-rc] = gch.zct.d[gch.zct.len-1] + gch.zct.d[-rc].refcount = rc + dec(gch.zct.len) + cell.refcount = 1 + when stressGC: assert(checkZCT()) + else: + inc(cell.refcount) + when stressGC: assert(checkZCT()) proc asgnRef(dest: ppointer, src: pointer) = # the code generator calls this proc! @@ -514,18 +632,18 @@ proc asgnRef(dest: ppointer, src: pointer) = if src != nil: incRef(usrToCell(src)) if dest^ != nil: decRef(usrToCell(dest^)) dest^ = src - #assert(checkRefc()) + when stressGC: assert(GC_invariant()) proc unsureAsgnRef(dest: ppointer, src: pointer) = if not IsOnStack(dest): if src != nil: incRef(usrToCell(src)) if dest^ != nil: decRef(usrToCell(dest^)) dest^ = src - #assert(checkRefc()) + when stressGC: assert(GC_invariant()) proc restore(cell: PCell) = - if cell notin ct.newAT: - incl(ct.newAT, Cell) + if cell notin gch.newAT: + incl(gch.newAT, Cell) forAllChildren(cell, waCycleIncRef) proc doOperation(p: pointer, op: TWalkOp) = @@ -536,19 +654,15 @@ proc doOperation(p: pointer, op: TWalkOp) = of waNone: assert(false) of waRelease: decRef(cell) # DEAD CODE! of waZctDecRef: - assert(cell.refcount > 0) - assert(seqCheck(cell)) - dec(cell.refcount) - if cell.refcount == 0: - incl(ct.newZCT, cell) + decRef(cell) of waCycleDecRef: - assert(cell.refcount != 0) + assert(cell.refcount > 0) dec(cell.refcount) of waCycleIncRef: inc(cell.refcount) # restore proper reference counts! restore(cell) of waDebugIncRef: - inc(cell.drefc) + when stressGC: inc(cell.drefc) type TByteArray = array[0..1000_0000, byte] @@ -590,16 +704,20 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) = if m != nil: forAllSlotsAux(dest, m, op) proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) = + const + handledTypes = {tyArray, tyArrayConstr, tyOpenArray, tyRef, + tyString, tySequence, tyObject, tyPureObject, tyTuple} var d = cast[TAddress](dest) if dest == nil: return # nothing to do case mt.Kind of tyArray, tyArrayConstr, tyOpenArray: - for i in 0..(mt.size div mt.base.size)-1: - forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op) + if mt.base.kind in handledTypes: + for i in 0..(mt.size div mt.base.size)-1: + forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op) of tyRef, tyString, tySequence: # leaf: doOperation(cast[ppointer](d)^, op) - of tyRecord, tyObject, tyTuple: + of tyObject, tyTuple, tyPureObject: forAllSlotsAux(dest, mt.node, op) else: nil @@ -608,6 +726,13 @@ proc forAllChildren(cell: PCell, op: TWalkOp) = when defined(debugGC): if cell.typ == nil: writeCell("cell has no type descriptor", cell) + when traceGC: + if cell notin states[csAllocated]: + writeCell("cell has never been allocated!", cell) + if cell in states[csCycFreed]: + writeCell("cell has been freed by Cyc", cell) + if cell in states[csZctFreed]: + writeCell("cell has been freed by Zct", cell) assert(cell.typ != nil) case cell.typ.Kind of tyRef: # common case @@ -625,36 +750,36 @@ proc forAllChildren(cell: PCell, op: TWalkOp) = proc checkCollection() {.inline.} = # checks if a collection should be done if recGcLock == 0: - if memUsed >= rcThreshold or stressGC: - collectCT(ct) - when defined(debugGC): - write(stdout, "threshold is now: ") - writeln(stdout, rcThreshold) + collectCT(gch) proc newObj(typ: PNimType, size: int): pointer = # generates a new object and sets its reference counter to 0 var res: PCell + when stressGC: assert(checkZCT()) assert(typ.kind in {tyRef, tyString, tySequence}) # check if we have to collect: checkCollection() res = cast[PCell](Alloc0(size + sizeof(TCell))) + when stressGC: assert((cast[TAddress](res) and (MemAlignment-1)) == 0) if res == nil: raiseOutOfMem() when defined(nimSize): memUsed = memUsed + nimSize(res) else: memUsed = memUsed + size - res.refcount = 0 # now it is buffered in the ZCT res.typ = typ - incl(ct.zct, res) # its refcount is zero, so add it to the ZCT - incl(ct.at, res) # add it to the any table too - ct.mask = ct.mask or cast[TAddress](res) + res.refcount = -gch.zct.len + add(gch.zct, res) # its refcount is zero, so add it to the ZCT + incl(gch.at, res) # add it to the any table too + gch.mask = gch.mask or cast[TAddress](res) when defined(debugGC): - writeCell("new cell", res) - assert(gcInvariant()) + when defined(logGC): writeCell("new cell", res) + gcTrace(res, csAllocated) result = cellToUsr(res) + assert(res.typ == typ) + when stressGC: assert(checkZCT()) proc newSeq(typ: PNimType, len: int): pointer = # XXX: overflow checks! @@ -665,16 +790,19 @@ proc newSeq(typ: PNimType, len: int): pointer = proc growObj(old: pointer, newsize: int): pointer = var res, ol: PCell + when stressGC: assert(checkZCT()) checkCollection() ol = usrToCell(old) assert(ol.typ.kind in {tyString, tySequence}) - assert(seqCheck(ol)) when defined(nimSize): memUsed = memUsed - nimSize(ol) else: memUsed = memUsed - ol.size # this is not exact - # pity that we don't know the old size + # pity that we don't know the old size res = cast[PCell](realloc(ol, newsize + sizeof(TCell))) + #res = cast[PCell](gcAlloc(newsize + sizeof(TCell))) + #copyMem(res, ol, nimSize(ol)) + assert((cast[TAddress](res) and (MemAlignment-1)) == 0) when defined(nimSize): memUsed = memUsed + nimSize(res) else: @@ -682,74 +810,69 @@ proc growObj(old: pointer, newsize: int): pointer = if res != ol: if res == nil: raiseOutOfMem() - excl(ct.zct, ol) # remove old pointer in any case: - # It may have a refcount > 0 and is still in the ZCT. - # So do it safe here and remove it anyway. - excl(ct.at, ol) - if res.refcount == 0: - # store new pointer in ZCT, if refcount == 0: - incl(ct.zct, res) - incl(ct.at, res) - ct.mask = ct.mask or cast[TAddress](res) - when defined(debugGC): + if res.refcount <= 0: + assert(gch.zct.d[-res.refcount] == ol) + gch.zct.d[-res.refcount] = res + excl(gch.at, ol) + incl(gch.at, res) + gch.mask = gch.mask or cast[TAddress](res) + when defined(logGC): writeCell("growObj old cell", ol) writeCell("growObj new cell", res) + gcTrace(ol, csZctFreed) + gcTrace(res, csAllocated) result = cellToUsr(res) - #assert(checkRefc()) + when stressGC: assert(checkZCT()) -proc collectCycles() = - when defined(debugGC): - echo("collecting cycles!\n") +proc collectCycles(gch: var TGcHeap) = + when defined(logGC): + c_fprintf(c_stdout, "collecting cycles!\n") # step 1: pretend that any node is dead - for c in elements(ct.at): + for c in elements(gch.at): forallChildren(c, waCycleDecRef) - CellSetInit(ct.newAt) + CellSetInit(gch.newAt) # step 2: restore life cells - for c in elements(ct.at): + for c in elements(gch.at): if c.refcount > 0: restore(c) # step 3: free dead cells: - for cell in elements(ct.at): + for cell in elements(gch.at): if cell.refcount == 0: - assert(cell notin ct.zct) # We free an object that is part of a cycle here. Its children # may have been freed already. Thus the finalizer could access # garbage. To handle this case properly we need two passes for # freeing here which is too expensive. We just don't call the # finalizer for now. YYY: Any better ideas? prepareDealloc(cell) - dealloc(cell) - when defined(debugGC): + gcTrace(cell, csCycFreed) + when defined(logGC): writeCell("cycle collector dealloc cell", cell) - CellSetDeinit(ct.at) - ct.at = ct.newAt - #ct.newAt = nil + when reallyDealloc: dealloc(cell) + CellSetDeinit(gch.at) + gch.at = gch.newAt -proc gcMark(p: pointer) = +proc gcMark(gch: var TGcHeap, p: pointer) = # the addresses are not as objects on the stack, so turn them to objects: var cell = usrToCell(p) var c = cast[TAddress](cell) - if ((c and ct.mask) == c) and cell in ct.at: + if ((c and gch.mask) == c) and cell in gch.at: # is the page that p "points to" in the AT? (All allocated pages are # always in the AT) - inc(cell.refcount) - inc(cell.stackcount) - addStackCell(ct, cell) - -proc unmarkStackAndRegisters() = - for i in 0 .. ct.stackLen-1: - var cell = ct.stackCells[i] + incRef(cell) + when stressGC: inc(cell.stackcount) + add(gch.stackCells, cell) + +proc unmarkStackAndRegisters(gch: var TGcHeap) = + when stressGC: assert(checkZCT()) + for i in 0 .. gch.stackCells.len-1: + var cell = gch.stackCells.d[i] assert(cell.refcount > 0) - when defined(debugGC): - if cell.stackcount == 0: - writeGraph() - writePtr("broken stackcount", cellToUsr(cell)) - assert(cell.stackcount > 0) - dec(cell.refcount) - dec(cell.stackcount) - if cell.refcount == 0: - incl(ct.zct, cell) - ct.stackLen = 0 # reset to zero + when stressGC: + assert(cell.stackcount > 0) + dec(cell.stackcount) + decRef(cell) + gch.stackCells.len = 0 # reset to zero + when stressGC: assert(checkZCT()) # ----------------- stack management -------------------------------------- # inspired from Smart Eiffel (c) @@ -765,7 +888,7 @@ when defined(sparc): # For SPARC architecture. stackTop: array[0..1, pointer] result = p >= addr(stackTop[0]) and p <= stackBottom - proc markStackAndRegisters() = + proc markStackAndRegisters(gch: var TGcHeap) = when defined(sparcv9): asm " flushw" else: @@ -780,7 +903,7 @@ when defined(sparc): # For SPARC architecture. sp = addr(stackTop[0]) # Addresses decrease as the stack grows. while sp <= max: - gcMark(sp^) + gcMark(gch, sp^) sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer)) elif defined(ELATE): @@ -802,7 +925,7 @@ elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or # a little hack to get the size of a TJmpBuf in the generated C code # in a platform independant way - proc markStackAndRegisters() = + proc markStackAndRegisters(gch: var TGcHeap) = var max = stackBottom registers: C_JmpBuf # The jmp_buf buffer is in the C stack. @@ -814,7 +937,7 @@ elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or # sp will traverse the JMP_BUF as well (jmp_buf size is added, # otherwise sp would be below the registers structure). while sp >= max: - gcMark(sp^) + gcMark(gch, sp^) sp = cast[ppointer](cast[TAddress](sp) -% sizeof(pointer)) else: @@ -826,7 +949,7 @@ else: stackTop: array [0..1, pointer] result = p >= addr(stackTop[0]) and p <= stackBottom - proc markStackAndRegisters() = + proc markStackAndRegisters(gch: var TGcHeap) = var max = stackBottom registers: C_JmpBuf # The jmp_buf buffer is in the C stack. @@ -835,63 +958,58 @@ else: c_setjmp(registers) # To fill the C stack with registers. sp = cast[ppointer](addr(registers)) while sp <= max: - gcMark(sp^) + gcMark(gch, sp^) sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer)) # ---------------------------------------------------------------------------- # end of non-portable code # ---------------------------------------------------------------------------- -proc CollectZCT = - CellSetInit(ct.newZCT) - for c in elements(ct.zct): - if c.refcount == 0: - # if != 0 the reference count has been increased, so this does not - # belong to the ZCT. We simply do nothing - it won't appear in the newZCT - # anyway. - # We are about to free the object, call the finalizer BEFORE its - # children are deleted as well, because otherwise the finalizer may - # access invalid memory. This is done by prepareDealloc(): - prepareDealloc(c) - forAllChildren(c, waZctDecRef) - assert(c.refcount == 0) # should still be zero - excl(ct.at, c) - excl(ct.newZCT, c) # BUGFIX - when defined(debugGC): - writeCell("zct dealloc cell", c) - dealloc(c) - CellSetDeinit(ct.zct) - ct.zct = ct.newZCT - #ct.newZCT = nil - -proc collectCT(ct: var TCountTables) = - when defined(debugGC): +proc CollectZCT(gch: var TGcHeap) = + while gch.zct.len > 0: + var c = gch.zct.d[0] + assert(c.refcount <= 0) + # remove from ZCT: + gch.zct.d[0] = gch.zct.d[gch.zct.len-1] + gch.zct.d[0].refcount = 0 + dec(gch.zct.len) + # We are about to free the object, call the finalizer BEFORE its + # children are deleted as well, because otherwise the finalizer may + # access invalid memory. This is done by prepareDealloc(): + gcTrace(c, csZctFreed) + prepareDealloc(c) + forAllChildren(c, waZctDecRef) + excl(gch.at, c) + when defined(logGC): + writeCell("zct dealloc cell", c) + #when defined(debugGC) and defined(nimSize): zeroMem(c, nimSize(c)) + when reallyDealloc: dealloc(c) + +proc collectCT(gch: var TGcHeap) = + when defined(logGC): c_fprintf(c_stdout, "collecting zero count table; stack size: %ld\n", stackSize()) - markStackAndRegisters() - assert(GC_invariant()) - while True: - collectZCT() - if ct.zct.counter == 0: break - # ``counter`` counts the pages, but zero pages means zero cells - - when defined(cycleGC): - # still over the cycle threshold? - if memUsed >= cycleThreshold or stressGC: - # collect the cyclic things: - assert(ct.zct.counter == 0) - assert(GC_invariant()) - collectCycles() - - # recompute the thresholds: - rcThreshold = (memUsed div RC_increase + 1) * RC_Increase - cycleThreshold = memUsed * cycleIncrease - - assert(GC_invariant()) - unmarkStackAndRegisters() + when stressGC: assert(checkZCT()) + if gch.zct.len >= ZctThreshold or memUsed >= cycleThreshold or stressGC: + markStackAndRegisters(gch) + when stressGC: assert(GC_invariant()) + collectZCT(gch) + when stressGC: assert(GC_invariant()) + assert(gch.zct.len == 0) + when defined(cycleGC): + if memUsed >= cycleThreshold or stressGC: + when defined(logGC): + c_fprintf(c_stdout, "collecting cycles; memory used: %ld\n", memUsed) + collectCycles(gch) + cycleThreshold = max(InitialCycleThreshold, memUsed * cycleIncrease) + when defined(logGC): + c_fprintf(c_stdout, "now used: %ld; threshold: %ld\n", + memUsed, cycleThreshold) + unmarkStackAndRegisters(gch) + when stressGC: assert(GC_invariant()) proc GC_fullCollect() = var oldThreshold = cycleThreshold cycleThreshold = 0 # forces cycle collection - collectCT(ct) + collectCT(gch) cycleThreshold = oldThreshold diff --git a/lib/hti.nim b/lib/hti.nim index 8fc46cdd7..563414b26 100644 --- a/lib/hti.nim +++ b/lib/hti.nim @@ -10,29 +10,38 @@ type # This should be he same as ast.TTypeKind # some enum fields are not used at runtime TNimKind = enum - tyNone, tyBool, tyChar, - tyEmptySet, tyArrayConstr, tyNil, tyRecordConstr, - tyGeneric, - tyGenericInst, - tyGenericParam, - tyEnum, tyAnyEnum, - tyArray, - tyRecord, - tyObject, - tyTuple, - tySet, - tyRange, - tyPtr, tyRef, - tyVar, - tySequence, - tyProc, - tyPointer, tyOpenArray, - tyString, tyCString, tyForward, + tyNone, # 0 + tyBool, # 1 + tyChar, # 2 + tyEmptySet, # 3 + tyArrayConstr, # 4 + tyNil, # 5 + tyGeneric, # 6 + tyGenericInst, # 7 + tyGenericParam, # 8 + tyEnum, # 9 + tyAnyEnum, # 10 + tyArray, # 11 + tyObject, # 12 + tyTuple, # 13 + tySet, # 14 + tyRange, # 15 + tyPtr, # 16 + tyRef, # 17 + tyVar, # 18 + tySequence, # 19 + tyProc, # 20 + tyPointer, # 21 + tyOpenArray, # 22 + tyString, # 23 + tyCString, # 24 + tyForward, # 25 tyInt, tyInt8, tyInt16, tyInt32, tyInt64, - tyFloat, tyFloat32, tyFloat64, tyFloat128 + tyFloat, tyFloat32, tyFloat64, tyFloat128, + tyPureObject # 35: signals that object has no `n_type` field TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase - TNimNode {.compilerproc.} = record + TNimNode {.compilerproc, final.} = object kind: TNimNodeKind offset: int typ: ptr TNimType @@ -40,7 +49,7 @@ type # This should be he same as ast.TTypeKind len: int sons: ptr array [0..0x7fff, ptr TNimNode] - TNimType {.compilerproc.} = record + TNimType {.compilerproc, final.} = object size: int kind: TNimKind base: ptr TNimType diff --git a/lib/int64s.nim b/lib/int64s.nim index bac6b9ccd..430514ce3 100644 --- a/lib/int64s.nim +++ b/lib/int64s.nim @@ -10,8 +10,7 @@ # 64 bit integers for platforms that don't have those type - IInt64 = record # "internal" int64 - lo, hi: int32 + IInt64 = tuple[lo, hi: int32] proc cmpI64(x, y: IInt64): int32 {.compilerproc.} = result = x.hi -% y.hi diff --git a/lib/math.nim b/lib/math.nim index 84cba9894..aff5815ce 100644 --- a/lib/math.nim +++ b/lib/math.nim @@ -1,75 +1,22 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2006 Andreas Rumpf +# (c) Copyright 2008 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # - - -# math routines - -# interface +## Basic math routines for Nimrod. +## This module is available for the ECMAScript target. {.push debugger:off .} # the user does not want to trace a part # of the standard library! {.push checks:off, line_dir:off, stack_trace:off.} -proc nextPowerOfTwo*(x: int): int - ## returns the nearest power of two, so that - ## result**2 >= x > (result-1)**2. -proc isPowerOfTwo*(x: int): bool {.noSideEffect.} - ## returns true, if x is a power of two, false otherwise. - ## Negative numbers are not a power of two. -proc countBits*(n: int32): int {.noSideEffect.} - ## counts the set bits in `n`. - -proc random*(max: int): int - ## returns a random number in the range 0..max-1. The sequence of - ## random number is always the same, unless `randomize` is called - ## which initializes the random number generator with a "random" - ## number, i.e. a tickcount. -proc randomize*() - ## initializes the random number generator with a "random" - ## number, i.e. a tickcount. - -proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".} - ## computes the square root of `x`. - -proc ln*(x: float): float {.importc: "log", header: "<math.h>".} - ## computes ln(x). -proc exp*(x: float): float {.importc: "exp", header: "<math.h>".} - ## computes e**x. - -proc frexp*(x: float, exponent: var int): float {. - importc: "frexp", header: "<math.h>".} - ## Split a number into mantissa and exponent. - ## `frexp` calculates the mantissa m (a float greater than or equal to 0.5 - ## and less than 1) and the integer value n such that `x` (the original - ## float value) equals m * 2**n. frexp stores n in `exponent` and returns - ## m. - -proc arccos*(x: float): float {.importc: "acos", header: "<math.h>".} -proc arcsin*(x: float): float {.importc: "asin", header: "<math.h>".} -proc arctan*(x: float): float {.importc: "atan", header: "<math.h>".} -proc arctan2*(y, x: float): float {.importc: "atan2", header: "<math.h>".} - ## Calculate the arc tangent of `y` / `x`. - ## `atan2` returns the arc tangent of `y` / `x`; it produces correct - ## results even when the resulting angle is near pi/2 or -pi/2 - ## (`x` near 0). - -proc cos*(x: float): float {.importc: "cos", header: "<math.h>".} -proc cosh*(x: float): float {.importc: "cosh", header: "<math.h>".} -proc hypot*(x: float): float {.importc: "hypot", header: "<math.h>".} -proc log10*(x: float): float {.importc: "log10", header: "<math.h>".} -proc sinh*(x: float): float {.importc: "sinh", header: "<math.h>".} -proc tan*(x: float): float {.importc: "tan", header: "<math.h>".} -proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".} -proc pow*(x, y: float): float {.importc: "pos", header: "<math.h>".} - ## computes x to power raised of y. +when defined(Posix): + {.passl: "-lm".} type TFloatClass* = enum ## describes the class a floating point value belongs to. @@ -82,15 +29,32 @@ type fcInf, ## value is positive infinity fcNegInf ## value is negative infinity -proc classify*(x: float): TFloatClass +proc classify*(x: float): TFloatClass = ## classifies a floating point value. Returns `x`'s class as specified by - ## `TFloatClass` + ## `TFloatClass`. + + # ECMAScript and most C compilers have no classify: + if x == 0.0: + if 1.0/x == 1.0/0.0: + return fcZero + else: + return fcNegZero + if x*0.5 == x: + if x > 0.0: return fcInf + else: return fcNegInf + if x != x: return fcNan + return fcNormal + # XXX: fcSubnormal is not detected! -# implementation -include cntbits +proc isPowerOfTwo*(x: int): bool {.noSideEffect.} = + ## returns true, if x is a power of two, false otherwise. + ## Negative numbers are not a power of two. + return (x and -x) == x -proc nextPowerOfTwo(x: int): int = +proc nextPowerOfTwo*(x: int): int = + ## returns the nearest power of two, so that + ## result**2 >= x > (result-1)**2. result = x - 1 when defined(cpu64): result = result or (result shr 32) @@ -101,31 +65,111 @@ proc nextPowerOfTwo(x: int): int = result = result or (result shr 1) Inc(result) -# C procs: -proc gettime(dummy: ptr cint): cint {. - importc: "time", header: "<time.h>".} -proc srand(seed: cint) {. - importc: "srand", nodecl.} -proc rand(): cint {.importc: "rand", nodecl.} +proc countBits*(n: int32): int {.noSideEffect.} + ## counts the set bits in `n`. -# most C compilers have no classify: -proc classify(x: float): TFloatClass = - if x == 0.0: - if 1.0/x == 1.0/0.0: - return fcZero - else: - return fcNegZero - if x*0.5 == x: - if x > 0.0: return fcInf - else: return fcNegInf - if x != x: return fcNan - return fcNormal - # XXX: fcSubnormal is not detected! +include cntbits -proc randomize() = srand(gettime(nil)) -proc random(max: int): int = return rand() mod max -proc isPowerOfTwo(x: int): bool = return (x and -x) == x +when not defined(ECMAScript): + proc random*(max: int): int + ## returns a random number in the range 0..max-1. The sequence of + ## random number is always the same, unless `randomize` is called + ## which initializes the random number generator with a "random" + ## number, i.e. a tickcount. + proc randomize*() + ## initializes the random number generator with a "random" + ## number, i.e. a tickcount. Note: Does nothing for the ECMAScript target, + ## as ECMAScript does not support this. + + proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".} + ## computes the square root of `x`. + + proc ln*(x: float): float {.importc: "log", header: "<math.h>".} + ## computes ln(x). + proc log10*(x: float): float {.importc: "log10", header: "<math.h>".} + proc log2*(x: float): float = return ln(x) / ln(2.0) + proc exp*(x: float): float {.importc: "exp", header: "<math.h>".} + ## computes e**x. + + proc frexp*(x: float, exponent: var int): float {. + importc: "frexp", header: "<math.h>".} + ## Split a number into mantissa and exponent. + ## `frexp` calculates the mantissa m (a float greater than or equal to 0.5 + ## and less than 1) and the integer value n such that `x` (the original + ## float value) equals m * 2**n. frexp stores n in `exponent` and returns + ## m. + + proc round*(x: float): int {.importc: "lrint", nodecl.} + ## converts a float to an int by rounding. + + proc arccos*(x: float): float {.importc: "acos", header: "<math.h>".} + proc arcsin*(x: float): float {.importc: "asin", header: "<math.h>".} + proc arctan*(x: float): float {.importc: "atan", header: "<math.h>".} + proc arctan2*(y, x: float): float {.importc: "atan2", header: "<math.h>".} + ## Calculate the arc tangent of `y` / `x`. + ## `atan2` returns the arc tangent of `y` / `x`; it produces correct + ## results even when the resulting angle is near pi/2 or -pi/2 + ## (`x` near 0). + + proc cos*(x: float): float {.importc: "cos", header: "<math.h>".} + proc cosh*(x: float): float {.importc: "cosh", header: "<math.h>".} + proc hypot*(x, y: float): float {.importc: "hypot", header: "<math.h>".} + ## same as ``sqrt(x*x + y*y)``. + + proc sinh*(x: float): float {.importc: "sinh", header: "<math.h>".} + proc tan*(x: float): float {.importc: "tan", header: "<math.h>".} + proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".} + proc pow*(x, y: float): float {.importc: "pow", header: "<math.h>".} + ## computes x to power raised of y. + + # C procs: + proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".} + proc srand(seed: cint) {.importc: "srand", nodecl.} + proc rand(): cint {.importc: "rand", nodecl.} + + proc randomize() = srand(gettime(nil)) + proc random(max: int): int = return rand() mod max + +else: + proc mathrandom(): float {.importc: "Math.random", nodecl.} + proc mathfloor(x: float): float {.importc: "Math.floor", nodecl.} + proc random*(max: int): int = return mathfloor(mathrandom() * max) + proc randomize*() = nil + + proc sqrt*(x: float): float {.importc: "Math.sqrt", nodecl.} + proc ln*(x: float): float {.importc: "Math.log", nodecl.} + proc log10*(x: float): float = return ln(x) / ln(10.0) + proc log2*(x: float): float = return ln(x) / ln(2.0) + + proc exp*(x: float): float {.importc: "Math.exp", nodecl.} + proc round*(x: float): int {.importc: "Math.round", nodecl.} + proc pow*(x, y: float): float {.importc: "Math.pow", nodecl.} + + proc frexp*(x: float, exponent: var int): float = + if x == 0.0: + exponent = 0.0 + result = 0.0 + elif x < 0.0: + result = -frexp(-x, exponent) + else: + var ex = mathfloor(log2(x)) + exponent = round(ex) + result = x / pow(2.0, ex) + + proc arccos*(x: float): float {.importc: "Math.acos", nodecl.} + proc arcsin*(x: float): float {.importc: "Math.asin", nodecl.} + proc arctan*(x: float): float {.importc: "Math.atan", nodecl.} + proc arctan2*(y, x: float): float {.importc: "Math.atan2", nodecl.} + + proc cos*(x: float): float {.importc: "Math.cos", nodecl.} + proc cosh*(x: float): float = return (exp(x)+exp(-x))*0.5 + proc hypot*(x, y: float): float = return sqrt(x*x + y*y) + proc sinh*(x: float): float = return (exp(x)-exp(-x))*0.5 + proc tan*(x: float): float {.importc: "Math.tan", nodecl.} + proc tanh*(x: float): float = + var y = exp(2.0*x) + return (y-1.0)/(y+1.0) {.pop.} {.pop.} diff --git a/lib/memman.nim b/lib/memman.nim index f0ca078f7..81919389b 100644 --- a/lib/memman.nim +++ b/lib/memman.nim @@ -37,24 +37,24 @@ const realFli = MaxFli - fliOffset type - TFreePtr = record + TFreePtr {.final.} = object prev, next: PBhdr Pbhdr = ptr Tbhdr - Tbhdr = record + Tbhdr {.final.} = object prevHdr: Pbhdr # this is just valid if the first bit of size is set size: int # the size is stored in bytes # bit 0 indicates whether the block is used and # bit 1 allows to know whether the previous block is free freePtr: TFreePtr # at this offset bhdr.buffer starts (was a union in the # C version) - TAreaInfo = record # This structure is embedded at the beginning of each - # area, giving us enough information to cope with a set - # of areas + TAreaInfo {.final.} = object # This structure is embedded at the beginning + # of each area, giving us enough information + # to cope with a set of areas theEnd: Pbhdr next: PAreaInfo PAreaInfo = ptr TAreaInfo - TLSF = record + TLSF {.final.} = object tlsf_signature: int32 # the TLSF's structure signature usedSize, maxSize: int areaHead: PAreaInfo # A linked list holding all the existing areas @@ -147,6 +147,7 @@ elif defined(windows): if result == nil: raiseOutOfMem() else: + {.warning: "Generic code for allocating pages is used".} # generic implementation relying on malloc: proc malloc(size: int): pointer {.nodecl, importc.} @@ -155,6 +156,124 @@ else: result = malloc(size) if result == nil: raiseOutOfMem() +# --------------------------------------------------------------------------- +# small fixed size allocator: + +# Design: We manage pages. A page is of constant size, but not necessarily +# the OS's page size. Pages are managed in a hash table taking advantage of +# the fact that the OS is likely to give us pages with contingous numbers. +# A page contains either small fixed size objects of the same size or +# variable length objects. An object's size is always aligned at 16 byte +# boundry. Huge objects are dealt with the TLSF algorithm. +# The design supports iterating over any object in a fast way. + +# A bitset contains any page that starts an allocated page. The page may be +# empty however. This bitset can be used to quickly determine if a given +# page belongs to the GC heap. The design of the memory allocator makes it +# simple to return unused pages back to the OS. + + +# Small bocks +# ----------- +# +# If we use a list in the free object's space. Allocation and deallocation are +# O(1). Since any object is of the same size, iteration is quite efficient too. +# However, pointer detection is easy too: Just check if the type-field is nil. +# Deallocation sets it to nil. +# Algorithm: + +# i = 0 +# f = b.f # first free address +# while i < max: +# if a[i] == f: # not a valid block +# f = f.next # next free address +# else: +# a[i] is a valid object of size s +# inc(i) + +# The zero count table is an array. Since we know that the RC is zero, we can +# use the bits for an index into this array. Thus multiple ZCT tables are not +# difficult to support and insertion and removal is O(1). We use negative +# indexes for this. This makes it even fast enough (and necessary!) to do a ZCT +# removal if the RC is incremented. +# + +# Huge blocks +# ----------- +# +# Huge blocks are always rounded up to a multiple of the page size. These are +# called *strides*. We also need to keep an index structure +# of (stridesize, pagelist). +# + +const + MemAlign = 8 + PageShift = if sizeof(int) == 4: 12 else: 13 + PageSize = 1 shl PageShift +type + TFreeList {.final.} = object + next, prev: ptr TFreeList + + TPageDesc {.final.} = object # the start of a stride always starts with this! + size: int # lowest bit is set, if it is a huge block + free: ptr TFreeList # only used if it manages multiple cells + snext, sprev: ptr TPageDesc # next and prev pagedescs with the same size + + TCellArray {.final.} = object + i: int # length + d: ptr array [0..1000_000, TCell] + + TPageManager = table[page, ptr TPageDesc] + + TGcHeap {.final.} = object + # structure that manages the garbage collected heap + zct: TCellArray + stackCells: TCellArray + smallBlocks: array [PageSize div MemAlign, ptr TPageDesc] + pages: TPageManager + usedPages: TPageList + freePages: TPageList + +# small blocks: +proc allocSmall(var h: TGcHeap, size: int): pointer = + var s = align(size) + var p = h.smallBlocks[s] + if p == nil or p.free == nil: + p = newSmallBlock(s, p) + h.smallBlocks[s] = p + + + +proc decRef(cell: PCell) {.inline.} = + assert(cell in ct.AT) + assert(cell.refcount > 0) # this should be the case! + assert(seqCheck(cell)) + dec(cell.refcount) + if cell.refcount == 0: + # add to zero count table: + zct.d[zct.i] = cell + cell.recfcount = -zct.i + inc(zct.i) + +proc incRef(cell: PCell) {.inline.} = + assert(seqCheck(cell)) + if cell.refcount < 0: + # remove from zero count table: + zct.d[-cell.refcount] = zct.d[zct.i-1] + dec(zct.i) + cell.refcount = 1 + else: + inc(cell.refcount) + +proc asgnRef(dest: ppointer, src: pointer) = + # the code generator calls this proc! + assert(not isOnStack(dest)) + # BUGFIX: first incRef then decRef! + if src != nil: incRef(usrToCell(src)) + if dest^ != nil: decRef(usrToCell(dest^)) + dest^ = src + + # ---------------------------------------------------------------------------- # helpers @@ -261,7 +380,7 @@ proc extractBlock(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} = proc insertBlock(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} = b.freePtr.prev = nil b.freePtr.next = t.matrix[fl][sl] - if t.matrix[fl][sl] != 0: + if t.matrix[fl][sl] != nil: t.matrix[fl][sl].freePtr.prev = b t.matrix[fl][sl] = b set_bit(sl, t.slBitmap[fl]) @@ -295,9 +414,6 @@ proc processArea(area: pointer, size: int): Pbhdr = # ---------------------------------------------------------------------------- # Begin of the allocator code -var - mp: pointer # default memory pool. - proc initMemoryPool(memPoolSize: int, memPool: pointer): int = var t: PLSF @@ -307,16 +423,14 @@ proc initMemoryPool(memPoolSize: int, memPool: pointer): int = writeToStdErr("initMemoryPool(): memory_pool invalid\n") return -1 - if (memPool and ptrMask) != 0: + if (cast[TAddress](memPool) and ptrMask) != 0: writeToStdErr("initMemoryPool(): memPool must be aligned to a word\n") return -1 t = cast[PLSF](memPool) # Check if already initialised if t.signature == tlsfSignature: - mp = memPool - b = getNextBlock(mp, roundupSize(sizeof(TLSF))) + b = getNextBlock(memPool, roundupSize(sizeof(TLSF))) return b.size and blockSize - mp = memPool zeroMem(memPool, sizeof(TLSF)) t.signature = tlsfSignature @@ -456,7 +570,7 @@ proc freeEx(p: pointer, t: var TLSF) = b.freePtr.prev = nil b.freePtr.next = nil tmpB = getNextBlock(getBuffer(b), b.size and blockSize) - if tmpB.size and freeBlock != 0: + if (tmpB.size and freeBlock) != 0: mappingInsert(tmpB.size and blockSize, fl, sl) extractBlock(tmpB, t, fl, sl) inc(b.size, (tmpB.size and blockSize) + bhdrOverhead) @@ -549,51 +663,30 @@ proc ansiCrealloc(p: pointer, newSize: int, t: var TLSF): pointer = else: result = reallocEx(p, newSize, t) +proc InitTLSF(t: var TLSF) = + var areaSize = sizeof(TLSF) + BHDR_OVERHEAD * 8 # Just a safety constant + areaSize = max(areaSize, DEFAULT_areaSize) + var area = getNewArea(areaSize) + + + initMemoryPool(areaSize, area) + + var + t: PLSF + b, ib: Pbhdr + + t = cast[PLSF](memPool) + + zeroMem(area, areaSize) + + t.signature = tlsfSignature + var ib = processArea(getNextBlock(memPool, roundupSize(sizeof(TLSF))), + rounddownSize(memPoolSize - sizeof(TLSF))) + var b = getNextBlock(getBuffer(ib), ib.size and blockSize) + freeEx(getBuffer(b), t) + t.areaHead = cast[PAreaInfo](getBuffer(ib)) + + t.used_size = memPoolSize - (b.size and blockSize) + t.max_size = t.used_size -void *tlsf_malloc(size_t size) -{ - void *ret - -#if USE_MMAP || USE_SBRK - if (!mp) { - size_t areaSize - void *area - - areaSize = sizeof(tlsf_t) + BHDR_OVERHEAD * 8 # Just a safety constant - areaSize = (areaSize > DEFAULT_areaSize) ? areaSize : DEFAULT_areaSize - area = get_new_area(&areaSize) - if (area == ((void *) ~0)) - return NULL # Not enough system memory - initMemoryPool(areaSize, area) - } -#endif - - TLSF_ACQUIRE_LOCK(&((tlsf_t *)mp)->lock) - - ret = malloc_ex(size, mp) - - TLSF_RELEASE_LOCK(&((tlsf_t *)mp)->lock) - - return ret -} - -void tlsf_free(void *p) -{ - TLSF_ACQUIRE_LOCK(&((tlsf_t *)mp)->lock) - free_ex(p, mp) - TLSF_RELEASE_LOCK(&((tlsf_t *)mp)->lock) -} - -void *tlsf_realloc(void *p, size_t size) -{ - void *ret -#if USE_MMAP || USE_SBRK - if (!mp) { - return tlsf_malloc(size) - } -#endif - TLSF_ACQUIRE_LOCK(&((tlsf_t *)mp)->lock) - ret = realloc_ex(p, size, mp) - TLSF_RELEASE_LOCK(&((tlsf_t *)mp)->lock) - return ret -} + # XXX diff --git a/lib/nimbase.h b/lib/nimbase.h index 99ee2f20c..8d7c287e0 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -1,7 +1,7 @@ /* Nimrod's Runtime Library - (c) Copyright 2006 Andreas Rumpf + (c) Copyright 2008 Andreas Rumpf See the file "copying.txt", included in this distribution, for details about the copyright. @@ -11,7 +11,8 @@ #define NIMBASE_H /* calling convention mess ----------------------------------------------- */ -#if defined(__GNUC__) || defined(__LCC__) || defined(__POCC__) +#if defined(__GNUC__) || defined(__LCC__) || defined(__POCC__) \ + || defined(__TINYC__) /* these should support C99's inline */ /* the test for __POCC__ has to come before the test for _MSC_VER, because PellesC defines _MSC_VER too. This is brain-dead. */ @@ -30,10 +31,18 @@ # define N_INLINE(rettype, name) rettype __inline name #endif -#if defined(_MSC_VER) +#if defined(__POCC__) || defined(_MSC_VER) # define HAVE_LRINT 1 #endif +#if defined(__POCC__) +# define NIM_CONST /* PCC is really picky with const modifiers */ +#elif defined(__cplusplus) +# define NIM_CONST /* C++ is picky with const modifiers */ +#else +# define NIM_CONST const +#endif + /* --------------- how int64 constants should be declared: ----------- */ #if defined(__GNUC__) || defined(__LCC__) || \ defined(__POCC__) || defined(__DMC__) @@ -136,8 +145,7 @@ ** long int lrint (double x); */ -#if defined(__LCC__) || defined(__POCC__) \ - || (defined(__GNUC__) && defined(WIN32)) +#if defined(__LCC__) || (defined(__GNUC__) && defined(WIN32)) /* Linux' GCC does not seem to have these. Why? */ # define HAVE_LRINT # define HAVE_LRINTF @@ -159,7 +167,7 @@ # include <math.h> #elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \ - && !defined(__BORLANDC__) + && !defined(__BORLANDC__) && !defined(__POCC__) # include <math.h> @@ -206,6 +214,17 @@ static N_INLINE(long int, lrintf)(float flt) { #include <signal.h> #include <setjmp.h> +#ifndef NAN +static unsigned long nimNaN[2]={0xffffffff, 0x7fffffff}; +# define NAN (*(double*) nimNaN) +#endif + +/* +#ifndef INF +static unsigned long nimInf[2]={0xffffffff, 0x7fffffff}; +# define INF (*(double*) nimInf) +#endif */ + /* compiler symbols: __BORLANDC__ _MSC_VER @@ -214,6 +233,7 @@ __LCC__ __GNUC__ __DMC__ __POCC__ +__TINYC__ */ /* C99 compiler? */ @@ -250,50 +270,41 @@ __POCC__ #endif #define NIM_NIL ((void*)0) /* C's NULL is fucked up in some C compilers, so - the generated code does not rely on it anymore */ + the generated code does not rely on it anymore */ #if defined(HAVE_STDINT_H) # include <stdint.h> -typedef int8_t NS8; -typedef int16_t NS16; -typedef int32_t NS32; -typedef int64_t NS64; +typedef int8_t NI8; +typedef int16_t NI16; +typedef int32_t NI32; +typedef int64_t NI64; typedef uint64_t NU64; typedef uint8_t NU8; typedef uint16_t NU16; typedef uint32_t NU32; #elif defined(__BORLANDC__) || defined(__DMC__) \ || defined(__WATCOMC__) || defined(_MSC_VER) -typedef signed char NS8; -typedef signed short int NS16; -typedef signed int NS32; +typedef signed char NI8; +typedef signed short int NI16; +typedef signed int NI32; /* XXX: Float128? */ typedef unsigned char NU8; typedef unsigned short int NU16; typedef unsigned __int64 NU64; -typedef __int64 NS64; +typedef __int64 NI64; typedef unsigned int NU32; #else -typedef signed char NS8; -typedef signed short int NS16; -typedef signed int NS32; +typedef signed char NI8; +typedef signed short int NI16; +typedef signed int NI32; /* XXX: Float128? */ typedef unsigned char NU8; typedef unsigned short int NU16; typedef unsigned long long int NU64; -typedef long long int NS64; +typedef long long int NI64; typedef unsigned int NU32; #endif -#if defined(_MSC_VER) && (defined(AMD64) || defined(_M_AMD64)) -/* Microsoft C is brain-dead in this case; long is still not an int64 */ -typedef unsigned long long int NU; -typedef signed long long int NS; -#else -typedef unsigned long int NU; /* note: int would be wrong for AMD64 */ -typedef signed long int NS; -#endif - typedef float NF32; typedef double NF64; typedef double NF; @@ -307,13 +318,13 @@ typedef char* NCSTRING; # define NIM_IMAN 0 #endif -static N_INLINE(NS32, float64ToInt32)(double val) { +static N_INLINE(NI32, float64ToInt32)(double val) { val = val + 68719476736.0*1.5; /* 2^36 * 1.5, (52-_shiftamt=36) uses limited precisicion to floor */ - return ((NS32*)&val)[NIM_IMAN] >> 16; /* 16.16 fixed point representation */ + return ((NI32*)&val)[NIM_IMAN] >> 16; /* 16.16 fixed point representation */ } -static N_INLINE(NS32, float32ToInt32)(float val) { +static N_INLINE(NI32, float32ToInt32)(float val) { return float64ToInt32((double)val); } @@ -322,7 +333,7 @@ static N_INLINE(NS32, float32ToInt32)(float val) { #define STRING_LITERAL(name, str, length) \ static const struct { \ - NS len, space; \ + NI len, space; \ NIM_CHAR data[length + 1]; \ } name = {length, length, str} @@ -357,7 +368,7 @@ typedef struct TStringDesc* string; /* typedef struct TSafePoint TSafePoint; struct TSafePoint { - NS exc; + NI exc; NCSTRING excname; NCSTRING msg; TSafePoint* prev; @@ -368,19 +379,19 @@ typedef struct TFrame TFrame; struct TFrame { TFrame* prev; NCSTRING procname; - NS line; + NI line; NCSTRING filename; - NS len; + NI len; }; -extern TFrame* volatile framePtr; -/*extern TSafePoint* volatile excHandler; */ +extern TFrame* framePtr; +/*extern TSafePoint* excHandler; */ #if defined(__cplusplus) struct NimException { TSafePoint sp; - NimException(NS aExc, NCSTRING aExcname, NCSTRING aMsg) { + NimException(NI aExc, NCSTRING aExcname, NCSTRING aMsg) { sp.exc = aExc; sp.excname = aExcname; sp.msg = aMsg; sp.prev = excHandler; excHandler = &sp; @@ -389,13 +400,13 @@ struct NimException { #endif typedef struct TStringDesc { - NS len; - NS space; + NI len; + NI space; NIM_CHAR data[1]; /* SEQ_DECL_SIZE]; */ } TStringDesc; typedef struct { - NS len, space; + NI len, space; } TGenericSeq; typedef TGenericSeq* PGenericSeq; diff --git a/lib/optparse.nim b/lib/optparse.nim deleted file mode 100644 index 58007b5a9..000000000 --- a/lib/optparse.nim +++ /dev/null @@ -1,39 +0,0 @@ -# -# -# Nimrod's Runtime Library -# (c) Copyright 2006 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - - -## This module provides a command line parser. -## It supports one iterator over all command line options. - -#interface - -{.push debugger: off.} - -import - os - -proc findSep(s: string): int {.nostatic.} = - for i in 0 .. high(s)-1: - if s[i] in {'=', ':'}: return i - return high(s)+1 - -iterator getopt*(): tuple[string, string] = - # returns a (cmd, arg) tuple. - for k in 1 .. ParamCount(): - var param = paramStr(k) - if param[0] == '-': - var j = findSep(param) - cmd = copy(param, 0, j-1) - arg = copy(param, j+1) - else: - cmd = "" - arg = param - yield cmd, arg - -{.pop.} diff --git a/lib/os.nim b/lib/os.nim index cd835c480..f07045143 100644 --- a/lib/os.nim +++ b/lib/os.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2006 Andreas Rumpf +# (c) Copyright 2008 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -10,7 +10,9 @@ ## Basic operating system facilities like retrieving environment variables, ## reading command line arguments, working with directories, running shell ## commands, etc. This module is -- like any other basic library -- -## platform independant. +## platform independant. However, the ECMAScript target is not supported, +## as there is no way to perform these operations in ECMAScript portably +## or at all. {.push debugger:off.} @@ -18,7 +20,7 @@ import strutils, times # copied from excpt.nim, because I don't want to make this template public -template newException(exceptn, message: expr): expr = +template newException(exceptn, message: expr): expr = block: # open a new scope var e: ref exceptn @@ -294,7 +296,7 @@ proc existsDir*(dir: string): bool proc getLastModificationTime*(file: string): TTime ## Gets the time of the `file`'s last modification. -proc fileNewer*(a, b: string): bool +proc fileNewer*(a, b: string): bool ## returns true if the file `a` is newer than file `b`, i.e. if `a`'s ## modification time is later than `b`'s. @@ -371,8 +373,11 @@ proc UnixToNativePath(path: string): string = # interface to C library: +const + cunder = if defined(pcc): "_" else: "" + type - TStat {.importc: "struct stat".} = record + TStat {.importc: "struct " & cunder & "stat", final.} = object st_dev: int16 st_ino: int16 st_mode: int16 @@ -397,7 +402,8 @@ else: {.error: "os library not ported to your OS. Please help!".} -proc chdir(path: CString): cint {.importc: "chdir", header: dirHeader.} +proc chdir(path: CString): cint {. + importc: cunder & "chdir", header: dirHeader.} when defined(unix): proc mkdir(dir: CString, theAccess: cint): cint {. @@ -412,7 +418,7 @@ elif defined(windows): proc fullpath(buffer, file: CString, size: int): CString {. importc: "_fullpath", header: "<stdlib.h>".} proc getcwd(buf: CString, buflen: cint): CString {. - importc: "getcwd", header: "<direct.h>".} + importc: cunder & "getcwd", header: "<direct.h>".} proc CreateDirectory(pathName: cstring, security: Pointer): cint {. importc: "CreateDirectory", header: "<windows.h>".} @@ -421,7 +427,8 @@ else: {.error: "os library not ported to your OS. Please help!".} -proc rmdir(dir: CString): cint {.importc: "rmdir", header: "<time.h>".} +proc rmdir(dir: CString): cint {. + importc: cunder & "rmdir", header: "<time.h>".} # rmdir is of course in ``dirHeader``, but we check here to include # time.h which is needed for stat(). stat() needs time.h and # sys/stat.h; we workaround a C library issue here. @@ -432,17 +439,7 @@ proc free(c: cstring) {.importc: "free", nodecl.} proc strlen(str: CString): int {.importc: "strlen", nodecl.} proc stat(f: CString, res: var TStat): cint {. - importc: "stat", header: "<sys/stat.h>".} - -proc sameFile*(path1, path2: string): bool = - ## Returns True if both pathname arguments refer to the same file or - ## directory (as indicated by device number and i-node number). - ## Raises an exception if an os.stat() call on either pathname fails. - var - a, b: TStat - if stat(path1, a) < 0 or stat(path2, b) < 0: - raise newException(EOS, "stat() call failed") - return int(a.st_dev) == b.st_dev and int(a.st_ino) == b.st_ino + importc: cunder & "stat", header: "<sys/stat.h>".} when defined(windows): proc getModuleFilename(handle: int32, buf: CString, size: int32): int32 {. @@ -456,13 +453,13 @@ proc getLastModificationTime(file: string): TTime = proc setCurrentDir(newDir: string) = if chdir(newDir) != 0: - raise newException(EOS, "cannot change the working directory to '$1'" % + raise newException(EOS, "cannot change the working directory to '$1'" % newDir) when defined(linux) or defined(solaris) or defined(bsd): proc readlink(link, buf: cstring, size: int): int {. header: "<unistd.h>", cdecl.} - + proc getApplAux(procPath: string): string = result = newString(256) var len = readlink(procPath, result, 256) @@ -473,6 +470,13 @@ when defined(linux) or defined(solaris) or defined(bsd): when defined(solaris) or defined(bsd): proc getpid(): int {.importc, header: "<unistd.h>", cdecl.} +elif defined(macosx): + # a really hacky solution: since we like to include 2 headers we have to + # define two procs which in reality are the same + proc getExecPath1(c: cstring, size: var int32) {. + importc: "_NSGetExecutablePath", header: "<sys/param.h>".} + proc getExecPath2(c: cstring, size: var int32): bool {. + importc: "_NSGetExecutablePath", header: "<mach-o/dyld.h>".} proc getApplicationFilename(): string = # Linux: /proc/<pid>/exe @@ -491,6 +495,12 @@ proc getApplicationFilename(): string = result = getApplAux("/proc/" & $getpid() & "/path/a.out") elif defined(bsd): result = getApplAux("/proc/" & $getpid() & "file") + elif defined(macosx): + var size: int32 + getExecPath1(nil, size) + result = newString(int(size)) + if getExecPath2(result, size): + result = "" # error! else: # little heuristic that may work on other POSIX-like systems: result = getEnv("_") @@ -612,7 +622,7 @@ when defined(wcc): proc cputenv(env: CString): cint {.importc: "putenv", header: "<process.h>".} else: # is in <stdlib.h> - proc cputenv(env: CString): cint {.importc: "putenv", noDecl.} + proc cputenv(env: CString): cint {.importc: cunder & "putenv", noDecl.} proc cgetenv(env: CString): CString {.importc: "getenv", noDecl.} @@ -621,7 +631,7 @@ proc cgetenv(env: CString): CString {.importc: "getenv", noDecl.} #int _findclose(long); when defined(windows): type - TFindData {.importc: "struct _finddata_t".} = record + TFindData {.importc: "struct _finddata_t", final.} = object attrib {.importc: "attrib".}: cint time_create {.importc: "time_create".}: cint time_access {.importc: "time_access".}: cint @@ -636,7 +646,7 @@ when defined(windows): proc findclose(handle: cint) {.importc: "_findclose", header: "<io.h>".} else: type - TFindData {.importc: "glob_t".} = record + TFindData {.importc: "glob_t", final.} = object gl_pathc: int # count of paths matched by pattern gl_pathv: ptr array[0..1000_000, CString] # list of matched path names gl_offs: int # slots to reserve at beginning of gl_pathv @@ -649,6 +659,30 @@ else: proc globfree(pglob: PFindData) {. importc: "globfree", header: "<glob.h>".} +proc sameFile*(path1, path2: string): bool = + ## Returns True if both pathname arguments refer to the same file or + ## directory (as indicated by device number and i-node number). + ## Raises an exception if an os.stat() call on either pathname fails. + when defined(Windows): + var + a, b: TFindData + var resA = findfirst(path1, addr(a)) + var resB = findfirst(path2, addr(b)) + if resA != -1 and resB != -1: + result = $a.name == $b.name + else: + # work around some ``findfirst`` bugs + result = cmpPaths(path1, path2) == 0 + if resA != -1: findclose(resA) + if resB != -1: findclose(resB) + else: + var + a, b: TStat + if stat(path1, a) < 0 or stat(path2, b) < 0: + result = cmpPaths(path1, path2) == 0 # be consistent with Windows + else: + result = int(a.st_dev) == b.st_dev and int(a.st_ino) == b.st_ino + proc cremove(filename: CString): cint {.importc: "remove", noDecl.} proc crename(oldname, newname: CString): cint {.importc: "rename", noDecl.} @@ -776,9 +810,9 @@ proc findEnvVar(key: string): int = proc getEnv(key: string): string = var i = findEnvVar(key) - if i >= 0: + if i >= 0: return copy(environment[i], findSubStr("=", environment[i])+1) - else: + else: var env = cgetenv(key) if env == nil: return "" result = $env @@ -787,7 +821,7 @@ proc existsEnv(key: string): bool = if cgetenv(key) != nil: return true else: return findEnvVar(key) >= 0 -iterator iterOverEnvironment*(): tuple[string, string] = +iterator iterOverEnvironment*(): tuple[key, value: string] = ## Iterate over all environments varialbes. In the first component of the ## tuple is the name of the current variable stored, in the second its value. getEnvVarsC() @@ -798,7 +832,7 @@ iterator iterOverEnvironment*(): tuple[string, string] = proc putEnv(key, val: string) = # Note: by storing the string in the environment sequence, # we gurantee that we don't free the memory before the program - # ends (this is needed for POSIX compliance). It is also needed so that + # ends (this is needed for POSIX compliance). It is also needed so that # the process itself may access its modified environment variables! var indx = findEnvVar(key) if indx >= 0: diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 9a18d0e17..35fe0a0df 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -14,7 +14,7 @@ ## This is a raw POSIX interface module. It does not not provide any ## convenience: cstrings are used instead of proper Nimrod strings and ## return codes indicate errors. If you want exceptions -## and a proper Nimrod-like interface, use the OS module. +## and a proper Nimrod-like interface, use the OS module or write a wrapper. ## Coding conventions: ## ALL types are named the same as in the POSIX standard except that they start @@ -60,7 +60,7 @@ const STDOUT_FILENO = 1 ## File number of stdout; type - Taiocb* {.importc: "struct aiocb", header: "<aio.h>".} = record + Taiocb* {.importc: "struct aiocb", header: "<aio.h>", final.} = object aio_fildes*: cint ## File descriptor. aio_offset*: TOff ## File offset. aio_buf*: pointer ## Location of buffer. @@ -69,14 +69,14 @@ type aio_sigevent*: TSigEvent ## Signal number and value. aio_lio_opcode: cint ## Operation to be performed. - TDIR* {.importc: "DIR", header: "<dirent.h>".} = record + TDIR* {.importc: "DIR", header: "<dirent.h>", final.} = object ## A type representing a directory stream. - Tdirent* {.importc: "struct dirent", header: "<dirent.h>".} = record + Tdirent* {.importc: "struct dirent", header: "<dirent.h>", final.} = object d_ino*: TIno ## File serial number. d_name*: array [0..255, char] ## Name of entry. - Tflock* {.importc: "flock", header: "<fcntl>".} = record + Tflock* {.importc: "flock", header: "<fcntl>", final.} = object l_type*: cshort ## Type of lock; F_RDLCK, F_WRLCK, F_UNLCK. l_whence*: cshort ## Flag for starting offset. l_start*: Toff ## Relative offset in bytes. @@ -84,13 +84,13 @@ type l_pid*: TPid ## Process ID of the process holding the lock; ## returned with F_GETLK. - Tfenv* {.importc: "fenv_t", header: "<fenv.h>".} = - record ## Represents the entire floating-point environment. The + Tfenv* {.importc: "fenv_t", header: "<fenv.h>", final.} = + object ## Represents the entire floating-point environment. The ## floating-point environment refers collectively to any ## floating-point status flags and control modes supported ## by the implementation. - Tfexcept* {.importc: "fexcept_t", header: "<fenv.h>".} = - record ## Represents the floating-point status flags collectively, + Tfexcept* {.importc: "fexcept_t", header: "<fenv.h>", final.} = + object ## Represents the floating-point status flags collectively, ## including any status the implementation associates with the ## flags. A floating-point status flag is a system variable ## whose value is set (but never cleared) when a floating-point @@ -100,25 +100,25 @@ type ## whose value may be set by the user to affect the subsequent ## behavior of floating-point arithmetic. - TFTW* {.importc: "struct FTW", header: "<ftw.h>".} = record + TFTW* {.importc: "struct FTW", header: "<ftw.h>", final.} = object base*: cint level*: cint - TGlob* {.importc: "glob_t", header: "<glob.h>".} = record + TGlob* {.importc: "glob_t", header: "<glob.h>", final.} = object gl_pathc*: int ## Count of paths matched by pattern. gl_pathv*: ptr cstring ## Pointer to a list of matched pathnames. gl_offs*: int ## Slots to reserve at the beginning of gl_pathv. - TGroup* {.importc: "struct group", header: "<grp.h>".} = record + TGroup* {.importc: "struct group", header: "<grp.h>", final.} = object gr_name*: cstring ## The name of the group. gr_gid*: TGid ## Numerical group ID. gr_mem*: cstringArray ## Pointer to a null-terminated array of character ## pointers to member names. - Ticonv* {.importc: "iconv_t", header: "<iconv.h>".} = - record ## Identifies the conversion from one codeset to another. + Ticonv* {.importc: "iconv_t", header: "<iconv.h>", final.} = + object ## Identifies the conversion from one codeset to another. - Tlconv* {.importc: "struct lconv", header: "<locale.h>".} = record + Tlconv* {.importc: "struct lconv", header: "<locale.h>", final.} = object currency_symbol*: cstring decimal_point*: cstring frac_digits*: char @@ -144,14 +144,14 @@ type p_sign_posn*: char thousands_sep*: cstring - TMqd* {.importc: "mqd_t", header: "<mqueue.h>".} = record - TMqAttr* {.importc: "struct mq_attr", header: "<mqueue.h>".} = record + TMqd* {.importc: "mqd_t", header: "<mqueue.h>", final.} = object + TMqAttr* {.importc: "struct mq_attr", header: "<mqueue.h>", final.} = object mq_flags*: int ## Message queue flags. mq_maxmsg*: int ## Maximum number of messages. mq_msgsize*: int ## Maximum message size. mq_curmsgs*: int ## Number of messages currently queued. - TPasswd* {.importc: "struct passwd", header: "<pwd.h>".} = record + TPasswd* {.importc: "struct passwd", header: "<pwd.h>", final.} = object pw_name*: cstring ## User's login name. pw_uid*: TUid ## Numerical user ID. pw_gid*: TGid ## Numerical group ID. @@ -198,7 +198,7 @@ type Tuid* {.importc: "uid_t", header: "<sys/types.h>".} = int Tuseconds* {.importc: "useconds_t", header: "<sys/types.h>".} = int - Tutsname* {.importc: "struct utsname", header: "<sys/utsname.h>".} = record + Tutsname* {.importc: "struct utsname", header: "<sys/utsname.h>", final.} = object sysname*, ## Name of this implementation of the operating system. nodename*, ## Name of this node within the communications ## network to which this node is attached, if any. @@ -207,15 +207,15 @@ type machine*: array [0..255, char] ## Name of the hardware type on which the ## system is running. - TSem* {.importc: "sem_t", header: "<semaphore.h>".} = record - Tipc_perm* {.importc: "struct ipc_perm", header: "<sys/ipc.h>".} = record + TSem* {.importc: "sem_t", header: "<semaphore.h>", final.} = object + Tipc_perm* {.importc: "struct ipc_perm", header: "<sys/ipc.h>", final.} = object uid*: tuid ## Owner's user ID. gid*: tgid ## Owner's group ID. cuid*: Tuid ## Creator's user ID. cgid*: Tgid ## Creator's group ID. mode*: TMode ## Read/write permission. - TStat* {.importc: "struct stat", header: "<sys/stat.h>".} = record + TStat* {.importc: "struct stat", header: "<sys/stat.h>", final.} = object st_dev*: TDev ## Device ID of device containing file. st_ino*: TIno ## File serial number. st_mode*: TMode ## Mode of file (see below). @@ -239,7 +239,7 @@ type st_blocks*: Tblkcnt ## Number of blocks allocated for this object. - TStatvfs* {.importc: "struct statvfs", header: "<sys/statvfs.h>".} = record + TStatvfs* {.importc: "struct statvfs", header: "<sys/statvfs.h>", final.} = object f_bsize*: int ## File system block size. f_frsize*: int ## Fundamental file system block size. f_blocks*: Tfsblkcnt ## Total number of blocks on file system in units of f_frsize. @@ -255,10 +255,10 @@ type f_namemax*: int ## Maximum filename length. Tposix_typed_mem_info* {.importc: "struct posix_typed_mem_info", - header: "<sys/mman.h>".} = record + header: "<sys/mman.h>", final.} = object posix_tmi_length*: int - Ttm* {.importc: "struct tm", header: "<time.h>".} = record + Ttm* {.importc: "struct tm", header: "<time.h>", final.} = object tm_sec*: cint ## Seconds [0,60]. tm_min*: cint ## Minutes [0,59]. tm_hour*: cint ## Hour [0,23]. @@ -268,10 +268,10 @@ type tm_wday*: cint ## Day of week [0,6] (Sunday =0). tm_yday*: cint ## Day of year [0,365]. tm_isdst*: cint ## Daylight Savings flag. - Ttimespec* {.importc: "struct timespec", header: "<time.h>".} = record + Ttimespec* {.importc: "struct timespec", header: "<time.h>", final.} = object tv_sec*: Ttime ## Seconds. tv_nsec*: int ## Nanoseconds. - titimerspec* {.importc: "struct itimerspec", header: "<time.h>".} = record + titimerspec* {.importc: "struct itimerspec", header: "<time.h>", final.} = object it_interval*: ttimespec ## Timer period. it_value*: ttimespec ## Timer expiration. @@ -279,19 +279,19 @@ type ## Possibly volatile-qualified integer type of an object that can be ## accessed as an atomic entity, even in the presence of asynchronous ## interrupts. - Tsigset* {.importc: "sigset_t", header: "<signal.h>".} = record + Tsigset* {.importc: "sigset_t", header: "<signal.h>", final.} = object - TsigEvent* {.importc: "struct sigevent", header: "<signal.h>".} = record + TsigEvent* {.importc: "struct sigevent", header: "<signal.h>", final.} = object sigev_notify*: cint ## Notification type. sigev_signo*: cint ## Signal number. sigev_value*: Tsigval ## Signal value. sigev_notify_function*: proc (x: TSigval) {.noconv.} ## Notification function. sigev_notify_attributes*: ptr Tpthreadattr ## Notification attributes. - TsigVal* {.importc: "union sigval", header: "<signal.h>".} = record + TsigVal* {.importc: "union sigval", header: "<signal.h>", final.} = object sival_ptr*: pointer ## pointer signal value; ## integer signal value not defined! - TSigaction* {.importc: "struct sigaction", header: "<signal.h>".} = record + TSigaction* {.importc: "struct sigaction", header: "<signal.h>", final.} = object sa_handler*: proc (x: cint) {.noconv.} ## Pointer to a signal-catching ## function or one of the macros ## SIG_IGN or SIG_DFL. @@ -300,16 +300,16 @@ type sa_flags*: cint ## Special flags. sa_sigaction*: proc (x: cint, y: var TSigInfo, z: pointer) {.noconv.} - TStack* {.importc: "stack_t", header: "<signal.h>".} = record + TStack* {.importc: "stack_t", header: "<signal.h>", final.} = object ss_sp*: pointer ## Stack base or pointer. ss_size*: int ## Stack size. ss_flags*: cint ## Flags. - TSigStack* {.importc: "struct sigstack", header: "<signal.h>".} = record + TSigStack* {.importc: "struct sigstack", header: "<signal.h>", final.} = object ss_onstack*: cint ## Non-zero when signal stack is in use. ss_sp*: pointer ## Signal stack pointer. - TsigInfo* {.importc: "siginfo_t", header: "<signal.h>".} = record + TsigInfo* {.importc: "siginfo_t", header: "<signal.h>", final.} = object si_signo*: cint ## Signal number. si_code*: cint ## Signal code. si_errno*: cint ## If non-zero, an errno value associated with @@ -324,7 +324,7 @@ type Tnl_item* {.importc: "nl_item", header: "<nl_types.h>".} = cint Tnl_catd* {.importc: "nl_catd", header: "<nl_types.h>".} = cint - Tsched_param* {.importc: "struct sched_param", header: "<sched.h>".} = record + Tsched_param* {.importc: "struct sched_param", header: "<sched.h>", final.} = object sched_priority*: cint sched_ss_low_priority*: cint ## Low scheduling priority for ## sporadic server. @@ -334,15 +334,15 @@ type sched_ss_max_repl*: cint ## Maximum pending replenishments for ## sporadic server. - Ttimeval* {.importc: "struct timeval", header: "<sys/select.h>".} = record + Ttimeval* {.importc: "struct timeval", header: "<sys/select.h>", final.} = object tv_sec*: ttime ## Seconds. tv_usec*: tsuseconds ## Microseconds. - Tfd_set* {.importc: "struct fd_set", header: "<sys/select.h>".} = record + Tfd_set* {.importc: "struct fd_set", header: "<sys/select.h>", final.} = object Tposix_spawnattr* {.importc: "posix_spawnattr_t", header: "<spawn.h>".} = cint Tposix_spawn_file_actions* {.importc: "posix_spawn_file_actions_t", header: "<spawn.h>".} = cint - Tmcontext* {.importc: "mcontext_t", header: "<ucontext.h>".} = record - Tucontext* {.importc: "ucontext_t", header: "<ucontext.h>".} = record + Tmcontext* {.importc: "mcontext_t", header: "<ucontext.h>", final.} = object + Tucontext* {.importc: "ucontext_t", header: "<ucontext.h>", final.} = object uc_link*: ptr Tucontext ## Pointer to the context that is resumed ## when this context returns. uc_sigmask*: Tsigset ## The set of signals that are blocked when this @@ -729,7 +729,7 @@ var GLOB_NOSORT* {.importc, header: "<glob.h>".}: cint ## Do not sort the pathnames returned. GLOB_ABORTED* {.importc, header: "<glob.h>".}: cint - ## The scan was stopped because GLOB_ERR was set or (*errfunc)() + ## The scan was stopped because GLOB_ERR was set or errfunc() ## returned non-zero. GLOB_NOMATCH* {.importc, header: "<glob.h>".}: cint ## The pattern does not match any existing pathname, and GLOB_NOCHECK diff --git a/lib/process.nim b/lib/process.nim index ebeeb3f47..8806264b9 100644 --- a/lib/process.nim +++ b/lib/process.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2006 Andreas Rumpf +# (c) Copyright 2008 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. diff --git a/lib/ptrset.nim b/lib/ptrset.nim index f1b9e58e5..95f01b16f 100644 --- a/lib/ptrset.nim +++ b/lib/ptrset.nim @@ -18,7 +18,7 @@ type PPointer = ptr pointer TCollectorData = int - TCell = record + TCell {.final.} = object refcount: TCollectorData # the refcount and bit flags typ: PNimType stackcount: int # stack counter for debugging @@ -67,18 +67,18 @@ type TBitIndex = range[0..UnitsPerPage-1] - TPageDesc = record + TPageDesc {.final.} = object next: PPageDesc # all nodes are connected with this pointer key: TAddress # start address at bit 0 bits: array[TBitIndex, int] # a bit vector PPageDescArray = ptr array[0..1000_000, PPageDesc] - TCellSet = record + TCellSet {.final.} = object counter, max: int head: PPageDesc data: PPageDescArray - TSetNode = record + TSetNode {.final.} = object n: array[0.. (1 shl bitsPerNode)-1, PSetNode] PSetNode = ptr TSetNode diff --git a/lib/repr.nim b/lib/repr.nim index e5106c38d..34a2ce2fb 100644 --- a/lib/repr.nim +++ b/lib/repr.nim @@ -1,233 +1,247 @@ -# -# -# Nimrod's Runtime Library -# (c) Copyright 2006 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# The generic ``repr`` procedure. It is an invaluable debugging tool. - -#proc cstrToNimStrDummy(s: cstring): string {.inline.} = -# result = cast[string](cstrToNimStr(s)) - -proc reprInt(x: int64): string {.compilerproc.} = return $x -proc reprFloat(x: float): string {.compilerproc.} = return $x - -proc reprPointer(x: pointer): string {.compilerproc.} = - var buf: array [0..59, char] - c_sprintf(buf, "%p", x) - return $buf - -proc reprStrAux(result: var string, s: string) = - if cast[pointer](s) == nil: - add result "nil" - return - add result, reprPointer(cast[pointer](s)) & "\"" - for c in items(s): - case c - of '"': add result "\\\"" - of '\\': add result, "\\\\" # BUGFIX: forgotten - of '\10': add result, "\\10\"\n\"" # " \n " # better readability - of '\128' .. '\255', '\0'..'\9', '\11'..'\31': - add result, "\\" & reprInt(ord(c)) - else: result.add(c) - add result, "\"" - -proc reprStr(s: string): string {.compilerproc.} = - result = "" - reprStrAux(result, s) - -proc reprBool(x: bool): string {.compilerproc.} = - if x: result = "true" - else: result = "false" - -proc reprChar(x: char): string {.compilerproc.} = - result = "\'" - case x - of '"': add result, "\\\"" - of '\\': add result, "\\\\" - of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x)) - else: add result, x - add result, "\'" - -proc reprEnum(e: int, typ: PNimType): string {.compilerproc.} = - if e <% typ.node.len: # BUGFIX - result = $typ.node.sons[e].name - else: - result = $e & " (invalid data!)" - -type - pbyteArray = ptr array[0.. 0xffff, byte] - -proc addSetElem(result: var string, elem: int, typ: PNimType) = - case typ.kind - of tyEnum: add result, reprEnum(elem, typ) - of tyBool: add result, reprBool(bool(elem)) - of tyChar: add result, reprChar(chr(elem)) - of tyRange: addSetElem(result, elem, typ.base) - of tyInt..tyInt64: add result, reprInt(elem) - else: # data corrupt --> inform the user - add result, " (invalid data!)" - -proc reprSetAux(result: var string, p: pointer, typ: PNimType) = - # "typ.slots.len" field is for sets the "first" field - var elemCounter = 0 # we need this flag for adding the comma at - # the right places - add result, "{" - var u: int64 - case typ.size - of 1: u = ze64(cast[ptr int8](p)^) - of 2: u = ze64(cast[ptr int16](p)^) - of 4: u = ze64(cast[ptr int32](p)^) - of 8: u = ze64(cast[ptr int64](p)^) - else: - var a = cast[pbyteArray](p)^ - for i in 0 .. typ.size*8-1: - if (a[i div 8] and (1 shl (i mod 8))) != 0: - if elemCounter > 0: add result, ", " - addSetElem(result, i+typ.node.len, typ.base) - inc(elemCounter) - if typ.size <= 8: - for i in 0..sizeof(int64)*8-1: - if (u and (1 shl i)) != 0: - if elemCounter > 0: add result, ", " - addSetElem(result, i+typ.node.len, typ.base) - inc(elemCounter) - add result, "}" - -proc reprSet(p: pointer, typ: PNimType): string {.compilerproc.} = - result = "" - reprSetAux(result, p, typ) - -type - TReprClosure = record # we cannot use a global variable here - # as this wouldn't be thread-safe - marked: TCellSet - recdepth: int # do not recurse endless - indent: int # indentation - -proc initReprClosure(cl: var TReprClosure) = - CellSetInit(cl.marked) - cl.recdepth = -1 # default is to display everything! - cl.indent = 0 - -proc deinitReprClosure(cl: var TReprClosure) = - CellSetDeinit(cl.marked) - -proc reprBreak(result: var string, cl: TReprClosure) = - add result, "\n" - for i in 0..cl.indent-1: add result, ' ' - -proc reprAux(result: var string, p: pointer, typ: PNimType, - cl: var TReprClosure) - -proc reprArray(result: var string, p: pointer, typ: PNimType, - cl: var TReprClosure) = - add result, "[" - var bs = typ.base.size - for i in 0..typ.size div bs - 1: - if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl) - add result, "]" - -proc reprSequence(result: var string, p: pointer, typ: PNimType, - cl: var TReprClosure) = - if p == nil: - add result, "nil" - return - result.add(reprPointer(p) & "[") - var bs = typ.base.size - for i in 0..cast[PGenericSeq](p).len-1: - if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs), - typ.Base, cl) - add result, "]" - - -proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode, - cl: var TReprClosure) = - case n.kind - of nkNone: assert(false) - of nkSlot: - add result, $n.name - add result, " = " - reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl) - of nkList: - for i in 0..n.len-1: - if i > 0: add result, ",\n" - reprRecordAux(result, p, n.sons[i], cl) - of nkCase: - var m = selectBranch(p, n) - reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl) - if m != nil: reprRecordAux(result, p, m, cl) - -proc reprRecord(result: var string, p: pointer, typ: PNimType, - cl: var TReprClosure) = - add result, "[" - reprRecordAux(result, p, typ.node, cl) - add result, "]" - -proc reprRef(result: var string, p: pointer, typ: PNimType, - cl: var TReprClosure) = - # we know that p is not nil here: - var cell = usrToCell(p) - add result, "ref " & reprPointer(p) - if cell notin cl.marked: - # only the address is shown: - incl(cl.marked, cell) - add result, " --> " - reprAux(result, p, typ.base, cl) - -proc reprAux(result: var string, p: pointer, typ: PNimType, - cl: var TReprClosure) = - if cl.recdepth == 0: - add result, "..." - return - dec(cl.recdepth) - case typ.kind - of tySet: reprSetAux(result, p, typ) - of tyArray: reprArray(result, p, typ, cl) - of tyRecord: reprRecord(result, p, typ, cl) - of tyObject: # result = reprRecord(p, typ, cl) - var t = cast[ptr PNimType](p)^ - reprRecord(result, p, t, cl) - of tyRef, tyPtr: - assert(p != nil) - if cast[ppointer](p)^ == nil: add result, "nil" - else: reprRef(result, cast[ppointer](p)^, typ, cl) - of tySequence: - reprSequence(result, cast[ppointer](p)^, typ, cl) - of tyInt: add result, $(cast[ptr int](p)^) - of tyInt8: add result, $int(cast[ptr Int8](p)^) - of tyInt16: add result, $int(cast[ptr Int16](p)^) - of tyInt32: add result, $int(cast[ptr Int32](p)^) - of tyInt64: add result, $(cast[ptr Int64](p)^) - of tyFloat: add result, $(cast[ptr float](p)^) - of tyFloat32: add result, $(cast[ptr float32](p)^) - of tyFloat64: add result, $(cast[ptr float64](p)^) - of tyEnum: add result, reprEnum(cast[ptr int](p)^, typ) - of tyBool: add result, reprBool(cast[ptr bool](p)^) - of tyChar: add result, reprChar(cast[ptr char](p)^) - of tyString: reprStrAux(result, cast[ptr string](p)^) - of tyCString: reprStrAux(result, $(cast[ptr cstring](p)^)) - of tyRange: reprAux(result, p, typ.base, cl) - of tyProc, tyPointer: - if cast[ppointer](p)^ == nil: add result, "nil" - else: add result, reprPointer(cast[ppointer](p)^) - else: - add result, "(invalid data!)" - inc(cl.recdepth) - -proc reprAny(p: pointer, typ: PNimType): string = - var - cl: TReprClosure - initReprClosure(cl) - result = "" - if typ.kind in {tyObject, tyRecord, tyArray, tySet}: - reprAux(result, p, typ, cl) - else: - reprAux(result, addr(p), typ, cl) - add result, "\n" - deinitReprClosure(cl) +# +# +# Nimrod's Runtime Library +# (c) Copyright 2006 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# The generic ``repr`` procedure. It is an invaluable debugging tool. + +#proc cstrToNimStrDummy(s: cstring): string {.inline.} = +# result = cast[string](cstrToNimStr(s)) + +proc reprInt(x: int64): string {.compilerproc.} = return $x +proc reprFloat(x: float): string {.compilerproc.} = return $x + +proc reprPointer(x: pointer): string {.compilerproc.} = + var buf: array [0..59, char] + c_sprintf(buf, "%p", x) + return $buf + +proc reprStrAux(result: var string, s: string) = + if cast[pointer](s) == nil: + add result "nil" + return + add result, reprPointer(cast[pointer](s)) & "\"" + for c in items(s): + case c + of '"': add result "\\\"" + of '\\': add result, "\\\\" # BUGFIX: forgotten + of '\10': add result, "\\10\"\n\"" # " \n " # better readability + of '\128' .. '\255', '\0'..'\9', '\11'..'\31': + add result, "\\" & reprInt(ord(c)) + else: result.add(c) + add result, "\"" + +proc reprStr(s: string): string {.compilerproc.} = + result = "" + reprStrAux(result, s) + +proc reprBool(x: bool): string {.compilerproc.} = + if x: result = "true" + else: result = "false" + +proc reprChar(x: char): string {.compilerproc.} = + result = "\'" + case x + of '"': add result, "\\\"" + of '\\': add result, "\\\\" + of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x)) + else: add result, x + add result, "\'" + +proc reprEnum(e: int, typ: PNimType): string {.compilerproc.} = + if e <% typ.node.len: # BUGFIX + result = $typ.node.sons[e].name + else: + result = $e & " (invalid data!)" + +type + pbyteArray = ptr array[0.. 0xffff, byte] + +proc addSetElem(result: var string, elem: int, typ: PNimType) = + case typ.kind + of tyEnum: add result, reprEnum(elem, typ) + of tyBool: add result, reprBool(bool(elem)) + of tyChar: add result, reprChar(chr(elem)) + of tyRange: addSetElem(result, elem, typ.base) + of tyInt..tyInt64: add result, reprInt(elem) + else: # data corrupt --> inform the user + add result, " (invalid data!)" + +proc reprSetAux(result: var string, p: pointer, typ: PNimType) = + # "typ.slots.len" field is for sets the "first" field + var elemCounter = 0 # we need this flag for adding the comma at + # the right places + add result, "{" + var u: int64 + case typ.size + of 1: u = ze64(cast[ptr int8](p)^) + of 2: u = ze64(cast[ptr int16](p)^) + of 4: u = ze64(cast[ptr int32](p)^) + of 8: u = cast[ptr int64](p)^ + else: + var a = cast[pbyteArray](p) + for i in 0 .. typ.size*8-1: + if (a[i div 8] and (1 shl (i mod 8))) != 0: + if elemCounter > 0: add result, ", " + addSetElem(result, i+typ.node.len, typ.base) + inc(elemCounter) + if typ.size <= 8: + for i in 0..sizeof(int64)*8-1: + if (u and (1 shl i)) != 0: + if elemCounter > 0: add result, ", " + addSetElem(result, i+typ.node.len, typ.base) + inc(elemCounter) + add result, "}" + +proc reprSet(p: pointer, typ: PNimType): string {.compilerproc.} = + result = "" + reprSetAux(result, p, typ) + +type + TReprClosure {.final.} = object # we cannot use a global variable here + # as this wouldn't be thread-safe + marked: TCellSet + recdepth: int # do not recurse endless + indent: int # indentation + +proc initReprClosure(cl: var TReprClosure) = + CellSetInit(cl.marked) + cl.recdepth = -1 # default is to display everything! + cl.indent = 0 + +proc deinitReprClosure(cl: var TReprClosure) = + CellSetDeinit(cl.marked) + +proc reprBreak(result: var string, cl: TReprClosure) = + add result, "\n" + for i in 0..cl.indent-1: add result, ' ' + +proc reprAux(result: var string, p: pointer, typ: PNimType, + cl: var TReprClosure) + +proc reprArray(result: var string, p: pointer, typ: PNimType, + cl: var TReprClosure) = + add result, "[" + var bs = typ.base.size + for i in 0..typ.size div bs - 1: + if i > 0: add result, ", " + reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl) + add result, "]" + +proc reprSequence(result: var string, p: pointer, typ: PNimType, + cl: var TReprClosure) = + if p == nil: + add result, "nil" + return + result.add(reprPointer(p) & "[") + var bs = typ.base.size + for i in 0..cast[PGenericSeq](p).len-1: + if i > 0: add result, ", " + reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs), + typ.Base, cl) + add result, "]" + + +proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode, + cl: var TReprClosure) = + case n.kind + of nkNone: assert(false) + of nkSlot: + add result, $n.name + add result, " = " + reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl) + of nkList: + for i in 0..n.len-1: + if i > 0: add result, ",\n" + reprRecordAux(result, p, n.sons[i], cl) + of nkCase: + var m = selectBranch(p, n) + reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl) + if m != nil: reprRecordAux(result, p, m, cl) + +proc reprRecord(result: var string, p: pointer, typ: PNimType, + cl: var TReprClosure) = + add result, "[" + reprRecordAux(result, p, typ.node, cl) + add result, "]" + +proc reprRef(result: var string, p: pointer, typ: PNimType, + cl: var TReprClosure) = + # we know that p is not nil here: + var cell = usrToCell(p) + add result, "ref " & reprPointer(p) + if cell notin cl.marked: + # only the address is shown: + incl(cl.marked, cell) + add result, " --> " + reprAux(result, p, typ.base, cl) + +proc reprAux(result: var string, p: pointer, typ: PNimType, + cl: var TReprClosure) = + if cl.recdepth == 0: + add result, "..." + return + dec(cl.recdepth) + case typ.kind + of tySet: reprSetAux(result, p, typ) + of tyArray: reprArray(result, p, typ, cl) + of tyTuple, tyPureObject: reprRecord(result, p, typ, cl) + of tyObject: + var t = cast[ptr PNimType](p)^ + reprRecord(result, p, t, cl) + of tyRef, tyPtr: + assert(p != nil) + if cast[ppointer](p)^ == nil: add result, "nil" + else: reprRef(result, cast[ppointer](p)^, typ, cl) + of tySequence: + reprSequence(result, cast[ppointer](p)^, typ, cl) + of tyInt: add result, $(cast[ptr int](p)^) + of tyInt8: add result, $int(cast[ptr Int8](p)^) + of tyInt16: add result, $int(cast[ptr Int16](p)^) + of tyInt32: add result, $int(cast[ptr Int32](p)^) + of tyInt64: add result, $(cast[ptr Int64](p)^) + of tyFloat: add result, $(cast[ptr float](p)^) + of tyFloat32: add result, $(cast[ptr float32](p)^) + of tyFloat64: add result, $(cast[ptr float64](p)^) + of tyEnum: add result, reprEnum(cast[ptr int](p)^, typ) + of tyBool: add result, reprBool(cast[ptr bool](p)^) + of tyChar: add result, reprChar(cast[ptr char](p)^) + of tyString: reprStrAux(result, cast[ptr string](p)^) + of tyCString: reprStrAux(result, $(cast[ptr cstring](p)^)) + of tyRange: reprAux(result, p, typ.base, cl) + of tyProc, tyPointer: + if cast[ppointer](p)^ == nil: add result, "nil" + else: add result, reprPointer(cast[ppointer](p)^) + else: + add result, "(invalid data!)" + inc(cl.recdepth) + +proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {. + compilerproc.} = + var + cl: TReprClosure + initReprClosure(cl) + result = "[" + var bs = elemtyp.size + for i in 0..length - 1: + if i > 0: add result, ", " + reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), elemtyp, cl) + add result, "]" + deinitReprClosure(cl) + +proc reprAny(p: pointer, typ: PNimType): string = + var + cl: TReprClosure + initReprClosure(cl) + result = "" + if typ.kind in {tyObject, tyPureObject, tyTuple, tyArray, tySet}: + reprAux(result, p, typ, cl) + else: + var p = p + reprAux(result, addr(p), typ, cl) + add result, "\n" + deinitReprClosure(cl) diff --git a/lib/strutils.nim b/lib/strutils.nim index e2aca01b4..039a06251 100644 --- a/lib/strutils.nim +++ b/lib/strutils.nim @@ -7,16 +7,16 @@ # distribution, for details about the copyright. # - - ## This module contains various string utility routines. ## See the module `regexprs` for regular expression support. +## All the routines here are avaiable for the EMCAScript target +## too! {.push debugger:off .} # the user does not want to trace a part # of the standard library! # copied from excpt.nim, because I don't want to make this template public -template newException(exceptn, message: expr): expr = +template newException(exceptn, message: expr): expr = block: # open a new scope var e: ref exceptn @@ -153,6 +153,10 @@ proc ParseInt*(s: string): int {.noSideEffect.} ## a valid integer, `EInvalidValue` is raised. # XXX: make this biggestint! +proc ParseBiggestInt*(s: string): biggestInt {.noSideEffect.} + ## Parses a decimal integer value contained in `s`. If `s` is not + ## a valid integer, `EInvalidValue` is raised. + proc ParseFloat*(s: string): float {.noSideEffect.} ## Parses a decimal floating point value contained in `s`. If `s` is not ## a valid floating point number, `EInvalidValue` is raised. @@ -187,7 +191,7 @@ proc `%` *(formatstr: string, a: openarray[string]): string {.noSideEffect.} ## ## "The cat eats fish." ## - ## The variables are compared with `cmpIgnoreStyle`. `EInvalidValue` is + ## The variables are compared with `cmpIgnoreStyle`. `EInvalidValue` is ## raised if an ill-formed format string has been passed to the `%` operator. proc `%` *(formatstr, a: string): string {.noSideEffect.} @@ -213,7 +217,13 @@ proc allCharsInSet*(s: string, theSet: TCharSet): bool = if not (c in theSet): return false return true -proc c_strcmp(a, b: CString): int {.importc: "strcmp", nodecl.} +proc quoteIfSpaceExists*(s: string): string = + ## returns ``'"' & s & '"'`` if `s` contains a space and does not + ## start with a quote, else returns `s` + if findSubStr(' ', s) >= 0 and s[0] != '"': + result = '"' & s & '"' + else: + result = s proc startsWith(s, prefix: string): bool = var i = 0 @@ -262,7 +272,7 @@ proc findNormalized(x: string, inArray: openarray[string]): int = while i < high(inArray): if cmpIgnoreStyle(x, inArray[i]) == 0: return i inc(i, 2) # incrementing by 1 would probably result in a - # security whole ... + # security whole ... return -1 proc `%`(formatstr: string, a: openarray[string]): string = @@ -306,11 +316,9 @@ proc `%`(formatstr: string, a: openarray[string]): string = proc cmpIgnoreCase(a, b: string): int = # makes usage of the fact that strings are zero-terminated - var - aa, bb: char for i in 0..len(a)-1: - aa = toLower(a[i]) - bb = toLower(b[i]) + var aa = toLower(a[i]) + var bb = toLower(b[i]) result = ord(aa) - ord(bb) if result != 0: break @@ -319,14 +327,13 @@ proc cmpIgnoreCase(a, b: string): int = proc cmpIgnoreStyle(a, b: string): int = var - aa, bb: char i = 0 j = 0 while True: while a[i] == '_': inc(i) while b[j] == '_': inc(j) # BUGFIX: typo - aa = toLower(a[i]) - bb = toLower(b[j]) + var aa = toLower(a[i]) + var bb = toLower(b[j]) result = ord(aa) - ord(bb) if result != 0 or aa == '\0': break inc(i) @@ -475,15 +482,12 @@ proc deleteStr(s: var string, first, last: int) = # parsing numbers: -proc sprintf(buf, frmt: CString) {.nodecl, importc: "sprintf", varargs.} - proc toHex(x: BiggestInt, len: int): string = const HexChars = "0123456789ABCDEF" var shift: BiggestInt result = newString(len) - shift = 0 for j in countdown(len-1, 0): result[j] = HexChars[toU32(x shr shift) and 0xF] shift = shift + 4 @@ -497,11 +501,8 @@ proc rawParseInt(s: string, index: var int): BiggestInt = # one more valid negative than prositive integer. Thus we perform the # computation as a negative number and then change the sign at the end. var - i: int - sign: BiggestInt - i = index - # a local i is more efficient than accessing an in out parameter - sign = -1 + i: int = index # a local i is more efficient than accessing a var parameter + sign: BiggestInt = -1 if s[i] == '+': inc(i) elif s[i] == '-': @@ -523,10 +524,8 @@ proc rawParseInt(s: string, index: var int): BiggestInt = proc parseInt(s: string): int = var - index: int - res: BiggestInt - index = strStart - res = rawParseInt(s, index) + index: int = 0 + res = rawParseInt(s, index) if index == -1: raise newException(EInvalidValue, "invalid integer: " & s) elif (sizeof(int) <= 4) and @@ -535,17 +534,20 @@ proc parseInt(s: string): int = else: result = int(res) # convert to smaller integer type +proc ParseBiggestInt(s: string): biggestInt = + var + index: int = 0 + result = rawParseInt(s, index) + if index == -1: + raise newException(EInvalidValue, "invalid integer: " & s) + proc ParseFloat(s: string): float = var - hd, esign, sign: float + esign = 1.0 + sign = 1.0 exponent, i: int flags: int result = 0.0 - i = 0 - exponent = 0 - esign = 1.0 - flags = 0 - sign = 1.0 if s[i] == '+': inc(i) elif s[i] == '-': sign = -1.0 @@ -558,7 +560,7 @@ proc ParseFloat(s: string): float = while s[i] == '_': inc(i) # Decimal? if s[i] == '.': - hd = 1.0 + var hd = 1.0 inc(i) while s[i] in {'0'..'9'}: # Read fractional part @@ -579,14 +581,14 @@ proc ParseFloat(s: string): float = elif s[i] == '-': esign = -1.0 inc(i) - if s[i] notin {'0'..'9'}: + if s[i] notin {'0'..'9'}: raise newException(EInvalidValue, "invalid float: " & s) while s[i] in {'0'..'9'}: exponent = exponent * 10 + ord(s[i]) - ord('0') inc(i) while s[i] == '_': inc(i) # Calculate Exponent - hd = 1.0 + var hd = 1.0 for j in 1..exponent: hd = hd * 10.0 if esign > 0.0: result = result * hd @@ -600,11 +602,10 @@ proc toOct*(x: BiggestInt, len: int): string = ## converts `x` into its octal representation. The resulting string is ## always `len` characters long. No leading ``0c`` prefix is generated. var - mask, shift: BiggestInt + mask: BiggestInt = 7 + shift: BiggestInt = 0 assert(len > 0) result = newString(len) - mask = 7 - shift = 0 for j in countdown(len-1, 0): result[j] = chr(int((x and mask) shr shift) + ord('0')) shift = shift + 3 @@ -614,11 +615,10 @@ proc toBin*(x: BiggestInt, len: int): string = ## converts `x` into its binary representation. The resulting string is ## always `len` characters long. No leading ``0b`` prefix is generated. var - mask, shift: BiggestInt + mask: BiggestInt = 1 + shift: BiggestInt = 0 assert(len > 0) result = newString(len) - mask = 1 - shift = 0 for j in countdown(len-1, 0): result[j] = chr(int((x and mask) shr shift) + ord('0')) shift = shift + 1 diff --git a/lib/sysio.nim b/lib/sysio.nim index bb028b0de..6da47eb20 100644 --- a/lib/sysio.nim +++ b/lib/sysio.nim @@ -33,10 +33,6 @@ var IOFBF {.importc: "_IOFBF", nodecl.}: cint IONBF {.importc: "_IONBF", nodecl.}: cint -# copied here to remove dependancy on strutils: -#proc toNimstr(x: Cstring, len: int): string {. -# noSideEffect, importc: "toNimStr".} - proc rawReadLine(f: TFile, result: var string) {.noStatic.} = # of course this could be optimized a bit; but IO is slow anyway... # and it was difficult to get this CORRECT with Ansi C's methods @@ -81,6 +77,8 @@ proc write(f: TFile, b: bool) = else: write(f, "false") proc write(f: TFile, r: float) = fprintf(f, "%g", r) proc write(f: TFile, c: Char) = putc(c, f) +proc write(f: TFile, a: openArray[string]) = + for x in items(a): write(f, x) proc EndOfFile(f: TFile): bool = # do not blame me; blame the ANSI C standard this is so brain-damaged @@ -93,6 +91,11 @@ proc EndOfFile(f: TFile): bool = proc writeln[Ty](f: TFile, x: Ty) = write(f, x) write(f, "\n") + +proc writeln[Ty](f: TFile, x: openArray[Ty]) = + write(f, x) + write(f, "\n") + proc echo[Ty](x: Ty) = writeln(stdout, x) # interface to the C procs: @@ -128,7 +131,6 @@ proc ftell(f: TFile): int {.importc: "ftell", noDecl.} proc fwrite(buf: Pointer, size, n: int, f: TFile): int {. importc: "fwrite", noDecl.} -# size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream); proc readBuffer(f: TFile, buffer: pointer, len: int): int = result = fread(buffer, 1, len, f) @@ -140,9 +142,11 @@ proc ReadChars(f: TFile, a: var openarray[char], start, len: int): int = result = readBuffer(f, addr(a[start]), len) proc writeBytes(f: TFile, a: openarray[byte], start, len: int): int = - result = writeBuffer(f, addr(a[start]), len) + var x = cast[ptr array[0..1000_000_000, byte]](a) + result = writeBuffer(f, addr(x[start]), len) proc writeChars(f: TFile, a: openarray[char], start, len: int): int = - result = writeBuffer(f, addr(a[start]), len) + var x = cast[ptr array[0..1000_000_000, byte]](a) + result = writeBuffer(f, addr(x[start]), len) proc writeBuffer(f: TFile, buffer: pointer, len: int): int = result = fwrite(buffer, 1, len, f) diff --git a/lib/sysstr.nim b/lib/sysstr.nim index 0ff43216c..a3e5ab9f8 100644 --- a/lib/sysstr.nim +++ b/lib/sysstr.nim @@ -16,7 +16,7 @@ # the programmer may not want type - TStringDesc {.importc, nodecl.} = record + TStringDesc {.importc, nodecl, final.} = object len, space: int # len and space without counting the terminating zero data: array[0..0, char] # for the '\0' character @@ -25,7 +25,6 @@ type # implementation: proc resize(old: int): int {.inline.} = - assert(old < 65536 * 4) if old <= 0: return 1 elif old < 65536: return old * 2 else: return old * 3 div 2 # for large arrays * 3/2 is better @@ -64,6 +63,7 @@ proc cstrToNimstr(str: CString): mstring {.compilerProc.} = return toNimstr(str, c_strlen(str)) proc copyString(src: mstring): mstring {.compilerProc.} = + if src == nil: return nil result = rawNewString(src.space) result.len = src.len c_memcpy(result.data, src.data, (src.len + 1) * sizeof(Char)) @@ -220,7 +220,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. result.len = newLen # --------------- other string routines ---------------------------------- -proc `$`(x: int): string = +proc nimIntToStr(x: int): string {.compilerproc.} = result = newString(sizeof(x)*4) var i = 0 var y = x @@ -238,14 +238,12 @@ proc `$`(x: int): string = for j in 0..i div 2 - 1: swap(result[j], result[i-j-1]) -{.push warnings: off.} -proc `$`(x: float): string = +proc nimFloatToStr(x: float): string {.compilerproc.} = var buf: array [0..59, char] c_sprintf(buf, "%#g", x) return $buf -{.pop.} -proc `$`(x: int64): string = +proc nimInt64ToStr(x: int64): string {.compilerproc.} = # we don't rely on C's runtime here as some C compiler's # int64 support is weak result = newString(sizeof(x)*4) @@ -265,19 +263,13 @@ proc `$`(x: int64): string = for j in 0..i div 2 - 1: swap(result[j], result[i-j-1]) -proc `$`(x: bool): string = - if x: result = "true" - else: result = "false" +proc nimBoolToStr(x: bool): string {.compilerproc.} = + return if x: "true" else: "false" -proc `$`(x: char): string = +proc nimCharToStr(x: char): string {.compilerproc.} = result = newString(1) result[0] = x -proc `$`(x: string): string = - # this is useful for generic code! - return x - - proc binaryStrSearch(x: openarray[string], y: string): int {.compilerproc.} = var a = 0 diff --git a/lib/system.nim b/lib/system.nim index 8e8fc5d6d..285b921f8 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -58,10 +58,10 @@ proc new*[T](a: var ref T) {.magic: "New".} proc new*[T](a: var ref T, finalizer: proc (x: ref T)) {.magic: "NewFinalize".} ## creates a new object of type ``T`` and returns a safe (traced) ## reference to it in ``a``. When the garbage collector frees the object, - ## `finalizer` is called. The `finalizer` may not keep a reference to the + ## `finalizer` is called. The `finalizer` may not keep a reference to the ## object pointed to by `x`. The `finalizer` cannot prevent the GC from ## freeing the object. Note: The `finalizer` refers to the type `T`, not to - ## the object! This means that for each object of type `T` the finalizer + ## the object! This means that for each object of type `T` the finalizer ## will be called! # for low and high the return type T may not be correct, but @@ -86,7 +86,6 @@ type ## length field. seq*{.magic: "Seq".}[T] ## Generic type to construct sequences. set*{.magic: "Set".}[T] ## Generic type to construct bit sets. - tuple*{.magic: "Tuple".}[T] ## Generic type to construct tuple types. Byte* = Int8 ## this is an alias for ``int8``, that is a signed ## int 8 bits wide. @@ -104,14 +103,15 @@ type ## objects that have no ancestor are allowed. PObject* = ref TObject ## reference to TObject - E_Base* {.compilerproc.} = object of TObject ## base exception class; + E_Base* {.compilerproc.} = object of TObject ## base exception class; ## each exception has to ## inherit from `E_Base`. name*: cstring ## The exception's name is its Nimrod identifier. ## This field is filled automatically in the ## ``raise`` statement. - msg*: cstring ## the exception's message. Not providing an - ## exception message is bad style. + msg* {.exportc: "message".}: cstring ## the exception's message. Not + ## providing an + ## exception message is bad style. EAsynch* = object of E_Base ## Abstract exception class for ## *asynchronous exceptions* (interrupts). @@ -129,18 +129,21 @@ type ## could not be fullfilled. EArithmetic* = object of ESynch ## raised if any kind of arithmetic ## error occured. - EDivByZero* = object of EArithmetic ## is the exception class for integer - ## divide-by-zero errors. - EOverflow* = object of EArithmetic ## is the exception class for integer - ## calculations whose results are too - ## large to fit in the provided bits. - - EAccessViolation* = object of ESynch ## the exception class for - ## invalid memory access errors - - EAssertionFailed* = object of ESynch ## is the exception class for Assert - ## procedures that is raised if the - ## assertion proves wrong + EDivByZero* {.compilerproc.} = + object of EArithmetic ## is the exception class for integer divide-by-zero + ## errors. + EOverflow* {.compilerproc.} = + object of EArithmetic ## is the exception class for integer calculations + ## whose results are too large to fit in the + ## provided bits. + + EAccessViolation* {.compilerproc.} = + object of ESynch ## the exception class for invalid memory access errors + + EAssertionFailed* {.compilerproc.} = + object of ESynch ## is the exception class for Assert + ## procedures that is raised if the + ## assertion proves wrong EControlC* = object of EAsynch ## is the exception class for Ctrl+C ## key presses in console applications. @@ -154,6 +157,9 @@ type EInvalidIndex* = object of ESynch ## is raised if an array index is out ## of bounds. + EInvalidField* = object of ESynch ## is raised if a record field is not + ## accessible because its dicriminant's + ## value does not fit. EOutOfRange* = object of ESynch ## is raised if a range check error ## occured. @@ -164,13 +170,13 @@ type ENoExceptionToReraise* = object of ESynch ## is raised if there is no ## exception to reraise. - EInvalidObjectAssignment* = object of ESynch ## is raised if an object - ## gets assigned to its - ## farther's object. + EInvalidObjectAssignment* = + object of ESynch ## is raised if an object gets assigned to its + ## farther's object. - EInvalidObjectConversion* = object of ESynch ## is raised if an object is - ## converted to an incompatible - ## object type. + EInvalidObjectConversion* = + object of ESynch ## is raised if an object is converted to an incompatible + ## object type. TResult* = enum Failure, Success @@ -394,7 +400,7 @@ proc in_Operator*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.} ## writeln(stdout, 'b' in s) ## ## If ``in`` had been declared as ``[T](elem: T, s: set[T])`` then ``T`` would - ## have been bound to ``char``. But ``s`` is not compatible with type + ## have been bound to ``char``. But ``s`` is not compatible to type ## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This ## is achieved by reversing the parameters for ``in_operator``; ``in`` then ## passes its arguments in reverse order. @@ -418,25 +424,31 @@ proc cmp*(x, y: string): int {.noSideEffect.} ## Compare proc for strings. More efficient than the generic version. # concat operator: -proc `&` * (x: string, y: char): string {. - magic: "ConStrStr", noSideEffect, returnsNew.} -proc `&` * (x: char, y: char): string {. - magic: "ConStrStr", noSideEffect, returnsNew.} -proc `&` * (x, y: string): string {. - magic: "ConStrStr", noSideEffect, returnsNew.} -proc `&` * (x: char, y: string): string {. - magic: "ConStrStr", noSideEffect, returnsNew.} - ## is the `concatenation operator`. It - ## concatenates `x` and `y`. +proc `&` * (x: string, y: char): string {.magic: "ConStrStr", noSideEffect.} +proc `&` * (x: char, y: char): string {.magic: "ConStrStr", noSideEffect.} +proc `&` * (x, y: string): string {.magic: "ConStrStr", noSideEffect.} +proc `&` * (x: char, y: string): string {.magic: "ConStrStr", noSideEffect.} + ## is the `concatenation operator`. It concatenates `x` and `y`. proc add * (x: var string, y: char) {.magic: "AppendStrCh".} proc add * (x: var string, y: string) {.magic: "AppendStrStr".} -proc add* (x: var string, y: cstring) = - var i = 0 - while y[i] != '\0': - add(x, y[i]) - inc(i) +when not defined(ECMAScript): + proc add* (x: var string, y: cstring) = + var i = 0 + while y[i] != '\0': + add(x, y[i]) + inc(i) +else: + proc add* (x: var string, y: cstring) {.pure.} = + asm """ + var len = `x`[0].length-1; + for (var i = 0; i < `y`.length; ++i) { + `x`[0][len] = `y`.charCodeAt(i); + ++len; + } + `x`[0][len] = 0 + """ proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem".} proc add *[T](x: var seq[T], y: seq[T]) {.magic: "AppendSeqSeq".} @@ -493,7 +505,7 @@ type # these work for most platforms: TEndian* = enum ## is a type describing the endianness of a processor. littleEndian, bigEndian - + PFloat32* = ptr Float32 ## an alias for ``ptr float32`` PFloat64* = ptr Float64 ## an alias for ``ptr float64`` PInt64* = ptr Int64 ## an alias for ``ptr int64`` @@ -675,20 +687,27 @@ proc swap*[T](a, b: var T) {.magic: "Swap".} ## swaps the values `a` and `b`. This is often more efficient than ## ``tmp = a; a = b; b = tmp``. Particularly useful for sorting algorithms. -proc ze*(x: int8): int {.magic: "Ze", noSideEffect.} +proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect.} ## zero extends a smaller integer type to ``int``. This treats `x` as ## unsigned. -proc ze*(x: int16): int {.magic: "Ze", noSideEffect.} +proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect.} ## zero extends a smaller integer type to ``int``. This treats `x` as ## unsigned. -proc ze64*(x: int32): int64 {.magic: "Ze64", noSideEffect.} +proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect.} ## zero extends a smaller integer type to ``int64``. This treats `x` as ## unsigned. -proc ze*(x: int): int64 {.magic: "Ze", noDecl, noSideEffect.} +proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + +proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. +proc ze64*(x: int): int64 {.magic: "ZeIToI64", noDecl, noSideEffect.} ## zero extends a smaller integer type to ``int64``. This treats `x` as ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``. - ## (This is the case an 64 bit processors.) + ## (This is the case on 64 bit processors.) proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.} ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits @@ -749,39 +768,39 @@ template `>%` *(x, y: expr): expr = y <% x ## treats `x` and `y` as unsigned and compares them. ## Returns true iff ``unsigned(x) > unsigned(y)``. -proc `$` *(x: int): string {.noSideEffect.} +proc `$` *(x: int): string {.magic: "IntToStr", noSideEffect.} ## The stingify operator for an integer argument. Returns `x` ## converted to a decimal string. -proc `$` *(x: int64): string {.noSideEffect.} +proc `$` *(x: int64): string {.magic: "Int64ToStr", noSideEffect.} ## The stingify operator for an integer argument. Returns `x` ## converted to a decimal string. -proc `$` *(x: float): string {.noSideEffect.} +proc `$` *(x: float): string {.magic: "FloatToStr", noSideEffect.} ## The stingify operator for a float argument. Returns `x` ## converted to a decimal string. -proc `$` *(x: bool): string {.noSideEffect.} +proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.} ## The stingify operator for a boolean argument. Returns `x` ## converted to the string "false" or "true". -proc `$` *(x: char): string {.noSideEffect.} +proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.} ## The stingify operator for a character argument. Returns `x` ## converted to a string. -proc `$` *(x: Cstring): string {.noSideEffect, importc: "cstrToNimstr".} +proc `$` *(x: Cstring): string {.magic: "CStrToStr", noSideEffect.} ## The stingify operator for a CString argument. Returns `x` ## converted to a string. -proc `$` *(x: string): string {.noSideEffect.} +proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.} ## The stingify operator for a string argument. Returns `x` ## as it is. This operator is useful for generic code, so - ## that ``$expr`` works if ``expr`` is already a string. + ## that ``$expr`` also works if ``expr`` is already a string. # undocumented: proc getRefcount*[T](x: ref T): int {.importc: "getRefcount".} ## retrieves the reference count of an heap-allocated object. The - ## value is implementation-dependant. + ## value is implementation-dependant. #proc writeStackTrace() {.export: "writeStackTrace".} proc getCurrentExceptionMsg*(): string {.exportc.} @@ -790,10 +809,12 @@ proc getCurrentExceptionMsg*(): string {.exportc.} # new constants: const - inf* = 1.0 / 0.0 + inf* {.magic: "Inf".} = 0.0 ## contains the IEEE floating point value of positive infinity. - nan* = 0.0 / 0.0 - ## contains the IEEE floating point value of *Not A Number*. Note + neginf* {.magic: "NegInf".} = 0.0 + ## contains the IEEE floating point value of negative infinity. + nan* {.magic: "NaN".} = 0.0 + ## contains an IEEE floating point value of *Not A Number*. Note ## that you cannot compare a floating point value to this value ## and expect a reasonable result - use the `classify` procedure ## in the module ``math`` for checking for NaN. @@ -805,18 +826,18 @@ var ## Only code compiled with the ``debugger:on`` switch calls this hook. # GC interface: -when defined(Unix) and not defined(macosX) and not defined(linux): +when defined(Unix) and not defined(macosX) and not defined(linux): # BUGFIX for macosX {.define: nativeDL.} when defined(useDL) or defined(nativeDL): proc getOccupiedMem*(): int ## returns the number of bytes that are owned by the process and hold data. - + proc getFreeMem*(): int ## returns the number of bytes that are owned by the process, but do not ## hold any meaningful data. - + proc getTotalMem*(): int ## returns the number of bytes that are owned by the process. @@ -885,11 +906,22 @@ iterator items*(a: cstring): char {.inline.} = yield a[i] inc(i) + +proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".} +proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".} +proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".} +proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".} +proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".} +proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".} + ## Fast check whether `x` is nil. This is sometimes more efficient than + ## ``== nil``. + + # Fixup some magic symbols here: {.fixup_system.} # This is an undocumented pragma that can only be used # once in the system module. -proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect, returnsNew.} = +proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect.} = result = [] setLen(result, x.len + y.len) for i in 0..x.len-1: @@ -897,110 +929,74 @@ proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect, returnsNew.} = for i in 0..y.len-1: result[i] = y[i] -proc `&` *[T](x: seq[T], y: T): seq[T] {.noSideEffect, returnsNew.} = +proc `&` *[T](x: seq[T], y: T): seq[T] {.noSideEffect.} = result = [] setLen(x.len + 1) for i in 0..x.len-1: result[i] = x[i] result[x.len] = y -proc `&` *[T](x: T, y: seq[T]): seq[T] {.noSideEffect, returnsNew.} = +proc `&` *[T](x: T, y: seq[T]): seq[T] {.noSideEffect.} = result = [] setLen(y.len + 1) for i in 0..y.len-1: result[i] = y[i] result[y.len] = x -proc `&` *[T](x, y: T): seq[T] {.noSideEffect, returnsNew.} = +proc `&` *[T](x, y: T): seq[T] {.noSideEffect.} = return [x, y] +when not defined(ECMAScript): # XXX make this local procs + proc seqToPtr*[T](x: seq[T]): pointer {.inline, nosideeffect.} = + result = cast[pointer](x) +else: + proc seqToPtr*[T](x: seq[T]): pointer {.pure, nosideeffect.} = + asm """return `x`""" + proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} = ## Generic equals operator for sequences: relies on a equals operator for ## the element type `T`. - if cast[pointer](x) == cast[pointer](y): + if seqToPtr(x) == seqToPtr(y): result = true - elif cast[pointer](x) == nil or cast[pointer](y) == nil: + elif seqToPtr(x) == nil or seqToPtr(y) == nil: result = false elif x.len == y.len: for i in 0..x.len-1: if x[i] != y[i]: return false result = true -{.push checks: off, line_dir: off, debugger: off, - assertions: on.} # obviously we cannot generate checking operations here :-) - # because it would yield into an endless recursion - # however, stack-traces are available for most parts - # of the code - -include hti - -proc initGC() - -var - strDesc: TNimType - -strDesc.size = sizeof(string) -strDesc.kind = tyString -initGC() # BUGFIX: need to be called here! - -{.push stack_trace: off.} +# ----------------- FPU ------------------------------------------------------ -include ansi_c +#proc disableFPUExceptions*() +# disables all floating point unit exceptions -proc cmp(x, y: string): int = - return c_strcmp(x, y) +#proc enableFPUExceptions*() +# enables all floating point unit exceptions -when defined(windows): - # work-around C's sucking abstraction: - # BUGFIX: stdin and stdout should be binary files! - const pccHack = if defined(pcc): "_" else: "" # Hack for PCC - proc setmode(handle, mode: int) {.importc: pccHack & "setmode", - header: "<io.h>".} - proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno", - header: "<fcntl.h>".} - var - O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int - - # we use binary mode in Windows: - setmode(fileno(c_stdin), O_BINARY) - setmode(fileno(c_stdout), O_BINARY) - -when defined(endb): - proc endbStep() - - -template newException(exceptn, message: expr): expr = - block: # open a new scope - var - e: ref exceptn - new(e) - e.msg = message - e - # ----------------- GC interface --------------------------------------------- -proc GC_disable*() +proc GC_disable*() ## disables the GC. If called n-times, n calls to `GC_enable` are needed to ## reactivate the GC. Note that in most circumstances one should only disable - ## the mark and sweep phase with `GC_disableMarkAndSweep`. + ## the mark and sweep phase with `GC_disableMarkAndSweep`. -proc GC_enable*() +proc GC_enable*() ## enables the GC again. - + proc GC_fullCollect*() - ## forces a full garbage collection pass. + ## forces a full garbage collection pass. ## Ordinary code does not need to call this. type TGC_Strategy* = enum ## the strategy the GC should use for the application - gcThroughput , ## optimize for throughput + gcThroughput, ## optimize for throughput gcResponsiveness, ## optimize for responsiveness (default) gcOptimizeTime, ## optimize for speed gcOptimizeSpace ## optimize for memory footprint proc GC_setStrategy*(strategy: TGC_Strategy) ## tells the GC the desired strategy for the application. - + proc GC_enableMarkAndSweep*() proc GC_disableMarkAndSweep*() ## the current implementation uses a reference counting garbage collector @@ -1009,176 +1005,242 @@ proc GC_disableMarkAndSweep*() ## does not create cycles. Thus the mark and sweep phase can be deactivated ## and activated separately from the rest of the GC. - -# ----------------- IO Part -------------------------------------------------- -type - CFile {.importc: "FILE", nodecl.} = record # empty record for - # data hiding - TFile* = ptr CFile ## The type representing a file handle. - - TFileMode* = enum ## The file mode when opening a file. - fmRead, ## Open the file for read access only. - fmWrite, ## Open the file for write access only. - fmReadWrite, ## Open the file for read and write access. - ## If the file does not exist, it will be - ## created. - fmReadWriteExisting, ## Open the file for read and write access. - ## If the file does not exist, it will not be - ## created. - fmAppend ## Open the file for writing only; append data - ## at the end. - -# text file handling: -var - stdin* {.importc: "stdin", noDecl.}: TFile ## The standard input stream. - stdout* {.importc: "stdout", noDecl.}: TFile ## The standard output stream. - stderr* {.importc: "stderr", noDecl.}: TFile - ## The standard error stream. - ## - ## Note: In my opinion, this should not be used -- the concept of a - ## separate error stream is a design flaw of UNIX. A seperate *message - ## stream* is a good idea, but since it is named ``stderr`` there are few - ## programs out there that distinguish properly between ``stdout`` and - ## ``stderr``. So, that's what you get if you don't name your variables - ## appropriately. It also annoys people if redirection via ``>output.txt`` - ## does not work because the program writes to ``stderr``. - -proc OpenFile*(f: var TFile, filename: string, - mode: TFileMode = fmRead, bufSize: int = -1): Bool - ## Opens a file named `filename` with given `mode`. - ## - ## Default mode is readonly. Returns true iff the file could be opened. - ## This throws no exception if the file could not be opened. The reason is - ## that the programmer needs to provide an appropriate error message anyway - ## (yes, even in scripts). - -proc CloseFile*(f: TFile) {.importc: "fclose", nodecl.} - ## Closes the file. -proc EndOfFile*(f: TFile): Bool - ## Returns true iff `f` is at the end. -proc readChar*(f: TFile): char {.importc: "fgetc", nodecl.} - ## Reads a single character from the stream `f`. If the stream - ## has no more characters, `EEndOfFile` is raised. -proc FlushFile*(f: TFile) {.importc: "fflush", noDecl.} - ## Flushes `f`'s buffer. - -proc readFile*(filename: string): string - ## Opens a file name `filename` for reading. Then reads the - ## file's content completely into a string and - ## closes the file afterwards. Returns the string. Returns nil if there was - ## an error. Does not throw an IO exception. - -proc write*(f: TFile, r: float) -proc write*(f: TFile, i: int) -proc write*(f: TFile, s: string) -proc write*(f: TFile, b: Bool) -proc write*(f: TFile, c: char) -proc write*(f: TFile, c: cstring) - ## Writes a value to the file `f`. May throw an IO exception. - -proc readLine*(f: TFile): string - ## reads a line of text from the file `f`. May throw an IO exception. - ## Reading from an empty file buffer, does not throw an exception, but - ## returns nil. A line of text may be delimited by ``CR``, ``LF`` or - ## ``CRLF``. The newline character(s) are not part of the returned string. - -proc writeln*[Ty](f: TFile, x: Ty) {.inline.} - ## writes a value `x` to `f` and then writes "\n". May throw an IO exception. +{.push checks: off, line_dir: off, debugger: off, + assertions: on.} # obviously we cannot generate checking operations here :-) + # because it would yield into an endless recursion + # however, stack-traces are available for most parts + # of the code + proc echo*[Ty](x: Ty) {.inline.} - ## equivalent to ``writeln(stdout, x); flush(stdout)``. - -proc getFileSize*(f: TFile): int64 - ## retrieves the file size (in bytes) of `f`. - -proc ReadBytes*(f: TFile, a: var openarray[byte], start, len: int): int - ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns - ## the actual number of bytes that have been read which may be less than - ## `len` (if not as many bytes are remaining), but not greater. - -proc ReadChars*(f: TFile, a: var openarray[char], start, len: int): int - ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns - ## the actual number of bytes that have been read which may be less than - ## `len` (if not as many bytes are remaining), but not greater. - -proc readBuffer*(f: TFile, buffer: pointer, len: int): int - ## reads `len` bytes into the buffer pointed to by `buffer`. Returns - ## the actual number of bytes that have been read which may be less than - ## `len` (if not as many bytes are remaining), but not greater. - -proc writeBytes*(f: TFile, a: openarray[byte], start, len: int): int - ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns - ## the number of actual written bytes, which may be less than `len` in case - ## of an error. - -proc writeChars*(f: tFile, a: openarray[char], start, len: int): int - ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns - ## the number of actual written bytes, which may be less than `len` in case - ## of an error. - -proc writeBuffer*(f: TFile, buffer: pointer, len: int): int - ## writes the bytes of buffer pointed to by the parameter `buffer` to the - ## file `f`. Returns the number of actual written bytes, which may be less - ## than `len` in case of an error. - -proc setFilePos*(f: TFile, pos: int64) - ## sets the position of the file pointer that is used for read/write - ## operations. The file's first byte has the index zero. - -proc getFilePos*(f: TFile): int64 - ## retrieves the current position of the file pointer that is used to - ## read from the file `f`. The file's first byte has the index zero. - -include sysio - -iterator lines*(filename: string): string = - ## Iterate over any line in the file named `filename`. - ## If the file does not exist `EIO` is raised. - var - f: TFile - if not openFile(f, filename): - raise newException(EIO, "cannot open: " & filename) - var res = "" - while not endOfFile(f): - rawReadLine(f, res) - yield res - CloseFile(f) + ## equivalent to ``writeln(stdout, x); flush(stdout)``. BUT: This is + ## available for the ECMAScript target too! + + +template newException(exceptn, message: expr): expr = + block: # open a new scope + var + e: ref exceptn + new(e) + e.msg = message + e -# ---------------------------------------------------------------------------- +when not defined(EcmaScript): -include excpt -# we cannot compile this with stack tracing on -# as it would recurse endlessly! -include arithm -{.pop.} # stack trace + include hti -# sequence type declarations here because the GC needs them too: -type - TGenericSeq {.importc, nodecl.} = record - len, space: int + proc initGC() - PGenericSeq {.importc, nodecl.} = ptr TGenericSeq + var + strDesc: TNimType -const - GenericSeqSize = (2 * sizeof(int)) + strDesc.size = sizeof(string) + strDesc.kind = tyString + initGC() # BUGFIX: need to be called here! -when not defined(boehmgc) and not defined(nogc): - include gc + {.push stack_trace: off.} -include sysstr -include assign -include dyncalls -include repr + include ansi_c -# we have to implement it here after gentostr for the cstrToNimStrDummy proc -proc getCurrentExceptionMsg(): string = - if excHandler == nil: return "" - return $excHandler.exc.msg + proc cmp(x, y: string): int = + return c_strcmp(x, y) -{.push stack_trace: off.} -when defined(endb): - include debugger -{.pop.} # stacktrace -{.pop.} # checks + when defined(windows): + # work-around C's sucking abstraction: + # BUGFIX: stdin and stdout should be binary files! + const pccHack = if defined(pcc): "_" else: "" # Hack for PCC + proc setmode(handle, mode: int) {.importc: pccHack & "setmode", + header: "<io.h>".} + proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno", + header: "<fcntl.h>".} + var + O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int + + # we use binary mode in Windows: + setmode(fileno(c_stdin), O_BINARY) + setmode(fileno(c_stdout), O_BINARY) + + when defined(endb): + proc endbStep() + + # ----------------- IO Part -------------------------------------------------- + + type + CFile {.importc: "FILE", nodecl, final.} = object # empty record for + # data hiding + TFile* = ptr CFile ## The type representing a file handle. + + TFileMode* = enum ## The file mode when opening a file. + fmRead, ## Open the file for read access only. + fmWrite, ## Open the file for write access only. + fmReadWrite, ## Open the file for read and write access. + ## If the file does not exist, it will be + ## created. + fmReadWriteExisting, ## Open the file for read and write access. + ## If the file does not exist, it will not be + ## created. + fmAppend ## Open the file for writing only; append data + ## at the end. + + # text file handling: + var + stdin* {.importc: "stdin", noDecl.}: TFile ## The standard input stream. + stdout* {.importc: "stdout", noDecl.}: TFile ## The standard output stream. + stderr* {.importc: "stderr", noDecl.}: TFile + ## The standard error stream. + ## + ## Note: In my opinion, this should not be used -- the concept of a + ## separate error stream is a design flaw of UNIX. A seperate *message + ## stream* is a good idea, but since it is named ``stderr`` there are few + ## programs out there that distinguish properly between ``stdout`` and + ## ``stderr``. So, that's what you get if you don't name your variables + ## appropriately. It also annoys people if redirection via ``>output.txt`` + ## does not work because the program writes to ``stderr``. + + proc OpenFile*(f: var TFile, filename: string, + mode: TFileMode = fmRead, bufSize: int = -1): Bool + ## Opens a file named `filename` with given `mode`. + ## + ## Default mode is readonly. Returns true iff the file could be opened. + ## This throws no exception if the file could not be opened. The reason is + ## that the programmer needs to provide an appropriate error message anyway + ## (yes, even in scripts). + + proc CloseFile*(f: TFile) {.importc: "fclose", nodecl.} + ## Closes the file. + proc EndOfFile*(f: TFile): Bool + ## Returns true iff `f` is at the end. + proc readChar*(f: TFile): char {.importc: "fgetc", nodecl.} + ## Reads a single character from the stream `f`. If the stream + ## has no more characters, `EEndOfFile` is raised. + proc FlushFile*(f: TFile) {.importc: "fflush", noDecl.} + ## Flushes `f`'s buffer. + + proc readFile*(filename: string): string + ## Opens a file name `filename` for reading. Then reads the + ## file's content completely into a string and + ## closes the file afterwards. Returns the string. Returns nil if there was + ## an error. Does not throw an IO exception. + + proc write*(f: TFile, r: float) + proc write*(f: TFile, i: int) + proc write*(f: TFile, s: string) + proc write*(f: TFile, b: Bool) + proc write*(f: TFile, c: char) + proc write*(f: TFile, c: cstring) + proc write*(f: TFile, a: openArray[string]) + ## Writes a value to the file `f`. May throw an IO exception. + + proc readLine*(f: TFile): string + ## reads a line of text from the file `f`. May throw an IO exception. + ## Reading from an empty file buffer, does not throw an exception, but + ## returns nil. A line of text may be delimited by ``CR``, ``LF`` or + ## ``CRLF``. The newline character(s) are not part of the returned string. + + proc writeln*[Ty](f: TFile, x: Ty) {.inline.} + ## writes a value `x` to `f` and then writes "\n". + ## May throw an IO exception. + + proc writeln*[Ty](f: TFile, x: openArray[Ty]) {.inline.} + ## writes a value `x` to `f` and then writes "\n". + ## May throw an IO exception. + + proc getFileSize*(f: TFile): int64 + ## retrieves the file size (in bytes) of `f`. + + proc ReadBytes*(f: TFile, a: var openarray[byte], start, len: int): int + ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns + ## the actual number of bytes that have been read which may be less than + ## `len` (if not as many bytes are remaining), but not greater. + + proc ReadChars*(f: TFile, a: var openarray[char], start, len: int): int + ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns + ## the actual number of bytes that have been read which may be less than + ## `len` (if not as many bytes are remaining), but not greater. + + proc readBuffer*(f: TFile, buffer: pointer, len: int): int + ## reads `len` bytes into the buffer pointed to by `buffer`. Returns + ## the actual number of bytes that have been read which may be less than + ## `len` (if not as many bytes are remaining), but not greater. + + proc writeBytes*(f: TFile, a: openarray[byte], start, len: int): int + ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns + ## the number of actual written bytes, which may be less than `len` in case + ## of an error. + + proc writeChars*(f: tFile, a: openarray[char], start, len: int): int + ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns + ## the number of actual written bytes, which may be less than `len` in case + ## of an error. + + proc writeBuffer*(f: TFile, buffer: pointer, len: int): int + ## writes the bytes of buffer pointed to by the parameter `buffer` to the + ## file `f`. Returns the number of actual written bytes, which may be less + ## than `len` in case of an error. + + proc setFilePos*(f: TFile, pos: int64) + ## sets the position of the file pointer that is used for read/write + ## operations. The file's first byte has the index zero. + + proc getFilePos*(f: TFile): int64 + ## retrieves the current position of the file pointer that is used to + ## read from the file `f`. The file's first byte has the index zero. + + include sysio + + iterator lines*(filename: string): string = + ## Iterate over any line in the file named `filename`. + ## If the file does not exist `EIO` is raised. + var + f: TFile + if not openFile(f, filename): + raise newException(EIO, "cannot open: " & filename) + var res = "" + while not endOfFile(f): + rawReadLine(f, res) + yield res + CloseFile(f) + + # ---------------------------------------------------------------------------- + + include excpt + # we cannot compile this with stack tracing on + # as it would recurse endlessly! + include arithm + {.pop.} # stack trace + + # sequence type declarations here because the GC needs them too: + type + TGenericSeq {.importc, nodecl, final.} = object + len, space: int + + PGenericSeq {.importc, nodecl.} = ptr TGenericSeq + + const + GenericSeqSize = (2 * sizeof(int)) + + when not defined(boehmgc) and not defined(nogc): + include gc + + include sysstr + include assign + include dyncalls + include repr + + # we have to implement it here after gentostr for the cstrToNimStrDummy proc + proc getCurrentExceptionMsg(): string = + if excHandler == nil: return "" + return $excHandler.exc.msg + + {.push stack_trace: off.} + when defined(endb): + include debugger + {.pop.} # stacktrace +else: + include ecmasys + +include macros + +{.pop.} # checks {.pop.} # hints diff --git a/lib/times.nim b/lib/times.nim index e1b32e754..93524f568 100644 --- a/lib/times.nim +++ b/lib/times.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2006 Andreas Rumpf +# (c) Copyright 2008 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -9,6 +9,7 @@ ## This module contains routines and types for dealing with time. +## This module is available for the ECMAScript target. {.push debugger:off .} # the user does not want to trace a part # of the standard library! @@ -22,9 +23,49 @@ type TWeekDay* = enum ## represents a weekday dMon, dTue, dWed, dThu, dFri, dSat, dSun - TTime* {.importc: "time_t".} = record ## abstract type that represents a time + TTime* {.importc: "time_t", final.} = object ## abstract type that + ## represents a time + when defined(ECMAScript): + getDay: proc (): int + getFullYear: proc (): int + getHours: proc (): int + getMilliseconds: proc (): int + getMinutes: proc (): int + getMonth: proc (): int + getSeconds: proc (): int + getTime: proc (): int + getTimezoneOffset: proc (): int + getUTCDate: proc (): int + getUTCFullYear: proc (): int + getUTCHours: proc (): int + getUTCMilliseconds: proc (): int + getUTCMinutes: proc (): int + getUTCMonth: proc (): int + getUTCSeconds: proc (): int + getYear: proc (): int + parse: proc (s: cstring): TTime + setDate: proc (x: int) + setFullYear: proc (x: int) + setHours: proc (x: int) + setMilliseconds: proc (x: int) + setMinutes: proc (x: int) + setMonth: proc (x: int) + setSeconds: proc (x: int) + setTime: proc (x: int) + setUTCDate: proc (x: int) + setUTCFullYear: proc (x: int) + setUTCHours: proc (x: int) + setUTCMilliseconds: proc (x: int) + setUTCMinutes: proc (x: int) + setUTCMonth: proc (x: int) + setUTCSeconds: proc (x: int) + setYear: proc (x: int) + toGMTString: proc (): cstring + toLocaleString: proc (): cstring + UTC: proc (): int - TTimeInfo* = record ## represents a time in different parts + + TTimeInfo* = object of TObject ## represents a time in different parts second*: range[0..61] ## The number of seconds after the minute, ## normally in the range 0 to 59, but can ## be up to 61 to allow for leap seconds. @@ -38,6 +79,7 @@ type weekday*: TWeekDay ## The current day of the week. yearday*: range[0..365] ## The number of days since January 1, ## in the range 0 to 365. + ## Always 0 if the target is ECMAScript. proc getTime*(): TTime ## gets the current calendar time proc getLocalTime*(t: TTime): TTimeInfo @@ -54,7 +96,7 @@ proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime ## them from the other information in the broken-down time structure. proc `$` *(timeInfo: TTimeInfo): string - ## converts a `TTimeInfo` record to a + ## converts a `TTimeInfo` object to a ## string representation. proc `$` *(time: TTime): string ## converts a calendar time to a @@ -72,92 +114,149 @@ proc `-` *(a, b: TTime): int64 proc getStartMilsecs*(): int ## get the miliseconds from the start of the program -#implementation -# C wrapper: -type - structTM {.importc: "struct tm".} = record - second {.importc: "tm_sec".}, - minute {.importc: "tm_min".}, - hour {.importc: "tm_hour".}, - monthday {.importc: "tm_mday".}, - month {.importc: "tm_mon".}, - year {.importc: "tm_year".}, - weekday {.importc: "tm_wday".}, - yearday {.importc: "tm_yday".}, - isdst {.importc: "tm_isdst".}: cint - - PTimeInfo = ptr structTM - PTime = ptr TTime - - TClock {.importc: "clock_t".} = range[low(int)..high(int)] - -proc localtime(timer: PTime): PTimeInfo {. - importc: "localtime", header: "<time.h>".} -proc gmtime(timer: PTime): PTimeInfo {.importc: "gmtime", header: "<time.h>".} -proc timec(timer: PTime): TTime {.importc: "time", header: "<time.h>".} -proc mktime(t: structTM): TTime {.importc: "mktime", header: "<time.h>".} -proc asctime(tblock: structTM): CString {. - importc: "asctime", header: "<time.h>".} -proc ctime(time: PTime): CString {.importc: "ctime", header: "<time.h>".} -# strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {. -# importc: "strftime", header: "<time.h>".} -proc clock(): TClock {.importc: "clock", header: "<time.h>".} -proc difftime(a, b: TTime): float {.importc: "difftime", header: "<time.h>".} - -var - clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int - - -# our own procs on top of that: -proc tmToTimeInfo(tm: structTM): TTimeInfo = +when not defined(ECMAScript): + + # C wrapper: + type + structTM {.importc: "struct tm", final.} = object + second {.importc: "tm_sec".}, + minute {.importc: "tm_min".}, + hour {.importc: "tm_hour".}, + monthday {.importc: "tm_mday".}, + month {.importc: "tm_mon".}, + year {.importc: "tm_year".}, + weekday {.importc: "tm_wday".}, + yearday {.importc: "tm_yday".}, + isdst {.importc: "tm_isdst".}: cint + + PTimeInfo = ptr structTM + PTime = ptr TTime + + TClock {.importc: "clock_t".} = range[low(int)..high(int)] + + proc localtime(timer: PTime): PTimeInfo {. + importc: "localtime", header: "<time.h>".} + proc gmtime(timer: PTime): PTimeInfo {.importc: "gmtime", header: "<time.h>".} + proc timec(timer: PTime): TTime {.importc: "time", header: "<time.h>".} + proc mktime(t: structTM): TTime {.importc: "mktime", header: "<time.h>".} + proc asctime(tblock: structTM): CString {. + importc: "asctime", header: "<time.h>".} + proc ctime(time: PTime): CString {.importc: "ctime", header: "<time.h>".} + # strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {. + # importc: "strftime", header: "<time.h>".} + proc clock(): TClock {.importc: "clock", header: "<time.h>".} + proc difftime(a, b: TTime): float {.importc: "difftime", header: "<time.h>".} + + var + clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int + + + # our own procs on top of that: + proc tmToTimeInfo(tm: structTM): TTimeInfo = + const + weekDays: array [0..6, TWeekDay] = [ + dSun, dMon, dTue, dWed, dThu, dFri, dSat] + result.second = int(tm.second) + result.minute = int(tm.minute) + result.hour = int(tm.hour) + result.monthday = int(tm.monthday) + result.month = TMonth(tm.month) + result.year = tm.year + 1900 + result.weekday = weekDays[int(tm.weekDay)] + result.yearday = int(tm.yearday) + + proc timeInfoToTM(t: TTimeInfo): structTM = + const + weekDays: array [TWeekDay, int] = [1, 2, 3, 4, 5, 6, 0] + result.second = t.second + result.minute = t.minute + result.hour = t.hour + result.monthday = t.monthday + result.month = ord(t.month) + result.year = t.year - 1900 + result.weekday = weekDays[t.weekDay] + result.yearday = t.yearday + result.isdst = -1 + + proc `-` (a, b: TTime): int64 = + return toInt(difftime(a, b)) # XXX: toBiggestInt is needed here, but + # Nim does not support it! + + proc getStartMilsecs(): int = return clock() div (clocksPerSec div 1000) + proc getTime(): TTime = return timec(nil) + proc getLocalTime(t: TTime): TTimeInfo = + var a = t + result = tmToTimeInfo(localtime(addr(a))^) + # copying is needed anyway to provide reentrancity; thus + # the convertion is not expensive + + proc getGMTime(t: TTime): TTimeInfo = + var a = t + result = tmToTimeInfo(gmtime(addr(a))^) + # copying is needed anyway to provide reentrancity; thus + # the convertion is not expensive + + proc TimeInfoToTime(timeInfo: TTimeInfo): TTime = + var cTimeInfo = timeInfo # for C++ we have to make a copy, + # because the header of mktime is broken in my version of libc + return mktime(timeInfoToTM(cTimeInfo)) + + proc `$`(timeInfo: TTimeInfo): string = + return $asctime(timeInfoToTM(timeInfo)) + + proc `$`(time: TTime): string = + var a = time + return $ctime(addr(a)) + +else: + proc getTime(): TTime {.importc: "new Date", nodecl.} + const weekDays: array [0..6, TWeekDay] = [ dSun, dMon, dTue, dWed, dThu, dFri, dSat] - result.second = int(tm.second) - result.minute = int(tm.minute) - result.hour = int(tm.hour) - result.monthday = int(tm.monthday) - result.month = TMonth(tm.month) - result.year = tm.year + 1900 - result.weekday = weekDays[int(tm.weekDay)] - result.yearday = int(tm.yearday) - -proc timeInfoToTM(t: TTimeInfo): structTM = - const - weekDays: array [TWeekDay, int] = [1, 2, 3, 4, 5, 6, 0] - result.second = t.second - result.minute = t.minute - result.hour = t.hour - result.monthday = t.monthday - result.month = ord(t.month) - result.year = t.year - 1900 - result.weekday = weekDays[t.weekDay] - result.yearday = t.yearday - result.isdst = -1 - -proc `-` (a, b: TTime): int64 = - return toInt(difftime(a, b)) # XXX: toBiggestInt is needed here, but - # Nim does not support it! - -proc getStartMilsecs(): int = return clock() div (clocksPerSec div 1000) -proc getTime(): TTime = return timec(nil) -proc getLocalTime(t: TTime): TTimeInfo = - var a = t - result = tmToTimeInfo(localtime(addr(a))^) - # copying is needed anyway to provide reentrancity; thus - # the convertion is not expensive - -proc getGMTime(t: TTime): TTimeInfo = - var a = t - result = tmToTimeInfo(gmtime(addr(a))^) - # copying is needed anyway to provide reentrancity; thus - # the convertion is not expensive - -proc TimeInfoToTime(timeInfo: TTimeInfo): TTime = - var cTimeInfo = timeInfo # for C++ we have to make a copy, - # because the header of mktime is broken in my version of libc - return mktime(timeInfoToTM(cTimeInfo)) + + proc getLocalTime(t: TTime): TTimeInfo = + result.second = t.getSeconds() + result.minute = t.getMinutes() + result.hour = t.getHours() + result.monthday = t.getDate() + result.month = TMonth(t.getMonth()) + result.year = t.getFullYear() + result.weekday = weekDays[t.getDay()] + result.yearday = 0 + + proc getGMTime(t: TTime): TTimeInfo = + result.second = t.getUTCSeconds() + result.minute = t.getUTCMinutes() + result.hour = t.getUTCHours() + result.monthday = t.getUTCDate() + result.month = TMonth(t.getUTCMonth()) + result.year = t.getUTCFullYear() + result.weekday = weekDays[t.getDay()] + result.yearday = 0 + + proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime = + result = getTime() + result.setSeconds(timeInfo.second) + result.setMinutes(timeInfo.minute) + result.setHours(timeInfo.hour) + result.setMonth(ord(timeInfo.month)) + result.setFullYear(timeInfo.year) + result.setDate(timeInfo.monthday) + + proc `$`(timeInfo: TTimeInfo): string = return $(TimeInfoToTIme(timeInfo)) + proc `$`(time: TTime): string = $time.toLocaleString() + + proc `-` (a, b: TTime): int64 = + return a.getTime() - b.getTime() + + var + startMilsecs = getTime() + + proc getStartMilsecs(): int = + ## get the miliseconds from the start of the program + return int(getTime() - startMilsecs) proc getDateStr(): string = var ti = getLocalTime(getTime()) @@ -169,11 +268,4 @@ proc getClockStr(): string = result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) & ':' & intToStr(ti.second, 2) -proc `$`(timeInfo: TTimeInfo): string = - return $asctime(timeInfoToTM(timeInfo)) - -proc `$`(time: TTime): string = - var a = time - return $ctime(addr(a)) - {.pop.} diff --git a/lib/typeinfo.nim b/lib/typeinfo.nim deleted file mode 100644 index b4d8f8f3a..000000000 --- a/lib/typeinfo.nim +++ /dev/null @@ -1,221 +0,0 @@ -# -# -# Nimrod's Runtime Library -# (c) Copyright 2006 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# type-info module for Nimrod - -include hti - -proc typeid(x: any): PNimType - -type - Variant = opaque record - # contains the address and a typeinfo - a: pointer # an address - k: TNimTypeKind - -# conversions to any and from any are inserted by the compiler! -# x.attr is supported, as well as x[]! -# here is a special iterator for variants: -iterator fields(x: variant): (fieldname: string, value: variant) = -proc setField(structure: variant, fieldname: string, value: variant) -proc getField(structure: variant, fieldname: string) - -# any is implemented as a pair (val: pointer, info: PTypeInfo) -# val is for: -# an array - its address -# a record - its address -# an object - its address -# a string - the address of the pointer to the string data -# a sequence - the address of the pointer to the sequence data -# a float - the address of a memory location where the float is stored -# this is a given address; storage comes from compiler or is -# already there (in a container) -# an int - the address of a memory location where the int is stored -# storage comes from compiler or is -# already there (in a container) -# a cstring - the address of an address of an array of chars -# a ref - the address of the ref! (not the ref itself!) - -# But this does not work too well... -# Better: any is a ref to Object; than we define intObj, floatObj, -# etc.; for strings this not needed as they already fit into the -# scheme! -# - -type - TAnyImpl {.exportc: "TAnyImpl".} = record - typ {.exportc: "info".}: PNimType - val {.exportc: "val".}: pointer - -proc - typeKind(p: PNimType): TTypeKind {.inline.} - - getAnyLength(x: any): int - - isContainer(x: any): bool - - writeAny(container: any, index: int, val: any) - readAny(container: any, index: int): any - - writeAny(container: any, name: string, val: any) - readAny(container: any, name: string): any - - getAttr(container: any, index: int, out name: string, out val: any) - - getEnumStrings(enumeration: any): sequence of string - - anyToInt(x: any): biggestint - anyToFloat(x: any): biggestfloat - anyToString(x: any): string - anyToChar(x: any): char - anyToBool(x: any): bool - #anyToT{T}(x: any, out result: T) - - # etc... - - #write(a: array of any) # also possible! - -#generic proc -# deepCopy{T}(x: T): T - -import - strutils - -proc anyToImpl(a: any): TAnyImpl {.inline.} = - result = cast{TAnyImpl}(a) - -proc typeKind(p: PNimType): TTypeKind = - result = p.typeKind - -type - Pint = untraced ref int - Pint8 = untraced ref int8 - Pint16 = untraced ref int16 - Pint32 = untraced ref int32 - Pint64 = untraced ref int64 - Puint = untraced ref uint - Puint8 = untraced ref uint8 - Puint16 = untraced ref uint16 - Puint32 = untraced ref uint32 - Puint64 = untraced ref uint64 - Pfloat = untraced ref float - Pfloat32 = untraced ref float32 - Pfloat64 = untraced ref float64 - Pstring = untraced ref string - Pbool = untraced ref bool - Pchar = untraced ref char - -proc anyToInt(x: any): biggestint = - var impl = anyToImpl(x) - case impl.typ.typeKind - of tyInt, tyEnum: result = cast{pint}(x.val)^ - of tySInt8: result = cast{pint8}(x.val)^ - of tySInt16: result = cast{pint16}(x.val)^ - of tySInt32: result = cast{pint32}(x.val)^ - of tySInt64: result = cast{pint64}(x.val)^ - of tyUInt: result = cast{puint}(x.val)^ - of tyUInt8: result = cast{puint8}(x.val)^ - of tyUInt16: result = cast{puint16}(x.val)^ - of tyUInt32: result = cast{puint32}(x.val)^ - of tyUInt64: result = cast{puint64}(x.val)^ - else: raise EConvertError - -proc anyToFloat(x: any): biggestfloat = - var impl = anyToImpl(x) - case impl.typ.typeKind - of tyReal: result = cast{pfloat}(x.val)^ - of tyReal32: result = cast{pfloat32}(x.val)^ - of tyReal64: result = cast{pfloat64}(x.val)^ - # of tyReal128: - else: raise EConvertError - -proc anyToString(x: any): string = - var impl = anyToImpl(x) - case impl.typ.typeKind - of tyString: result = cast{pstring}(x.val)^ - else: raise EConvertError - -proc anyToChar(x: any): char = - var impl = anyToImpl(x) - case impl.typ.typeKind - of tyChar: result = cast{pchar}(x.val)^ - else: raise EConvertError - -proc anyToBool(x: any): bool = - var impl = anyToImpl(x) - case impl.typ.typeKind - of tyBool: result = cast{pbool}(x.val)^ - else: raise EConvertError - -proc getAnyLength(x: any): int = - result = anyToImpl(x).typ.len - -const - ContainerSet = {tyArray, tyRecord, tyObject, tyOpenArray, tySequence, tyTable} - -proc isContainer(x: any): bool = - result = anyToImpl(x).typ.typeKind in ContainerSet - -proc strcmp(a, b: cstring): int {.external: "strcmp", nodecl.} - -proc strToIndex(info: PTypeInfo, str: string): int = - for i in 0..typ.len-1: - if strcmp(info.slots[i].name, str) == 0: - return i - raise EConvertError - -proc writeAny(container: any, index: int, val: any) = - var x = anyToImpl(container) - if index >= 0 and index < container.len: - case x.typ.typeKind - of tySequence: - var u = cast{TAddress}(x.val) - genericAssignAux(cast{pointer}(u) +% x.typ.slots[index].offset +% - GenericSeqSize, - anyToImpl(val).val, u.typ.baseType) - of tyArray: - of tyRecord, tyObject: - else: raise EConvertError - else: - raise EIndexError - - -proc readAny(container: any, index: int): any = - var x = anyToImpl(container) - if x.typ.typeKind in ContainerSet: - if index >= 0 and index < container.len: - # XXX - - else: - raise EIndexError - else: - raise EConvertError - -proc writeAny(container: any, name: string, val: any) = - result = writeAny(container, strToIndex(anyToImpl(container).typ), val) - -proc readAny(container: any, name: string): any = - result = readAny(container, strToIndex(anyToImpl(container).typ)) - -proc getAttr(container: any, index: int, out name: string, out val: any) = - var x = anyToImpl(container) - if x.typ.typeKind in ContainerSet: - val = readAny(container, index) - name = $x.typ.slots[index].name - else: - raise EConvertError - -proc getEnumStrings(enumeration: any): sequence of string = - result = [] - var x = anyToImpl(enumeration) - if x.typ.typekind == tyEnum: - for i in 0 .. x.typ.len-1: - result &= $x.typ.slots[i].name - else: - raise EConvertError diff --git a/lib/windows/mmsystem.nim b/lib/windows/mmsystem.nim index b18ae2be4..a44e4dfca 100644 --- a/lib/windows/mmsystem.nim +++ b/lib/windows/mmsystem.nim @@ -980,7 +980,7 @@ const #///////////////////////////////////////////////////////// type - mmtime* = record + mmtime* {.final.} = object wType*: UINT hour*, min*, sec*, frame*, fps*, dummy*: int8 pad*: array[0..1, int8] @@ -990,7 +990,7 @@ type LPMMTIME* = ptr mmtime PWAVEHDR* = ptr wavehdr TMMTime* = mmtime - wavehdr* = record + wavehdr* {.final.} = object lpData*: cstring dwBufferLength*: DWORD dwBytesRecorded*: DWORD @@ -1003,7 +1003,7 @@ type TWAVEHDR* = WAVEHDR NPWAVEHDR* = ptr wavehdr LPWAVEHDR* = ptr wavehdr - WAVEOUTCAPSA* = record + WAVEOUTCAPSA* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION @@ -1017,7 +1017,7 @@ type PWAVEOUTCAPSA* = ptr WAVEOUTCAPSA NPWAVEOUTCAPSA* = ptr WAVEOUTCAPSA LPWAVEOUTCAPSA* = ptr WAVEOUTCAPSA - WAVEOUTCAPSW* = record + WAVEOUTCAPSW* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION @@ -1046,7 +1046,7 @@ else: LPWAVEOUTCAPS* = LPWAVEOUTCAPSA type TWAVEOUTCAPS* = WAVEOUTCAPS - WAVEINCAPSA* = record + WAVEINCAPSA* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION @@ -1059,7 +1059,7 @@ type NPWAVEINCAPSA* = ptr WAVEINCAPSA LPWAVEINCAPSA* = ptr WAVEINCAPSA TWAVEINCAPSA* = WAVEINCAPSA - WAVEINCAPSW* = record + WAVEINCAPSW* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION @@ -1087,7 +1087,7 @@ else: LPWAVEINCAPS* = LPWAVEINCAPSA type TWAVEINCAPS* = WAVEINCAPS - waveformat* = record + waveformat* {.final.} = object wFormatTag*: int16 nChannels*: int16 nSamplesPerSec*: DWORD @@ -1103,7 +1103,7 @@ const WAVE_FORMAT_PCM* = 1 type - pcmwaveformat* = record + pcmwaveformat* {.final.} = object wf*: WAVEFORMAT wBitsPerSample*: int16 @@ -1111,7 +1111,7 @@ type NPPCMWAVEFORMAT* = ptr pcmwaveformat LPPCMWAVEFORMAT* = ptr pcmwaveformat TPCMWAVEFORMAT* = PCMWAVEFORMAT - WAVEFORMATEX* = record + WAVEFORMATEX* {.final.} = object wFormatTag*: int16 nChannels*: int16 nSamplesPerSec*: DWORD @@ -1143,7 +1143,7 @@ type LPPATCHARRAY* = ptr int16 KEYARRAY* = array[0..Pred(MIDIPATCHSIZE), int16] LPKEYARRAY* = ptr int16 - MIDIOUTCAPSA* = record + MIDIOUTCAPSA* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION @@ -1158,7 +1158,7 @@ type NPMIDIOUTCAPSA* = ptr MIDIOUTCAPSA LPMIDIOUTCAPSA* = ptr MIDIOUTCAPSA TMIDIOUTCAPSA* = MIDIOUTCAPSA - MIDIOUTCAPSW* = record + MIDIOUTCAPSW* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION @@ -1173,7 +1173,7 @@ type NPMIDIOUTCAPSW* = ptr MIDIOUTCAPSW LPMIDIOUTCAPSW* = ptr MIDIOUTCAPSW TMIDIOUTCAPSW* = MIDIOUTCAPSW - MIDIINCAPSA* = record + MIDIINCAPSA* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION @@ -1184,7 +1184,7 @@ type NPMIDIINCAPSA* = ptr MIDIINCAPSA LPMIDIINCAPSA* = ptr MIDIINCAPSA TMIDIINCAPSA* = MIDIINCAPSA - MIDIINCAPSW* = record + MIDIINCAPSW* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION @@ -1219,7 +1219,7 @@ else: type TMIDIINCAPS* = MIDIINCAPS PMIDIHDR* = ptr midihdr - midihdr* = record + midihdr* {.final.} = object lpData*: cstring dwBufferLength*: DWORD dwBytesRecorded*: DWORD @@ -1233,30 +1233,30 @@ type NPMIDIHDR* = ptr midihdr LPMIDIHDR* = ptr midihdr TMIDIHDR* = MIDIHDR - midievent* = record + midievent* {.final.} = object dwDeltaTime*: DWORD dwStreamID*: DWORD dwEvent*: DWORD dwParms*: array[0..Pred(1), DWORD] TMIDIEVENT* = MIDIEVENT - midistrmbuffver* = record + midistrmbuffver* {.final.} = object dwVersion*: DWORD dwMid*: DWORD dwOEMVersion*: DWORD TMIDISTRMBUFFVER* = MIDISTRMBUFFVER - Tmidiproptimediv* = record + Tmidiproptimediv* {.final.} = object cbStruct*: DWORD dwTimeDiv*: DWORD LPMIDIPROPTIMEDIV* = ptr Tmidiproptimediv - Tmidiproptempo* = record + Tmidiproptempo* {.final.} = object cbStruct*: DWORD dwTempo*: DWORD LPMIDIPROPTEMPO* = ptr Tmidiproptempo - AUXCAPSA* = record + AUXCAPSA* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION @@ -1269,7 +1269,7 @@ type NPAUXCAPSA* = ptr AUXCAPSA LPAUXCAPSA* = ptr AUXCAPSA TAUXCAPSA* = AUXCAPSA - AUXCAPSW* = record + AUXCAPSW* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION @@ -1305,7 +1305,7 @@ type proc mixerGetNumDevs*(): UINT{.stdcall, dynlib: "winmm.dll", importc: "mixerGetNumDevs".} type - MIXERCAPSA* = record + MIXERCAPSA* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION @@ -1316,7 +1316,7 @@ type PMIXERCAPSA* = ptr MIXERCAPSA LPMIXERCAPSA* = ptr MIXERCAPSA TMIXERCAPSA* = MIXERCAPSA - MIXERCAPSW* = record + MIXERCAPSW* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION @@ -1340,7 +1340,7 @@ else: LPMIXERCAPS* = LPMIXERCAPSA type TMIXERCAPS* = MIXERCAPS - MIXERLINEA* = record + MIXERLINEA* {.final.} = object cbStruct*: DWORD dwDestination*: DWORD dwSource*: DWORD @@ -1361,7 +1361,7 @@ type PMIXERLINEA* = ptr MIXERLINEA LPMIXERLINEA* = ptr MIXERLINEA TMIXERLINEA* = MIXERLINEA - MIXERLINEW* = record + MIXERLINEW* {.final.} = object cbStruct*: DWORD dwDestination*: DWORD dwSource*: DWORD @@ -1395,7 +1395,7 @@ else: LPMIXERLINE* = LPMIXERLINEA type TMIXERLINE* = MIXERLINE - MIXERCONTROLA* = record + MIXERCONTROLA* {.final.} = object cbStruct*: DWORD dwControlID*: DWORD dwControlType*: DWORD @@ -1411,7 +1411,7 @@ type PMIXERCONTROLA* = ptr MIXERCONTROLA LPMIXERCONTROLA* = ptr MIXERCONTROLA TMIXERCONTROLA* = MIXERCONTROLA - MIXERCONTROLW* = record + MIXERCONTROLW* {.final.} = object cbStruct*: DWORD dwControlID*: DWORD dwControlType*: DWORD @@ -1440,7 +1440,7 @@ else: LPMIXERCONTROL* = LPMIXERCONTROLA type TMIXERCONTROL* = MIXERCONTROL - MIXERLINECONTROLSA* = record + MIXERLINECONTROLSA* {.final.} = object cbStruct*: DWORD dwLineID*: DWORD dwControlType*, cControls*, cbmxctrl*: DWORD @@ -1449,7 +1449,7 @@ type PMIXERLINECONTROLSA* = ptr MIXERLINECONTROLSA LPMIXERLINECONTROLSA* = ptr MIXERLINECONTROLSA TMIXERLINECONTROLSA* = MIXERLINECONTROLSA - MIXERLINECONTROLSW* = record + MIXERLINECONTROLSW* {.final.} = object cbStruct*: DWORD dwLineID*: DWORD dwControlType*, cControls*, cbmxctrl*: DWORD @@ -1471,7 +1471,7 @@ else: LPMIXERLINECONTROLS* = LPMIXERLINECONTROLSA type TMIXERLINECONTROLS* = MIXERLINECONTROLS - TMIXERCONTROLDETAILS* = record + TMIXERCONTROLDETAILS* {.final.} = object cbStruct*: DWORD dwControlID*: DWORD cChannels*: DWORD @@ -1481,7 +1481,7 @@ type MIXERCONTROLDETAILS* = tMIXERCONTROLDETAILS PMIXERCONTROLDETAILS* = ptr tMIXERCONTROLDETAILS LPMIXERCONTROLDETAILS* = ptr tMIXERCONTROLDETAILS - MIXERCONTROLDETAILS_LISTTEXTA* = record + MIXERCONTROLDETAILS_LISTTEXTA* {.final.} = object dwParam1*: DWORD dwParam2*: DWORD szName*: array[0..Pred(MIXER_LONG_NAME_CHARS), CHAR] @@ -1489,7 +1489,7 @@ type PMIXERCONTROLDETAILS_LISTTEXTA* = ptr MIXERCONTROLDETAILS_LISTTEXTA LPMIXERCONTROLDETAILS_LISTTEXTA* = ptr MIXERCONTROLDETAILS_LISTTEXTA TMIXERCONTROLDETAILS_LISTTEXTA* = MIXERCONTROLDETAILS_LISTTEXTA - MIXERCONTROLDETAILS_LISTTEXTW* = record + MIXERCONTROLDETAILS_LISTTEXTW* {.final.} = object dwParam1*: DWORD dwParam2*: DWORD szName*: array[0..Pred(MIXER_LONG_NAME_CHARS), WCHAR] @@ -1510,19 +1510,19 @@ else: LPMIXERCONTROLDETAILS_LISTTEXT* = LPMIXERCONTROLDETAILS_LISTTEXTA type TMIXERCONTROLDETAILS_LISTTEXT* = MIXERCONTROLDETAILS_LISTTEXT - MIXERCONTROLDETAILS_BOOLEAN* = record + MIXERCONTROLDETAILS_BOOLEAN* {.final.} = object fValue*: int32 PMIXERCONTROLDETAILS_BOOLEAN* = ptr MIXERCONTROLDETAILS_BOOLEAN LPMIXERCONTROLDETAILS_BOOLEAN* = ptr MIXERCONTROLDETAILS_BOOLEAN TMIXERCONTROLDETAILS_BOOLEAN* = MIXERCONTROLDETAILS_BOOLEAN - MIXERCONTROLDETAILS_SIGNED* = record + MIXERCONTROLDETAILS_SIGNED* {.final.} = object lValue*: int32 PMIXERCONTROLDETAILS_SIGNED* = ptr MIXERCONTROLDETAILS_SIGNED LPMIXERCONTROLDETAILS_SIGNED* = ptr MIXERCONTROLDETAILS_SIGNED TMIXERCONTROLDETAILS_SIGNED* = MIXERCONTROLDETAILS_SIGNED - MIXERCONTROLDETAILS_UNSIGNED* = record + MIXERCONTROLDETAILS_UNSIGNED* {.final.} = object dwValue*: DWORD PMIXERCONTROLDETAILS_UNSIGNED* = ptr MIXERCONTROLDETAILS_UNSIGNED @@ -1531,7 +1531,7 @@ type LPTIMECALLBACK* = proc (uTimerID, uMsg: UINT, dwUser, dw1, dw2: DWORD){. stdcall.} TTIMECALLBACK* = LPTIMECALLBACK - timecaps* = record + timecaps* {.final.} = object wPeriodMin*: UINT wPeriodMax*: UINT @@ -1539,7 +1539,7 @@ type NPTIMECAPS* = ptr timecaps LPTIMECAPS* = ptr timecaps TTIMECAS* = TIMECAPS - JOYCAPSA* = record + JOYCAPSA* {.final.} = object wMid*: int16 wPid*: int16 szPname*: array[0..Pred(MAXPNAMELEN), CHAR] @@ -1569,7 +1569,7 @@ type NPJOYCAPSA* = ptr JOYCAPSA LPJOYCAPSA* = ptr JOYCAPSA TJOYCAPSA* = JOYCAPSA - JOYCAPSW* = record + JOYCAPSW* {.final.} = object wMid*: int16 wPid*: int16 szPname*: array[0..Pred(MAXPNAMELEN), WCHAR] @@ -1614,7 +1614,7 @@ else: LPJOYCAPS* = LPJOYCAPSA type TJOYCAPS* = JOYCAPS - joyinfo* = record + joyinfo* {.final.} = object wXpos*: UINT wYpos*: UINT wZpos*: UINT @@ -1624,7 +1624,7 @@ type NPJOYINFO* = ptr joyinfo LPJOYINFO* = ptr joyinfo TJOYINFO* = JOYINFO - joyinfoex* = record + joyinfoex* {.final.} = object dwSize*: DWORD dwFlags*: DWORD wXpos*: UINT @@ -1648,7 +1648,7 @@ type HMMIO* = THandle LPMMIOPROC* = proc (x1: LPSTR, x2: UINT, x3, x4: LPARAM): LRESULT{.stdcall.} TMMIOPROC* = LPMMIOPROC - MMIOINFO* = record + MMIOINFO* {.final.} = object dwFlags*: DWORD fccIOProc*: FOURCC pIOProc*: LPMMIOPROC @@ -1671,7 +1671,7 @@ type LPMMIOINFO* = ptr MMIOINFO LPCMMIOINFO* = ptr MMIOINFO TMMIOINFO* = MMIOINFO - MMCKINFO* = record + MMCKINFO* {.final.} = object ckid*: FOURCC cksize*: DWORD fccType*: FOURCC @@ -1687,13 +1687,13 @@ type MCIDEVICEID* = UINT YIELDPROC* = proc (mciId: MCIDEVICEID, dwYieldData: DWORD): UINT{.stdcall.} TYIELDPROC* = YIELDPROC - MCI_GENERIC_PARMS* = record + MCI_GENERIC_PARMS* {.final.} = object dwCallback*: DWORD PMCI_GENERIC_PARMS* = ptr MCI_GENERIC_PARMS LPMCI_GENERIC_PARMS* = ptr MCI_GENERIC_PARMS TMCI_GENERIC_PARMS* = MCI_GENERIC_PARMS - MCI_OPEN_PARMSA* = record + MCI_OPEN_PARMSA* {.final.} = object dwCallback*: DWORD wDeviceID*: MCIDEVICEID lpstrDeviceType*: LPCSTR @@ -1703,7 +1703,7 @@ type PMCI_OPEN_PARMSA* = ptr MCI_OPEN_PARMSA LPMCI_OPEN_PARMSA* = ptr MCI_OPEN_PARMSA TMCI_OPEN_PARMSA* = MCI_OPEN_PARMSA - MCI_OPEN_PARMSW* = record + MCI_OPEN_PARMSW* {.final.} = object dwCallback*: DWORD wDeviceID*: MCIDEVICEID lpstrDeviceType*: LPCWSTR @@ -1726,7 +1726,7 @@ else: LPMCI_OPEN_PARMS* = LPMCI_OPEN_PARMSA type TMCI_OPEN_PARMS* = MCI_OPEN_PARMS - MCI_PLAY_PARMS* = record + MCI_PLAY_PARMS* {.final.} = object dwCallback*: DWORD dwFrom*: DWORD dwTo*: DWORD @@ -1734,14 +1734,14 @@ type PMCI_PLAY_PARMS* = ptr MCI_PLAY_PARMS LPMCI_PLAY_PARMS* = ptr MCI_PLAY_PARMS TMCI_PLAY_PARMS* = MCI_PLAY_PARMS - MCI_SEEK_PARMS* = record + MCI_SEEK_PARMS* {.final.} = object dwCallback*: DWORD dwTo*: DWORD PMCI_SEEK_PARMS* = ptr MCI_SEEK_PARMS LPMCI_SEEK_PARMS* = ptr MCI_SEEK_PARMS TMCI_SEEK_PARMS* = MCI_SEEK_PARMS - MCI_STATUS_PARMS* = record + MCI_STATUS_PARMS* {.final.} = object dwCallback*: DWORD dwReturn*: DWORD dwItem*: DWORD @@ -1750,14 +1750,14 @@ type PMCI_STATUS_PARMS* = ptr MCI_STATUS_PARMS LPMCI_STATUS_PARMS* = ptr MCI_STATUS_PARMS TMCI_STATUS_PARMS* = MCI_STATUS_PARMS - MCI_INFO_PARMSA* = record + MCI_INFO_PARMSA* {.final.} = object dwCallback*: DWORD lpstrReturn*: cstring dwRetSize*: DWORD LPMCI_INFO_PARMSA* = ptr MCI_INFO_PARMSA TMCI_INFO_PARMSA* = MCI_INFO_PARMSA - MCI_INFO_PARMSW* = record + MCI_INFO_PARMSW* {.final.} = object dwCallback*: DWORD lpstrReturn*: LPWSTR dwRetSize*: DWORD @@ -1775,7 +1775,7 @@ else: LPMCI_INFO_PARMS* = LPMCI_INFO_PARMSA type TMCI_INFO_PARMS* = MCI_INFO_PARMS - MCI_GETDEVCAPS_PARMS* = record + MCI_GETDEVCAPS_PARMS* {.final.} = object dwCallback*: DWORD dwReturn*: DWORD dwItem*: DWORD @@ -1783,7 +1783,7 @@ type PMCI_GETDEVCAPS_PARMS* = ptr MCI_GETDEVCAPS_PARMS LPMCI_GETDEVCAPS_PARMS* = ptr MCI_GETDEVCAPS_PARMS TMCI_GETDEVCAPS_PARMS* = MCI_GETDEVCAPS_PARMS - MCI_SYSINFO_PARMSA* = record + MCI_SYSINFO_PARMSA* {.final.} = object dwCallback*: DWORD lpstrReturn*: cstring dwRetSize*: DWORD @@ -1793,7 +1793,7 @@ type PMCI_SYSINFO_PARMSA* = ptr MCI_SYSINFO_PARMSA LPMCI_SYSINFO_PARMSA* = ptr MCI_SYSINFO_PARMSA TMCI_SYSINFO_PARMSA* = MCI_SYSINFO_PARMSA - MCI_SYSINFO_PARMSW* = record + MCI_SYSINFO_PARMSW* {.final.} = object dwCallback*: DWORD lpstrReturn*: LPWSTR dwRetSize*: DWORD @@ -1816,7 +1816,7 @@ else: LPMCI_SYSINFO_PARMS* = LPMCI_SYSINFO_PARMSA type TMCI_SYSINFO_PARMS* = MCI_SYSINFO_PARMS - MCI_SET_PARMS* = record + MCI_SET_PARMS* {.final.} = object dwCallback*: DWORD dwTimeFormat*: DWORD dwAudio*: DWORD @@ -1824,7 +1824,7 @@ type PMCI_SET_PARMS* = ptr MCI_SET_PARMS LPMCI_SET_PARMS* = ptr MCI_SET_PARMS TMCI_SET_PARMS* = MCI_SET_PARMS - MCI_BREAK_PARMS* = record + MCI_BREAK_PARMS* {.final.} = object dwCallback*: DWORD nVirtKey*: int32 hwndBreak*: HWND @@ -1832,14 +1832,14 @@ type PMCI_BREAK_PARMS* = ptr MCI_BREAK_PARMS LPMCI_BREAK_PARMS* = ptr MCI_BREAK_PARMS TMCI_BREAK_PARMS* = MCI_BREAK_PARMS - MCI_SAVE_PARMSA* = record + MCI_SAVE_PARMSA* {.final.} = object dwCallback*: DWORD lpfilename*: LPCSTR PMCI_SAVE_PARMSA* = ptr MCI_SAVE_PARMSA LPMCI_SAVE_PARMSA* = ptr MCI_SAVE_PARMSA TMCI_SAVE_PARMSA* = MCI_SAVE_PARMSA - MCI_SAVE_PARMSW* = record + MCI_SAVE_PARMSW* {.final.} = object dwCallback*: DWORD lpfilename*: LPCWSTR @@ -1859,14 +1859,14 @@ else: LPMCI_SAVE_PARMS* = LPMCI_SAVE_PARMSA type TMCI_SAVE_PARMS* = MCI_SAVE_PARMS - MCI_LOAD_PARMSA* = record + MCI_LOAD_PARMSA* {.final.} = object dwCallback*: DWORD lpfilename*: LPCSTR PMCI_LOAD_PARMSA* = ptr MCI_LOAD_PARMSA LPMCI_LOAD_PARMSA* = ptr MCI_LOAD_PARMSA TMCI_LOAD_PARMSA* = MCI_LOAD_PARMSA - MCI_LOAD_PARMSW* = record + MCI_LOAD_PARMSW* {.final.} = object dwCallback*: DWORD lpfilename*: LPCWSTR @@ -1886,14 +1886,14 @@ else: LPMCI_LOAD_PARMS* = LPMCI_LOAD_PARMSA type TMCI_LOAD_PARMS* = MCI_LOAD_PARMS - MCI_RECORD_PARMS* = record + MCI_RECORD_PARMS* {.final.} = object dwCallback*: DWORD dwFrom*: DWORD dwTo*: DWORD LPMCI_RECORD_PARMS* = ptr MCI_RECORD_PARMS TMCI_RECORD_PARMS* = MCI_RECORD_PARMS - MCI_VD_PLAY_PARMS* = record + MCI_VD_PLAY_PARMS* {.final.} = object dwCallback*: DWORD dwFrom*: DWORD dwTo*: DWORD @@ -1902,20 +1902,20 @@ type PMCI_VD_PLAY_PARMS* = ptr MCI_VD_PLAY_PARMS LPMCI_VD_PLAY_PARMS* = ptr MCI_VD_PLAY_PARMS TMCI_VD_PLAY_PARMS* = MCI_VD_PLAY_PARMS - MCI_VD_STEP_PARMS* = record + MCI_VD_STEP_PARMS* {.final.} = object dwCallback*: DWORD dwFrames*: DWORD PMCI_VD_STEP_PARMS* = ptr MCI_VD_STEP_PARMS LPMCI_VD_STEP_PARMS* = ptr MCI_VD_STEP_PARMS - MCI_VD_ESCAPE_PARMSA* = record + MCI_VD_ESCAPE_PARMSA* {.final.} = object dwCallback*: DWORD lpstrCommand*: LPCSTR PMCI_VD_ESCAPE_PARMSA* = ptr MCI_VD_ESCAPE_PARMSA LPMCI_VD_ESCAPE_PARMSA* = ptr MCI_VD_ESCAPE_PARMSA TMCI_VD_ESCAPE_PARMSA* = MCI_VD_ESCAPE_PARMSA - MCI_VD_ESCAPE_PARMSW* = record + MCI_VD_ESCAPE_PARMSW* {.final.} = object dwCallback*: DWORD lpstrCommand*: LPCWSTR @@ -1935,7 +1935,7 @@ else: LPMCI_VD_ESCAPE_PARMS* = LPMCI_VD_ESCAPE_PARMSA type TMCI_VD_ESCAPE_PARMS* = MCI_VD_ESCAPE_PARMS - MCI_WAVE_OPEN_PARMSA* = record + MCI_WAVE_OPEN_PARMSA* {.final.} = object dwCallback*: DWORD wDeviceID*: MCIDEVICEID lpstrDeviceType*: LPCSTR @@ -1946,7 +1946,7 @@ type PMCI_WAVE_OPEN_PARMSA* = ptr MCI_WAVE_OPEN_PARMSA LPMCI_WAVE_OPEN_PARMSA* = ptr MCI_WAVE_OPEN_PARMSA TMCI_WAVE_OPEN_PARMSA* = MCI_WAVE_OPEN_PARMSA - MCI_WAVE_OPEN_PARMSW* = record + MCI_WAVE_OPEN_PARMSW* {.final.} = object dwCallback*: DWORD wDeviceID*: MCIDEVICEID lpstrDeviceType*: LPCWSTR @@ -1970,7 +1970,7 @@ else: LPMCI_WAVE_OPEN_PARMS* = LPMCI_WAVE_OPEN_PARMSA type TMCI_WAVE_OPEN_PARMS* = MCI_WAVE_OPEN_PARMS - MCI_WAVE_DELETE_PARMS* = record + MCI_WAVE_DELETE_PARMS* {.final.} = object dwCallback*: DWORD dwFrom*: DWORD dwTo*: DWORD @@ -1978,7 +1978,7 @@ type PMCI_WAVE_DELETE_PARMS* = ptr MCI_WAVE_DELETE_PARMS LPMCI_WAVE_DELETE_PARMS* = ptr MCI_WAVE_DELETE_PARMS TMCI_WAVE_DELETE_PARMS* = MCI_WAVE_DELETE_PARMS - MCI_WAVE_SET_PARMS* = record + MCI_WAVE_SET_PARMS* {.final.} = object dwCallback*: DWORD dwTimeFormat*: DWORD dwAudio*: DWORD @@ -1998,7 +1998,7 @@ type PMCI_WAVE_SET_PARMS* = ptr MCI_WAVE_SET_PARMS LPMCI_WAVE_SET_PARMS* = ptr MCI_WAVE_SET_PARMS TMCI_WAVE_SET_PARMS* = MCI_WAVE_SET_PARMS - MCI_SEQ_SET_PARMS* = record + MCI_SEQ_SET_PARMS* {.final.} = object dwCallback*: DWORD dwTimeFormat*: DWORD dwAudio*: DWORD @@ -2011,7 +2011,7 @@ type PMCI_SEQ_SET_PARMS* = ptr MCI_SEQ_SET_PARMS LPMCI_SEQ_SET_PARMS* = ptr MCI_SEQ_SET_PARMS TMCI_SEQ_SET_PARMS* = MCI_SEQ_SET_PARMS - MCI_ANIM_OPEN_PARMSA* = record + MCI_ANIM_OPEN_PARMSA* {.final.} = object dwCallback*: DWORD wDeviceID*: MCIDEVICEID lpstrDeviceType*: LPCSTR @@ -2023,7 +2023,7 @@ type PMCI_ANIM_OPEN_PARMSA* = ptr MCI_ANIM_OPEN_PARMSA LPMCI_ANIM_OPEN_PARMSA* = ptr MCI_ANIM_OPEN_PARMSA TMCI_ANIM_OPEN_PARMSA* = MCI_ANIM_OPEN_PARMSA - MCI_ANIM_OPEN_PARMSW* = record + MCI_ANIM_OPEN_PARMSW* {.final.} = object dwCallback*: DWORD wDeviceID*: MCIDEVICEID lpstrDeviceType*: LPCWSTR @@ -2047,7 +2047,7 @@ else: LPMCI_ANIM_OPEN_PARMS* = LPMCI_ANIM_OPEN_PARMSA type TMCI_ANIM_OPEN_PARMS* = MCI_ANIM_OPEN_PARMS - MCI_ANIM_WINDOW_PARMSW* = record + MCI_ANIM_WINDOW_PARMSW* {.final.} = object dwCallback*: DWORD hWnd*: HWND nCmdShow*: UINT @@ -2056,14 +2056,14 @@ type PMCI_ANIM_WINDOW_PARMSW* = ptr MCI_ANIM_WINDOW_PARMSW LPMCI_ANIM_WINDOW_PARMSW* = ptr MCI_ANIM_WINDOW_PARMSW TMCI_ANIM_WINDOW_PARMSW* = MCI_ANIM_WINDOW_PARMSW - MCI_ANIM_STEP_PARMS* = record + MCI_ANIM_STEP_PARMS* {.final.} = object dwCallback*: DWORD dwFrames*: DWORD PMCI_ANIM_STEP_PARMS* = ptr MCI_ANIM_STEP_PARMS LPMCI_ANIM_STEP_PARMS* = ptr MCI_ANIM_STEP_PARMS TMCI_ANIM_STEP_PARMS* = MCI_ANIM_STEP_PARMS - MCI_ANIM_WINDOW_PARMSA* = record + MCI_ANIM_WINDOW_PARMSA* {.final.} = object dwCallback*: DWORD hWnd*: HWND nCmdShow*: UINT @@ -2072,7 +2072,7 @@ type PMCI_ANIM_WINDOW_PARMSA* = ptr MCI_ANIM_WINDOW_PARMSA LPMCI_ANIM_WINDOW_PARMSA* = ptr MCI_ANIM_WINDOW_PARMSA TMCI_ANIM_WINDOW_PARMSA* = MCI_ANIM_WINDOW_PARMSA - MCI_ANIM_PLAY_PARMS* = record + MCI_ANIM_PLAY_PARMS* {.final.} = object dwCallback*: DWORD dwFrom*: DWORD dwTo*: DWORD @@ -2092,14 +2092,14 @@ else: PMCI_ANIM_WINDOW_PARMS* = PMCI_ANIM_WINDOW_PARMSA LPMCI_ANIM_WINDOW_PARMS* = LPMCI_ANIM_WINDOW_PARMSA type - MCI_ANIM_RECT_PARMS* = record + MCI_ANIM_RECT_PARMS* {.final.} = object dwCallback*: DWORD rc*: TRECT PMCI_ANIM_RECT_PARMS* = ptr MCI_ANIM_RECT_PARMS LPMCI_ANIM_RECT_PARMS* = ptr MCI_ANIM_RECT_PARMS TMCI_ANIM_RECT_PARMS* = MCI_ANIM_RECT_PARMS - MCI_ANIM_UPDATE_PARMS* = record + MCI_ANIM_UPDATE_PARMS* {.final.} = object dwCallback*: DWORD rc*: TRECT hDC*: HDC @@ -2107,7 +2107,7 @@ type PMCI_ANIM_UPDATE_PARMS* = ptr MCI_ANIM_UPDATE_PARMS LPMCI_ANIM_UPDATE_PARMS* = ptr MCI_ANIM_UPDATE_PARMS TMCI_ANIM_UPDATE_PARMS* = MCI_ANIM_UPDATE_PARMS - MCI_OVLY_OPEN_PARMSA* = record + MCI_OVLY_OPEN_PARMSA* {.final.} = object dwCallback*: DWORD wDeviceID*: MCIDEVICEID lpstrDeviceType*: LPCSTR @@ -2119,7 +2119,7 @@ type PMCI_OVLY_OPEN_PARMSA* = ptr MCI_OVLY_OPEN_PARMSA LPMCI_OVLY_OPEN_PARMSA* = ptr MCI_OVLY_OPEN_PARMSA TMCI_OVLY_OPEN_PARMSA* = MCI_OVLY_OPEN_PARMSA - MCI_OVLY_OPEN_PARMSW* = record + MCI_OVLY_OPEN_PARMSW* {.final.} = object dwCallback*: DWORD wDeviceID*: MCIDEVICEID lpstrDeviceType*: LPCWSTR @@ -2144,7 +2144,7 @@ else: LPMCI_OVLY_OPEN_PARMS* = LPMCI_OVLY_OPEN_PARMSA type TMCI_OVLY_OPEN_PARMS* = MCI_OVLY_OPEN_PARMS - MCI_OVLY_WINDOW_PARMSA* = record + MCI_OVLY_WINDOW_PARMSA* {.final.} = object dwCallback*: DWORD hWnd*: HWND nCmdShow*: UINT @@ -2153,7 +2153,7 @@ type PMCI_OVLY_WINDOW_PARMSA* = ptr MCI_OVLY_WINDOW_PARMSA LPMCI_OVLY_WINDOW_PARMSA* = ptr MCI_OVLY_WINDOW_PARMSA TMCI_OVLY_WINDOW_PARMSA* = MCI_OVLY_WINDOW_PARMSA - MCI_OVLY_WINDOW_PARMSW* = record + MCI_OVLY_WINDOW_PARMSW* {.final.} = object dwCallback*: DWORD hWnd*: HWND nCmdShow*: UINT @@ -2175,14 +2175,14 @@ else: LPMCI_OVLY_WINDOW_PARMS* = LPMCI_OVLY_WINDOW_PARMSA type TMCI_OVLY_WINDOW_PARMS* = MCI_OVLY_WINDOW_PARMSW - MCI_OVLY_RECT_PARMS* = record + MCI_OVLY_RECT_PARMS* {.final.} = object dwCallback*: DWORD rc*: TRECT PMCI_OVLY_RECT_PARMS* = ptr MCI_OVLY_RECT_PARMS LPMCI_OVLY_RECT_PARMS* = ptr MCI_OVLY_RECT_PARMS TMCI_OVLY_RECT_PARMS* = MCI_OVLY_RECT_PARMS - MCI_OVLY_SAVE_PARMSA* = record + MCI_OVLY_SAVE_PARMSA* {.final.} = object dwCallback*: DWORD lpfilename*: LPCSTR rc*: TRECT @@ -2190,7 +2190,7 @@ type PMCI_OVLY_SAVE_PARMSA* = ptr MCI_OVLY_SAVE_PARMSA LPMCI_OVLY_SAVE_PARMSA* = ptr MCI_OVLY_SAVE_PARMSA TMCI_OVLY_SAVE_PARMSA* = MCI_OVLY_SAVE_PARMSA - MCI_OVLY_SAVE_PARMSW* = record + MCI_OVLY_SAVE_PARMSW* {.final.} = object dwCallback*: DWORD lpfilename*: LPCWSTR rc*: TRECT @@ -2211,7 +2211,7 @@ else: LPMCI_OVLY_SAVE_PARMS* = LPMCI_OVLY_SAVE_PARMSA type TMCI_OVLY_SAVE_PARMS* = MCI_OVLY_SAVE_PARMS - MCI_OVLY_LOAD_PARMSA* = record + MCI_OVLY_LOAD_PARMSA* {.final.} = object dwCallback*: DWORD lpfilename*: LPCSTR rc*: TRECT @@ -2219,7 +2219,7 @@ type PMCI_OVLY_LOAD_PARMSA* = ptr MCI_OVLY_LOAD_PARMSA LPMCI_OVLY_LOAD_PARMSA* = ptr MCI_OVLY_LOAD_PARMSA TMCI_OVLY_LOAD_PARMSA* = MCI_OVLY_LOAD_PARMSA - MCI_OVLY_LOAD_PARMSW* = record + MCI_OVLY_LOAD_PARMSW* {.final.} = object dwCallback*: DWORD lpfilename*: LPCWSTR rc*: TRECT diff --git a/lib/windows/nb30.nim b/lib/windows/nb30.nim index 8c61bbaf7..615488ac1 100644 --- a/lib/windows/nb30.nim +++ b/lib/windows/nb30.nim @@ -8,7 +8,7 @@ # # NetBIOS 3.0 interface unit -# This unit contains the definitions for portable NetBIOS 3.0 support. +# This module contains the definitions for portable NetBIOS 3.0 support. import # Data structure templates Windows @@ -20,8 +20,8 @@ const type # Network Control Block PNCB* = ptr TNCB TNCBPostProc* = proc (P: PNCB) - TNCB* = record # Structure returned to the NCB command NCBASTAT is ADAPTER_STATUS followed - # by an array of NAME_BUFFER structures. + TNCB* {.final.} = object # Structure returned to the NCB command NCBASTAT is ADAPTER_STATUS followed + # by an array of NAME_BUFFER structures. ncb_command*: Char # command code ncb_retcode*: Char # return code ncb_lsn*: Char # local session number @@ -42,7 +42,7 @@ type # Network Control Block # completes PAdapterStatus* = ptr TAdapterStatus - TAdapterStatus* = record + TAdapterStatus* {.final.} = object adapter_address*: array[0..5, Char] rev_major*: Char reserved0*: Char @@ -72,7 +72,7 @@ type # Network Control Block name_count*: int16 PNameBuffer* = ptr TNameBuffer - TNameBuffer* = record + TNameBuffer* {.final.} = object name*: array[0..NCBNAMSZ - 1, Char] name_num*: Char name_flags*: Char @@ -93,14 +93,14 @@ type # Structure returned to the NCB command NCBSSTAT is SESSION_HEADER followed # asterisk then an array of these structures is returned containing the # status for all names. PSessionHeader* = ptr TSessionHeader - TSessionHeader* = record + TSessionHeader* {.final.} = object sess_name*: Char num_sess*: Char rcv_dg_outstanding*: Char rcv_any_outstanding*: Char PSessionBuffer* = ptr TSessionBuffer - TSessionBuffer* = record + TSessionBuffer* {.final.} = object lsn*: Char state*: Char local_name*: array[0..NCBNAMSZ - 1, Char] @@ -121,20 +121,20 @@ type # Structure returned to the NCB command NCBENUM. # On a system containing lana's 0, 2 and 3, a structure with # length =3, lana[0]=0, lana[1]=2 and lana[2]=3 will be returned. PLanaEnum* = ptr TLanaEnum - TLanaEnum* = record # Structure returned to the NCB command NCBFINDNAME is FIND_NAME_HEADER followed - # by an array of FIND_NAME_BUFFER structures. + TLanaEnum* {.final.} = object # Structure returned to the NCB command NCBFINDNAME is FIND_NAME_HEADER followed + # by an array of FIND_NAME_BUFFER structures. len*: Char # Number of valid entries in lana[] lana*: array[0..MAX_LANA, Char] PFindNameHeader* = ptr TFindNameHeader - TFindNameHeader* = record + TFindNameHeader* {.final.} = object node_count*: int16 reserved*: Char unique_group*: Char PFindNameBuffer* = ptr TFindNameBuffer - TFindNameBuffer* = record # Structure provided with NCBACTION. The purpose of NCBACTION is to provide - # transport specific extensions to netbios. + TFindNameBuffer* {.final.} = object # Structure provided with NCBACTION. The purpose of NCBACTION is to provide + # transport specific extensions to netbios. len*: Char access_control*: Char frame_control*: Char @@ -143,7 +143,7 @@ type # Structure returned to the NCB command NCBENUM. routing_info*: array[0..17, Char] PActionHeader* = ptr TActionHeader - TActionHeader* = record + TActionHeader* {.final.} = object transport_id*: int32 action_code*: int16 reserved*: int16 diff --git a/lib/windows/shellapi.nim b/lib/windows/shellapi.nim index fbbd1999a..af6972c96 100644 --- a/lib/windows/shellapi.nim +++ b/lib/windows/shellapi.nim @@ -33,7 +33,7 @@ type DWORD_PTR* = ptr DWORD pHICON* = ptr HICON pBool* = ptr BOOL - STARTUPINFOW* = record # a guess. Omission should get fixed in Windows. + STARTUPINFOW* {.final.} = object # a guess. Omission should get fixed in Windows. cb*: DWORD lpReserved*: LPTSTR lpDesktop*: LPTSTR @@ -122,7 +122,7 @@ proc ExtractIcon*(hInst: HINST, lpszExeFileName: LPCWSTR, nIconIndex: UINT): HIC stdcall, dynlib: "shell32.dll", importc: "ExtractIconW".} # if(WINVER >= 0x0400) type # init with sizeof(DRAGINFO) - DRAGINFOA* = record + DRAGINFOA* {.final.} = object uSize*: UINT pt*: POINT fNC*: BOOL @@ -131,7 +131,7 @@ type # init with sizeof(DRAGINFO) TDRAGINFOA* = DRAGINFOA LPDRAGINFOA* = ptr DRAGINFOA # init with sizeof(DRAGINFO) - DRAGINFOW* = record + DRAGINFOW* {.final.} = object uSize*: UINT pt*: POINT fNC*: BOOL @@ -178,7 +178,7 @@ const ABE_BOTTOM* = 3 type - AppBarData* = record + AppBarData* {.final.} = object cbSize*: DWORD hWnd*: HWND uCallbackMessage*: UINT @@ -286,7 +286,7 @@ type # only used if FOF_SIMPLEPROGRESS type - SHFILEOPSTRUCTA* = record + SHFILEOPSTRUCTA* {.final.} = object hwnd*: HWND wFunc*: UINT pFrom*: LPCSTR @@ -298,7 +298,7 @@ type TSHFILEOPSTRUCTA* = SHFILEOPSTRUCTA LPSHFILEOPSTRUCTA* = ptr SHFILEOPSTRUCTA - SHFILEOPSTRUCTW* = record + SHFILEOPSTRUCTW* {.final.} = object hwnd*: HWND wFunc*: UINT pFrom*: LPCWSTR @@ -332,7 +332,7 @@ proc SHFileOperation*(lpFileOp: LPSHFILEOPSTRUCTW): int32{.stdcall, proc SHFreeNameMappings*(hNameMappings: THandle){.stdcall, dynlib: "shell32.dll", importc: "SHFreeNameMappings".} type - SHNAMEMAPPINGA* = record + SHNAMEMAPPINGA* {.final.} = object pszOldPath*: LPSTR pszNewPath*: LPSTR cchOldPath*: int32 @@ -340,7 +340,7 @@ type TSHNAMEMAPPINGA* = SHNAMEMAPPINGA LPSHNAMEMAPPINGA* = ptr SHNAMEMAPPINGA - SHNAMEMAPPINGW* = record + SHNAMEMAPPINGW* {.final.} = object pszOldPath*: LPWSTR pszNewPath*: LPWSTR cchOldPath*: int32 @@ -404,7 +404,7 @@ const # (_WIN32_IE >= 0x560) type - SHELLEXECUTEINFOA* = record + SHELLEXECUTEINFOA* {.final.} = object cbSize*: DWORD fMask*: ULONG hwnd*: HWND @@ -423,7 +423,7 @@ type TSHELLEXECUTEINFOA* = SHELLEXECUTEINFOA LPSHELLEXECUTEINFOA* = ptr SHELLEXECUTEINFOA - SHELLEXECUTEINFOW* = record + SHELLEXECUTEINFOW* {.final.} = object cbSize*: DWORD fMask*: ULONG hwnd*: HWND @@ -474,7 +474,7 @@ proc WinExecError*(HWND: hwnd, error: int32, lpstrFileName: LPCWSTR, lpstrTitle: LPCWSTR){.stdcall, dynlib: "shell32.dll", importc: "WinExecErrorW".} type - SHCREATEPROCESSINFOW* = record + SHCREATEPROCESSINFOW* {.final.} = object cbSize*: DWORD fMask*: ULONG hwnd*: HWND @@ -502,7 +502,7 @@ proc SHCreateProcessAsUserW*(pscpi: PSHCREATEPROCESSINFOW): Bool{.stdcall, # # struct for query recycle bin info type - SHQUERYRBINFO* = record + SHQUERYRBINFO* {.final.} = object cbSize*: DWORD i64Size*: int64 i64NumItems*: int64 @@ -538,7 +538,7 @@ proc SHEmptyRecycleBin*(hwnd: HWND, pszRootPath: LPCWSTR, dwFlags: DWORD): HRESU # Tray notification definitions # type - NOTIFYICONDATAA* = record + NOTIFYICONDATAA* {.final.} = object cbSize*: DWORD hWnd*: HWND uID*: UINT @@ -556,7 +556,7 @@ type TNOTIFYICONDATAA* = NOTIFYICONDATAA PNOTIFYICONDATAA* = ptr NOTIFYICONDATAA - NOTIFYICONDATAW* = record + NOTIFYICONDATAW* {.final.} = object cbSize*: DWORD hWnd*: HWND uID*: UINT @@ -645,7 +645,7 @@ proc Shell_NotifyIcon*(dwMessage: Dword, lpData: PNOTIFYICONDATAW): Bool{. # out: display name (or path) # out: type name type - SHFILEINFOA* = record + SHFILEINFOA* {.final.} = object hIcon*: HICON # out: icon iIcon*: int32 # out: icon index dwAttributes*: DWORD # out: SFGAO_ flags @@ -654,7 +654,7 @@ type TSHFILEINFOA* = SHFILEINFOA pSHFILEINFOA* = ptr SHFILEINFOA - SHFILEINFOW* = record + SHFILEINFOW* {.final.} = object hIcon*: HICON # out: icon iIcon*: int32 # out: icon index dwAttributes*: DWORD # out: SFGAO_ flags diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim index 409977e7a..ab87bbd98 100644 --- a/lib/windows/windows.nim +++ b/lib/windows/windows.nim @@ -5030,7 +5030,7 @@ const # added manually PM, TREEITEM is not defined in the C headers type - TREEITEM* = record + TREEITEM* {.final.} = object HTREEITEM* = ptr TREEITEM TTREEITEM* = TREEITEM PTREEITEM* = ptr TREEITEM # was #define dname def_expr @@ -6481,7 +6481,7 @@ type # WARNING # va_list is just a dummy record # MvdV: Nevertheless it should be a pointer type, not a record va_list* = cstring - ABC* = record + ABC* {.final.} = object abcA*: int32 abcB*: UINT abcC*: int32 @@ -6489,7 +6489,7 @@ type # WARNING LPABC* = ptr ABC TABC* = ABC PABC* = ptr ABC - ABCFLOAT* = record + ABCFLOAT* {.final.} = object abcfA*: float32 abcfB*: float32 abcfC*: float32 @@ -6497,7 +6497,7 @@ type # WARNING LPABCFLOAT* = ptr ABCFLOAT TABCFLOAT* = ABCFLOAT PABCFLOAT* = ptr ABCFLOAT - ACCEL* = record + ACCEL* {.final.} = object fVirt*: int8 key*: int16 cmd*: int16 @@ -6505,7 +6505,7 @@ type # WARNING LPACCEL* = ptr ACCEL TACCEL* = ACCEL PACCEL* = ptr ACCEL - ACE_HEADER* = record + ACE_HEADER* {.final.} = object AceType*: int8 AceFlags*: int8 AceSize*: int16 @@ -6514,27 +6514,27 @@ type # WARNING PACE_HEADER* = ptr ACE_HEADER ACCESS_MASK* = DWORD REGSAM* = ACCESS_MASK - ACCESS_ALLOWED_ACE* = record + ACCESS_ALLOWED_ACE* {.final.} = object Header*: ACE_HEADER Mask*: ACCESS_MASK SidStart*: DWORD TACCESS_ALLOWED_ACE* = ACCESS_ALLOWED_ACE PACCESS_ALLOWED_ACE* = ptr ACCESS_ALLOWED_ACE - ACCESS_DENIED_ACE* = record + ACCESS_DENIED_ACE* {.final.} = object Header*: ACE_HEADER Mask*: ACCESS_MASK SidStart*: DWORD TACCESS_DENIED_ACE* = ACCESS_DENIED_ACE - ACCESSTIMEOUT* = record + ACCESSTIMEOUT* {.final.} = object cbSize*: UINT dwFlags*: DWORD iTimeOutMSec*: DWORD TACCESSTIMEOUT* = ACCESSTIMEOUT PACCESSTIMEOUT* = ptr ACCESSTIMEOUT - ACL* = record + ACL* {.final.} = object AclRevision*: int8 Sbz1*: int8 AclSize*: int16 @@ -6543,23 +6543,23 @@ type # WARNING PACL* = ptr ACL TACL* = ACL - TACL_REVISION_INFORMATION* = record + TACL_REVISION_INFORMATION* {.final.} = object AclRevision*: DWORD PACLREVISIONINFORMATION* = ptr TACL_REVISION_INFORMATION - TACL_SIZE_INFORMATION* = record + TACL_SIZE_INFORMATION* {.final.} = object AceCount*: DWORD AclBytesInUse*: DWORD AclBytesFree*: DWORD PACLSIZEINFORMATION* = ptr TACL_SIZE_INFORMATION - ACTION_HEADER* = record + ACTION_HEADER* {.final.} = object transport_id*: ULONG action_code*: USHORT reserved*: USHORT TACTIONHEADER* = ACTION_HEADER PACTIONHEADER* = ptr ACTION_HEADER - ADAPTER_STATUS* = record + ADAPTER_STATUS* {.final.} = object adapter_address*: array[0..5, UCHAR] rev_major*: UCHAR reserved0*: UCHAR @@ -6590,33 +6590,33 @@ type # WARNING TADAPTERSTATUS* = ADAPTER_STATUS PADAPTERSTATUS* = ptr ADAPTER_STATUS - ADDJOB_INFO_1* = record + ADDJOB_INFO_1* {.final.} = object Path*: LPTSTR JobId*: DWORD TADDJOB_INFO_1* = ADDJOB_INFO_1 PADDJOB_INFO_1* = ptr ADDJOB_INFO_1 - ANIMATIONINFO* = record + ANIMATIONINFO* {.final.} = object cbSize*: UINT iMinAnimate*: int32 LPANIMATIONINFO* = ptr ANIMATIONINFO TANIMATIONINFO* = ANIMATIONINFO PANIMATIONINFO* = ptr ANIMATIONINFO - POINT* = record + POINT* {.final.} = object x*: LONG y*: LONG LPPOINT* = ptr POINT TPOINT* = POINT PPOINT* = ptr POINT - RECT* = record + RECT* {.final.} = object TopLeft*, BottomRight*: TPoint LPRECT* = ptr RECT TRECT* = RECT PRECT* = ptr RECT - RECTL* = record + RECTL* {.final.} = object left*: LONG top*: LONG right*: LONG @@ -6624,7 +6624,7 @@ type # WARNING TRECTL* = RECTL PRECTL* = ptr RECTL - APPBARDATA* = record + APPBARDATA* {.final.} = object cbSize*: DWORD hWnd*: HWND uCallbackMessage*: UINT @@ -6634,7 +6634,7 @@ type # WARNING TAppBarData* = APPBARDATA PAppBarData* = ptr APPBARDATA - BITMAP* = record + BITMAP* {.final.} = object bmType*: LONG bmWidth*: LONG bmHeight*: LONG @@ -6648,7 +6648,7 @@ type # WARNING LPBITMAP* = ptr BITMAP tagBITMAP* = BITMAP TBITMAP* = BITMAP - BITMAPCOREHEADER* = record + BITMAPCOREHEADER* {.final.} = object bcSize*: DWORD bcWidth*: int16 bcHeight*: int16 @@ -6657,14 +6657,14 @@ type # WARNING TBITMAPCOREHEADER* = BITMAPCOREHEADER PBITMAPCOREHEADER* = ptr BITMAPCOREHEADER - RGBTRIPLE* = record + RGBTRIPLE* {.final.} = object rgbtBlue*: int8 rgbtGreen*: int8 rgbtRed*: int8 TRGBTRIPLE* = RGBTRIPLE PRGBTRIPLE* = ptr RGBTRIPLE - BITMAPCOREINFO* = record + BITMAPCOREINFO* {.final.} = object bmciHeader*: BITMAPCOREHEADER bmciColors*: array[0..0, RGBTRIPLE] @@ -6674,7 +6674,7 @@ type # WARNING # WORD bfReserved1; # WORD bfReserved2; # in declarator_list - BITMAPINFOHEADER* = record + BITMAPINFOHEADER* {.final.} = object biSize*: DWORD biWidth*: LONG biHeight*: LONG @@ -6690,7 +6690,7 @@ type # WARNING LPBITMAPINFOHEADER* = ptr BITMAPINFOHEADER TBITMAPINFOHEADER* = BITMAPINFOHEADER PBITMAPINFOHEADER* = ptr BITMAPINFOHEADER - RGBQUAD* = record + RGBQUAD* {.final.} = object rgbBlue*: int8 rgbGreen*: int8 rgbRed*: int8 @@ -6699,7 +6699,7 @@ type # WARNING tagRGBQUAD* = RGBQUAD TRGBQUAD* = RGBQUAD PRGBQUAD* = ptr RGBQUAD - BITMAPINFO* = record + BITMAPINFO* {.final.} = object bmiHeader*: BITMAPINFOHEADER bmiColors*: array[0..0, RGBQUAD] @@ -6710,7 +6710,7 @@ type # WARNING LPFXPT2DOT30* = ptr FXPT2DOT30 TPFXPT2DOT30* = FXPT2DOT30 PPFXPT2DOT30* = ptr FXPT2DOT30 - CIEXYZ* = record + CIEXYZ* {.final.} = object ciexyzX*: FXPT2DOT30 ciexyzY*: FXPT2DOT30 ciexyzZ*: FXPT2DOT30 @@ -6719,7 +6719,7 @@ type # WARNING LPCIEXYZ* = ptr CIEXYZ TPCIEXYZ* = CIEXYZ PCIEXYZ* = ptr CIEXYZ - CIEXYZTRIPLE* = record + CIEXYZTRIPLE* {.final.} = object ciexyzRed*: CIEXYZ ciexyzGreen*: CIEXYZ ciexyzBlue*: CIEXYZ @@ -6728,7 +6728,7 @@ type # WARNING LPCIEXYZTRIPLE* = ptr CIEXYZTRIPLE TCIEXYZTRIPLE* = CIEXYZTRIPLE PCIEXYZTRIPLE* = ptr CIEXYZTRIPLE - BITMAPV4HEADER* = record + BITMAPV4HEADER* {.final.} = object bV4Size*: DWORD bV4Width*: LONG bV4Height*: LONG @@ -6753,20 +6753,20 @@ type # WARNING LPBITMAPV4HEADER* = ptr BITMAPV4HEADER TBITMAPV4HEADER* = BITMAPV4HEADER PBITMAPV4HEADER* = ptr BITMAPV4HEADER - BITMAPFILEHEADER* = record + BITMAPFILEHEADER* {.final.} = object bfType*: int16 bfSize*: DWord bfReserved1*: int16 bfReserved2*: int16 bfOffBits*: DWord - BLOB* = record + BLOB* {.final.} = object cbSize*: ULONG pBlobData*: ptr int8 TBLOB* = BLOB PBLOB* = ptr BLOB - SHITEMID* = record + SHITEMID* {.final.} = object cb*: USHORT abID*: array[0..0, int8] @@ -6774,14 +6774,14 @@ type # WARNING LPCSHITEMID* = ptr SHITEMID TSHITEMID* = SHITEMID PSHITEMID* = ptr SHITEMID - ITEMIDLIST* = record + ITEMIDLIST* {.final.} = object mkid*: SHITEMID LPITEMIDLIST* = ptr ITEMIDLIST LPCITEMIDLIST* = ptr ITEMIDLIST TITEMIDLIST* = ITEMIDLIST PITEMIDLIST* = ptr ITEMIDLIST - BROWSEINFO* = record + BROWSEINFO* {.final.} = object hwndOwner*: HWND pidlRoot*: LPCITEMIDLIST pszDisplayName*: LPSTR @@ -6794,14 +6794,14 @@ type # WARNING LPBROWSEINFO* = ptr BROWSEINFO Tbrowseinfo* = BROWSEINFO PBROWSEINFO* = ptr BROWSEINFO - FILETIME* = record + FILETIME* {.final.} = object dwLowDateTime*: DWORD dwHighDateTime*: DWORD LPFILETIME* = ptr FILETIME TFILETIME* = FILETIME PFILETIME* = ptr FILETIME - BY_HANDLE_FILE_INFORMATION* = record + BY_HANDLE_FILE_INFORMATION* {.final.} = object dwFileAttributes*: DWORD ftCreationTime*: FILETIME ftLastAccessTime*: FILETIME @@ -6816,34 +6816,34 @@ type # WARNING LPBY_HANDLE_FILE_INFORMATION* = ptr BY_HANDLE_FILE_INFORMATION TBYHANDLEFILEINFORMATION* = BY_HANDLE_FILE_INFORMATION PBYHANDLEFILEINFORMATION* = ptr BY_HANDLE_FILE_INFORMATION - FIXED* = record + FIXED* {.final.} = object fract*: int16 value*: SHORT TFIXED* = FIXED PFIXED* = ptr FIXED - POINTFX* = record + POINTFX* {.final.} = object x*: FIXED y*: FIXED TPOINTFX* = POINTFX PPOINTFX* = ptr POINTFX - POINTL* = record + POINTL* {.final.} = object x*: LONG y*: LONG TPOINTL* = POINTL PPOINTL* = ptr POINTL - TSmallPoint* = record + TSmallPoint* {.final.} = object X*, Y*: SHORT - POINTS* = record + POINTS* {.final.} = object x*: SHORT y*: SHORT TPOINTS* = POINTS PPOINTS* = ptr POINTS - CANDIDATEFORM* = record + CANDIDATEFORM* {.final.} = object dwIndex*: DWORD dwStyle*: DWORD ptCurrentPos*: POINT @@ -6852,7 +6852,7 @@ type # WARNING LPCANDIDATEFORM* = ptr CANDIDATEFORM TCANDIDATEFORM* = CANDIDATEFORM PCANDIDATEFORM* = ptr CANDIDATEFORM - CANDIDATELIST* = record + CANDIDATELIST* {.final.} = object dwSize*: DWORD dwStyle*: DWORD dwCount*: DWORD @@ -6864,7 +6864,7 @@ type # WARNING LPCANDIDATELIST* = ptr CANDIDATELIST TCANDIDATELIST* = CANDIDATELIST PCANDIDATELIST* = ptr CANDIDATELIST - CREATESTRUCT* = record + CREATESTRUCT* {.final.} = object lpCreateParams*: LPVOID hInstance*: HINST hMenu*: HMENU @@ -6881,25 +6881,25 @@ type # WARNING LPCREATESTRUCT* = ptr CREATESTRUCT TCREATESTRUCT* = CREATESTRUCT PCREATESTRUCT* = ptr CREATESTRUCT - CBT_CREATEWND* = record + CBT_CREATEWND* {.final.} = object lpcs*: LPCREATESTRUCT hwndInsertAfter*: HWND TCBT_CREATEWND* = CBT_CREATEWND PCBT_CREATEWND* = ptr CBT_CREATEWND - CBTACTIVATESTRUCT* = record + CBTACTIVATESTRUCT* {.final.} = object fMouse*: WINBOOL hWndActive*: HWND TCBTACTIVATESTRUCT* = CBTACTIVATESTRUCT PCBTACTIVATESTRUCT* = ptr CBTACTIVATESTRUCT - CHAR_INFO* = record + CHAR_INFO* {.final.} = object UnicodeChar*: WCHAR Attributes*: int16 # other union part: AsciiChar : CHAR TCHAR_INFO* = CHAR_INFO PCHAR_INFO* = ptr CHAR_INFO - CHARFORMAT* = record + CHARFORMAT* {.final.} = object cbSize*: UINT dwMask*: DWORD dwEffects*: DWORD @@ -6912,19 +6912,19 @@ type # WARNING Tcharformat* = CHARFORMAT Pcharformat* = ptr CHARFORMAT - CHARRANGE* = record + CHARRANGE* {.final.} = object cpMin*: LONG cpMax*: LONG Tcharrange* = CHARRANGE Pcharrange* = ptr CHARRANGE - CHARSET* = record + CHARSET* {.final.} = object aflBlock*: array[0..2, DWORD] flLang*: DWORD TCHARSET* = CHARSET PCHARSET* = ptr CHARSET - FONTSIGNATURE* = record + FONTSIGNATURE* {.final.} = object fsUsb*: array[0..3, DWORD] fsCsb*: array[0..1, DWORD] @@ -6932,7 +6932,7 @@ type # WARNING tagFONTSIGNATURE* = FONTSIGNATURE TFONTSIGNATURE* = FONTSIGNATURE PFONTSIGNATURE* = ptr FONTSIGNATURE - CHARSETINFO* = record + CHARSETINFO* {.final.} = object ciCharset*: UINT ciACP*: UINT fs*: FONTSIGNATURE @@ -6940,7 +6940,7 @@ type # WARNING LPCHARSETINFO* = ptr CHARSETINFO TCHARSETINFO* = CHARSETINFO PCHARSETINFO* = ptr CHARSETINFO #CHOOSECOLOR = record confilcts with function ChooseColor - TCHOOSECOLOR* = record + TCHOOSECOLOR* {.final.} = object lStructSize*: DWORD hwndOwner*: HWND hInstance*: HWND @@ -6953,7 +6953,7 @@ type # WARNING LPCHOOSECOLOR* = ptr TCHOOSECOLOR PCHOOSECOLOR* = ptr TCHOOSECOLOR - LOGFONT* = record + LOGFONT* {.final.} = object lfHeight*: LONG lfWidth*: LONG lfEscapement*: LONG @@ -6974,7 +6974,7 @@ type # WARNING TLOGFONTA* = LOGFONT PLOGFONT* = ptr LOGFONT PLOGFONTA* = PLOGFONT - LOGFONTW* = record + LOGFONTW* {.final.} = object lfHeight*: LONG lfWidth*: LONG lfEscapement*: LONG @@ -6994,7 +6994,7 @@ type # WARNING NPLOGFONTW* = ptr LOGFONTW TLogFontW* = LOGFONTW PLogFontW* = ptr TLogFontW - TCHOOSEFONT* = record + TCHOOSEFONT* {.final.} = object lStructSize*: DWORD hwndOwner*: HWND hDC*: HDC @@ -7014,14 +7014,14 @@ type # WARNING LPCHOOSEFONT* = ptr TCHOOSEFONT PCHOOSEFONT* = ptr TCHOOSEFONT - CIDA* = record + CIDA* {.final.} = object cidl*: UINT aoffset*: array[0..0, UINT] LPIDA* = ptr CIDA TIDA* = CIDA PIDA* = ptr CIDA - CLIENTCREATESTRUCT* = record + CLIENTCREATESTRUCT* {.final.} = object hWindowMenu*: HANDLE idFirstChild*: UINT @@ -7029,7 +7029,7 @@ type # WARNING tagCLIENTCREATESTRUCT* = CLIENTCREATESTRUCT TCLIENTCREATESTRUCT* = CLIENTCREATESTRUCT PCLIENTCREATESTRUCT* = ptr CLIENTCREATESTRUCT - CMINVOKECOMMANDINFO* = record + CMINVOKECOMMANDINFO* {.final.} = object cbSize*: DWORD fMask*: DWORD hwnd*: HWND @@ -7043,7 +7043,7 @@ type # WARNING LPCMINVOKECOMMANDINFO* = ptr CMINVOKECOMMANDINFO TCMInvokeCommandInfo* = CMINVOKECOMMANDINFO PCMInvokeCommandInfo* = ptr CMINVOKECOMMANDINFO - COLORADJUSTMENT* = record + COLORADJUSTMENT* {.final.} = object caSize*: int16 caFlags*: int16 caIlluminantIndex*: int16 @@ -7061,14 +7061,14 @@ type # WARNING tagCOLORADJUSTMENT* = COLORADJUSTMENT TCOLORADJUSTMENT* = COLORADJUSTMENT PCOLORADJUSTMENT* = ptr COLORADJUSTMENT - COLORMAP* = record + COLORMAP* {.final.} = object `from`*: COLORREF `to`*: COLORREF # XXX! LPCOLORMAP* = ptr COLORMAP TCOLORMAP* = COLORMAP PCOLORMAP* = ptr COLORMAP - DCB* = record + DCB* {.final.} = object DCBlength*: DWORD BaudRate*: DWORD flags*: DWORD @@ -7148,7 +7148,7 @@ proc set_fAbortOnError*(a: var DCB, fAbortOnError: DWORD) proc fDummy2*(a: var DCB): DWORD proc set_fDummy2*(a: var DCB, fDummy2: DWORD) type - COMMCONFIG* = record + COMMCONFIG* {.final.} = object dwSize*: DWORD wVersion*: int16 wReserved*: int16 @@ -7161,7 +7161,7 @@ type LPCOMMCONFIG* = ptr COMMCONFIG TCOMMCONFIG* = COMMCONFIG PCOMMCONFIG* = ptr COMMCONFIG - COMMPROP* = record + COMMPROP* {.final.} = object wPacketLength*: int16 wPacketVersion*: int16 dwServiceMask*: DWORD @@ -7184,7 +7184,7 @@ type LPCOMMPROP* = ptr COMMPROP TCOMMPROP* = COMMPROP PCOMMPROP* = ptr COMMPROP - COMMTIMEOUTS* = record + COMMTIMEOUTS* {.final.} = object ReadIntervalTimeout*: DWORD ReadTotalTimeoutMultiplier*: DWORD ReadTotalTimeoutConstant*: DWORD @@ -7194,7 +7194,7 @@ type LPCOMMTIMEOUTS* = ptr COMMTIMEOUTS TCOMMTIMEOUTS* = COMMTIMEOUTS PCOMMTIMEOUTS* = ptr COMMTIMEOUTS - COMPAREITEMSTRUCT* = record + COMPAREITEMSTRUCT* {.final.} = object CtlType*: UINT CtlID*: UINT hwndItem*: HWND @@ -7206,14 +7206,14 @@ type tagCOMPAREITEMSTRUCT* = COMPAREITEMSTRUCT TCOMPAREITEMSTRUCT* = COMPAREITEMSTRUCT PCOMPAREITEMSTRUCT* = ptr COMPAREITEMSTRUCT - COMPCOLOR* = record + COMPCOLOR* {.final.} = object crText*: COLORREF crBackground*: COLORREF dwEffects*: DWORD TCOMPCOLOR* = COMPCOLOR PCOMPCOLOR* = ptr COMPCOLOR - COMPOSITIONFORM* = record + COMPOSITIONFORM* {.final.} = object dwStyle*: DWORD ptCurrentPos*: POINT rcArea*: RECT @@ -7222,7 +7222,7 @@ type TCOMPOSITIONFORM* = COMPOSITIONFORM PCOMPOSITIONFORM* = ptr COMPOSITIONFORM # TComStatFlags = set of (fCtsHold, fDsrHold, fRlsdHold , fXoffHold , # fXoffSent , fEof , fTxim , fReserved); - COMSTAT* = record + COMSTAT* {.final.} = object flag0*: DWORD # can't use tcomstatflags, set packing issues # and conflicts with macro's cbInQue*: DWORD @@ -7268,20 +7268,20 @@ proc set_fTxim*(a: var COMSTAT, fTxim: DWORD) proc fReserved*(a: var COMSTAT): DWORD proc set_fReserved*(a: var COMSTAT, fReserved: DWORD) type - CONSOLE_CURSOR_INFO* = record + CONSOLE_CURSOR_INFO* {.final.} = object dwSize*: DWORD bVisible*: WINBOOL PCONSOLE_CURSOR_INFO* = ptr CONSOLE_CURSOR_INFO TCONSOLECURSORINFO* = CONSOLE_CURSOR_INFO TCURSORINFO* = CONSOLE_CURSOR_INFO - COORD* = record + COORD* {.final.} = object X*: SHORT Y*: SHORT TCOORD* = COORD PCOORD* = ptr COORD - SMALL_RECT* = record + SMALL_RECT* {.final.} = object Left*: SHORT Top*: SHORT Right*: SHORT @@ -7289,7 +7289,7 @@ type TSMALL_RECT* = SMALL_RECT PSMALL_RECT* = ptr SMALL_RECT - CONSOLE_SCREEN_BUFFER_INFO* = record + CONSOLE_SCREEN_BUFFER_INFO* {.final.} = object dwSize*: COORD dwCursorPosition*: COORD wAttributes*: int16 @@ -7301,7 +7301,7 @@ type when defined(i386): type - FLOATING_SAVE_AREA* = record + FLOATING_SAVE_AREA* {.final.} = object ControlWord*: DWORD StatusWord*: DWORD TagWord*: DWORD @@ -7314,7 +7314,7 @@ when defined(i386): TFLOATINGSAVEAREA* = FLOATING_SAVE_AREA PFLOATINGSAVEAREA* = ptr FLOATING_SAVE_AREA - CONTEXT* = record + CONTEXT* {.final.} = object ContextFlags*: DWORD Dr0*: DWORD Dr1*: DWORD @@ -7345,7 +7345,7 @@ when defined(x86_64): # Define 128-bit 16-byte aligned xmm register type. # type - M128A* = record + M128A* {.final.} = object Low*: ULONGLONG High*: LONGLONG @@ -7355,7 +7355,7 @@ when defined(x86_64): # #typedef struct _XMM_SAVE_AREA32 { type - XMM_SAVE_AREA32* = record + XMM_SAVE_AREA32* {.final.} = object ControlWord*: int16 StatusWord*: int16 TagWord*: int8 @@ -7378,7 +7378,7 @@ when defined(x86_64): const LEGACY_SAVE_AREA_LENGTH* = sizeof(XMM_SAVE_AREA32) type - CONTEXT* = record + CONTEXT* {.final.} = object P1Home*: DWORD64 P2Home*: DWORD64 P3Home*: DWORD64 @@ -7465,7 +7465,7 @@ when defined(powerpc32): # Debug Status Register # Debug Control Register type - CONTEXT* = record + CONTEXT* {.final.} = object Fpr0*: float64 Fpr1*: float64 Fpr2*: float64 @@ -7554,13 +7554,13 @@ type PCONTEXT* = ptr CONTEXT type - LIST_ENTRY* = record + LIST_ENTRY* {.final.} = object Flink*: ptr LIST_ENTRY Blink*: ptr LIST_ENTRY TLISTENTRY* = LIST_ENTRY PLISTENTRY* = ptr LIST_ENTRY - CRITICAL_SECTION_DEBUG* = record + CRITICAL_SECTION_DEBUG* {.final.} = object `type`*: int16 CreatorBackTraceIndex*: int16 CriticalSection*: ptr TCRITICAL_SECTION @@ -7570,7 +7570,7 @@ type Depth*: DWORD OwnerBackTrace*: array[0..4, PVOID] - TRTL_CRITICAL_SECTION* = record + TRTL_CRITICAL_SECTION* {.final.} = object DebugInfo*: ptr CRITICAL_SECTION_DEBUG LockCount*: int32 RecursionCount*: int32 @@ -7586,7 +7586,7 @@ type TCRITICAL_SECTION* = TRTLCriticalSection PCRITICAL_SECTION* = PRTLCriticalSection LPCRITICAL_SECTION* = PRTLCriticalSection - SECURITY_QUALITY_OF_SERVICE* = record + SECURITY_QUALITY_OF_SERVICE* {.final.} = object len*: DWORD ImpersonationLevel*: SECURITY_IMPERSONATION_LEVEL ContextTrackingMode*: WINBOOL @@ -7594,7 +7594,7 @@ type PSECURITY_QUALITY_OF_SERVICE* = ptr SECURITY_QUALITY_OF_SERVICE TSECURITYQUALITYOFSERVICE* = SECURITY_QUALITY_OF_SERVICE - CONVCONTEXT* = record + CONVCONTEXT* {.final.} = object cb*: UINT wFlags*: UINT wCountryID*: UINT @@ -7605,7 +7605,7 @@ type TCONVCONTEXT* = CONVCONTEXT PCONVCONTEXT* = ptr CONVCONTEXT - CONVINFO* = record + CONVINFO* {.final.} = object cb*: DWORD hUser*: DWORD hConvPartner*: HCONV @@ -7626,7 +7626,7 @@ type tagCONVINFO* = CONVINFO TCONVINFO* = CONVINFO PCONVINFO* = ptr CONVINFO - COPYDATASTRUCT* = record + COPYDATASTRUCT* {.final.} = object dwData*: DWORD cbData*: DWORD lpData*: PVOID @@ -7634,7 +7634,7 @@ type tagCOPYDATASTRUCT* = COPYDATASTRUCT TCOPYDATASTRUCT* = COPYDATASTRUCT PCOPYDATASTRUCT* = ptr COPYDATASTRUCT - CPINFO* = record + CPINFO* {.final.} = object MaxCharSize*: UINT DefaultChar*: array[0..(MAX_DEFAULTCHAR) - 1, int8] LeadByte*: array[0..(MAX_LEADBYTES) - 1, int8] @@ -7642,7 +7642,7 @@ type LPCPINFO* = ptr CPINFO Tcpinfo* = CPINFO Pcpinfo* = ptr CPINFO - CPLINFO* = record + CPLINFO* {.final.} = object idIcon*: int32 idName*: int32 idInfo*: int32 @@ -7651,7 +7651,7 @@ type tagCPLINFO* = CPLINFO TCPLINFO* = CPLINFO PCPLINFO* = ptr CPLINFO - CREATE_PROCESS_DEBUG_INFO* = record + CREATE_PROCESS_DEBUG_INFO* {.final.} = object hFile*: HANDLE hProcess*: HANDLE hThread*: HANDLE @@ -7665,7 +7665,7 @@ type TCREATEPROCESSDEBUGINFO* = CREATE_PROCESS_DEBUG_INFO PCREATEPROCESSDEBUGINFO* = ptr CREATE_PROCESS_DEBUG_INFO - CREATE_THREAD_DEBUG_INFO* = record + CREATE_THREAD_DEBUG_INFO* {.final.} = object hThread*: HANDLE lpThreadLocalBase*: LPVOID lpStartAddress*: LPTHREAD_START_ROUTINE @@ -7686,7 +7686,7 @@ type # INT iProtocol; # } CSADDR_INFO; # - CURRENCYFMT* = record + CURRENCYFMT* {.final.} = object NumDigits*: UINT LeadingZero*: UINT Grouping*: UINT @@ -7698,7 +7698,7 @@ type Tcurrencyfmt* = CURRENCYFMT Pcurrencyfmt* = ptr CURRENCYFMT - CURSORSHAPE* = record + CURSORSHAPE* {.final.} = object xHotSpot*: int32 yHotSpot*: int32 cx*: int32 @@ -7710,7 +7710,7 @@ type LPCURSORSHAPE* = ptr CURSORSHAPE TCURSORSHAPE* = CURSORSHAPE PCURSORSHAPE* = ptr CURSORSHAPE - CWPRETSTRUCT* = record + CWPRETSTRUCT* {.final.} = object lResult*: LRESULT lParam*: LPARAM wParam*: WPARAM @@ -7719,7 +7719,7 @@ type TCWPRETSTRUCT* = CWPRETSTRUCT PCWPRETSTRUCT* = ptr CWPRETSTRUCT - CWPSTRUCT* = record + CWPSTRUCT* {.final.} = object lParam*: LPARAM wParam*: WPARAM message*: UINT @@ -7727,12 +7727,12 @@ type TCWPSTRUCT* = CWPSTRUCT PCWPSTRUCT* = ptr CWPSTRUCT - DATATYPES_INFO_1* = record + DATATYPES_INFO_1* {.final.} = object pName*: LPTSTR TDATATYPESINFO1* = DATATYPES_INFO_1 PDATATYPESINFO1* = ptr DATATYPES_INFO_1 - DDEACK* = record + DDEACK* {.final.} = object flag0*: int16 TDDEACK* = DDEACK @@ -7757,7 +7757,7 @@ proc set_fBusy*(a: var DDEACK, fBusy: int16) proc fAck*(a: var DDEACK): int16 proc set_fAck*(a: var DDEACK, fAck: int16) type - DDEADVISE* = record + DDEADVISE* {.final.} = object flag0*: int16 cfFormat*: SHORT @@ -7779,7 +7779,7 @@ proc set_fDeferUpd*(a: var DDEADVISE, fDeferUpd: int16) proc fAckReq*(a: var DDEADVISE): int16 proc set_fAckReq*(a: var DDEADVISE, fAckReq: int16) type - DDEDATA* = record + DDEDATA* {.final.} = object flag0*: int16 cfFormat*: SHORT Value*: array[0..0, int8] @@ -7809,7 +7809,7 @@ proc set_reserved*(a: var DDEDATA, reserved: int16) proc fAckReq*(a: var DDEDATA): int16 proc set_fAckReq*(a: var DDEDATA, fAckReq: int16) type - DDELN* = record + DDELN* {.final.} = object flag0*: int16 cfFormat*: SHORT @@ -7835,7 +7835,7 @@ proc set_fDeferUpd*(a: var DDELN, fDeferUpd: int16) proc fAckReq*(a: var DDELN): int16 proc set_fAckReq*(a: var DDELN, fAckReq: int16) type - DDEML_MSG_HOOK_DATA* = record + DDEML_MSG_HOOK_DATA* {.final.} = object uiLo*: UINT uiHi*: UINT cbData*: DWORD @@ -7843,7 +7843,7 @@ type TDDEMLMSGHOOKDATA* = DDEML_MSG_HOOK_DATA PDDEMLMSGHOOKDATA* = ptr DDEML_MSG_HOOK_DATA - DDEPOKE* = record + DDEPOKE* {.final.} = object flag0*: int16 cfFormat*: SHORT Value*: array[0..0, int8] @@ -7866,7 +7866,7 @@ proc set_fRelease*(a: var DDEPOKE, fRelease: int16) proc fReserved*(a: var DDEPOKE): int16 proc set_fReserved*(a: var DDEPOKE, fReserved: int16) type - DDEUP* = record + DDEUP* {.final.} = object flag0*: int16 cfFormat*: SHORT rgb*: array[0..0, int8] @@ -7897,7 +7897,7 @@ proc set_fReserved*(a: var DDEUP, fReserved: int16) proc fAckReq*(a: var DDEUP): int16 proc set_fAckReq*(a: var DDEUP, fAckReq: int16) type - EXCEPTION_RECORD* = record + EXCEPTION_RECORD* {.final.} = object ExceptionCode*: DWORD ExceptionFlags*: DWORD ExceptionRecord*: ptr EXCEPTION_RECORD @@ -7908,13 +7908,13 @@ type PEXCEPTION_RECORD* = ptr EXCEPTION_RECORD TEXCEPTIONRECORD* = EXCEPTION_RECORD - EXCEPTION_DEBUG_INFO* = record + EXCEPTION_DEBUG_INFO* {.final.} = object ExceptionRecord*: EXCEPTION_RECORD dwFirstChance*: DWORD PEXCEPTION_DEBUG_INFO* = ptr EXCEPTION_DEBUG_INFO TEXCEPTIONDEBUGINFO* = EXCEPTION_DEBUG_INFO - EXCEPTION_RECORD32* = record + EXCEPTION_RECORD32* {.final.} = object ExceptionCode*: DWORD ExceptionFlags*: DWORD ExceptionRecord*: DWORD @@ -7924,13 +7924,13 @@ type PEXCEPTION_RECORD32* = ptr EXCEPTION_RECORD32 TExceptionRecord32* = EXCEPTION_RECORD32 - EXCEPTION_DEBUG_INFO32* = record + EXCEPTION_DEBUG_INFO32* {.final.} = object ExceptionRecord*: EXCEPTION_RECORD32 dwFirstChance*: DWORD PEXCEPTION_DEBUG_INFO32* = ptr EXCEPTION_DEBUG_INFO32 TExceptionDebugInfo32* = EXCEPTION_DEBUG_INFO32 - EXCEPTION_RECORD64* = record + EXCEPTION_RECORD64* {.final.} = object ExceptionCode*: DWORD ExceptionFlags*: DWORD ExceptionRecord*: DWORD64 @@ -7941,23 +7941,23 @@ type PEXCEPTION_RECORD64* = ptr EXCEPTION_RECORD64 TExceptionRecord64* = EXCEPTION_RECORD64 - EXCEPTION_DEBUG_INFO64* = record + EXCEPTION_DEBUG_INFO64* {.final.} = object ExceptionRecord*: EXCEPTION_RECORD64 dwFirstChance*: DWORD PEXCEPTION_DEBUG_INFO64* = ptr EXCEPTION_DEBUG_INFO64 TExceptionDebugInfo64* = EXCEPTION_DEBUG_INFO64 - EXIT_PROCESS_DEBUG_INFO* = record + EXIT_PROCESS_DEBUG_INFO* {.final.} = object dwExitCode*: DWORD TEXITPROCESSDEBUGINFO* = EXIT_PROCESS_DEBUG_INFO PEXITPROCESSDEBUGINFO* = ptr EXIT_PROCESS_DEBUG_INFO - EXIT_THREAD_DEBUG_INFO* = record + EXIT_THREAD_DEBUG_INFO* {.final.} = object dwExitCode*: DWORD TEXITTHREADDEBUGINFO* = EXIT_THREAD_DEBUG_INFO PEXITTHREADDEBUGINFO* = ptr EXIT_THREAD_DEBUG_INFO - LOAD_DLL_DEBUG_INFO* = record + LOAD_DLL_DEBUG_INFO* {.final.} = object hFile*: HANDLE lpBaseOfDll*: LPVOID dwDebugInfoFileOffset*: DWORD @@ -7967,25 +7967,25 @@ type TLOADDLLDEBUGINFO* = LOAD_DLL_DEBUG_INFO PLOADDLLDEBUGINFO* = ptr LOAD_DLL_DEBUG_INFO - UNLOAD_DLL_DEBUG_INFO* = record + UNLOAD_DLL_DEBUG_INFO* {.final.} = object lpBaseOfDll*: LPVOID TUNLOADDLLDEBUGINFO* = UNLOAD_DLL_DEBUG_INFO PUNLOADDLLDEBUGINFO* = ptr UNLOAD_DLL_DEBUG_INFO - OUTPUT_DEBUG_STRING_INFO* = record + OUTPUT_DEBUG_STRING_INFO* {.final.} = object lpDebugStringData*: LPSTR fUnicode*: int16 nDebugStringLength*: int16 TOUTPUTDEBUGSTRINGINFO* = OUTPUT_DEBUG_STRING_INFO POUTPUTDEBUGSTRINGINFO* = ptr OUTPUT_DEBUG_STRING_INFO - RIP_INFO* = record + RIP_INFO* {.final.} = object dwError*: DWORD dwType*: DWORD TRIPINFO* = RIP_INFO PRIPINFO* = ptr RIP_INFO - DEBUG_EVENT* = record + DEBUG_EVENT* {.final.} = object dwDebugEventCode*: DWORD dwProcessId*: DWORD dwThreadId*: DWORD @@ -8004,7 +8004,7 @@ type LPDEBUG_EVENT* = ptr DEBUG_EVENT TDEBUGEVENT* = DEBUG_EVENT PDEBUGEVENT* = ptr DEBUG_EVENT - DEBUGHOOKINFO* = record + DEBUGHOOKINFO* {.final.} = object idThread*: DWORD idThreadInstaller*: DWORD lParam*: LPARAM @@ -8013,7 +8013,7 @@ type TDEBUGHOOKINFO* = DEBUGHOOKINFO PDEBUGHOOKINFO* = ptr DEBUGHOOKINFO - DELETEITEMSTRUCT* = record + DELETEITEMSTRUCT* {.final.} = object CtlType*: UINT CtlID*: UINT itemID*: UINT @@ -8022,14 +8022,14 @@ type TDELETEITEMSTRUCT* = DELETEITEMSTRUCT PDELETEITEMSTRUCT* = ptr DELETEITEMSTRUCT - DEV_BROADCAST_HDR* = record + DEV_BROADCAST_HDR* {.final.} = object dbch_size*: ULONG dbch_devicetype*: ULONG dbch_reserved*: ULONG PDEV_BROADCAST_HDR* = ptr DEV_BROADCAST_HDR TDEVBROADCASTHDR* = DEV_BROADCAST_HDR - DEV_BROADCAST_OEM* = record + DEV_BROADCAST_OEM* {.final.} = object dbco_size*: ULONG dbco_devicetype*: ULONG dbco_reserved*: ULONG @@ -8038,7 +8038,7 @@ type PDEV_BROADCAST_OEM* = ptr DEV_BROADCAST_OEM TDEVBROADCASTOEM* = DEV_BROADCAST_OEM - DEV_BROADCAST_PORT* = record + DEV_BROADCAST_PORT* {.final.} = object dbcp_size*: ULONG dbcp_devicetype*: ULONG dbcp_reserved*: ULONG @@ -8046,14 +8046,14 @@ type PDEV_BROADCAST_PORT* = ptr DEV_BROADCAST_PORT TDEVBROADCASTPORT* = DEV_BROADCAST_PORT - DEV_BROADCAST_USERDEFINED* = record + DEV_BROADCAST_USERDEFINED* {.final.} = object dbud_dbh*: DEV_BROADCAST_HDR dbud_szName*: array[0..0, char] dbud_rgbUserDefined*: array[0..0, int8] TDEVBROADCASTUSERDEFINED* = DEV_BROADCAST_USERDEFINED PDEVBROADCASTUSERDEFINED* = ptr DEV_BROADCAST_USERDEFINED - DEV_BROADCAST_VOLUME* = record + DEV_BROADCAST_VOLUME* {.final.} = object dbcv_size*: ULONG dbcv_devicetype*: ULONG dbcv_reserved*: ULONG @@ -8062,7 +8062,7 @@ type PDEV_BROADCAST_VOLUME* = ptr DEV_BROADCAST_VOLUME TDEVBROADCASTVOLUME* = DEV_BROADCAST_VOLUME - DEVMODE* = record + DEVMODE* {.final.} = object dmDeviceName*: array[0..(CCHDEVICENAME) - 1, BCHAR] dmSpecVersion*: int16 dmDriverVersion*: int16 @@ -8107,7 +8107,7 @@ type PDeviceMode* = LPDEVMODE TDEVMODE* = DEVMODE PDEVMODE* = LPDEVMODE - devmodeW* = record + devmodeW* {.final.} = object dmDeviceName*: array[0..CCHDEVICENAME - 1, WCHAR] dmSpecVersion*: int16 dmDriverVersion*: int16 @@ -8149,7 +8149,7 @@ type PDeviceModeW* = LPDEVMODEW TDEVMODEW* = DEVMODEW PDEVMODEW* = LPDEVMODEW - DEVNAMES* = record + DEVNAMES* {.final.} = object wDriverOffset*: int16 wDeviceOffset*: int16 wOutputOffset*: int16 @@ -8159,7 +8159,7 @@ type tagDEVNAMES* = DEVNAMES TDEVNAMES* = DEVNAMES PDEVNAMES* = ptr DEVNAMES - DIBSECTION* = record + DIBSECTION* {.final.} = object dsBm*: BITMAP dsBmih*: BITMAPINFOHEADER dsBitfields*: array[0..2, DWORD] @@ -8187,7 +8187,7 @@ type TLargeInteger* = Int64 PULARGE_INTEGER* = ptr ULARGE_INTEGER TULargeInteger* = int64 - DISK_GEOMETRY* = record + DISK_GEOMETRY* {.final.} = object Cylinders*: LARGE_INTEGER MediaType*: MEDIA_TYPE TracksPerCylinder*: DWORD @@ -8196,7 +8196,7 @@ type TDISKGEOMETRY* = DISK_GEOMETRY PDISKGEOMETRY* = ptr DISK_GEOMETRY - DISK_PERFORMANCE* = record + DISK_PERFORMANCE* {.final.} = object BytesRead*: LARGE_INTEGER BytesWritten*: LARGE_INTEGER ReadTime*: LARGE_INTEGER @@ -8207,7 +8207,7 @@ type TDISKPERFORMANCE* = DISK_PERFORMANCE PDISKPERFORMANCE* = ptr DISK_PERFORMANCE - DLGITEMTEMPLATE* = record + DLGITEMTEMPLATE* {.final.} = object style*: DWORD dwExtendedStyle*: DWORD x*: int16 @@ -8219,7 +8219,7 @@ type LPDLGITEMTEMPLATE* = ptr DLGITEMTEMPLATE TDLGITEMTEMPLATE* = DLGITEMTEMPLATE PDLGITEMTEMPLATE* = ptr DLGITEMTEMPLATE - DLGTEMPLATE* = record + DLGTEMPLATE* {.final.} = object style*: DWORD dwExtendedStyle*: DWORD cdit*: int16 @@ -8232,14 +8232,14 @@ type LPCDLGTEMPLATE* = ptr DLGTEMPLATE TDLGTEMPLATE* = DLGTEMPLATE PDLGTEMPLATE* = ptr DLGTEMPLATE - DOC_INFO_1* = record + DOC_INFO_1* {.final.} = object pDocName*: LPTSTR pOutputFile*: LPTSTR pDatatype*: LPTSTR TDOCINFO1* = DOC_INFO_1 PDOCINFO1* = ptr DOC_INFO_1 - DOC_INFO_2* = record + DOC_INFO_2* {.final.} = object pDocName*: LPTSTR pOutputFile*: LPTSTR pDatatype*: LPTSTR @@ -8248,7 +8248,7 @@ type TDOCINFO2* = DOC_INFO_2 PDOCINFO2* = ptr DOC_INFO_2 - DOCINFO* = record + DOCINFO* {.final.} = object cbSize*: int32 lpszDocName*: LPCTSTR lpszOutput*: LPCTSTR @@ -8258,7 +8258,7 @@ type TDOCINFO* = DOCINFO TDOCINFOA* = DOCINFO PDOCINFO* = ptr DOCINFO - DRAGLISTINFO* = record + DRAGLISTINFO* {.final.} = object uNotification*: UINT hWnd*: HWND ptCursor*: POINT @@ -8266,7 +8266,7 @@ type LPDRAGLISTINFO* = ptr DRAGLISTINFO TDRAGLISTINFO* = DRAGLISTINFO PDRAGLISTINFO* = ptr DRAGLISTINFO - DRAWITEMSTRUCT* = record + DRAWITEMSTRUCT* {.final.} = object CtlType*: UINT CtlID*: UINT itemID*: UINT @@ -8281,7 +8281,7 @@ type tagDRAWITEMSTRUCT* = DRAWITEMSTRUCT TDRAWITEMSTRUCT* = DRAWITEMSTRUCT PDRAWITEMSTRUCT* = ptr DRAWITEMSTRUCT - DRAWTEXTPARAMS* = record + DRAWTEXTPARAMS* {.final.} = object cbSize*: UINT iTabLength*: int32 iLeftMargin*: int32 @@ -8291,7 +8291,7 @@ type LPDRAWTEXTPARAMS* = ptr DRAWTEXTPARAMS TDRAWTEXTPARAMS* = DRAWTEXTPARAMS PDRAWTEXTPARAMS* = ptr DRAWTEXTPARAMS - PARTITION_INFORMATION* = record + PARTITION_INFORMATION* {.final.} = object PartitionType*: int8 BootIndicator*: bool RecognizedPartition*: bool @@ -8302,19 +8302,19 @@ type TPARTITIONINFORMATION* = PARTITION_INFORMATION PPARTITIONINFORMATION* = ptr PARTITION_INFORMATION - DRIVE_LAYOUT_INFORMATION* = record + DRIVE_LAYOUT_INFORMATION* {.final.} = object PartitionCount*: DWORD Signature*: DWORD PartitionEntry*: array[0..0, PARTITION_INFORMATION] TDRIVELAYOUTINFORMATION* = DRIVE_LAYOUT_INFORMATION PDRIVELAYOUTINFORMATION* = ptr DRIVE_LAYOUT_INFORMATION - DRIVER_INFO_1* = record + DRIVER_INFO_1* {.final.} = object pName*: LPTSTR TDRIVERINFO1* = DRIVER_INFO_1 PDRIVERINFO1* = ptr DRIVER_INFO_1 - DRIVER_INFO_2* = record + DRIVER_INFO_2* {.final.} = object cVersion*: DWORD pName*: LPTSTR pEnvironment*: LPTSTR @@ -8324,7 +8324,7 @@ type TDRIVERINFO2* = DRIVER_INFO_2 PDRIVERINFO2* = ptr DRIVER_INFO_2 - DRIVER_INFO_3* = record + DRIVER_INFO_3* {.final.} = object cVersion*: DWORD pName*: LPTSTR pEnvironment*: LPTSTR @@ -8338,21 +8338,21 @@ type TDRIVERINFO3* = DRIVER_INFO_3 PDRIVERINFO3* = ptr DRIVER_INFO_3 - EDITSTREAM* = record + EDITSTREAM* {.final.} = object dwCookie*: DWORD dwError*: DWORD pfnCallback*: EDITSTREAMCALLBACK Teditstream* = EDITSTREAM Peditstream* = ptr EDITSTREAM - EMR* = record + EMR* {.final.} = object iType*: DWORD nSize*: DWORD tagEMR* = EMR TEMR* = EMR PEMR* = ptr EMR - EMRANGLEARC* = record + EMRANGLEARC* {.final.} = object emr*: EMR ptlCenter*: POINTL nRadius*: DWORD @@ -8362,7 +8362,7 @@ type tagEMRANGLEARC* = EMRANGLEARC TEMRANGLEARC* = EMRANGLEARC PEMRANGLEARC* = ptr EMRANGLEARC - EMRARC* = record + EMRARC* {.final.} = object emr*: EMR rclBox*: RECTL ptlStart*: POINTL @@ -8380,7 +8380,7 @@ type EMRPIE* = EMRARC TEMRPIE* = EMRARC PEMRPIE* = ptr EMRARC - XFORM* = record + XFORM* {.final.} = object eM11*: float32 eM12*: float32 eM21*: float32 @@ -8391,7 +8391,7 @@ type LPXFORM* = ptr XFORM TXFORM* = XFORM PXFORM* = ptr XFORM - EMRBITBLT* = record + EMRBITBLT* {.final.} = object emr*: EMR rclBounds*: RECTL xDest*: LONG @@ -8411,7 +8411,7 @@ type tagEMRBITBLT* = EMRBITBLT TEMRBITBLT* = EMRBITBLT PEMRBITBLT* = ptr EMRBITBLT - LOGBRUSH* = record + LOGBRUSH* {.final.} = object lbStyle*: UINT lbColor*: COLORREF lbHatch*: LONG @@ -8419,7 +8419,7 @@ type tagLOGBRUSH* = LOGBRUSH TLOGBRUSH* = LOGBRUSH PLOGBRUSH* = ptr LOGBRUSH - EMRCREATEBRUSHINDIRECT* = record + EMRCREATEBRUSHINDIRECT* {.final.} = object emr*: EMR ihBrush*: DWORD lb*: LOGBRUSH @@ -8429,7 +8429,7 @@ type PEMRCREATEBRUSHINDIRECT* = ptr EMRCREATEBRUSHINDIRECT LCSCSTYPE* = LONG LCSGAMUTMATCH* = LONG - LOGCOLORSPACE* = record + LOGCOLORSPACE* {.final.} = object lcsSignature*: DWORD lcsVersion*: DWORD lcsSize*: DWORD @@ -8446,7 +8446,7 @@ type TLOGCOLORSPACE* = LOGCOLORSPACE TLOGCOLORSPACEA* = LOGCOLORSPACE PLOGCOLORSPACE* = ptr LOGCOLORSPACE - EMRCREATECOLORSPACE* = record + EMRCREATECOLORSPACE* {.final.} = object emr*: EMR ihCS*: DWORD lcs*: LOGCOLORSPACE @@ -8454,7 +8454,7 @@ type tagEMRCREATECOLORSPACE* = EMRCREATECOLORSPACE TEMRCREATECOLORSPACE* = EMRCREATECOLORSPACE PEMRCREATECOLORSPACE* = ptr EMRCREATECOLORSPACE - EMRCREATEDIBPATTERNBRUSHPT* = record + EMRCREATEDIBPATTERNBRUSHPT* {.final.} = object emr*: EMR ihBrush*: DWORD iUsage*: DWORD @@ -8466,7 +8466,7 @@ type tagEMRCREATEDIBPATTERNBRUSHPT* = EMRCREATEDIBPATTERNBRUSHPT TEMRCREATEDIBPATTERNBRUSHPT* = EMRCREATEDIBPATTERNBRUSHPT PEMRCREATEDIBPATTERNBRUSHPT* = EMRCREATEDIBPATTERNBRUSHPT - EMRCREATEMONOBRUSH* = record + EMRCREATEMONOBRUSH* {.final.} = object emr*: EMR ihBrush*: DWORD iUsage*: DWORD @@ -8478,7 +8478,7 @@ type tagEMRCREATEMONOBRUSH* = EMRCREATEMONOBRUSH TEMRCREATEMONOBRUSH* = EMRCREATEMONOBRUSH PEMRCREATEMONOBRUSH* = ptr EMRCREATEMONOBRUSH - PALETTEENTRY* = record + PALETTEENTRY* {.final.} = object peRed*: int8 peGreen*: int8 peBlue*: int8 @@ -8488,7 +8488,7 @@ type tagPALETTEENTRY* = PALETTEENTRY TPALETTEENTRY* = PALETTEENTRY PPALETTEENTRY* = ptr PALETTEENTRY - LOGPALETTE* = record + LOGPALETTE* {.final.} = object palVersion*: int16 palNumEntries*: int16 palPalEntry*: array[0..0, PALETTEENTRY] @@ -8497,7 +8497,7 @@ type tagLOGPALETTE* = LOGPALETTE TLOGPALETTE* = LOGPALETTE PLOGPALETTE* = ptr LOGPALETTE - EMRCREATEPALETTE* = record + EMRCREATEPALETTE* {.final.} = object emr*: EMR ihPal*: DWORD lgpl*: LOGPALETTE @@ -8505,7 +8505,7 @@ type tagEMRCREATEPALETTE* = EMRCREATEPALETTE TEMRCREATEPALETTE* = EMRCREATEPALETTE PEMRCREATEPALETTE* = ptr EMRCREATEPALETTE - LOGPEN* = record + LOGPEN* {.final.} = object lopnStyle*: UINT lopnWidth*: POINT lopnColor*: COLORREF @@ -8513,7 +8513,7 @@ type tagLOGPEN* = LOGPEN TLOGPEN* = LOGPEN PLOGPEN* = ptr LOGPEN - EMRCREATEPEN* = record + EMRCREATEPEN* {.final.} = object emr*: EMR ihPen*: DWORD lopn*: LOGPEN @@ -8521,7 +8521,7 @@ type tagEMRCREATEPEN* = EMRCREATEPEN TEMRCREATEPEN* = EMRCREATEPEN PEMRCREATEPEN* = ptr EMRCREATEPEN - EMRELLIPSE* = record + EMRELLIPSE* {.final.} = object emr*: EMR rclBox*: RECTL @@ -8531,7 +8531,7 @@ type EMRRECTANGLE* = EMRELLIPSE TEMRRECTANGLE* = EMRELLIPSE PEMRRECTANGLE* = ptr EMRELLIPSE - EMREOF* = record + EMREOF* {.final.} = object emr*: EMR nPalEntries*: DWORD offPalEntries*: DWORD @@ -8540,7 +8540,7 @@ type tagEMREOF* = EMREOF TEMREOF* = EMREOF PEMREOF* = ptr EMREOF - EMREXCLUDECLIPRECT* = record + EMREXCLUDECLIPRECT* {.final.} = object emr*: EMR rclClip*: RECTL @@ -8550,7 +8550,7 @@ type EMRINTERSECTCLIPRECT* = EMREXCLUDECLIPRECT TEMRINTERSECTCLIPRECT* = EMREXCLUDECLIPRECT PEMRINTERSECTCLIPRECT* = ptr EMREXCLUDECLIPRECT - PANOSE* = record + PANOSE* {.final.} = object bFamilyType*: int8 bSerifStyle*: int8 bWeight*: int8 @@ -8565,7 +8565,7 @@ type tagPANOSE* = PANOSE TPANOSE* = PANOSE PPANOSE* = ptr PANOSE - EXTLOGFONT* = record + EXTLOGFONT* {.final.} = object elfLogFont*: LOGFONT elfFullName*: array[0..(LF_FULLFACESIZE) - 1, BCHAR] elfStyle*: array[0..(LF_FACESIZE) - 1, BCHAR] @@ -8580,7 +8580,7 @@ type tagEXTLOGFONT* = EXTLOGFONT TEXTLOGFONT* = EXTLOGFONT PEXTLOGFONT* = ptr EXTLOGFONT - EMREXTCREATEFONTINDIRECTW* = record + EMREXTCREATEFONTINDIRECTW* {.final.} = object emr*: EMR ihFont*: DWORD elfw*: EXTLOGFONT @@ -8588,7 +8588,7 @@ type tagEMREXTCREATEFONTINDIRECTW* = EMREXTCREATEFONTINDIRECTW TEMREXTCREATEFONTINDIRECTW* = EMREXTCREATEFONTINDIRECTW PEMREXTCREATEFONTINDIRECTW* = ptr EMREXTCREATEFONTINDIRECTW - EXTLOGPEN* = record + EXTLOGPEN* {.final.} = object elpPenStyle*: UINT elpWidth*: UINT elpBrushStyle*: UINT @@ -8600,7 +8600,7 @@ type tagEXTLOGPEN* = EXTLOGPEN TEXTLOGPEN* = EXTLOGPEN PEXTLOGPEN* = ptr EXTLOGPEN - EMREXTCREATEPEN* = record + EMREXTCREATEPEN* {.final.} = object emr*: EMR ihPen*: DWORD offBmi*: DWORD @@ -8612,7 +8612,7 @@ type tagEMREXTCREATEPEN* = EMREXTCREATEPEN TEMREXTCREATEPEN* = EMREXTCREATEPEN PEMREXTCREATEPEN* = ptr EMREXTCREATEPEN - EMREXTFLOODFILL* = record + EMREXTFLOODFILL* {.final.} = object emr*: EMR ptlStart*: POINTL crColor*: COLORREF @@ -8621,7 +8621,7 @@ type tagEMREXTFLOODFILL* = EMREXTFLOODFILL TEMREXTFLOODFILL* = EMREXTFLOODFILL PEMREXTFLOODFILL* = ptr EMREXTFLOODFILL - EMREXTSELECTCLIPRGN* = record + EMREXTSELECTCLIPRGN* {.final.} = object emr*: EMR cbRgnData*: DWORD iMode*: DWORD @@ -8630,7 +8630,7 @@ type tagEMREXTSELECTCLIPRGN* = EMREXTSELECTCLIPRGN TEMREXTSELECTCLIPRGN* = EMREXTSELECTCLIPRGN PEMREXTSELECTCLIPRGN* = ptr EMREXTSELECTCLIPRGN - EMRTEXT* = record + EMRTEXT* {.final.} = object ptlReference*: POINTL nChars*: DWORD offString*: DWORD @@ -8641,7 +8641,7 @@ type tagEMRTEXT* = EMRTEXT TEMRTEXT* = EMRTEXT PEMRTEXT* = ptr EMRTEXT - EMREXTTEXTOUTA* = record + EMREXTTEXTOUTA* {.final.} = object emr*: EMR rclBounds*: RECTL iGraphicsMode*: DWORD @@ -8655,7 +8655,7 @@ type EMREXTTEXTOUTW* = EMREXTTEXTOUTA TEMREXTTEXTOUTW* = EMREXTTEXTOUTA PEMREXTTEXTOUTW* = ptr EMREXTTEXTOUTA - EMRFILLPATH* = record + EMRFILLPATH* {.final.} = object emr*: EMR rclBounds*: RECTL @@ -8668,7 +8668,7 @@ type EMRSTROKEPATH* = EMRFILLPATH TEMRSTROKEPATH* = EMRFILLPATH PEMRSTROKEPATH* = ptr EMRFILLPATH - EMRFILLRGN* = record + EMRFILLRGN* {.final.} = object emr*: EMR rclBounds*: RECTL cbRgnData*: DWORD @@ -8678,7 +8678,7 @@ type tagEMRFILLRGN* = EMRFILLRGN TEMRFILLRGN* = EMRFILLRGN PEMRFILLRGN* = ptr EMRFILLRGN - EMRFORMAT* = record + EMRFORMAT* {.final.} = object dSignature*: DWORD nVersion*: DWORD cbData*: DWORD @@ -8687,7 +8687,7 @@ type tagEMRFORMAT* = EMRFORMAT TEMRFORMAT* = EMRFORMAT PEMRFORMAT* = ptr EMRFORMAT - SIZE* = record + SIZE* {.final.} = object cx*: LONG cy*: LONG @@ -8699,7 +8699,7 @@ type TSIZEL* = SIZE PSIZEL* = ptr SIZE LPSIZEL* = ptr SIZE - EMRFRAMERGN* = record + EMRFRAMERGN* {.final.} = object emr*: EMR rclBounds*: RECTL cbRgnData*: DWORD @@ -8710,7 +8710,7 @@ type tagEMRFRAMERGN* = EMRFRAMERGN TEMRFRAMERGN* = EMRFRAMERGN PEMRFRAMERGN* = ptr EMRFRAMERGN - EMRGDICOMMENT* = record + EMRGDICOMMENT* {.final.} = object emr*: EMR cbData*: DWORD Data*: array[0..0, int8] @@ -8718,7 +8718,7 @@ type tagEMRGDICOMMENT* = EMRGDICOMMENT TEMRGDICOMMENT* = EMRGDICOMMENT PEMRGDICOMMENT* = ptr EMRGDICOMMENT - EMRINVERTRGN* = record + EMRINVERTRGN* {.final.} = object emr*: EMR rclBounds*: RECTL cbRgnData*: DWORD @@ -8730,7 +8730,7 @@ type EMRPAINTRGN* = EMRINVERTRGN TEMRPAINTRGN* = EMRINVERTRGN PEMRPAINTRGN* = ptr EMRINVERTRGN - EMRLINETO* = record + EMRLINETO* {.final.} = object emr*: EMR ptl*: POINTL @@ -8740,7 +8740,7 @@ type EMRMOVETOEX* = EMRLINETO TEMRMOVETOEX* = EMRLINETO PEMRMOVETOEX* = ptr EMRLINETO - EMRMASKBLT* = record + EMRMASKBLT* {.final.} = object emr*: EMR rclBounds*: RECTL xDest*: LONG @@ -8768,7 +8768,7 @@ type tagEMRMASKBLT* = EMRMASKBLT TEMRMASKBLT* = EMRMASKBLT PEMRMASKBLT* = ptr EMRMASKBLT - EMRMODIFYWORLDTRANSFORM* = record + EMRMODIFYWORLDTRANSFORM* {.final.} = object emr*: EMR xform*: XFORM iMode*: DWORD @@ -8776,14 +8776,14 @@ type tagEMRMODIFYWORLDTRANSFORM* = EMRMODIFYWORLDTRANSFORM TEMRMODIFYWORLDTRANSFORM* = EMRMODIFYWORLDTRANSFORM PEMRMODIFYWORLDTRANSFORM* = EMRMODIFYWORLDTRANSFORM - EMROFFSETCLIPRGN* = record + EMROFFSETCLIPRGN* {.final.} = object emr*: EMR ptlOffset*: POINTL tagEMROFFSETCLIPRGN* = EMROFFSETCLIPRGN TEMROFFSETCLIPRGN* = EMROFFSETCLIPRGN PEMROFFSETCLIPRGN* = ptr EMROFFSETCLIPRGN - EMRPLGBLT* = record + EMRPLGBLT* {.final.} = object emr*: EMR rclBounds*: RECTL aptlDest*: array[0..2, POINTL] @@ -8809,7 +8809,7 @@ type tagEMRPLGBLT* = EMRPLGBLT TEMRPLGBLT* = EMRPLGBLT PEMRPLGBLT* = ptr EMRPLGBLT - EMRPOLYDRAW* = record + EMRPOLYDRAW* {.final.} = object emr*: EMR rclBounds*: RECTL cptl*: DWORD @@ -8819,7 +8819,7 @@ type tagEMRPOLYDRAW* = EMRPOLYDRAW TEMRPOLYDRAW* = EMRPOLYDRAW PEMRPOLYDRAW* = ptr EMRPOLYDRAW - EMRPOLYDRAW16* = record + EMRPOLYDRAW16* {.final.} = object emr*: EMR rclBounds*: RECTL cpts*: DWORD @@ -8829,7 +8829,7 @@ type tagEMRPOLYDRAW16* = EMRPOLYDRAW16 TEMRPOLYDRAW16* = EMRPOLYDRAW16 PEMRPOLYDRAW16* = ptr EMRPOLYDRAW16 - EMRPOLYLINE* = record + EMRPOLYLINE* {.final.} = object emr*: EMR rclBounds*: RECTL cptl*: DWORD @@ -8850,7 +8850,7 @@ type EMRPOLYLINETO* = EMRPOLYLINE TEMRPOLYLINETO* = EMRPOLYLINE PEMRPOLYLINETO* = ptr EMRPOLYLINE - EMRPOLYLINE16* = record + EMRPOLYLINE16* {.final.} = object emr*: EMR rclBounds*: RECTL cpts*: DWORD @@ -8871,7 +8871,7 @@ type EMRPOLYLINETO16* = EMRPOLYLINE16 TEMRPOLYLINETO16* = EMRPOLYLINE16 PEMRPOLYLINETO16* = ptr EMRPOLYLINE16 - EMRPOLYPOLYLINE* = record + EMRPOLYPOLYLINE* {.final.} = object emr*: EMR rclBounds*: RECTL nPolys*: DWORD @@ -8885,7 +8885,7 @@ type EMRPOLYPOLYGON* = EMRPOLYPOLYLINE TEMRPOLYPOLYGON* = EMRPOLYPOLYLINE PEMRPOLYPOLYGON* = ptr EMRPOLYPOLYLINE - EMRPOLYPOLYLINE16* = record + EMRPOLYPOLYLINE16* {.final.} = object emr*: EMR rclBounds*: RECTL nPolys*: DWORD @@ -8899,7 +8899,7 @@ type EMRPOLYPOLYGON16* = EMRPOLYPOLYLINE16 TEMRPOLYPOLYGON16* = EMRPOLYPOLYLINE16 PEMRPOLYPOLYGON16* = ptr EMRPOLYPOLYLINE16 - EMRPOLYTEXTOUTA* = record + EMRPOLYTEXTOUTA* {.final.} = object emr*: EMR rclBounds*: RECTL iGraphicsMode*: DWORD @@ -8914,7 +8914,7 @@ type EMRPOLYTEXTOUTW* = EMRPOLYTEXTOUTA TEMRPOLYTEXTOUTW* = EMRPOLYTEXTOUTA PEMRPOLYTEXTOUTW* = ptr EMRPOLYTEXTOUTA - EMRRESIZEPALETTE* = record + EMRRESIZEPALETTE* {.final.} = object emr*: EMR ihPal*: DWORD cEntries*: DWORD @@ -8922,14 +8922,14 @@ type tagEMRRESIZEPALETTE* = EMRRESIZEPALETTE TEMRRESIZEPALETTE* = EMRRESIZEPALETTE PEMRRESIZEPALETTE* = ptr EMRRESIZEPALETTE - EMRRESTOREDC* = record + EMRRESTOREDC* {.final.} = object emr*: EMR iRelative*: LONG tagEMRRESTOREDC* = EMRRESTOREDC TEMRRESTOREDC* = EMRRESTOREDC PEMRRESTOREDC* = ptr EMRRESTOREDC - EMRROUNDRECT* = record + EMRROUNDRECT* {.final.} = object emr*: EMR rclBox*: RECTL szlCorner*: SIZEL @@ -8937,7 +8937,7 @@ type tagEMRROUNDRECT* = EMRROUNDRECT TEMRROUNDRECT* = EMRROUNDRECT PEMRROUNDRECT* = ptr EMRROUNDRECT - EMRSCALEVIEWPORTEXTEX* = record + EMRSCALEVIEWPORTEXTEX* {.final.} = object emr*: EMR xNum*: LONG xDenom*: LONG @@ -8950,7 +8950,7 @@ type EMRSCALEWINDOWEXTEX* = EMRSCALEVIEWPORTEXTEX TEMRSCALEWINDOWEXTEX* = EMRSCALEVIEWPORTEXTEX PEMRSCALEWINDOWEXTEX* = ptr EMRSCALEVIEWPORTEXTEX - EMRSELECTCOLORSPACE* = record + EMRSELECTCOLORSPACE* {.final.} = object emr*: EMR ihCS*: DWORD @@ -8960,7 +8960,7 @@ type EMRDELETECOLORSPACE* = EMRSELECTCOLORSPACE TEMRDELETECOLORSPACE* = EMRSELECTCOLORSPACE PEMRDELETECOLORSPACE* = ptr EMRSELECTCOLORSPACE - EMRSELECTOBJECT* = record + EMRSELECTOBJECT* {.final.} = object emr*: EMR ihObject*: DWORD @@ -8970,21 +8970,21 @@ type EMRDELETEOBJECT* = EMRSELECTOBJECT TEMRDELETEOBJECT* = EMRSELECTOBJECT PEMRDELETEOBJECT* = ptr EMRSELECTOBJECT - EMRSELECTPALETTE* = record + EMRSELECTPALETTE* {.final.} = object emr*: EMR ihPal*: DWORD tagEMRSELECTPALETTE* = EMRSELECTPALETTE TEMRSELECTPALETTE* = EMRSELECTPALETTE PEMRSELECTPALETTE* = ptr EMRSELECTPALETTE - EMRSETARCDIRECTION* = record + EMRSETARCDIRECTION* {.final.} = object emr*: EMR iArcDirection*: DWORD tagEMRSETARCDIRECTION* = EMRSETARCDIRECTION TEMRSETARCDIRECTION* = EMRSETARCDIRECTION PEMRSETARCDIRECTION* = ptr EMRSETARCDIRECTION - EMRSETBKCOLOR* = record + EMRSETBKCOLOR* {.final.} = object emr*: EMR crColor*: COLORREF @@ -8994,14 +8994,14 @@ type EMRSETTEXTCOLOR* = EMRSETBKCOLOR TEMRSETTEXTCOLOR* = EMRSETBKCOLOR PEMRSETTEXTCOLOR* = ptr EMRSETBKCOLOR - EMRSETCOLORADJUSTMENT* = record + EMRSETCOLORADJUSTMENT* {.final.} = object emr*: EMR ColorAdjustment*: COLORADJUSTMENT tagEMRSETCOLORADJUSTMENT* = EMRSETCOLORADJUSTMENT TEMRSETCOLORADJUSTMENT* = EMRSETCOLORADJUSTMENT PEMRSETCOLORADJUSTMENT* = ptr EMRSETCOLORADJUSTMENT - EMRSETDIBITSTODEVICE* = record + EMRSETDIBITSTODEVICE* {.final.} = object emr*: EMR rclBounds*: RECTL xDest*: LONG @@ -9021,21 +9021,21 @@ type tagEMRSETDIBITSTODEVICE* = EMRSETDIBITSTODEVICE TEMRSETDIBITSTODEVICE* = EMRSETDIBITSTODEVICE PEMRSETDIBITSTODEVICE* = ptr EMRSETDIBITSTODEVICE - EMRSETMAPPERFLAGS* = record + EMRSETMAPPERFLAGS* {.final.} = object emr*: EMR dwFlags*: DWORD tagEMRSETMAPPERFLAGS* = EMRSETMAPPERFLAGS TEMRSETMAPPERFLAGS* = EMRSETMAPPERFLAGS PEMRSETMAPPERFLAGS* = ptr EMRSETMAPPERFLAGS - EMRSETMITERLIMIT* = record + EMRSETMITERLIMIT* {.final.} = object emr*: EMR eMiterLimit*: float32 tagEMRSETMITERLIMIT* = EMRSETMITERLIMIT TEMRSETMITERLIMIT* = EMRSETMITERLIMIT PEMRSETMITERLIMIT* = ptr EMRSETMITERLIMIT - EMRSETPALETTEENTRIES* = record + EMRSETPALETTEENTRIES* {.final.} = object emr*: EMR ihPal*: DWORD iStart*: DWORD @@ -9045,7 +9045,7 @@ type tagEMRSETPALETTEENTRIES* = EMRSETPALETTEENTRIES TEMRSETPALETTEENTRIES* = EMRSETPALETTEENTRIES PEMRSETPALETTEENTRIES* = ptr EMRSETPALETTEENTRIES - EMRSETPIXELV* = record + EMRSETPIXELV* {.final.} = object emr*: EMR ptlPixel*: POINTL crColor*: COLORREF @@ -9053,7 +9053,7 @@ type tagEMRSETPIXELV* = EMRSETPIXELV TEMRSETPIXELV* = EMRSETPIXELV PEMRSETPIXELV* = ptr EMRSETPIXELV - EMRSETVIEWPORTEXTEX* = record + EMRSETVIEWPORTEXTEX* {.final.} = object emr*: EMR szlExtent*: SIZEL @@ -9063,7 +9063,7 @@ type EMRSETWINDOWEXTEX* = EMRSETVIEWPORTEXTEX TEMRSETWINDOWEXTEX* = EMRSETVIEWPORTEXTEX PEMRSETWINDOWEXTEX* = ptr EMRSETVIEWPORTEXTEX - EMRSETVIEWPORTORGEX* = record + EMRSETVIEWPORTORGEX* {.final.} = object emr*: EMR ptlOrigin*: POINTL @@ -9076,14 +9076,14 @@ type EMRSETBRUSHORGEX* = EMRSETVIEWPORTORGEX TEMRSETBRUSHORGEX* = EMRSETVIEWPORTORGEX PEMRSETBRUSHORGEX* = ptr EMRSETVIEWPORTORGEX - EMRSETWORLDTRANSFORM* = record + EMRSETWORLDTRANSFORM* {.final.} = object emr*: EMR xform*: XFORM tagEMRSETWORLDTRANSFORM* = EMRSETWORLDTRANSFORM TEMRSETWORLDTRANSFORM* = EMRSETWORLDTRANSFORM PEMRSETWORLDTRANSFORM* = ptr EMRSETWORLDTRANSFORM - EMRSTRETCHBLT* = record + EMRSTRETCHBLT* {.final.} = object emr*: EMR rclBounds*: RECTL xDest*: LONG @@ -9106,7 +9106,7 @@ type tagEMRSTRETCHBLT* = EMRSTRETCHBLT TEMRSTRETCHBLT* = EMRSTRETCHBLT PEMRSTRETCHBLT* = ptr EMRSTRETCHBLT - EMRSTRETCHDIBITS* = record + EMRSTRETCHDIBITS* {.final.} = object emr*: EMR rclBounds*: RECTL xDest*: LONG @@ -9127,7 +9127,7 @@ type tagEMRSTRETCHDIBITS* = EMRSTRETCHDIBITS TEMRSTRETCHDIBITS* = EMRSTRETCHDIBITS PEMRSTRETCHDIBITS* = ptr EMRSTRETCHDIBITS - EMRABORTPATH* = record + EMRABORTPATH* {.final.} = object emr*: EMR TEMRABORTPATH* = EMRABORTPATH @@ -9158,7 +9158,7 @@ type EMRREALIZEPALETTE* = EMRABORTPATH TEMRREALIZEPALETTE* = EMRABORTPATH PEMRREALIZEPALETTE* = ptr EMRABORTPATH - EMRSELECTCLIPPATH* = record + EMRSELECTCLIPPATH* {.final.} = object emr*: EMR iMode*: DWORD @@ -9186,7 +9186,7 @@ type EMRENABLEICM* = EMRSELECTCLIPPATH TEMRENABLEICM* = EMRSELECTCLIPPATH PEMRENABLEICM* = ptr EMRSELECTCLIPPATH - NMHDR* = record + NMHDR* {.final.} = object hwndFrom*: HWND idFrom*: UINT code*: UINT @@ -9194,33 +9194,33 @@ type tagNMHDR* = NMHDR TNMHDR* = NMHDR PNMHDR* = ptr NMHDR - TENCORRECTTEXT* = record + TENCORRECTTEXT* {.final.} = object nmhdr*: NMHDR chrg*: CHARRANGE seltyp*: int16 Pencorrecttext* = ptr TENCORRECTTEXT - TENDROPFILES* = record + TENDROPFILES* {.final.} = object nmhdr*: NMHDR hDrop*: HANDLE cp*: LONG fProtected*: WINBOOL Pendropfiles* = ptr TENDROPFILES - TENSAVECLIPBOARD* = record + TENSAVECLIPBOARD* {.final.} = object nmhdr*: NMHDR cObjectCount*: LONG cch*: LONG PENSAVECLIPBOARD* = ptr TENSAVECLIPBOARD - TENOLEOPFAILED* = record + TENOLEOPFAILED* {.final.} = object nmhdr*: NMHDR iob*: LONG lOper*: LONG hr*: HRESULT PENOLEOPFAILED* = ptr TENOLEOPFAILED - TENHMETAHEADER* = record + TENHMETAHEADER* {.final.} = object iType*: DWORD nSize*: DWORD rclBounds*: RECTL @@ -9239,14 +9239,14 @@ type LPENHMETAHEADER* = ptr TENHMETAHEADER PENHMETAHEADER* = ptr TENHMETAHEADER - TENHMETARECORD* = record + TENHMETARECORD* {.final.} = object iType*: DWORD nSize*: DWORD dParm*: array[0..0, DWORD] LPENHMETARECORD* = ptr TENHMETARECORD PENHMETARECORD* = ptr TENHMETARECORD - TENPROTECTED* = record + TENPROTECTED* {.final.} = object nmhdr*: NMHDR msg*: UINT wParam*: WPARAM @@ -9254,7 +9254,7 @@ type chrg*: CHARRANGE Penprotected* = ptr TENPROTECTED - SERVICE_STATUS* = record + SERVICE_STATUS* {.final.} = object dwServiceType*: DWORD dwCurrentState*: DWORD dwControlsAccepted*: DWORD @@ -9266,7 +9266,7 @@ type LPSERVICE_STATUS* = ptr SERVICE_STATUS TSERVICESTATUS* = SERVICE_STATUS PSERVICESTATUS* = ptr SERVICE_STATUS - ENUM_SERVICE_STATUS* = record + ENUM_SERVICE_STATUS* {.final.} = object lpServiceName*: LPTSTR lpDisplayName*: LPTSTR ServiceStatus*: SERVICE_STATUS @@ -9274,14 +9274,14 @@ type LPENUM_SERVICE_STATUS* = ptr ENUM_SERVICE_STATUS TENUMSERVICESTATUS* = ENUM_SERVICE_STATUS PENUMSERVICESTATUS* = ptr ENUM_SERVICE_STATUS - ENUMLOGFONT* = record + ENUMLOGFONT* {.final.} = object elfLogFont*: LOGFONT elfFullName*: array[0..(LF_FULLFACESIZE) - 1, BCHAR] elfStyle*: array[0..(LF_FACESIZE) - 1, BCHAR] TENUMLOGFONT* = ENUMLOGFONT PENUMLOGFONT* = ptr ENUMLOGFONT - ENUMLOGFONTEX* = record + ENUMLOGFONTEX* {.final.} = object elfLogFont*: LOGFONT elfFullName*: array[0..(LF_FULLFACESIZE) - 1, BCHAR] elfStyle*: array[0..(LF_FACESIZE) - 1, BCHAR] @@ -9300,7 +9300,7 @@ type # CHAR Pad[] # DWORD Length; # - EVENTLOGRECORD* = record + EVENTLOGRECORD* {.final.} = object len*: DWORD Reserved*: DWORD RecordNumber*: DWORD @@ -9320,7 +9320,7 @@ type TEVENTLOGRECORD* = EVENTLOGRECORD PEVENTLOGRECORD* = ptr EVENTLOGRECORD - EVENTMSG* = record + EVENTMSG* {.final.} = object message*: UINT paramL*: UINT paramH*: UINT @@ -9330,14 +9330,14 @@ type tagEVENTMSG* = EVENTMSG TEVENTMSG* = EVENTMSG PEVENTMSG* = ptr EVENTMSG - EXCEPTION_POINTERS* = record + EXCEPTION_POINTERS* {.final.} = object ExceptionRecord*: PEXCEPTION_RECORD ContextRecord*: PCONTEXT LPEXCEPTION_POINTERS* = ptr EXCEPTION_POINTERS PEXCEPTION_POINTERS* = ptr EXCEPTION_POINTERS TEXCEPTIONPOINTERS* = EXCEPTION_POINTERS - EXT_BUTTON* = record + EXT_BUTTON* {.final.} = object idCommand*: int16 idsHelp*: int16 fsStyle*: int16 @@ -9345,7 +9345,7 @@ type LPEXT_BUTTON* = ptr EXT_BUTTON TEXTBUTTON* = EXT_BUTTON PEXTBUTTON* = ptr EXT_BUTTON - FILTERKEYS* = record + FILTERKEYS* {.final.} = object cbSize*: UINT dwFlags*: DWORD iWaitMSec*: DWORD @@ -9355,7 +9355,7 @@ type TFILTERKEYS* = FILTERKEYS PFILTERKEYS* = ptr FILTERKEYS - FIND_NAME_BUFFER* = record + FIND_NAME_BUFFER* {.final.} = object len*: UCHAR access_control*: UCHAR frame_control*: UCHAR @@ -9365,14 +9365,14 @@ type TFINDNAMEBUFFER* = FIND_NAME_BUFFER PFINDNAMEBUFFER* = ptr FIND_NAME_BUFFER - FIND_NAME_HEADER* = record + FIND_NAME_HEADER* {.final.} = object node_count*: int16 reserved*: UCHAR unique_group*: UCHAR TFINDNAMEHEADER* = FIND_NAME_HEADER PFINDNAMEHEADER* = ptr FIND_NAME_HEADER - FINDREPLACE* = record + FINDREPLACE* {.final.} = object lStructSize*: DWORD hwndOwner*: HWND hInstance*: HINST @@ -9388,19 +9388,19 @@ type LPFINDREPLACE* = ptr FINDREPLACE TFINDREPLACE* = FINDREPLACE PFINDREPLACE* = ptr FINDREPLACE #FINDTEXT = record conflicts with FindText function - TFINDTEXT* = record + TFINDTEXT* {.final.} = object chrg*: CHARRANGE lpstrText*: LPSTR Pfindtext* = ptr TFINDTEXT - FINDTEXTEX* = record + FINDTEXTEX* {.final.} = object chrg*: CHARRANGE lpstrText*: LPSTR chrgText*: CHARRANGE Tfindtextex* = FINDTEXTEX Pfindtextex* = ptr FINDTEXTEX - FMS_GETDRIVEINFO* = record + FMS_GETDRIVEINFO* {.final.} = object dwTotalSpace*: DWORD dwFreeSpace*: DWORD szPath*: array[0..259, TCHAR] @@ -9409,7 +9409,7 @@ type TFMSGETDRIVEINFO* = FMS_GETDRIVEINFO PFMSGETDRIVEINFO* = ptr FMS_GETDRIVEINFO - FMS_GETFILESEL* = record + FMS_GETFILESEL* {.final.} = object ftTime*: FILETIME dwSize*: DWORD bAttr*: int8 @@ -9417,7 +9417,7 @@ type TFMSGETFILESEL* = FMS_GETFILESEL PFMSGETFILESEL* = ptr FMS_GETFILESEL - FMS_LOAD* = record + FMS_LOAD* {.final.} = object dwSize*: DWORD szMenuName*: array[0..(MENU_TEXT_LEN) - 1, TCHAR] hMenu*: HMENU @@ -9425,7 +9425,7 @@ type TFMSLOAD* = FMS_LOAD PFMSLOAD* = ptr FMS_LOAD - FMS_TOOLBARLOAD* = record + FMS_TOOLBARLOAD* {.final.} = object dwSize*: DWORD lpButtons*: LPEXT_BUTTON cButtons*: int16 @@ -9435,12 +9435,12 @@ type TFMSTOOLBARLOAD* = FMS_TOOLBARLOAD PFMSTOOLBARLOAD* = ptr FMS_TOOLBARLOAD - FOCUS_EVENT_RECORD* = record + FOCUS_EVENT_RECORD* {.final.} = object bSetFocus*: WINBOOL TFOCUSEVENTRECORD* = FOCUS_EVENT_RECORD PFOCUSEVENTRECORD* = ptr FOCUS_EVENT_RECORD - FORM_INFO_1* = record + FORM_INFO_1* {.final.} = object Flags*: DWORD pName*: LPTSTR Size*: SIZEL @@ -9448,7 +9448,7 @@ type TFORMINFO1* = FORM_INFO_1 PFORMINFO1* = ptr FORM_INFO_1 - FORMAT_PARAMETERS* = record + FORMAT_PARAMETERS* {.final.} = object MediaType*: MEDIA_TYPE StartCylinderNumber*: DWORD EndCylinderNumber*: DWORD @@ -9457,7 +9457,7 @@ type TFORMATPARAMETERS* = FORMAT_PARAMETERS PFORMATPARAMETERS* = ptr FORMAT_PARAMETERS - FORMATRANGE* = record + FORMATRANGE* {.final.} = object hdc*: HDC hdcTarget*: HDC rc*: RECT @@ -9466,7 +9466,7 @@ type Tformatrange* = FORMATRANGE Pformatrange* = ptr FORMATRANGE - GCP_RESULTS* = record + GCP_RESULTS* {.final.} = object lStructSize*: DWORD lpOutString*: LPTSTR lpOrder*: ptr UINT @@ -9481,7 +9481,7 @@ type tagGCP_RESULTS* = GCP_RESULTS TGCPRESULTS* = GCP_RESULTS PGCPRESULTS* = ptr GCP_RESULTS - GENERIC_MAPPING* = record + GENERIC_MAPPING* {.final.} = object GenericRead*: ACCESS_MASK GenericWrite*: ACCESS_MASK GenericExecute*: ACCESS_MASK @@ -9489,7 +9489,7 @@ type PGENERIC_MAPPING* = ptr GENERIC_MAPPING TGENERICMAPPING* = GENERIC_MAPPING - GLYPHMETRICS* = record + GLYPHMETRICS* {.final.} = object gmBlackBoxX*: UINT gmBlackBoxY*: UINT gmptGlyphOrigin*: POINT @@ -9499,20 +9499,20 @@ type LPGLYPHMETRICS* = ptr GLYPHMETRICS TGLYPHMETRICS* = GLYPHMETRICS PGLYPHMETRICS* = ptr GLYPHMETRICS - HANDLETABLE* = record + HANDLETABLE* {.final.} = object objectHandle*: array[0..0, HGDIOBJ] tagHANDLETABLE* = HANDLETABLE THANDLETABLE* = HANDLETABLE LPHANDLETABLE* = ptr HANDLETABLE - HD_HITTESTINFO* = record + HD_HITTESTINFO* {.final.} = object pt*: POINT flags*: UINT iItem*: int32 THDHITTESTINFO* = HD_HITTESTINFO PHDHITTESTINFO* = ptr HD_HITTESTINFO - HD_ITEM* = record + HD_ITEM* {.final.} = object mask*: UINT cxy*: int32 pszText*: LPTSTR @@ -9523,7 +9523,7 @@ type THDITEM* = HD_ITEM PHDITEM* = ptr HD_ITEM - WINDOWPOS* = record + WINDOWPOS* {.final.} = object hwnd*: HWND hwndInsertAfter*: HWND x*: int32 @@ -9535,13 +9535,13 @@ type LPWINDOWPOS* = ptr WINDOWPOS TWINDOWPOS* = WINDOWPOS PWINDOWPOS* = ptr WINDOWPOS - HD_LAYOUT* = record + HD_LAYOUT* {.final.} = object prc*: ptr RECT pwpos*: ptr WINDOWPOS THDLAYOUT* = HD_LAYOUT PHDLAYOUT* = ptr HD_LAYOUT - HD_NOTIFY* = record + HD_NOTIFY* {.final.} = object hdr*: NMHDR iItem*: int32 iButton*: int32 @@ -9549,7 +9549,7 @@ type THDNOTIFY* = HD_NOTIFY PHDNOTIFY* = ptr HD_NOTIFY - HELPINFO* = record + HELPINFO* {.final.} = object cbSize*: UINT iContextType*: int32 iCtrlId*: int32 @@ -9561,7 +9561,7 @@ type tagHELPINFO* = HELPINFO THELPINFO* = HELPINFO PHELPINFO* = ptr HELPINFO - HELPWININFO* = record + HELPWININFO* {.final.} = object wStructSize*: int32 x*: int32 y*: int32 @@ -9572,7 +9572,7 @@ type THELPWININFO* = HELPWININFO PHELPWININFO* = ptr HELPWININFO - HIGHCONTRAST* = record + HIGHCONTRAST* {.final.} = object cbSize*: UINT dwFlags*: DWORD lpszDefaultScheme*: LPTSTR @@ -9581,14 +9581,14 @@ type tagHIGHCONTRAST* = HIGHCONTRAST THIGHCONTRAST* = HIGHCONTRAST PHIGHCONTRAST* = ptr HIGHCONTRAST - HSZPAIR* = record + HSZPAIR* {.final.} = object hszSvc*: HSZ hszTopic*: HSZ tagHSZPAIR* = HSZPAIR THSZPAIR* = HSZPAIR PHSZPAIR* = ptr HSZPAIR - ICONINFO* = record + ICONINFO* {.final.} = object fIcon*: WINBOOL xHotspot*: DWORD yHotspot*: DWORD @@ -9597,7 +9597,7 @@ type TICONINFO* = ICONINFO PICONINFO* = ptr ICONINFO - ICONMETRICS* = record + ICONMETRICS* {.final.} = object cbSize*: UINT iHorzSpacing*: int32 iVertSpacing*: int32 @@ -9608,7 +9608,7 @@ type tagICONMETRICS* = ICONMETRICS TICONMETRICS* = ICONMETRICS PICONMETRICS* = ptr ICONMETRICS - IMAGEINFO* = record + IMAGEINFO* {.final.} = object hbmImage*: HBITMAP hbmMask*: HBITMAP Unused1*: int32 @@ -9617,7 +9617,7 @@ type TIMAGEINFO* = IMAGEINFO PIMAGEINFO* = ptr IMAGEINFO - KEY_EVENT_RECORD* = record + KEY_EVENT_RECORD* {.final.} = object bKeyDown*: WINBOOL wRepeatCount*: int16 wVirtualKeyCode*: int16 @@ -9627,7 +9627,7 @@ type TKEYEVENTRECORD* = KEY_EVENT_RECORD PKEYEVENTRECORD* = ptr KEY_EVENT_RECORD - MOUSE_EVENT_RECORD* = record + MOUSE_EVENT_RECORD* {.final.} = object dwMousePosition*: COORD dwButtonState*: DWORD dwControlKeyState*: DWORD @@ -9635,17 +9635,17 @@ type TMOUSEEVENTRECORD* = MOUSE_EVENT_RECORD PMOUSEEVENTRECORD* = ptr MOUSE_EVENT_RECORD - WINDOW_BUFFER_SIZE_RECORD* = record + WINDOW_BUFFER_SIZE_RECORD* {.final.} = object dwSize*: COORD TWINDOWBUFFERSIZERECORD* = WINDOW_BUFFER_SIZE_RECORD PWINDOWBUFFERSIZERECORD* = ptr WINDOW_BUFFER_SIZE_RECORD - MENU_EVENT_RECORD* = record + MENU_EVENT_RECORD* {.final.} = object dwCommandId*: UINT PMENU_EVENT_RECORD* = ptr MENU_EVENT_RECORD TMENUEVENTRECORD* = MENU_EVENT_RECORD - INPUT_RECORD* = record + INPUT_RECORD* {.final.} = object EventType*: int16 Reserved*: int16 event*: array[0..5, DWORD] #Event : record case longint of @@ -9658,7 +9658,7 @@ type PINPUT_RECORD* = ptr INPUT_RECORD TINPUTRECORD* = INPUT_RECORD - SYSTEMTIME* = record + SYSTEMTIME* {.final.} = object wYear*: int16 wMonth*: int16 wDayOfWeek*: int16 @@ -9671,7 +9671,7 @@ type LPSYSTEMTIME* = ptr SYSTEMTIME TSYSTEMTIME* = SYSTEMTIME PSYSTEMTIME* = ptr SYSTEMTIME - JOB_INFO_1* = record + JOB_INFO_1* {.final.} = object JobId*: DWORD pPrinterName*: LPTSTR pMachineName*: LPTSTR @@ -9688,13 +9688,13 @@ type TJOBINFO1* = JOB_INFO_1 PJOBINFO1* = ptr JOB_INFO_1 - SID_IDENTIFIER_AUTHORITY* = record + SID_IDENTIFIER_AUTHORITY* {.final.} = object Value*: array[0..5, int8] LPSID_IDENTIFIER_AUTHORITY* = ptr SID_IDENTIFIER_AUTHORITY PSID_IDENTIFIER_AUTHORITY* = ptr SID_IDENTIFIER_AUTHORITY TSIDIDENTIFIERAUTHORITY* = SID_IDENTIFIER_AUTHORITY - SID* = record + SID* {.final.} = object Revision*: int8 SubAuthorityCount*: int8 IdentifierAuthority*: SID_IDENTIFIER_AUTHORITY @@ -9705,7 +9705,7 @@ type SECURITY_DESCRIPTOR_CONTROL* = int16 PSECURITY_DESCRIPTOR_CONTROL* = ptr SECURITY_DESCRIPTOR_CONTROL TSECURITYDESCRIPTORCONTROL* = SECURITY_DESCRIPTOR_CONTROL - SECURITY_DESCRIPTOR* = record + SECURITY_DESCRIPTOR* {.final.} = object Revision*: int8 Sbz1*: int8 Control*: SECURITY_DESCRIPTOR_CONTROL @@ -9716,7 +9716,7 @@ type PSECURITY_DESCRIPTOR* = ptr SECURITY_DESCRIPTOR TSECURITYDESCRIPTOR* = SECURITY_DESCRIPTOR - JOB_INFO_2* = record + JOB_INFO_2* {.final.} = object JobId*: DWORD pPrinterName*: LPTSTR pMachineName*: LPTSTR @@ -9743,7 +9743,7 @@ type TJOBINFO2* = JOB_INFO_2 PJOBINFO2* = ptr JOB_INFO_2 - KERNINGPAIR* = record + KERNINGPAIR* {.final.} = object wFirst*: int16 wSecond*: int16 iKernAmount*: int32 @@ -9751,13 +9751,13 @@ type LPKERNINGPAIR* = ptr KERNINGPAIR TKERNINGPAIR* = KERNINGPAIR PKERNINGPAIR* = ptr KERNINGPAIR - LANA_ENUM* = record + LANA_ENUM* {.final.} = object len*: UCHAR lana*: array[0..(MAX_LANA) - 1, UCHAR] TLANAENUM* = LANA_ENUM PLANAENUM* = ptr LANA_ENUM - LDT_ENTRY* = record + LDT_ENTRY* {.final.} = object LimitLow*: int16 BaseLow*: int16 BaseMid*: int8 @@ -9792,7 +9792,7 @@ const bp_LDT_ENTRY_BaseHi* = 24 type - LOCALESIGNATURE* = record + LOCALESIGNATURE* {.final.} = object lsUsb*: array[0..3, DWORD] lsCsbDefault*: array[0..1, DWORD] lsCsbSupported*: array[0..1, DWORD] @@ -9800,12 +9800,12 @@ type tagLOCALESIGNATURE* = LOCALESIGNATURE TLOCALESIGNATURE* = LOCALESIGNATURE PLOCALESIGNATURE* = ptr LOCALESIGNATURE - LOCALGROUP_MEMBERS_INFO_0* = record + LOCALGROUP_MEMBERS_INFO_0* {.final.} = object lgrmi0_sid*: PSID TLOCALGROUPMEMBERSINFO0* = LOCALGROUP_MEMBERS_INFO_0 PLOCALGROUPMEMBERSINFO0* = ptr LOCALGROUP_MEMBERS_INFO_0 - LOCALGROUP_MEMBERS_INFO_3* = record + LOCALGROUP_MEMBERS_INFO_3* {.final.} = object lgrmi3_domainandname*: LPWSTR TLOCALGROUPMEMBERSINFO3* = LOCALGROUP_MEMBERS_INFO_3 @@ -9817,7 +9817,7 @@ type LUID* = TlargeInteger TLUID* = LUID PLUID* = ptr LUID - LUID_AND_ATTRIBUTES* = record + LUID_AND_ATTRIBUTES* {.final.} = object Luid*: LUID Attributes*: DWORD @@ -9826,7 +9826,7 @@ type LUID_AND_ATTRIBUTES_ARRAY* = array[0..(ANYSIZE_ARRAY) - 1, LUID_AND_ATTRIBUTES] PLUID_AND_ATTRIBUTES_ARRAY* = ptr LUID_AND_ATTRIBUTES_ARRAY TLUIDANDATTRIBUTESARRAY* = LUID_AND_ATTRIBUTES_ARRAY - LV_COLUMN* = record + LV_COLUMN* {.final.} = object mask*: UINT fmt*: int32 cx*: int32 @@ -9836,7 +9836,7 @@ type TLVCOLUMN* = LV_COLUMN PLVCOLUMN* = ptr LV_COLUMN - LV_ITEM* = record + LV_ITEM* {.final.} = object mask*: UINT iItem*: int32 iSubItem*: int32 @@ -9849,14 +9849,14 @@ type TLVITEM* = LV_ITEM PLVITEM* = ptr LV_ITEM - LV_DISPINFO* = record + LV_DISPINFO* {.final.} = object hdr*: NMHDR item*: LV_ITEM tagLV_DISPINFO* = LV_DISPINFO TLVDISPINFO* = LV_DISPINFO PLVDISPINFO* = ptr LV_DISPINFO - LV_FINDINFO* = record + LV_FINDINFO* {.final.} = object flags*: UINT psz*: LPCTSTR lParam*: LPARAM @@ -9865,14 +9865,14 @@ type TLVFINDINFO* = LV_FINDINFO PLVFINDINFO* = ptr LV_FINDINFO - LV_HITTESTINFO* = record + LV_HITTESTINFO* {.final.} = object pt*: POINT flags*: UINT iItem*: int32 TLVHITTESTINFO* = LV_HITTESTINFO PLVHITTESTINFO* = ptr LV_HITTESTINFO - LV_KEYDOWN* = record + LV_KEYDOWN* {.final.} = object hdr*: NMHDR wVKey*: int16 flags*: UINT @@ -9880,7 +9880,7 @@ type tagLV_KEYDOWN* = LV_KEYDOWN TLVKEYDOWN* = LV_KEYDOWN PLVKEYDOWN* = ptr LV_KEYDOWN - MAT2* = record + MAT2* {.final.} = object eM11*: FIXED eM12*: FIXED eM21*: FIXED @@ -9888,7 +9888,7 @@ type TMAT2* = MAT2 PMAT2* = ptr MAT2 - MDICREATESTRUCT* = record + MDICREATESTRUCT* {.final.} = object szClass*: LPCTSTR szTitle*: LPCTSTR hOwner*: HANDLE @@ -9903,7 +9903,7 @@ type tagMDICREATESTRUCT* = MDICREATESTRUCT TMDICREATESTRUCT* = MDICREATESTRUCT PMDICREATESTRUCT* = ptr MDICREATESTRUCT - MEASUREITEMSTRUCT* = record + MEASUREITEMSTRUCT* {.final.} = object CtlType*: UINT CtlID*: UINT itemID*: UINT @@ -9915,7 +9915,7 @@ type tagMEASUREITEMSTRUCT* = MEASUREITEMSTRUCT TMEASUREITEMSTRUCT* = MEASUREITEMSTRUCT PMEASUREITEMSTRUCT* = ptr MEASUREITEMSTRUCT - MEMORY_BASIC_INFORMATION* = record + MEMORY_BASIC_INFORMATION* {.final.} = object BaseAddress*: PVOID AllocationBase*: PVOID AllocationProtect*: DWORD @@ -9926,7 +9926,7 @@ type PMEMORY_BASIC_INFORMATION* = ptr MEMORY_BASIC_INFORMATION TMEMORYBASICINFORMATION* = MEMORY_BASIC_INFORMATION - MEMORYSTATUS* = record + MEMORYSTATUS* {.final.} = object dwLength*: DWORD dwMemoryLoad*: DWORD dwTotalPhys*: int @@ -9936,7 +9936,7 @@ type dwTotalVirtual*: int dwAvailVirtual*: int - TGUID* = record + TGUID* {.final.} = object D1*: int32 D2*: int16 D3*: int16 @@ -9945,14 +9945,14 @@ type LPMEMORYSTATUS* = ptr MEMORYSTATUS TMEMORYSTATUS* = MEMORYSTATUS PMEMORYSTATUS* = ptr MEMORYSTATUS - MENUEX_TEMPLATE_HEADER* = record + MENUEX_TEMPLATE_HEADER* {.final.} = object wVersion*: int16 wOffset*: int16 dwHelpId*: DWORD TMENUXTEMPLATEHEADER* = MENUEX_TEMPLATE_HEADER PMENUXTEMPLATEHEADER* = ptr MENUEX_TEMPLATE_HEADER - MENUEX_TEMPLATE_ITEM* = record + MENUEX_TEMPLATE_ITEM* {.final.} = object dwType*: DWORD dwState*: DWORD uId*: UINT @@ -9962,7 +9962,7 @@ type TMENUEXTEMPLATEITEM* = MENUEX_TEMPLATE_ITEM PMENUEXTEMPLATEITEM* = ptr MENUEX_TEMPLATE_ITEM - MENUINFO* = record + MENUINFO* {.final.} = object cbSize*: DWORD fMask*: DWORD dwStyle*: DWORD @@ -9976,7 +9976,7 @@ type tagMENUINFO* = MENUINFO TMENUINFO* = MENUINFO PMENUINFO* = ptr MENUINFO - MENUITEMINFO* = record + MENUITEMINFO* {.final.} = object cbSize*: UINT fMask*: UINT fType*: UINT @@ -9996,24 +9996,24 @@ type TMENUITEMINFO* = MENUITEMINFO TMENUITEMINFOA* = MENUITEMINFO PMENUITEMINFO* = ptr MENUITEMINFO - MENUITEMTEMPLATE* = record + MENUITEMTEMPLATE* {.final.} = object mtOption*: int16 mtID*: int16 mtString*: array[0..0, WCHAR] TMENUITEMTEMPLATE* = MENUITEMTEMPLATE PMENUITEMTEMPLATE* = ptr MENUITEMTEMPLATE - MENUITEMTEMPLATEHEADER* = record + MENUITEMTEMPLATEHEADER* {.final.} = object versionNumber*: int16 offset*: int16 TMENUITEMTEMPLATEHEADER* = MENUITEMTEMPLATEHEADER PMENUITEMTEMPLATEHEADER* = ptr MENUITEMTEMPLATEHEADER - MENUTEMPLATE* = record + MENUTEMPLATE* {.final.} = object LPMENUTEMPLATE* = ptr MENUTEMPLATE TMENUTEMPLATE* = MENUTEMPLATE PMENUTEMPLATE* = ptr MENUTEMPLATE - METAFILEPICT* = record + METAFILEPICT* {.final.} = object mm*: LONG xExt*: LONG yExt*: LONG @@ -10023,7 +10023,7 @@ type tagMETAFILEPICT* = METAFILEPICT TMETAFILEPICT* = METAFILEPICT PMETAFILEPICT* = ptr METAFILEPICT - METAHEADER* = record + METAHEADER* {.final.} = object mtType*: int16 mtHeaderSize*: int16 mtVersion*: int16 @@ -10035,7 +10035,7 @@ type tagMETAHEADER* = METAHEADER TMETAHEADER* = METAHEADER PMETAHEADER* = ptr METAHEADER - METARECORD* = record + METARECORD* {.final.} = object rdSize*: DWORD rdFunction*: int16 rdParm*: array[0..0, int16] @@ -10044,7 +10044,7 @@ type tagMETARECORD* = METARECORD TMETARECORD* = METARECORD PMETARECORD* = ptr METARECORD - MINIMIZEDMETRICS* = record + MINIMIZEDMETRICS* {.final.} = object cbSize*: UINT iWidth*: int32 iHorzGap*: int32 @@ -10055,7 +10055,7 @@ type tagMINIMIZEDMETRICS* = MINIMIZEDMETRICS TMINIMIZEDMETRICS* = MINIMIZEDMETRICS PMINIMIZEDMETRICS* = ptr MINIMIZEDMETRICS - MINMAXINFO* = record + MINMAXINFO* {.final.} = object ptReserved*: POINT ptMaxSize*: POINT ptMaxPosition*: POINT @@ -10065,7 +10065,7 @@ type tagMINMAXINFO* = MINMAXINFO TMINMAXINFO* = MINMAXINFO PMINMAXINFO* = ptr MINMAXINFO - MODEMDEVCAPS* = record + MODEMDEVCAPS* {.final.} = object dwActualSize*: DWORD dwRequiredSize*: DWORD dwDevSpecificOffset*: DWORD @@ -10091,7 +10091,7 @@ type TMODEMDEVCAPS* = MODEMDEVCAPS PMODEMDEVCAPS* = ptr MODEMDEVCAPS modemdevcaps_tag* = MODEMDEVCAPS - MODEMSETTINGS* = record + MODEMSETTINGS* {.final.} = object dwActualSize*: DWORD dwRequiredSize*: DWORD dwDevSpecificOffset*: DWORD @@ -10109,7 +10109,7 @@ type TMODEMSETTINGS* = MODEMSETTINGS PMODEMSETTINGS* = ptr MODEMSETTINGS modemsettings_tag* = MODEMSETTINGS - MONCBSTRUCT* = record + MONCBSTRUCT* {.final.} = object cb*: UINT dwTime*: DWORD hTask*: HANDLE @@ -10129,7 +10129,7 @@ type tagMONCBSTRUCT* = MONCBSTRUCT TMONCBSTRUCT* = MONCBSTRUCT PMONCBSTRUCT* = ptr MONCBSTRUCT - MONCONVSTRUCT* = record + MONCONVSTRUCT* {.final.} = object cb*: UINT fConnect*: WINBOOL dwTime*: DWORD @@ -10142,7 +10142,7 @@ type tagMONCONVSTRUCT* = MONCONVSTRUCT TMONCONVSTRUCT* = MONCONVSTRUCT PMONCONVSTRUCT* = ptr MONCONVSTRUCT - MONERRSTRUCT* = record + MONERRSTRUCT* {.final.} = object cb*: UINT wLastError*: UINT dwTime*: DWORD @@ -10151,7 +10151,7 @@ type tagMONERRSTRUCT* = MONERRSTRUCT TMONERRSTRUCT* = MONERRSTRUCT PMONERRSTRUCT* = ptr MONERRSTRUCT - MONHSZSTRUCT* = record + MONHSZSTRUCT* {.final.} = object cb*: UINT fsAction*: WINBOOL dwTime*: DWORD @@ -10162,19 +10162,19 @@ type tagMONHSZSTRUCT* = MONHSZSTRUCT TMONHSZSTRUCT* = MONHSZSTRUCT PMONHSZSTRUCT* = ptr MONHSZSTRUCT - MONITOR_INFO_1* = record + MONITOR_INFO_1* {.final.} = object pName*: LPTSTR TMONITORINFO1* = MONITOR_INFO_1 PMONITORINFO1* = ptr MONITOR_INFO_1 - MONITOR_INFO_2* = record + MONITOR_INFO_2* {.final.} = object pName*: LPTSTR pEnvironment*: LPTSTR pDLLName*: LPTSTR TMONITORINFO2* = MONITOR_INFO_2 PMONITORINFO2* = ptr MONITOR_INFO_2 - MONLINKSTRUCT* = record + MONLINKSTRUCT* {.final.} = object cb*: UINT dwTime*: DWORD hTask*: HANDLE @@ -10191,7 +10191,7 @@ type tagMONLINKSTRUCT* = MONLINKSTRUCT TMONLINKSTRUCT* = MONLINKSTRUCT PMONLINKSTRUCT* = ptr MONLINKSTRUCT - MONMSGSTRUCT* = record + MONMSGSTRUCT* {.final.} = object cb*: UINT hwndTo*: HWND dwTime*: DWORD @@ -10204,7 +10204,7 @@ type tagMONMSGSTRUCT* = MONMSGSTRUCT TMONMSGSTRUCT* = MONMSGSTRUCT PMONMSGSTRUCT* = ptr MONMSGSTRUCT - MOUSEHOOKSTRUCT* = record + MOUSEHOOKSTRUCT* {.final.} = object pt*: POINT hwnd*: HWND wHitTestCode*: UINT @@ -10214,7 +10214,7 @@ type tagMOUSEHOOKSTRUCT* = MOUSEHOOKSTRUCT TMOUSEHOOKSTRUCT* = MOUSEHOOKSTRUCT PMOUSEHOOKSTRUCT* = ptr MOUSEHOOKSTRUCT - MOUSEKEYS* = record + MOUSEKEYS* {.final.} = object cbSize*: DWORD dwFlags*: DWORD iMaxSpeed*: DWORD @@ -10227,7 +10227,7 @@ type PMOUSEKEYS* = ptr MOUSEKEYS MSGBOXCALLBACK* = proc (lpHelpInfo: LPHELPINFO){.stdcall.} TMSGBOXCALLBACK* = MSGBOXCALLBACK - MSGBOXPARAMS* = record + MSGBOXPARAMS* {.final.} = object cbSize*: UINT hwndOwner*: HWND hInstance*: HINST @@ -10243,7 +10243,7 @@ type TMSGBOXPARAMS* = MSGBOXPARAMS TMSGBOXPARAMSA* = MSGBOXPARAMS PMSGBOXPARAMS* = ptr MSGBOXPARAMS - MSGFILTER* = record + MSGFILTER* {.final.} = object nmhdr*: NMHDR msg*: UINT wParam*: WPARAM @@ -10251,7 +10251,7 @@ type Tmsgfilter* = MSGFILTER Pmsgfilter* = ptr MSGFILTER - MULTIKEYHELP* = record + MULTIKEYHELP* {.final.} = object mkSize*: DWORD mkKeylist*: TCHAR szKeyphrase*: array[0..0, TCHAR] @@ -10259,7 +10259,7 @@ type tagMULTIKEYHELP* = MULTIKEYHELP TMULTIKEYHELP* = MULTIKEYHELP PMULTIKEYHELP* = ptr MULTIKEYHELP - NAME_BUFFER* = record + NAME_BUFFER* {.final.} = object name*: array[0..(NCBNAMSZ) - 1, UCHAR] name_num*: UCHAR name_flags*: UCHAR @@ -10267,7 +10267,7 @@ type TNAMEBUFFER* = NAME_BUFFER PNAMEBUFFER* = ptr NAME_BUFFER p_NCB* = ptr NCB - NCB* = record + NCB* {.final.} = object ncb_command*: UCHAR ncb_retcode*: UCHAR ncb_lsn*: UCHAR @@ -10285,13 +10285,13 @@ type ncb_event*: HANDLE TNCB* = NCB - NCCALCSIZE_PARAMS* = record + NCCALCSIZE_PARAMS* {.final.} = object rgrc*: array[0..2, RECT] lppos*: PWINDOWPOS TNCCALCSIZEPARAMS* = NCCALCSIZE_PARAMS PNCCALCSIZEPARAMS* = ptr NCCALCSIZE_PARAMS - NDDESHAREINFO* = record + NDDESHAREINFO* {.final.} = object lRevision*: LONG lpszShareName*: LPTSTR lShareType*: LONG @@ -10306,7 +10306,7 @@ type TNDDESHAREINFO* = NDDESHAREINFO PNDDESHAREINFO* = ptr NDDESHAREINFO - NETRESOURCE* = record + NETRESOURCE* {.final.} = object dwScope*: DWORD dwType*: DWORD dwDisplayType*: DWORD @@ -10321,7 +10321,7 @@ type TNETRESOURCEA* = NETRESOURCE PNETRESOURCE* = ptr NETRESOURCE PNETRESOURCEA* = ptr NETRESOURCE - NEWCPLINFO* = record + NEWCPLINFO* {.final.} = object dwSize*: DWORD dwFlags*: DWORD dwHelpContext*: DWORD @@ -10334,7 +10334,7 @@ type tagNEWCPLINFO* = NEWCPLINFO TNEWCPLINFO* = NEWCPLINFO PNEWCPLINFO* = ptr NEWCPLINFO - NEWTEXTMETRIC* = record + NEWTEXTMETRIC* {.final.} = object tmHeight*: LONG tmAscent*: LONG tmDescent*: LONG @@ -10363,14 +10363,14 @@ type tagNEWTEXTMETRIC* = NEWTEXTMETRIC TNEWTEXTMETRIC* = NEWTEXTMETRIC PNEWTEXTMETRIC* = ptr NEWTEXTMETRIC - NEWTEXTMETRICEX* = record + NEWTEXTMETRICEX* {.final.} = object ntmentm*: NEWTEXTMETRIC ntmeFontSignature*: FONTSIGNATURE tagNEWTEXTMETRICEX* = NEWTEXTMETRICEX TNEWTEXTMETRICEX* = NEWTEXTMETRICEX PNEWTEXTMETRICEX* = ptr NEWTEXTMETRICEX - NM_LISTVIEW* = record + NM_LISTVIEW* {.final.} = object hdr*: NMHDR iItem*: int32 iSubItem*: int32 @@ -10383,7 +10383,7 @@ type tagNM_LISTVIEW* = NM_LISTVIEW TNMLISTVIEW* = NM_LISTVIEW PNMLISTVIEW* = ptr NM_LISTVIEW - TV_ITEM* = record + TV_ITEM* {.final.} = object mask*: UINT hItem*: HTREEITEM state*: UINT @@ -10398,7 +10398,7 @@ type LPTV_ITEM* = ptr TV_ITEM TTVITEM* = TV_ITEM PTVITEM* = ptr TV_ITEM - NM_TREEVIEW* = record + NM_TREEVIEW* {.final.} = object hdr*: NMHDR action*: UINT itemOld*: TV_ITEM @@ -10408,14 +10408,14 @@ type LPNM_TREEVIEW* = ptr NM_TREEVIEW TNMTREEVIEW* = NM_TREEVIEW PNMTREEVIEW* = ptr NM_TREEVIEW - NM_UPDOWNW* = record + NM_UPDOWNW* {.final.} = object hdr*: NMHDR iPos*: int32 iDelta*: int32 TNMUPDOWN* = NM_UPDOWNW PNMUPDOWN* = ptr NM_UPDOWNW - NONCLIENTMETRICS* = record + NONCLIENTMETRICS* {.final.} = object cbSize*: UINT iBorderWidth*: int32 iScrollWidth*: int32 @@ -10436,7 +10436,7 @@ type tagNONCLIENTMETRICS* = NONCLIENTMETRICS TNONCLIENTMETRICS* = NONCLIENTMETRICS PNONCLIENTMETRICS* = ptr NONCLIENTMETRICS - SERVICE_ADDRESS* = record + SERVICE_ADDRESS* {.final.} = object dwAddressType*: DWORD dwAddressFlags*: DWORD dwAddressLength*: DWORD @@ -10446,7 +10446,7 @@ type TSERVICEADDRESS* = SERVICE_ADDRESS PSERVICEADDRESS* = ptr SERVICE_ADDRESS - SERVICE_ADDRESSES* = record + SERVICE_ADDRESSES* {.final.} = object dwAddressCount*: DWORD Addresses*: array[0..0, SERVICE_ADDRESS] @@ -10459,7 +10459,7 @@ type LPCLSID* = ptr CLSID TCLSID* = CLSID PCLSID* = ptr CLSID - SERVICE_INFO* = record + SERVICE_INFO* {.final.} = object lpServiceType*: LPGUID lpServiceName*: LPTSTR lpComment*: LPTSTR @@ -10473,13 +10473,13 @@ type TSERVICEINFO* = SERVICE_INFO PSERVICEINFO* = ptr SERVICE_INFO - NS_SERVICE_INFO* = record + NS_SERVICE_INFO* {.final.} = object dwNameSpace*: DWORD ServiceInfo*: SERVICE_INFO TNSSERVICEINFO* = NS_SERVICE_INFO PNSSERVICEINFO* = ptr NS_SERVICE_INFO - NUMBERFMT* = record + NUMBERFMT* {.final.} = object NumDigits*: UINT LeadingZero*: UINT Grouping*: UINT @@ -10489,7 +10489,7 @@ type Tnumberfmt* = NUMBERFMT Pnumberfmt* = ptr NUMBERFMT - OFSTRUCT* = record + OFSTRUCT* {.final.} = object cBytes*: int8 fFixedDisk*: int8 nErrCode*: int16 @@ -10500,7 +10500,7 @@ type LPOFSTRUCT* = ptr OFSTRUCT TOFSTRUCT* = OFSTRUCT POFSTRUCT* = ptr OFSTRUCT - OPENFILENAME_NT4* = record + OPENFILENAME_NT4* {.final.} = object lStructSize*: DWORD hwndOwner*: HWND hInstance*: HINST @@ -10525,7 +10525,7 @@ type LPOPENFILENAME_NT4* = ptr OPENFILENAME_NT4 TOPENFILENAME_NT4* = OPENFILENAME_NT4 POPENFILENAME_NT4* = ptr OPENFILENAME_NT4 - TOPENFILENAME* = record + TOPENFILENAME* {.final.} = object lStructSize*: DWORD hwndOwner*: HWND hInstance*: HINST @@ -10554,7 +10554,7 @@ type POPENFILENAME* = ptr TOPENFILENAME OFN* = TOPENFILENAME POFN* = ptr TOPENFILENAME - OFNOTIFY* = record + OFNOTIFY* {.final.} = object hdr*: NMHDR lpOFN*: LPOPENFILENAME pszFile*: LPTSTR @@ -10562,7 +10562,7 @@ type LPOFNOTIFY* = ptr OFNOTIFY TOFNOTIFY* = OFNOTIFY POFNOTIFY* = ptr OFNOTIFY - OSVERSIONINFO* = record + OSVERSIONINFO* {.final.} = object dwOSVersionInfoSize*: DWORD dwMajorVersion*: DWORD dwMinorVersion*: DWORD @@ -10573,7 +10573,7 @@ type LPOSVERSIONINFO* = ptr OSVERSIONINFO TOSVERSIONINFO* = OSVERSIONINFO POSVERSIONINFO* = ptr OSVERSIONINFO - OSVERSIONINFOW* = record + OSVERSIONINFOW* {.final.} = object dwOSVersionInfoSize*: DWORD dwMajorVersion*: DWORD dwMinorVersion*: DWORD @@ -10584,7 +10584,7 @@ type LPOSVERSIONINFOW* = ptr OSVERSIONINFOW TOSVERSIONINFOW* = OSVERSIONINFOW POSVERSIONINFOW* = ptr OSVERSIONINFOW - TEXTMETRIC* = record + TEXTMETRIC* {.final.} = object tmHeight*: LONG tmAscent*: LONG tmDescent*: LONG @@ -10610,7 +10610,7 @@ type tagTEXTMETRIC* = TEXTMETRIC TTEXTMETRIC* = TEXTMETRIC PTEXTMETRIC* = ptr TEXTMETRIC - TEXTMETRICW* = record + TEXTMETRICW* {.final.} = object tmHeight*: LONG tmAscent*: LONG tmDescent*: LONG @@ -10636,7 +10636,7 @@ type tagTEXTMETRICW* = TEXTMETRICW TTEXTMETRICW* = TEXTMETRICW PTEXTMETRICW* = ptr TEXTMETRICW - OUTLINETEXTMETRIC* = record + OUTLINETEXTMETRIC* {.final.} = object otmSize*: UINT otmTextMetrics*: TEXTMETRIC otmFiller*: int8 @@ -10673,7 +10673,7 @@ type LPOUTLINETEXTMETRIC* = ptr OUTLINETEXTMETRIC TOUTLINETEXTMETRIC* = OUTLINETEXTMETRIC POUTLINETEXTMETRIC* = ptr OUTLINETEXTMETRIC - OVERLAPPED* = record + OVERLAPPED* {.final.} = object Internal*: DWORD InternalHigh*: DWORD Offset*: DWORD @@ -10683,7 +10683,7 @@ type LPOVERLAPPED* = ptr OVERLAPPED TOVERLAPPED* = OVERLAPPED POVERLAPPED* = ptr OVERLAPPED #PAGESETUPDLG = record conflicts with function PageSetupDlg - TPAGESETUPDLG* = record + TPAGESETUPDLG* {.final.} = object lStructSize*: DWORD hwndOwner*: HWND hDevMode*: HGLOBAL @@ -10704,7 +10704,7 @@ type tagPSD* = TPAGESETUPDLG TPSD* = TPAGESETUPDLG PPSD* = ptr TPAGESETUPDLG - PAINTSTRUCT* = record + PAINTSTRUCT* {.final.} = object hdc*: HDC fErase*: WINBOOL rcPaint*: RECT @@ -10716,7 +10716,7 @@ type tagPAINTSTRUCT* = PAINTSTRUCT TPAINTSTRUCT* = PAINTSTRUCT PPAINTSTRUCT* = ptr PAINTSTRUCT - PARAFORMAT* = record + PARAFORMAT* {.final.} = object cbSize*: UINT dwMask*: DWORD wNumbering*: int16 @@ -10730,12 +10730,12 @@ type Tparaformat* = PARAFORMAT Pparaformat* = ptr PARAFORMAT - PERF_COUNTER_BLOCK* = record + PERF_COUNTER_BLOCK* {.final.} = object ByteLength*: DWORD TPERFCOUNTERBLOCK* = PERF_COUNTER_BLOCK PPERFCOUNTERBLOCK* = ptr PERF_COUNTER_BLOCK - PERF_COUNTER_DEFINITION* = record + PERF_COUNTER_DEFINITION* {.final.} = object ByteLength*: DWORD CounterNameTitleIndex*: DWORD CounterNameTitle*: LPWSTR @@ -10749,7 +10749,7 @@ type TPERFCOUNTERDEFINITION* = PERF_COUNTER_DEFINITION PPERFCOUNTERDEFINITION* = ptr PERF_COUNTER_DEFINITION - PERF_DATA_BLOCK* = record + PERF_DATA_BLOCK* {.final.} = object Signature*: array[0..3, WCHAR] LittleEndian*: DWORD Version*: DWORD @@ -10767,7 +10767,7 @@ type TPERFDATABLOCK* = PERF_DATA_BLOCK PPERFDATABLOCK* = ptr PERF_DATA_BLOCK - PERF_INSTANCE_DEFINITION* = record + PERF_INSTANCE_DEFINITION* {.final.} = object ByteLength*: DWORD ParentObjectTitleIndex*: DWORD ParentObjectInstance*: DWORD @@ -10777,7 +10777,7 @@ type TPERFINSTANCEDEFINITION* = PERF_INSTANCE_DEFINITION PPERFINSTANCEDEFINITION* = PERF_INSTANCE_DEFINITION - PERF_OBJECT_TYPE* = record + PERF_OBJECT_TYPE* {.final.} = object TotalByteLength*: DWORD DefinitionLength*: DWORD HeaderLength*: DWORD @@ -10795,7 +10795,7 @@ type TPERFOBJECTTYPE* = PERF_OBJECT_TYPE PPERFOBJECTTYPE* = ptr PERF_OBJECT_TYPE - POLYTEXT* = record + POLYTEXT* {.final.} = object x*: int32 y*: int32 n*: UINT @@ -10806,12 +10806,12 @@ type TPOLYTEXT* = POLYTEXT PPOLYTEXT* = ptr POLYTEXT - PORT_INFO_1* = record + PORT_INFO_1* {.final.} = object pName*: LPTSTR TPORTINFO1* = PORT_INFO_1 PPORTINFO1* = ptr PORT_INFO_1 - PORT_INFO_2* = record + PORT_INFO_2* {.final.} = object pPortName*: LPSTR pMonitorName*: LPSTR pDescription*: LPSTR @@ -10820,12 +10820,12 @@ type TPORTINFO2* = PORT_INFO_2 PPORTINFO2* = ptr PORT_INFO_2 - PREVENT_MEDIA_REMOVAL* = record + PREVENT_MEDIA_REMOVAL* {.final.} = object PreventMediaRemoval*: bool TPREVENTMEDIAREMOVAL* = PREVENT_MEDIA_REMOVAL PPREVENTMEDIAREMOVAL* = ptr PREVENT_MEDIA_REMOVAL #PRINTDLG = record conflicts with PrintDlg function - TPRINTDLG* = record + TPRINTDLG* {.final.} = object lStructSize*: DWORD hwndOwner*: HWND hDevMode*: HANDLE @@ -10851,14 +10851,14 @@ type tagPD* = TPRINTDLG TPD* = TPRINTDLG PPD* = ptr TPRINTDLG - PRINTER_DEFAULTS* = record + PRINTER_DEFAULTS* {.final.} = object pDatatype*: LPTSTR pDevMode*: LPDEVMODE DesiredAccess*: ACCESS_MASK TPRINTERDEFAULTS* = PRINTER_DEFAULTS PPRINTERDEFAULTS* = ptr PRINTER_DEFAULTS - PRINTER_INFO_1* = record + PRINTER_INFO_1* {.final.} = object Flags*: DWORD pDescription*: LPTSTR pName*: LPTSTR @@ -10867,7 +10867,7 @@ type LPPRINTER_INFO_1* = ptr PRINTER_INFO_1 PPRINTER_INFO_1* = ptr PRINTER_INFO_1 TPRINTERINFO1* = PRINTER_INFO_1 - PRINTER_INFO_2* = record + PRINTER_INFO_2* {.final.} = object pServerName*: LPTSTR pPrinterName*: LPTSTR pShareName*: LPTSTR @@ -10892,19 +10892,19 @@ type TPRINTERINFO2* = PRINTER_INFO_2 PPRINTERINFO2* = ptr PRINTER_INFO_2 - PRINTER_INFO_3* = record + PRINTER_INFO_3* {.final.} = object pSecurityDescriptor*: PSECURITY_DESCRIPTOR TPRINTERINFO3* = PRINTER_INFO_3 PPRINTERINFO3* = ptr PRINTER_INFO_3 - PRINTER_INFO_4* = record + PRINTER_INFO_4* {.final.} = object pPrinterName*: LPTSTR pServerName*: LPTSTR Attributes*: DWORD TPRINTERINFO4* = PRINTER_INFO_4 PPRINTERINFO4* = ptr PRINTER_INFO_4 - PRINTER_INFO_5* = record + PRINTER_INFO_5* {.final.} = object pPrinterName*: LPTSTR pPortName*: LPTSTR Attributes*: DWORD @@ -10913,7 +10913,7 @@ type TPRINTERINFO5* = PRINTER_INFO_5 PPRINTERINFO5* = ptr PRINTER_INFO_5 - PRINTER_NOTIFY_INFO_DATA* = record + PRINTER_NOTIFY_INFO_DATA* {.final.} = object `type`*: int16 Field*: int16 Reserved*: DWORD @@ -10923,7 +10923,7 @@ type TPRINTERNOTIFYINFODATA* = PRINTER_NOTIFY_INFO_DATA PPRINTERNOTIFYINFODATA* = ptr PRINTER_NOTIFY_INFO_DATA - PRINTER_NOTIFY_INFO* = record + PRINTER_NOTIFY_INFO* {.final.} = object Version*: DWORD Flags*: DWORD Count*: DWORD @@ -10931,7 +10931,7 @@ type TPRINTERNOTIFYINFO* = PRINTER_NOTIFY_INFO PPRINTERNOTIFYINFO* = ptr PRINTER_NOTIFY_INFO - PRINTER_NOTIFY_OPTIONS_TYPE* = record + PRINTER_NOTIFY_OPTIONS_TYPE* {.final.} = object `type`*: int16 Reserved0*: int16 Reserved1*: DWORD @@ -10941,7 +10941,7 @@ type PPRINTER_NOTIFY_OPTIONS_TYPE* = ptr PRINTER_NOTIFY_OPTIONS_TYPE TPRINTERNOTIFYOPTIONSTYPE* = PRINTER_NOTIFY_OPTIONS_TYPE - PRINTER_NOTIFY_OPTIONS* = record + PRINTER_NOTIFY_OPTIONS* {.final.} = object Version*: DWORD Flags*: DWORD Count*: DWORD @@ -10949,12 +10949,12 @@ type TPRINTERNOTIFYOPTIONS* = PRINTER_NOTIFY_OPTIONS PPRINTERNOTIFYOPTIONS* = ptr PRINTER_NOTIFY_OPTIONS - PRINTPROCESSOR_INFO_1* = record + PRINTPROCESSOR_INFO_1* {.final.} = object pName*: LPTSTR TPRINTPROCESSORINFO1* = PRINTPROCESSOR_INFO_1 PPRINTPROCESSORINFO1* = ptr PRINTPROCESSOR_INFO_1 - PRIVILEGE_SET* = record + PRIVILEGE_SET* {.final.} = object PrivilegeCount*: DWORD Control*: DWORD Privilege*: array[0..(ANYSIZE_ARRAY) - 1, LUID_AND_ATTRIBUTES] @@ -10962,7 +10962,7 @@ type LPPRIVILEGE_SET* = ptr PRIVILEGE_SET PPRIVILEGE_SET* = ptr PRIVILEGE_SET TPRIVILEGESET* = PRIVILEGE_SET - PROCESS_HEAPENTRY* = record + PROCESS_HEAPENTRY* {.final.} = object lpData*: PVOID cbData*: DWORD cbOverhead*: int8 @@ -10977,7 +10977,7 @@ type LPPROCESS_HEAP_ENTRY* = ptr PROCESS_HEAPENTRY TPROCESSHEAPENTRY* = PROCESS_HEAPENTRY PPROCESSHEAPENTRY* = ptr PROCESS_HEAPENTRY - PROCESS_INFORMATION* = record + PROCESS_INFORMATION* {.final.} = object hProcess*: HANDLE hThread*: HANDLE dwProcessId*: DWORD @@ -10989,7 +10989,7 @@ type LPFNPSPCALLBACK* = proc (para1: HWND, para2: UINT, para3: LPVOID): UINT{. stdcall.} TFNPSPCALLBACK* = LPFNPSPCALLBACK - PROPSHEETPAGE* = record + PROPSHEETPAGE* {.final.} = object dwSize*: DWORD dwFlags*: DWORD hInstance*: HINST @@ -11004,10 +11004,10 @@ type LPCPROPSHEETPAGE* = ptr PROPSHEETPAGE TPROPSHEETPAGE* = PROPSHEETPAGE PPROPSHEETPAGE* = ptr PROPSHEETPAGE - emptyrecord* = record + emptyrecord* {.final.} = object lpemptyrecord* = ptr emptyrecord HPROPSHEETPAGE* = ptr emptyrecord - PROPSHEETHEADER* = record + PROPSHEETHEADER* {.final.} = object dwSize*: DWORD dwFlags*: DWORD hwndParent*: HWND @@ -11032,7 +11032,7 @@ type LPFNADDPROPSHEETPAGES* = proc (para1: LPVOID, para2: LPFNADDPROPSHEETPAGE, para3: LPARAM): WINBOOL{.stdcall.} TFNADDPROPSHEETPAGES* = LPFNADDPROPSHEETPAGES - PROTOCOL_INFO* = record + PROTOCOL_INFO* {.final.} = object dwServiceFlags*: DWORD iAddressFamily*: WINT iMaxSockAddr*: WINT @@ -11044,27 +11044,27 @@ type TPROTOCOLINFO* = PROTOCOL_INFO PPROTOCOLINFO* = ptr PROTOCOL_INFO - PROVIDOR_INFO_1* = record + PROVIDOR_INFO_1* {.final.} = object pName*: LPTSTR pEnvironment*: LPTSTR pDLLName*: LPTSTR TPROVIDORINFO1* = PROVIDOR_INFO_1 PPROVIDORINFO1* = ptr PROVIDOR_INFO_1 - PSHNOTIFY* = record + PSHNOTIFY* {.final.} = object hdr*: NMHDR lParam*: LPARAM LPPSHNOTIFY* = ptr PSHNOTIFY TPSHNOTIFY* = PSHNOTIFY PPSHNOTIFY* = ptr PSHNOTIFY - PUNCTUATION* = record + PUNCTUATION* {.final.} = object iSize*: UINT szPunctuation*: LPSTR Tpunctuation* = PUNCTUATION Ppunctuation* = ptr PUNCTUATION - TQUERY_SERVICE_CONFIG* = record + TQUERY_SERVICE_CONFIG* {.final.} = object dwServiceType*: DWORD dwStartType*: DWORD dwErrorControl*: DWORD @@ -11077,14 +11077,14 @@ type LPQUERY_SERVICE_CONFIG* = ptr TQUERY_SERVICE_CONFIG PQUERYSERVICECONFIG* = ptr TQUERY_SERVICE_CONFIG - TQUERY_SERVICE_LOCK_STATUS* = record + TQUERY_SERVICE_LOCK_STATUS* {.final.} = object fIsLocked*: DWORD lpLockOwner*: LPTSTR dwLockDuration*: DWORD LPQUERY_SERVICE_LOCK_STATUS* = ptr TQUERY_SERVICE_LOCK_STATUS PQUERYSERVICELOCKSTATUS* = ptr TQUERY_SERVICE_LOCK_STATUS - RASAMB* = record + RASAMB* {.final.} = object dwSize*: DWORD dwError*: DWORD szNetBiosError*: array[0..(NETBIOS_NAME_LEN + 1) - 1, TCHAR] @@ -11092,7 +11092,7 @@ type TRASAMB* = RASAMB PRASAMB* = ptr RASAMB - RASCONN* = record + RASCONN* {.final.} = object dwSize*: DWORD hrasconn*: HRASCONN szEntryName*: array[0..(RAS_MaxEntryName + 1) - 1, TCHAR] @@ -11101,7 +11101,7 @@ type TRASCONN* = RASCONN PRASCONN* = ptr RASCONN - RASCONNSTATUS* = record + RASCONNSTATUS* {.final.} = object dwSize*: DWORD rasconnstate*: RASCONNSTATE dwError*: DWORD @@ -11110,7 +11110,7 @@ type TRASCONNSTATUS* = RASCONNSTATUS PRASCONNSTATUS* = ptr RASCONNSTATUS - RASDIALEXTENSIONS* = record + RASDIALEXTENSIONS* {.final.} = object dwSize*: DWORD dwfOptions*: DWORD hwndParent*: HWND @@ -11118,7 +11118,7 @@ type TRASDIALEXTENSIONS* = RASDIALEXTENSIONS PRASDIALEXTENSIONS* = ptr RASDIALEXTENSIONS - RASDIALPARAMS* = record + RASDIALPARAMS* {.final.} = object dwSize*: DWORD szEntryName*: array[0..(RAS_MaxEntryName + 1) - 1, TCHAR] szPhoneNumber*: array[0..(RAS_MaxPhoneNumber + 1) - 1, TCHAR] @@ -11129,27 +11129,27 @@ type TRASDIALPARAMS* = RASDIALPARAMS PRASDIALPARAMS* = ptr RASDIALPARAMS - RASENTRYNAME* = record + RASENTRYNAME* {.final.} = object dwSize*: DWORD szEntryName*: array[0..(RAS_MaxEntryName + 1) - 1, TCHAR] TRASENTRYNAME* = RASENTRYNAME PRASENTRYNAME* = ptr RASENTRYNAME - RASPPPIP* = record + RASPPPIP* {.final.} = object dwSize*: DWORD dwError*: DWORD szIpAddress*: array[0..(RAS_MaxIpAddress + 1) - 1, TCHAR] TRASPPPIP* = RASPPPIP PRASPPPIP* = ptr RASPPPIP - RASPPPIPX* = record + RASPPPIPX* {.final.} = object dwSize*: DWORD dwError*: DWORD szIpxAddress*: array[0..(RAS_MaxIpxAddress + 1) - 1, TCHAR] TRASPPPIPX* = RASPPPIPX PRASPPPIPX* = ptr RASPPPIPX - RASPPPNBF* = record + RASPPPNBF* {.final.} = object dwSize*: DWORD dwError*: DWORD dwNetBiosError*: DWORD @@ -11159,7 +11159,7 @@ type TRASPPPNBF* = RASPPPNBF PRASPPPNBF* = ptr RASPPPNBF - RASTERIZER_STATUS* = record + RASTERIZER_STATUS* {.final.} = object nSize*: short wFlags*: short nLanguageID*: short @@ -11167,14 +11167,14 @@ type LPRASTERIZER_STATUS* = ptr RASTERIZER_STATUS TRASTERIZERSTATUS* = RASTERIZER_STATUS PRASTERIZERSTATUS* = ptr RASTERIZER_STATUS - REASSIGN_BLOCKS* = record + REASSIGN_BLOCKS* {.final.} = object Reserved*: int16 Count*: int16 BlockNumber*: array[0..0, DWORD] TREASSIGNBLOCKS* = REASSIGN_BLOCKS PREASSIGNBLOCKS* = ptr REASSIGN_BLOCKS - REMOTE_NAME_INFO* = record + REMOTE_NAME_INFO* {.final.} = object lpUniversalName*: LPTSTR lpConnectionName*: LPTSTR lpRemainingPath*: LPTSTR @@ -11195,19 +11195,19 @@ type # DWORD dwUser; # } REOBJECT; # - REPASTESPECIAL* = record + REPASTESPECIAL* {.final.} = object dwAspect*: DWORD dwParam*: DWORD Trepastespecial* = REPASTESPECIAL Prepastespecial* = ptr REPASTESPECIAL - REQRESIZE* = record + REQRESIZE* {.final.} = object nmhdr*: NMHDR rc*: RECT Treqresize* = REQRESIZE Preqresize* = ptr REQRESIZE - RGNDATAHEADER* = record + RGNDATAHEADER* {.final.} = object dwSize*: DWORD iType*: DWORD nCount*: DWORD @@ -11216,14 +11216,14 @@ type TRGNDATAHEADER* = RGNDATAHEADER PRGNDATAHEADER* = ptr RGNDATAHEADER - RGNDATA* = record + RGNDATA* {.final.} = object rdh*: RGNDATAHEADER Buffer*: array[0..0, char] LPRGNDATA* = ptr RGNDATA TRGNDATA* = RGNDATA PRGNDATA* = ptr RGNDATA - SCROLLINFO* = record + SCROLLINFO* {.final.} = object cbSize*: UINT fMask*: UINT nMin*: int32 @@ -11236,7 +11236,7 @@ type LPCSCROLLINFO* = ptr SCROLLINFO TSCROLLINFO* = SCROLLINFO PSCROLLINFO* = ptr SCROLLINFO - SECURITY_ATTRIBUTES* = record + SECURITY_ATTRIBUTES* {.final.} = object nLength*: DWORD lpSecurityDescriptor*: LPVOID bInheritHandle*: WINBOOL @@ -11247,14 +11247,14 @@ type SECURITY_INFORMATION* = DWORD PSECURITY_INFORMATION* = ptr SECURITY_INFORMATION TSECURITYINFORMATION* = SECURITY_INFORMATION - SELCHANGE* = record + SELCHANGE* {.final.} = object nmhdr*: NMHDR chrg*: CHARRANGE seltyp*: int16 Tselchange* = SELCHANGE Pselchange* = ptr SELCHANGE - SERIALKEYS* = record + SERIALKEYS* {.final.} = object cbSize*: DWORD dwFlags*: DWORD lpszActivePort*: LPSTR @@ -11265,14 +11265,14 @@ type LPSERIALKEYS* = ptr SERIALKEYS TSERIALKEYS* = SERIALKEYS PSERIALKEYS* = ptr SERIALKEYS - SERVICE_TABLE_ENTRY* = record + SERVICE_TABLE_ENTRY* {.final.} = object lpServiceName*: LPTSTR lpServiceProc*: LPSERVICE_MAIN_FUNCTION LPSERVICE_TABLE_ENTRY* = ptr SERVICE_TABLE_ENTRY TSERVICETABLEENTRY* = SERVICE_TABLE_ENTRY PSERVICETABLEENTRY* = ptr SERVICE_TABLE_ENTRY - SERVICE_TYPE_VALUE_ABS* = record + SERVICE_TYPE_VALUE_ABS* {.final.} = object dwNameSpace*: DWORD dwValueType*: DWORD dwValueSize*: DWORD @@ -11281,14 +11281,14 @@ type TSERVICETYPEVALUEABS* = SERVICE_TYPE_VALUE_ABS PSERVICETYPEVALUEABS* = ptr SERVICE_TYPE_VALUE_ABS - SERVICE_TYPE_INFO_ABS* = record + SERVICE_TYPE_INFO_ABS* {.final.} = object lpTypeName*: LPTSTR dwValueCount*: DWORD Values*: array[0..0, SERVICE_TYPE_VALUE_ABS] TSERVICETYPEINFOABS* = SERVICE_TYPE_INFO_ABS PSERVICETYPEINFOABS* = ptr SERVICE_TYPE_INFO_ABS - SESSION_BUFFER* = record + SESSION_BUFFER* {.final.} = object lsn*: UCHAR state*: UCHAR local_name*: array[0..(NCBNAMSZ) - 1, UCHAR] @@ -11298,7 +11298,7 @@ type TSESSIONBUFFER* = SESSION_BUFFER PSESSIONBUFFER* = ptr SESSION_BUFFER - SESSION_HEADER* = record + SESSION_HEADER* {.final.} = object sess_name*: UCHAR num_sess*: UCHAR rcv_dg_outstanding*: UCHAR @@ -11306,7 +11306,7 @@ type TSESSIONHEADER* = SESSION_HEADER PSESSIONHEADER* = ptr SESSION_HEADER - SET_PARTITION_INFORMATION* = record + SET_PARTITION_INFORMATION* {.final.} = object PartitionType*: int8 TSETPARTITIONINFORMATION* = SET_PARTITION_INFORMATION @@ -11314,7 +11314,7 @@ type SHCONTF* = enum SHCONTF_FOLDERS = 32, SHCONTF_NONFOLDERS = 64, SHCONTF_INCLUDEHIDDEN = 128 TSHCONTF* = SHCONTF - SHFILEINFO* = record + SHFILEINFO* {.final.} = object hIcon*: HICON iIcon*: int32 dwAttributes*: DWORD @@ -11326,7 +11326,7 @@ type FILEOP_FLAGS* = int16 TFILEOPFLAGS* = FILEOP_FLAGS PFILEOPFLAGS* = ptr FILEOP_FLAGS - SHFILEOPSTRUCT* = record + SHFILEOPSTRUCT* {.final.} = object hwnd*: HWND wFunc*: UINT pFrom*: LPCSTR @@ -11343,7 +11343,7 @@ type SHGDN_NORMAL = 0, SHGDN_INFOLDER = 1, SHGDN_FORPARSING = 0x00008000 tagSHGDN* = SHGNO TSHGDN* = SHGNO - SHNAMEMAPPING* = record + SHNAMEMAPPING* {.final.} = object pszOldPath*: LPSTR pszNewPath*: LPSTR cchOldPath*: int32 @@ -11352,7 +11352,7 @@ type LPSHNAMEMAPPING* = ptr SHNAMEMAPPING TSHNAMEMAPPING* = SHNAMEMAPPING PSHNAMEMAPPING* = ptr SHNAMEMAPPING - SID_AND_ATTRIBUTES* = record + SID_AND_ATTRIBUTES* {.final.} = object Sid*: PSID Attributes*: DWORD @@ -11361,12 +11361,12 @@ type SID_AND_ATTRIBUTES_ARRAY* = array[0..(ANYSIZE_ARRAY) - 1, SID_AND_ATTRIBUTES] PSID_AND_ATTRIBUTES_ARRAY* = ptr SID_AND_ATTRIBUTES_ARRAY TSIDANDATTRIBUTESARRAY* = SID_AND_ATTRIBUTES_ARRAY - SINGLE_LIST_ENTRY* = record + SINGLE_LIST_ENTRY* {.final.} = object Next*: ptr SINGLE_LIST_ENTRY TSINGLELISTENTRY* = SINGLE_LIST_ENTRY PSINGLELISTENTRY* = ptr SINGLE_LIST_ENTRY - SOUNDSENTRY* = record + SOUNDSENTRY* {.final.} = object cbSize*: UINT dwFlags*: DWORD iFSTextEffect*: DWORD @@ -11384,7 +11384,7 @@ type tagSOUNDSENTRY* = SOUNDSENTRY TSOUNDSENTRY* = SOUNDSENTRY PSOUNDSENTRY* = ptr SOUNDSENTRY - STARTUPINFO* = record + STARTUPINFO* {.final.} = object cb*: DWORD lpReserved*: LPTSTR lpDesktop*: LPTSTR @@ -11407,42 +11407,42 @@ type LPSTARTUPINFO* = ptr STARTUPINFO TSTARTUPINFO* = STARTUPINFO PSTARTUPINFO* = ptr STARTUPINFO - STICKYKEYS* = record + STICKYKEYS* {.final.} = object cbSize*: DWORD dwFlags*: DWORD LPSTICKYKEYS* = ptr STICKYKEYS TSTICKYKEYS* = STICKYKEYS PSTICKYKEYS* = ptr STICKYKEYS - STRRET* = record + STRRET* {.final.} = object uType*: UINT cStr*: array[0..(MAX_PATH) - 1, char] LPSTRRET* = ptr STRRET TSTRRET* = STRRET PSTRRET* = ptr STRRET - STYLEBUF* = record + STYLEBUF* {.final.} = object dwStyle*: DWORD szDescription*: array[0..31, CHAR] LPSTYLEBUF* = ptr STYLEBUF TSTYLEBUF* = STYLEBUF PSTYLEBUF* = ptr STYLEBUF - STYLESTRUCT* = record + STYLESTRUCT* {.final.} = object styleOld*: DWORD styleNew*: DWORD LPSTYLESTRUCT* = ptr STYLESTRUCT TSTYLESTRUCT* = STYLESTRUCT PSTYLESTRUCT* = ptr STYLESTRUCT - SYSTEM_AUDIT_ACE* = record + SYSTEM_AUDIT_ACE* {.final.} = object Header*: ACE_HEADER Mask*: ACCESS_MASK SidStart*: DWORD TSYSTEMAUDITACE* = SYSTEM_AUDIT_ACE PSYSTEMAUDITACE* = ptr SYSTEM_AUDIT_ACE - SYSTEM_INFO* = record + SYSTEM_INFO* {.final.} = object dwOemId*: DWORD dwPageSize*: DWORD lpMinimumApplicationAddress*: LPVOID @@ -11457,7 +11457,7 @@ type LPSYSTEM_INFO* = ptr SYSTEM_INFO TSYSTEMINFO* = SYSTEM_INFO PSYSTEMINFO* = ptr SYSTEM_INFO - SYSTEM_POWER_STATUS* = record + SYSTEM_POWER_STATUS* {.final.} = object ACLineStatus*: int8 BatteryFlag*: int8 BatteryLifePercent*: int8 @@ -11468,12 +11468,12 @@ type TSYSTEMPOWERSTATUS* = SYSTEM_POWER_STATUS PSYSTEMPOWERSTATUS* = ptr SYSTEM_POWER_STATUS LPSYSTEM_POWER_STATUS* = ptr emptyrecord - TAPE_ERASE* = record + TAPE_ERASE* {.final.} = object `type`*: ULONG TTAPEERASE* = TAPE_ERASE PTAPEERASE* = ptr TAPE_ERASE - TAPE_GET_DRIVE_PARAMETERS* = record + TAPE_GET_DRIVE_PARAMETERS* {.final.} = object ECC*: bool Compression*: bool DataPadding*: bool @@ -11488,7 +11488,7 @@ type TTAPEGETDRIVEPARAMETERS* = TAPE_GET_DRIVE_PARAMETERS PTAPEGETDRIVEPARAMETERS* = ptr TAPE_GET_DRIVE_PARAMETERS - TAPE_GET_MEDIA_PARAMETERS* = record + TAPE_GET_MEDIA_PARAMETERS* {.final.} = object Capacity*: LARGE_INTEGER Remaining*: LARGE_INTEGER BlockSize*: DWORD @@ -11497,7 +11497,7 @@ type TTAPEGETMEDIAPARAMETERS* = TAPE_GET_MEDIA_PARAMETERS PTAPEGETMEDIAPARAMETERS* = ptr TAPE_GET_MEDIA_PARAMETERS - TAPE_GET_POSITION* = record + TAPE_GET_POSITION* {.final.} = object `type`*: ULONG Partition*: ULONG OffsetLow*: ULONG @@ -11505,12 +11505,12 @@ type TTAPEGETPOSITION* = TAPE_GET_POSITION PTAPEGETPOSITION* = ptr TAPE_GET_POSITION - TAPE_PREPARE* = record + TAPE_PREPARE* {.final.} = object Operation*: ULONG TTAPEPREPARE* = TAPE_PREPARE PTAPEPREPARE* = ptr TAPE_PREPARE - TAPE_SET_DRIVE_PARAMETERS* = record + TAPE_SET_DRIVE_PARAMETERS* {.final.} = object ECC*: bool Compression*: bool DataPadding*: bool @@ -11519,12 +11519,12 @@ type TTAPESETDRIVEPARAMETERS* = TAPE_SET_DRIVE_PARAMETERS PTAPESETDRIVEPARAMETERS* = ptr TAPE_SET_DRIVE_PARAMETERS - TAPE_SET_MEDIA_PARAMETERS* = record + TAPE_SET_MEDIA_PARAMETERS* {.final.} = object BlockSize*: ULONG TTAPESETMEDIAPARAMETERS* = TAPE_SET_MEDIA_PARAMETERS PTAPESETMEDIAPARAMETERS* = ptr TAPE_SET_MEDIA_PARAMETERS - TAPE_SET_POSITION* = record + TAPE_SET_POSITION* {.final.} = object `Method`*: ULONG Partition*: ULONG OffsetLow*: ULONG @@ -11532,19 +11532,19 @@ type TTAPESETPOSITION* = TAPE_SET_POSITION PTAPESETPOSITION* = ptr TAPE_SET_POSITION - TAPE_WRITE_MARKS* = record + TAPE_WRITE_MARKS* {.final.} = object `type`*: ULONG Count*: ULONG TTAPEWRITEMARKS* = TAPE_WRITE_MARKS PTAPEWRITEMARKS* = ptr TAPE_WRITE_MARKS - TTBADDBITMAP* = record + TTBADDBITMAP* {.final.} = object hInst*: HINST nID*: UINT LPTBADDBITMAP* = ptr TTBADDBITMAP PTBADDBITMAP* = ptr TTBADDBITMAP - TBBUTTON* = record + TBBUTTON* {.final.} = object iBitmap*: int32 idCommand*: int32 fsState*: int8 @@ -11556,7 +11556,7 @@ type LPCTBBUTTON* = ptr TBBUTTON TTBBUTTON* = TBBUTTON PTBBUTTON* = ptr TBBUTTON - TBNOTIFY* = record + TBNOTIFY* {.final.} = object hdr*: NMHDR iItem*: int32 tbButton*: TBBUTTON @@ -11566,20 +11566,20 @@ type LPTBNOTIFY* = ptr TBNOTIFY TTBNOTIFY* = TBNOTIFY PTBNOTIFY* = ptr TBNOTIFY - TBSAVEPARAMS* = record + TBSAVEPARAMS* {.final.} = object hkr*: HKEY pszSubKey*: LPCTSTR pszValueName*: LPCTSTR TTBSAVEPARAMS* = TBSAVEPARAMS PTBSAVEPARAMS* = ptr TBSAVEPARAMS - TC_HITTESTINFO* = record + TC_HITTESTINFO* {.final.} = object pt*: POINT flags*: UINT TTCHITTESTINFO* = TC_HITTESTINFO PTCHITTESTINFO* = ptr TC_HITTESTINFO - TC_ITEM* = record + TC_ITEM* {.final.} = object mask*: UINT lpReserved1*: UINT lpReserved2*: UINT @@ -11590,7 +11590,7 @@ type TTCITEM* = TC_ITEM PTCITEM* = ptr TC_ITEM - TC_ITEMHEADER* = record + TC_ITEMHEADER* {.final.} = object mask*: UINT lpReserved1*: UINT lpReserved2*: UINT @@ -11600,20 +11600,20 @@ type TTCITEMHEADER* = TC_ITEMHEADER PTCITEMHEADER* = ptr TC_ITEMHEADER - TC_KEYDOWN* = record + TC_KEYDOWN* {.final.} = object hdr*: NMHDR wVKey*: int16 flags*: UINT TTCKEYDOWN* = TC_KEYDOWN PTCKEYDOWN* = ptr TC_KEYDOWN - TEXTRANGE* = record + TEXTRANGE* {.final.} = object chrg*: CHARRANGE lpstrText*: LPSTR Ttextrange* = TEXTRANGE Ptextrange* = ptr TEXTRANGE - TIME_ZONE_INFORMATION* = record + TIME_ZONE_INFORMATION* {.final.} = object Bias*: LONG StandardName*: array[0..31, WCHAR] StandardDate*: SYSTEMTIME @@ -11625,18 +11625,18 @@ type LPTIME_ZONE_INFORMATION* = ptr TIME_ZONE_INFORMATION TTIMEZONEINFORMATION* = TIME_ZONE_INFORMATION PTIMEZONEINFORMATION* = ptr TIME_ZONE_INFORMATION - TOGGLEKEYS* = record + TOGGLEKEYS* {.final.} = object cbSize*: DWORD dwFlags*: DWORD TTOGGLEKEYS* = TOGGLEKEYS PTOGGLEKEYS* = ptr TOGGLEKEYS - TTOKEN_SOURCE* = record + TTOKEN_SOURCE* {.final.} = object SourceName*: array[0..7, CHAR] SourceIdentifier*: LUID PTOKENSOURCE* = ptr TTOKEN_SOURCE - TOKEN_CONTROL* = record + TOKEN_CONTROL* {.final.} = object TokenId*: LUID AuthenticationId*: LUID ModifiedId*: LUID @@ -11644,31 +11644,31 @@ type TTOKENCONTROL* = TOKEN_CONTROL PTOKENCONTROL* = ptr TOKEN_CONTROL - TTOKEN_DEFAULT_DACL* = record + TTOKEN_DEFAULT_DACL* {.final.} = object DefaultDacl*: PACL PTOKENDEFAULTDACL* = ptr TTOKEN_DEFAULT_DACL - TTOKEN_GROUPS* = record + TTOKEN_GROUPS* {.final.} = object GroupCount*: DWORD Groups*: array[0..(ANYSIZE_ARRAY) - 1, SID_AND_ATTRIBUTES] LPTOKEN_GROUPS* = ptr TTOKEN_GROUPS PTOKENGROUPS* = ptr TTOKEN_GROUPS - TTOKEN_OWNER* = record + TTOKEN_OWNER* {.final.} = object Owner*: PSID PTOKENOWNER* = ptr TTOKEN_OWNER - TTOKEN_PRIMARY_GROUP* = record + TTOKEN_PRIMARY_GROUP* {.final.} = object PrimaryGroup*: PSID PTOKENPRIMARYGROUP* = ptr TTOKEN_PRIMARY_GROUP - TTOKEN_PRIVILEGES* = record + TTOKEN_PRIVILEGES* {.final.} = object PrivilegeCount*: DWORD Privileges*: array[0..(ANYSIZE_ARRAY) - 1, LUID_AND_ATTRIBUTES] PTOKEN_PRIVILEGES* = ptr TTOKEN_PRIVILEGES LPTOKEN_PRIVILEGES* = ptr TTOKEN_PRIVILEGES - TTOKEN_STATISTICS* = record + TTOKEN_STATISTICS* {.final.} = object TokenId*: LUID AuthenticationId*: LUID ExpirationTime*: LARGE_INTEGER @@ -11681,11 +11681,11 @@ type ModifiedId*: LUID PTOKENSTATISTICS* = ptr TTOKEN_STATISTICS - TTOKEN_USER* = record + TTOKEN_USER* {.final.} = object User*: SID_AND_ATTRIBUTES PTOKENUSER* = ptr TTOKEN_USER - TOOLINFO* = record + TOOLINFO* {.final.} = object cbSize*: UINT uFlags*: UINT hwnd*: HWND @@ -11697,7 +11697,7 @@ type LPTOOLINFO* = ptr TOOLINFO TTOOLINFO* = TOOLINFO PTOOLINFO* = ptr TOOLINFO - TOOLTIPTEXT* = record + TOOLTIPTEXT* {.final.} = object hdr*: NMHDR lpszText*: LPTSTR szText*: array[0..79, char] @@ -11707,7 +11707,7 @@ type LPTOOLTIPTEXT* = ptr TOOLTIPTEXT TTOOLTIPTEXT* = TOOLTIPTEXT PTOOLTIPTEXT* = ptr TOOLTIPTEXT - TPMPARAMS* = record + TPMPARAMS* {.final.} = object cbSize*: UINT rcExclude*: RECT @@ -11715,7 +11715,7 @@ type tagTPMPARAMS* = TPMPARAMS TTPMPARAMS* = TPMPARAMS PTPMPARAMS* = ptr TPMPARAMS - TRANSMIT_FILE_BUFFERS* = record + TRANSMIT_FILE_BUFFERS* {.final.} = object Head*: PVOID HeadLength*: DWORD Tail*: PVOID @@ -11723,7 +11723,7 @@ type TTRANSMITFILEBUFFERS* = TRANSMIT_FILE_BUFFERS PTRANSMITFILEBUFFERS* = ptr TRANSMIT_FILE_BUFFERS - TTHITTESTINFO* = record + TTHITTESTINFO* {.final.} = object hwnd*: HWND pt*: POINT ti*: TOOLINFO @@ -11731,7 +11731,7 @@ type LPHITTESTINFO* = ptr TTHITTESTINFO TTTHITTESTINFO* = TTHITTESTINFO PTTHITTESTINFO* = ptr TTHITTESTINFO - TTPOLYCURVE* = record + TTPOLYCURVE* {.final.} = object wType*: int16 cpfx*: int16 apfx*: array[0..0, POINTFX] @@ -11739,7 +11739,7 @@ type LPTTPOLYCURVE* = ptr TTPOLYCURVE TTTPOLYCURVE* = TTPOLYCURVE PTTPOLYCURVE* = ptr TTPOLYCURVE - TTPOLYGONHEADER* = record + TTPOLYGONHEADER* {.final.} = object cb*: DWORD dwType*: DWORD pfxStart*: POINTFX @@ -11747,13 +11747,13 @@ type LPTTPOLYGONHEADER* = ptr TTPOLYGONHEADER TTTPOLYGONHEADER* = TTPOLYGONHEADER PTTPOLYGONHEADER* = ptr TTPOLYGONHEADER - TV_DISPINFO* = record + TV_DISPINFO* {.final.} = object hdr*: NMHDR item*: TV_ITEM TTVDISPINFO* = TV_DISPINFO PTVDISPINFO* = ptr TV_DISPINFO - TV_HITTESTINFO* = record + TV_HITTESTINFO* {.final.} = object pt*: POINT flags*: UINT hItem*: HTREEITEM @@ -11761,7 +11761,7 @@ type LPTV_HITTESTINFO* = ptr TV_HITTESTINFO TTVHITTESTINFO* = TV_HITTESTINFO PTVHITTESTINFO* = ptr TV_HITTESTINFO - TV_INSERTSTRUCT* = record + TV_INSERTSTRUCT* {.final.} = object hParent*: HTREEITEM hInsertAfter*: HTREEITEM item*: TV_ITEM @@ -11769,14 +11769,14 @@ type LPTV_INSERTSTRUCT* = ptr TV_INSERTSTRUCT TTVINSERTSTRUCT* = TV_INSERTSTRUCT PTVINSERTSTRUCT* = ptr TV_INSERTSTRUCT - TV_KEYDOWN* = record + TV_KEYDOWN* {.final.} = object hdr*: NMHDR wVKey*: int16 flags*: UINT TTVKEYDOWN* = TV_KEYDOWN PTVKEYDOWN* = ptr TV_KEYDOWN - TV_SORTCB* = record + TV_SORTCB* {.final.} = object hParent*: HTREEITEM lpfnCompare*: PFNTVCOMPARE lParam*: LPARAM @@ -11784,18 +11784,18 @@ type LPTV_SORTCB* = ptr TV_SORTCB TTVSORTCB* = TV_SORTCB PTVSORTCB* = ptr TV_SORTCB - UDACCEL* = record + UDACCEL* {.final.} = object nSec*: UINT nInc*: UINT TUDACCEL* = UDACCEL PUDACCEL* = ptr UDACCEL - UNIVERSAL_NAME_INFO* = record + UNIVERSAL_NAME_INFO* {.final.} = object lpUniversalName*: LPTSTR TUNIVERSALNAMEINFO* = UNIVERSAL_NAME_INFO PUNIVERSALNAMEINFO* = ptr UNIVERSAL_NAME_INFO - USEROBJECTFLAGS* = record + USEROBJECTFLAGS* {.final.} = object fInherit*: WINBOOL fReserved*: WINBOOL dwFlags*: DWORD @@ -11803,7 +11803,7 @@ type tagUSEROBJECTFLAGS* = USEROBJECTFLAGS TUSEROBJECTFLAGS* = USEROBJECTFLAGS PUSEROBJECTFLAGS* = ptr USEROBJECTFLAGS - VALENT* = record + VALENT* {.final.} = object ve_valuename*: LPTSTR ve_valuelen*: DWORD ve_valueptr*: DWORD @@ -11814,13 +11814,13 @@ type value_ent* = VALENT Tvalue_ent* = VALENT Pvalue_ent* = ptr VALENT - VERIFY_INFORMATION* = record + VERIFY_INFORMATION* {.final.} = object StartingOffset*: LARGE_INTEGER len*: DWORD TVERIFYINFORMATION* = VERIFY_INFORMATION PVERIFYINFORMATION* = ptr VERIFY_INFORMATION - VS_FIXEDFILEINFO* = record + VS_FIXEDFILEINFO* {.final.} = object dwSignature*: DWORD dwStrucVersion*: DWORD dwFileVersionMS*: DWORD @@ -11837,7 +11837,7 @@ type TVSFIXEDFILEINFO* = VS_FIXEDFILEINFO PVSFIXEDFILEINFO* = ptr VS_FIXEDFILEINFO - WIN32_FIND_DATA* = record + WIN32_FIND_DATA* {.final.} = object dwFileAttributes*: DWORD ftCreationTime*: FILETIME ftLastAccessTime*: FILETIME @@ -11853,7 +11853,7 @@ type PWIN32_FIND_DATA* = ptr WIN32_FIND_DATA TWIN32FINDDATA* = WIN32_FIND_DATA TWIN32FINDDATAA* = WIN32_FIND_DATA - WIN32_FIND_DATAW* = record + WIN32_FIND_DATAW* {.final.} = object dwFileAttributes*: DWORD ftCreationTime*: FILETIME ftLastAccessTime*: FILETIME @@ -11868,7 +11868,7 @@ type LPWIN32_FIND_DATAW* = ptr WIN32_FIND_DATAW PWIN32_FIND_DATAW* = ptr WIN32_FIND_DATAW TWIN32FINDDATAW* = WIN32_FIND_DATAW - WIN32_STREAM_ID* = record + WIN32_STREAM_ID* {.final.} = object dwStreamId*: DWORD dwStreamAttributes*: DWORD Size*: LARGE_INTEGER @@ -11877,7 +11877,7 @@ type TWIN32STREAMID* = WIN32_STREAM_ID PWIN32STREAMID* = ptr WIN32_STREAM_ID - WINDOWPLACEMENT* = record + WINDOWPLACEMENT* {.final.} = object len*: UINT flags*: UINT showCmd*: UINT @@ -11887,7 +11887,7 @@ type TWINDOWPLACEMENT* = WINDOWPLACEMENT PWINDOWPLACEMENT* = ptr WINDOWPLACEMENT - WNDCLASS* = record + WNDCLASS* {.final.} = object style*: UINT lpfnWndProc*: WNDPROC cbClsExtra*: int32 @@ -11903,7 +11903,7 @@ type TWNDCLASS* = WNDCLASS TWNDCLASSA* = WNDCLASS PWNDCLASS* = ptr WNDCLASS - WNDCLASSW* = record + WNDCLASSW* {.final.} = object style*: UINT lpfnWndProc*: WNDPROC cbClsExtra*: int32 @@ -11918,7 +11918,7 @@ type LPWNDCLASSW* = ptr WNDCLASSW TWNDCLASSW* = WNDCLASSW PWNDCLASSW* = ptr WNDCLASSW - WNDCLASSEX* = record + WNDCLASSEX* {.final.} = object cbSize*: UINT style*: UINT lpfnWndProc*: WNDPROC @@ -11936,7 +11936,7 @@ type TWNDCLASSEX* = WNDCLASSEX TWNDCLASSEXA* = WNDCLASSEX PWNDCLASSEX* = ptr WNDCLASSEX - WNDCLASSEXW* = record + WNDCLASSEXW* {.final.} = object cbSize*: UINT style*: UINT lpfnWndProc*: WNDPROC @@ -11953,7 +11953,7 @@ type LPWNDCLASSEXW* = ptr WNDCLASSEXW TWNDCLASSEXW* = WNDCLASSEXW PWNDCLASSEXW* = ptr WNDCLASSEXW - CONNECTDLGSTRUCT* = record + CONNECTDLGSTRUCT* {.final.} = object cbStructure*: DWORD hwndOwner*: HWND lpConnRes*: LPNETRESOURCE @@ -11963,7 +11963,7 @@ type LPCONNECTDLGSTRUCT* = ptr CONNECTDLGSTRUCT TCONNECTDLGSTRUCT* = CONNECTDLGSTRUCT PCONNECTDLGSTRUCT* = ptr CONNECTDLGSTRUCT - DISCDLGSTRUCT* = record + DISCDLGSTRUCT* {.final.} = object cbStructure*: DWORD hwndOwner*: HWND lpLocalName*: LPTSTR @@ -11974,7 +11974,7 @@ type TDISCDLGSTRUCT* = DISCDLGSTRUCT TDISCDLGSTRUCTA* = DISCDLGSTRUCT PDISCDLGSTRUCT* = ptr DISCDLGSTRUCT - NETINFOSTRUCT* = record + NETINFOSTRUCT* {.final.} = object cbStructure*: DWORD dwProviderVersion*: DWORD dwStatus*: DWORD @@ -11987,7 +11987,7 @@ type LPNETINFOSTRUCT* = ptr NETINFOSTRUCT TNETINFOSTRUCT* = NETINFOSTRUCT PNETINFOSTRUCT* = ptr NETINFOSTRUCT - NETCONNECTINFOSTRUCT* = record + NETCONNECTINFOSTRUCT* {.final.} = object cbStructure*: DWORD dwFlags*: DWORD dwSpeed*: DWORD @@ -12009,13 +12009,13 @@ type para3: int32, para4: LPARAM): int32{.stdcall.} LPOVERLAPPED_COMPLETION_ROUTINE* = proc (para1: DWORD, para2: DWORD, para3: LPOVERLAPPED){.stdcall.} # Structures for the extensions to OpenGL - POINTFLOAT* = record + POINTFLOAT* {.final.} = object x*: float32 y*: float32 TPOINTFLOAT* = POINTFLOAT PPOINTFLOAT* = ptr POINTFLOAT - GLYPHMETRICSFLOAT* = record + GLYPHMETRICSFLOAT* {.final.} = object gmfBlackBoxX*: float32 gmfBlackBoxY*: float32 gmfptGlyphOrigin*: POINTFLOAT @@ -12025,7 +12025,7 @@ type LPGLYPHMETRICSFLOAT* = ptr GLYPHMETRICSFLOAT TGLYPHMETRICSFLOAT* = GLYPHMETRICSFLOAT PGLYPHMETRICSFLOAT* = ptr GLYPHMETRICSFLOAT - LAYERPLANEDESCRIPTOR* = record + LAYERPLANEDESCRIPTOR* {.final.} = object nSize*: int16 nVersion*: int16 dwFlags*: DWORD @@ -12055,7 +12055,7 @@ type tagLAYERPLANEDESCRIPTOR* = LAYERPLANEDESCRIPTOR TLAYERPLANEDESCRIPTOR* = LAYERPLANEDESCRIPTOR PLAYERPLANEDESCRIPTOR* = ptr LAYERPLANEDESCRIPTOR - PIXELFORMATDESCRIPTOR* = record + PIXELFORMATDESCRIPTOR* {.final.} = object nSize*: int16 nVersion*: int16 dwFlags*: DWORD @@ -12087,7 +12087,7 @@ type tagPIXELFORMATDESCRIPTOR* = PIXELFORMATDESCRIPTOR TPIXELFORMATDESCRIPTOR* = PIXELFORMATDESCRIPTOR PPIXELFORMATDESCRIPTOR* = ptr PIXELFORMATDESCRIPTOR - USER_INFO_2* = record + USER_INFO_2* {.final.} = object usri2_name*: LPWSTR usri2_password*: LPWSTR usri2_password_age*: DWORD @@ -12116,13 +12116,13 @@ type PUSER_INFO_2* = ptr USER_INFO_2 LPUSER_INFO_2* = ptr USER_INFO_2 TUSERINFO2* = USER_INFO_2 - USER_INFO_0* = record + USER_INFO_0* {.final.} = object usri0_name*: LPWSTR PUSER_INFO_0* = ptr USER_INFO_0 LPUSER_INFO_0* = ptr USER_INFO_0 TUSERINFO0* = USER_INFO_0 - USER_INFO_3* = record + USER_INFO_3* {.final.} = object usri3_name*: LPWSTR usri3_password*: LPWSTR usri3_password_age*: DWORD @@ -12156,7 +12156,7 @@ type PUSER_INFO_3* = ptr USER_INFO_3 LPUSER_INFO_3* = ptr USER_INFO_3 TUSERINFO3* = USER_INFO_3 - GROUP_INFO_2* = record + GROUP_INFO_2* {.final.} = object grpi2_name*: LPWSTR grpi2_comment*: LPWSTR grpi2_group_id*: DWORD @@ -12164,13 +12164,13 @@ type PGROUP_INFO_2* = ptr GROUP_INFO_2 TGROUPINFO2* = GROUP_INFO_2 - LOCALGROUP_INFO_0* = record + LOCALGROUP_INFO_0* {.final.} = object lgrpi0_name*: LPWSTR PLOCALGROUP_INFO_0* = ptr LOCALGROUP_INFO_0 LPLOCALGROUP_INFO_0* = ptr LOCALGROUP_INFO_0 TLOCALGROUPINFO0* = LOCALGROUP_INFO_0 - IMAGE_DOS_HEADER* = record + IMAGE_DOS_HEADER* {.final.} = object e_magic*: int16 e_cblp*: int16 e_cp*: int16 @@ -12193,7 +12193,7 @@ type PIMAGE_DOS_HEADER* = ptr IMAGE_DOS_HEADER TIMAGEDOSHEADER* = IMAGE_DOS_HEADER - NOTIFYICONDATAA* = record + NOTIFYICONDATAA* {.final.} = object cbSize*: DWORD Wnd*: HWND uID*: UINT @@ -12203,7 +12203,7 @@ type szTip*: array[0..63, Char] NOTIFYICONDATA* = NOTIFYICONDATAA - NOTIFYICONDATAW* = record + NOTIFYICONDATAW* {.final.} = object cbSize*: DWORD Wnd*: HWND uID*: UINT @@ -12224,7 +12224,7 @@ type type PWaveFormatEx* = ptr TWaveFormatEx - TWaveFormatEx* = record + TWaveFormatEx* {.final.} = object wFormatTag*: int16 # format type nChannels*: int16 # number of channels (i.e. mono, stereo, etc.) nSamplesPerSec*: DWORD # sample rate @@ -12233,7 +12233,7 @@ type wBitsPerSample*: int16 # number of bits per sample of mono data cbSize*: int16 # the count in bytes of the size of - WIN32_FILE_ATTRIBUTE_DATA* = record + WIN32_FILE_ATTRIBUTE_DATA* {.final.} = object dwFileAttributes*: DWORD ftCreationTime*: FILETIME ftLastAccessTime*: FILETIME @@ -12244,7 +12244,7 @@ type LPWIN32_FILE_ATTRIBUTE_DATA* = ptr WIN32_FILE_ATTRIBUTE_DATA TWIN32FILEATTRIBUTEDATA* = WIN32_FILE_ATTRIBUTE_DATA PWIN32FILEATTRIBUTEDATA* = ptr WIN32_FILE_ATTRIBUTE_DATA # TrackMouseEvent. NT or higher only. - TTrackMouseEvent* = record + TTrackMouseEvent* {.final.} = object cbSize*: DWORD dwFlags*: DWORD hwndTrack*: HWND @@ -13317,7 +13317,7 @@ else: HALFPARAM* = int16 HALFPARAMBOOL* = WORDBOOL type - MSG* = record + MSG* {.final.} = object hwnd*: HWND message*: UINT wParam*: WPARAM @@ -13330,20 +13330,20 @@ type TMSG* = MSG PMSG* = ptr MSG PMessage* = ptr TMessage - TMessage* = record #fields according to ICS + TMessage* {.final.} = object #fields according to ICS msg*: UINT wParam*: WPARAM lParam*: LPARAM Result*: LRESULT - TWMSize* = record + TWMSize* {.final.} = object Msg*: UINT SizeType*: WPARAM Width*: HALFPARAM Height*: HALFPARAM Result*: LRESULT - TWMNoParams* = record + TWMNoParams* {.final.} = object Msg*: UINT Unused*: array[0..3, HALFPARAM] Result*: LRESULT @@ -13353,7 +13353,7 @@ type TWMDestroy* = TWMNoParams TWMClose* = TWMNoParams TWMQueryUIState* = TWMNoParams - TWMUIState* = record + TWMUIState* {.final.} = object Msg*: UINT Action*: int16 Flags*: int16 @@ -13361,7 +13361,7 @@ type TWMChangeUIState* = TWMUIState TWMUpdateUIState* = TWMUIState - TWMKey* = record + TWMKey* {.final.} = object Msg*: UINT CharCode*: int16 Unused*: int16 @@ -13374,7 +13374,7 @@ type TWMSysChar* = TWMKey TWMSysKeyDown* = TWMKey TWMSysKeyUp* = TWMKey - TWMMenuChar* = record + TWMMenuChar* {.final.} = object Msg*: UINT User*: Char MenuFlag*: int16 @@ -13386,7 +13386,7 @@ type TWMGetFont* = TWMNoParams TWMSysColorChange* = TWMNoParams TWMQueryDragIcon* = TWMNoParams - TWMScroll* = record + TWMScroll* {.final.} = object Msg*: UINT ScrollCode*: HALFPARAM Pos*: HALFPARAM @@ -13395,59 +13395,59 @@ type TWMHScroll* = TWMScroll TWMVScroll* = TWMScroll - TWMGetText* = record + TWMGetText* {.final.} = object Msg*: UINT TextMax*: LPARAM Text*: cstring Result*: LRESULT TWMGetTextLength* = TWMNoParams - TWMKillFocus* = record + TWMKillFocus* {.final.} = object Msg*: UINT FocusedWnd*: HWND UnUsed*: WPARAM Result*: LRESULT - TWMSetCursor* = record + TWMSetCursor* {.final.} = object Msg*: UINT CursorWnd*: HWND HitTest*: HALFPARAM MouseMsg*: HALFPARAM Result*: LRESULT - TWMSetFocus* = record + TWMSetFocus* {.final.} = object Msg*: UINT FocusedWnd*: HWND Unused*: WPARAM Result*: LRESULT - TWMSetFont* = record + TWMSetFont* {.final.} = object Msg*: UINT Font*: HFONT Redraw*: HALFPARAMBOOL Unused*: HALFPARAM Result*: LRESULT - TWMShowWindow* = record + TWMShowWindow* {.final.} = object Msg*: UINT Show*: HALFPARAMBOOL Unused*: HALFPARAM Status*: WPARAM Result*: LRESULT - TWMEraseBkgnd* = record + TWMEraseBkgnd* {.final.} = object Msg*: UINT DC*: HDC Unused*: LPARAM Result*: LRESULT - TWMNCHitTest* = record + TWMNCHitTest* {.final.} = object Msg*: UINT Unused*: int32 Pos*: TSmallPoint Result*: LRESULT - TWMMouse* = record + TWMMouse* {.final.} = object Msg*: UINT Keys*: int32 Pos*: TSmallPoint @@ -13459,14 +13459,14 @@ type TWMMButtonDblClk* = TWMMouse TWMMButtonDown* = TWMMouse TWMMButtonUp* = TWMMouse - TWMMouseWheel* = record + TWMMouseWheel* {.final.} = object Msg*: UINT Keys*: int16 WheelDelta*: int16 Pos*: TSmallPoint Result*: LRESULT - TWMNCHitMessage* = record + TWMNCHitMessage* {.final.} = object Msg*: UINT HitTest*: int32 XCursor*: int16 @@ -13484,51 +13484,51 @@ type TWMRButtonDown* = TWMMouse TWMRButtonUp* = TWMMouse TWMMouseMove* = TWMMouse - TWMPaint* = record + TWMPaint* {.final.} = object Msg*: UINT DC*: HDC Unused*: int32 Result*: LRESULT - TWMCommand* = record + TWMCommand* {.final.} = object Msg*: UINT ItemID*: int16 NotifyCode*: int16 Ctl*: HWND Result*: LRESULT - TWMNotify* = record + TWMNotify* {.final.} = object Msg*: UINT IDCtrl*: int32 NMHdr*: PNMHdr Result*: LRESULT - TWMPrint* = record + TWMPrint* {.final.} = object Msg*: UINT DC*: HDC Flags*: int Result*: LRESULT TWMPrintClient* = TWMPrint - TWMWinIniChange* = record + TWMWinIniChange* {.final.} = object Msg*: UINT Unused*: int Section*: cstring Result*: LRESULT - TWMContextMenu* = record + TWMContextMenu* {.final.} = object Msg*: UINT hWnd*: HWND Pos*: TSmallPoint Result*: LRESULT - TWMNCCalcSize* = record + TWMNCCalcSize* {.final.} = object Msg*: UINT CalcValidRects*: WINBOOL CalcSize_Params*: PNCCalcSizeParams Result*: LRESULT - TWMCharToItem* = record + TWMCharToItem* {.final.} = object Msg*: UINT Key*: int16 CaretPos*: int16 @@ -13537,7 +13537,7 @@ type TWMVKeyToItem* = TWMCharToItem TMyEventRange = range[0'i16..16000'i16] - TWMParentNotify* = record + TWMParentNotify* {.final.} = object Msg*: UINT case Event*: TMyEventRange of TMyEventRange(WM_CREATE), TMyEventRange(WM_DESTROY): @@ -13556,7 +13556,7 @@ type Value2*: int32 Result*: LRESULT - TWMSysCommand* = record + TWMSysCommand* {.final.} = object Msg*: UINT CmdType*: int32 XPos*: int16 @@ -13574,13 +13574,13 @@ type # else: # of SC_KEYMENU: # Key*: int16 - TWMMove* = record + TWMMove* {.final.} = object Msg*: UINT Unused*: int Pos*: TSmallPoint Result*: LRESULT - TWMWindowPosMsg* = record + TWMWindowPosMsg* {.final.} = object Msg*: UINT Unused*: int WindowPos*: PWindowPos @@ -13588,101 +13588,101 @@ type TWMWindowPosChanged* = TWMWindowPosMsg TWMWindowPosChanging* = TWMWindowPosMsg - TWMCompareItem* = record + TWMCompareItem* {.final.} = object Msg*: UINT Ctl*: HWnd CompareItemStruct*: PCompareItemStruct Result*: LRESULT - TWMDeleteItem* = record + TWMDeleteItem* {.final.} = object Msg*: UINT Ctl*: HWND DeleteItemStruct*: PDeleteItemStruct Result*: LRESULT - TWMDrawItem* = record + TWMDrawItem* {.final.} = object Msg*: UINT Ctl*: HWND DrawItemStruct*: PDrawItemStruct Result*: LRESULT - TWMMeasureItem* = record + TWMMeasureItem* {.final.} = object Msg*: UINT IDCtl*: HWnd MeasureItemStruct*: PMeasureItemStruct Result*: LRESULT - TWMNCCreate* = record + TWMNCCreate* {.final.} = object Msg*: UINT Unused*: int CreateStruct*: PCreateStruct Result*: LRESULT - TWMInitMenuPopup* = record + TWMInitMenuPopup* {.final.} = object Msg*: UINT MenuPopup*: HMENU Pos*: int16 SystemMenu*: WordBool Result*: LRESULT - TWMMenuSelect* = record + TWMMenuSelect* {.final.} = object Msg*: UINT IDItem*: int16 MenuFlag*: int16 Menu*: HMENU Result*: LRESULT - TWMActivate* = record + TWMActivate* {.final.} = object Msg*: UINT Active*: int16 Minimized*: WordBool ActiveWindow*: HWND Result*: LRESULT - TWMQueryEndSession* = record + TWMQueryEndSession* {.final.} = object Msg*: UINT Source*: int32 Unused*: int32 Result*: LRESULT - TWMMDIActivate* = record + TWMMDIActivate* {.final.} = object Msg*: UINT DeactiveWnd*: HWND ActiveWnd*: HWND Result*: LRESULT - TWMNextDlgCtl* = record + TWMNextDlgCtl* {.final.} = object Msg*: UINT CtlFocus*: int32 Handle*: WordBool Unused*: int16 Result*: LRESULT - TWMHelp* = record + TWMHelp* {.final.} = object Msg*: UINT Unused*: int HelpInfo*: PHelpInfo Result*: LRESULT - TWMGetMinMaxInfo* = record + TWMGetMinMaxInfo* {.final.} = object Msg*: UINT Unused*: int MinMaxInfo*: PMinMaxInfo Result*: LRESULT - TWMSettingChange* = record + TWMSettingChange* {.final.} = object Msg*: UINT Flag*: int Section*: cstring Result*: LRESULT - TWMCreate* = record + TWMCreate* {.final.} = object Msg*: UINT Unused*: int CreateStruct*: PCreateStruct Result*: LRESULT - TWMCtlColor* = record + TWMCtlColor* {.final.} = object Msg*: UINT ChildDC*: HDC ChildWnd*: HWND @@ -13695,38 +13695,38 @@ type TWMCtlColorMsgbox* = TWMCtlColor TWMCtlColorDlg* = TWMCtlColor TWMCtlColorEdit* = TWMCtlColor - TWMInitDialog* = record + TWMInitDialog* {.final.} = object Msg*: UINT Focus*: HWND InitParam*: int32 Result*: LRESULT - TWMNCPaint* = record + TWMNCPaint* {.final.} = object Msg*: UINT RGN*: HRGN Unused*: int32 Result*: LRESULT - TWMSetText* = record + TWMSetText* {.final.} = object Msg*: UINT Unused*: int32 Text*: cstring Result*: LRESULT - TWMSizeClipboard* = record + TWMSizeClipboard* {.final.} = object Msg*: UINT Viewer*: HWND RC*: THandle Result*: LRESULT - TWMSpoolerStatus* = record + TWMSpoolerStatus* {.final.} = object Msg*: UINT JobStatus*: LPARAM JobsLeft*: WPARAM Unused*: WPARAM Result*: LRESULT - TWMStyleChange* = record + TWMStyleChange* {.final.} = object Msg*: UINT StyleType*: LPARAM StyleStruct*: PStyleStruct @@ -13734,54 +13734,54 @@ type TWMStyleChanged* = TWMStyleChange TWMStyleChanging* = TWMStyleChange - TWMSysDeadChar* = record + TWMSysDeadChar* {.final.} = object Msg*: UINT CharCode*: WPARAM Unused*: WPARAM KeyData*: LPARAM Result*: LRESULT - TWMSystemError* = record + TWMSystemError* {.final.} = object Msg*: UINT ErrSpec*: WPARAM Unused*: LPARAM Result*: LRESULT TWMTimeChange* = TWMNoParams - TWMTimer* = record + TWMTimer* {.final.} = object Msg*: UINT TimerID*: LPARAM TimerProc*: TFarProc Result*: LRESULT TWMUndo* = TWMNoParams - TWMVScrollClipboard* = record + TWMVScrollClipboard* {.final.} = object Msg*: UINT Viewer*: HWND ScollCode*: WPARAM ThumbPos*: WPARAM Result*: LRESULT - TWMDisplayChange* = record + TWMDisplayChange* {.final.} = object Msg*: UINT BitsPerPixel*: int Width*: WPARAM Height*: WPARAM Result*: LRESULT - TWMDropFiles* = record + TWMDropFiles* {.final.} = object Msg*: UINT Drop*: THANDLE Unused*: LPARAM Result*: LRESULT - TWMEnable* = record + TWMEnable* {.final.} = object Msg*: int Enabled*: WINBOOL Unused*: int32 Result*: int32 - TWMMouseActivate* = record + TWMMouseActivate* {.final.} = object Msg*: int TopLevel*: HWND HitTestCode*: int16 @@ -20686,7 +20686,7 @@ type TFNFiberStartRoutine* = FARPROC TFNHookProc* = HOOKPROC PObjectTypeList* = ptr TObjectTypeList - OBJECT_TYPE_LIST* = record + OBJECT_TYPE_LIST* {.final.} = object Level*: int16 Sbz*: int16 ObjectType*: PGUID @@ -20694,14 +20694,14 @@ type TObjectTypeList* = OBJECT_TYPE_LIST AUDIT_EVENT_TYPE* = DWORD PBlendFunction* = ptr TBlendFunction - BLENDFUNCTION* = record + BLENDFUNCTION* {.final.} = object BlendOp*: int8 BlendFlags*: int8 SourceConstantAlpha*: int8 AlphaFormat*: int8 TBlendFunction* = BLENDFUNCTION - WIN_CERTIFICATE* = record + WIN_CERTIFICATE* {.final.} = object dwLength*: DWord wRevision*: int16 wCertificateType*: int16 @@ -20709,7 +20709,7 @@ type TWinCertificate* = WIN_CERTIFICATE PWinCertificate* = ptr TWinCertificate - TMaxLogPalette* = record + TMaxLogPalette* {.final.} = object palVersion*: int16 palNumEntries*: int16 palPalEntry*: array[int8, TPaletteEntry] |