'From Squeak4.1 of 17 April 2010 [latest update: #9957] on 17 April 2010 at 5:22:05 pm'! ----STARTUP----{17 April 2010 . 5:21:54 pm} as C:\Squeak\4.0\4.1-final\Squeak4.1.image! Smalltalk appendChangesTo: 'SqueakV41.sources'.! ----QUIT----{17 April 2010 . 5:22:11 pm} Squeak4.1.image priorSource: 89! ----STARTUP----{23 January 2011 . 2:40 pm} as /Users/piumarta/squeak/Squeak4.1.image! SystemOrganization addCategory: #'VMMaker-Building'! SystemOrganization addCategory: #'VMMaker-Interpreter'! SystemOrganization addCategory: #'VMMaker-InterpreterSimulation'! SystemOrganization addCategory: #'VMMaker-Plugins'! SystemOrganization addCategory: #'VMMaker-SmartSyntaxPlugins'! SystemOrganization addCategory: #'VMMaker-Translation to C'! SystemOrganization addCategory: #'VMMaker-Tests'! !ParseNode methodsFor: '*VMMaker-C translation' stamp: 'dtl 10/12/2010 19:40'! asTranslatorNodeIn: aTMethod "make a CCodeGenerator equivalent of me" ^TNotImplementedNode new parseNode: self! ! !CascadeNode methodsFor: '*VMMaker-C translation' stamp: 'eem 10/2/2009 11:26'! asTranslatorNodeIn: aTMethod "make a CCodeGenerator equivalent of me" ^TStmtListNode new setArguments: #() statements: (Array streamContents: [:s| | receiverNode | receiverNode := receiver asTranslatorNodeIn: aTMethod. receiverNode isLeaf ifFalse: [| varNode | varNode := aTMethod newCascadeTempFor: receiverNode. s nextPut: (TAssignmentNode new setVariable: varNode expression: receiverNode). receiverNode := varNode]. messages do: [ :msg | s nextPut: ((msg asTranslatorNodeIn: aTMethod) receiver: receiverNode)]]); comment: comment! ! Model subclass: #VMMakerTool instanceVariableNames: 'vmMaker allPluginsList allPluginsSelection allPluginsSelectionsArray internalPluginsList internalPluginsSelection internalPluginsSelectionsArray externalPluginsList externalPluginsSelection externalPluginsSelectionsArray logger interpreterClassMorph platformPathMorph platformNameMorph generatedPathMorph configFileName' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Building'! !VMMakerTool commentStamp: '' prior: 0! VMMakerTool help information ------------------------------------ If you really get stuck, send mail to the Squeak mailing list, squeak-dev@lists.squeakfoundation.org VMMakerTool openInWorld What this is -------------- This tool is a simple interactive interface to VMMaker. You can change the directory paths for where the system looks for the platform files (those C files that are handwritten for each platform) and where it will put the assembled sources (the appropriate platform files and generated files) ready for you to compile into a new vm. You can change the platform for which it will generate files. You can choose which plugins are built and whether they are built for internal or external use. How to use it --------------- To build a configuration, drag plugins from the leftmost 'Plugins not built' list to either the 'Internal Plugins' list or the 'External Plugins' list. Plugins that cannot be built on your machine due to missing files will not be draggable. Once you have a configuration, you can save it for later retrieval by pressing the 'Save Configuration' button. Unsurprisingly you can reload a saved configuration with the 'Load Configuration' button. To generate an entire code tree, press the 'Generate All' button. This will process all the vm and plugin files needed for your configuration. To generate only the files for the vm and any internal plugins, use the 'Generate Core VM' button. This will be most useful if you are experimenting with the design of the vm internals or new object memory layouts etc. The 'Generate External Plugins' button will regenerate all the plugins in the External Plugins list. Note that 'excess' directories will be deleted each time you generate the vm in order to reduce potential confusion if you move a plugin from internal to external etc. If you repeatedly generate the vm only the files that appear to be out of date will be recreated; this drastically reduces the time taken if you have only changed a single plugin class for example. You can also generate internal or external plugins singly, using the menus in the lists but be warned - internal plugins are tightly related to the generated file 'vm/sqNamedPrims.h' and adding or removing an internal plugin without regenerating this (via 'Generate Core VM' or 'Generate All') will cause much grief. The application attempts to prevent this, but there are surely ways to confuse both yourself and the code. In general when writing experimental plugins it is much simpler to build them as external during the development cycle. If the default path for the platforms code is not correct for your machine you can use the 'Find Path' button to search for a plausible directory. Note that this could take an arbitrarily long time on a machine with connections to other machines since you may end up searching all their disc space as well. You can choose from a menu of all known platforms (at least, all those known in the set of files on your machine) by using the 'Find platform' button. This is useful if you want to generate files for some other platform and feel uncertain of the exact spelling. By default the platform will be set to that upon which you are running. If you feel the need to delete all the generated files you can press the 'Clean out' button - this will recursively delete everything below the path for the generated sources. Details ------- You really ought to read the class comment for VMMaker. Really. Go on, do it now. Errors ------- A number of errors are possible, mostly relating to the two directory paths and the platform name. As much as possible these are trapped and you will see 'inform' menus to let you know. Inevitably, if you put in the effort, you will be able to confuse the tool and break it. ! !VMMakerTool class methodsFor: 'instance creation' stamp: 'tbn 5/25/2010 19:03'! initialize Smalltalk at: #TheWorldMenu ifPresent: [ :class | class class methodDict at: #registerOpenCommand: ifPresent: [ :method | (method sendsSelector: #deprecated:) ifFalse: [ class registerOpenCommand: (Array with: 'VMMaker' with: (Array with: self with: #openInWorld)) ] ] ]! ! !VMMakerTool class methodsFor: 'world menu' stamp: 'tbn 5/25/2010 18:58'! menuCommandOn: aBuilder (aBuilder item: #'VMMaker') parent: #Tools; action:[self openInWorld]! ! !VMMakerTool class methodsFor: 'instance creation'! openInWorld "Build a VMMakerTool and open it" "VMMakerTool openInWorld" ^self new buildWindow openInWorld! ! !VMMakerTool class methodsFor: 'unloading' stamp: 'tbn 5/25/2010 19:02'! unload Smalltalk at: #TheWorldMenu ifPresent: [ :class | class class methodDict at: #unregisterOpenCommandWithReceiver: ifPresent: [ :method | (method sendsSelector: #deprecated:) ifFalse: [ class unregisterOpenCommandWithReceiver: self ] ] ]! ! !VMMakerTool methodsFor: 'drag and drop' stamp: 'nk 4/5/2005 23:02'! acceptDroppingMorph: transferMorph event: evt inMorph: aMorph "Here we are fetching information from the dropped transferMorph and performing the correct action for this drop. As long as the source is part of this tool, move the dragged item from the source list to the destination list" ^self moveItem: transferMorph passenger from: transferMorph source to: aMorph! ! !VMMakerTool methodsFor: 'window construction' stamp: 'dtl 5/27/2010 21:25'! addSecondButtonRowToWindow: sysWin startingAt: initialVerticalOffset | verticalOffset box | verticalOffset := initialVerticalOffset. "add a row of buttons to start up various actions" box := AlignmentMorph new vResizing: #shrinkWrap; layoutInset: 6@3; cellInset: 6@0; wrapCentering: #center. box addMorph: (TextMorph new contents: 'Generate:' translated asText allBold) lock. box addMorphBack: (SimpleButtonMorph new target: self; label: 'Entire'; actionSelector: #generateAll; hResizing: #spaceFill; setBalloonText: 'Generate the sources for the core VM and all chosen internal and external plugins'). box addMorphBack: (SimpleButtonMorph new target: self; label: 'Core+Internal'; actionSelector: #generateCore; hResizing: #spaceFill; setBalloonText: 'Generate the sources for the core vm and any internal plugins'). box addMorphBack: (SimpleButtonMorph new target: self; label: 'External Plugins'; actionSelector: #generateExternal; hResizing: #spaceFill; setBalloonText: 'Generate the sources for all external plugins'). sysWin addMorph: box fullFrame: (LayoutFrame fractions: (0 @ 0 corner: 1 @ 0) offsets: (0 @ verticalOffset corner: 0 @ (verticalOffset := verticalOffset + box height - 1))). ^verticalOffset.! ! !VMMakerTool methodsFor: 'window construction' stamp: 'dtl 10/24/2009 10:00'! addTopButtonRowToWindow: sysWin | verticalOffset box | verticalOffset := 0. "add a row of buttons to start up various actions" box := AlignmentMorph new vResizing: #shrinkWrap; layoutInset: 6 @ 3; cellInset: 6 @ 0; wrapCentering: #center. box addMorphBack: (SimpleButtonMorph new target: self; label: 'Help'; actionSelector: #helpText; hResizing: #spaceFill; setBalloonText: 'Open the help window'). box addMorphBack: (TextMorph new contents: 'Configuration File:' translated asText allBold) lock. box addMorphBack: (SimpleButtonMorph new target: self; label: 'Load'; actionSelector: #loadConfig; hResizing: #spaceFill; setBalloonText: 'Load a previously saved configuration'). box addMorphBack: (SimpleButtonMorph new target: self; label: 'Save'; actionSelector: #saveConfig; hResizing: #spaceFill; setBalloonText: 'Save the current configuration'). box addMorphBack: (SimpleButtonMorph new target: self; label: 'Rescan'; actionSelector: #rescanPlugins; hResizing: #spaceFill; setBalloonText: 'Rescan image, adding any new plugins and removing those no longer available in the image'). sysWin addMorph: box fullFrame: (LayoutFrame fractions: (0 @ 0 corner: 1 @ 0) offsets: (0 @ verticalOffset corner: 0 @ (verticalOffset := verticalOffset + box height - 1))). ^ verticalOffset! ! !VMMakerTool methodsFor: 'menus' stamp: 'nk 4/5/2005 20:24'! availableListMenu: aMenu aMenu addTranslatedList: #( ('make all external' makeAllPluginsExternal) ('make all internal' makeAllPluginsInternal) ('make all available' makeAllPluginsAvailable) - ('browse plugin' browseSelectedAvailablePlugin)). ^ aMenu! ! !VMMakerTool methodsFor: 'list access' stamp: 'tpr 10/10/2001 12:36'! availableListSelectionAt: index "return the boolean to say if the available plugin at index is selected" ^allPluginsSelectionsArray at: index! ! !VMMakerTool methodsFor: 'list access' stamp: 'tpr 10/10/2001 12:37'! availableListSelectionAt: index put: bool "set the boolean to say if the available plugin at index is selected" ^allPluginsSelectionsArray at: index put: bool! ! !VMMakerTool methodsFor: 'list access'! availableModules ^vmMaker availablePlugins! ! !VMMakerTool methodsFor: 'menus' stamp: 'rww 9/25/2001 02:00'! browseSelectedAvailablePlugin | plugin | plugin := self availableModules at: self currentAvailableModuleIndex ifAbsent: [^self]. (Smalltalk classNamed: plugin) browseHierarchy! ! !VMMakerTool methodsFor: 'menus' stamp: 'rww 9/25/2001 02:00'! browseSelectedExternalPlugin | plugin | plugin := self externalModules at: self currentExternalModuleIndex ifAbsent: [^self]. (Smalltalk classNamed: plugin) browseHierarchy! ! !VMMakerTool methodsFor: 'menus' stamp: 'rww 9/25/2001 02:01'! browseSelectedInternalPlugin | plugin | plugin := self internalModules at: self currentInternalModuleIndex ifAbsent: [^self]. (Smalltalk classNamed: plugin) browseHierarchy! ! !VMMakerTool methodsFor: 'window construction' stamp: 'dtl 3/14/2010 18:38'! buildCenterRows | rows color1 color2 labelWidth longestLabel | color1 := Color blue veryMuchLighter. color2 := Color green veryMuchLighter. longestLabel := 'Path to platforms code:'. "calculate labelWidth for acceptable results on varous images" labelWidth := (TextMorph new contents: longestLabel translated asText allBold) width *1.13. rows := Morph new color: Color transparent; layoutPolicy: TableLayout new; vResizing: #spaceFill; extent: 550 @ (TextStyle defaultFont height * 8); hResizing: #spaceFill; listDirection: #topToBottom; borderStyle: (BorderStyle complexAltRaised width: 2); wrapDirection: #none; wrapCentering: #center; yourself. rows addMorphBack: ((self entryRowWithLabel: 'Interpreter class name:' labelWidth: labelWidth balloonText: 'The name of the Interpreter class' getFieldText: #interpreterClassName setFieldText: #interpreterClassName: buttonLabel: nil buttonAction: nil buttonBalloonText: nil) color: color1). interpreterClassMorph := rows submorphs last submorphs first. rows addMorphBack: ((self entryRowWithLabel: 'Path to platforms code:' labelWidth: labelWidth balloonText: 'The directory where the platform source tree is found; can be edited in text field to the right. Default of {working directory}/src is strongly recommended' getFieldText: #platformsPathText setFieldText: #platformsPathText: buttonLabel: 'Find Path' buttonAction: #findPlatformsPath buttonBalloonText: 'Choose the directory where you keep the platform specific code from a file dialogue') color: color2). platformPathMorph := rows submorphs last submorphs second. rows addMorphBack: ((self entryRowWithLabel: 'Platform name:' labelWidth: labelWidth balloonText: 'The platform name (as returned by Smalltalk platformName - unix, Mac OS, RISCOS, win32 etc); can be edited (in text field to the right) to cross generate' getFieldText: #platformNameText setFieldText: #platformNameText: buttonLabel: 'Find platform' buttonAction: #platformsListMenu buttonBalloonText: 'Choose from a list of known platforms. The default is this current platform.') color: color1). platformNameMorph := rows submorphs last submorphs second. rows addMorphBack: ((self entryRowWithLabel: 'Path to generated sources:' labelWidth: labelWidth balloonText: 'The directory where the built sources will be placed; can be edited in text field to the right. The default is strongly recommended; makefile alterations may be needed if you use a different path.' getFieldText: #sourcePathText setFieldText: #sourcePathText: buttonLabel: 'Clean out' buttonAction: #cleanoutSrcDir buttonBalloonText: 'Clean out all the files in the target directory, ready for a clean build') color: color2). generatedPathMorph := rows submorphs last submorphs second. ^ rows! ! !VMMakerTool methodsFor: 'window construction' stamp: 'nk 4/5/2005 23:05'! buildWindow "VMMakerTool openInWorld" | sysWin box verticalOffset | sysWin := (SystemWindow labelled: 'VMMaker') model: self. verticalOffset := self addTopButtonRowToWindow: sysWin. verticalOffset := self addSecondButtonRowToWindow: sysWin startingAt: verticalOffset. box := self buildCenterRows. sysWin addMorph: box fullFrame: (LayoutFrame fractions: (0 @ 0 corner: 1 @ 0) offsets: (0 @ verticalOffset corner: 0 @ (verticalOffset := verticalOffset + box height - 1))). "Add the list of plugins that are available to build" allPluginsList := (PluggableListMorph on: self list: #availableModules selected: #currentAvailableModuleIndex changeSelected: #currentAvailableModuleIndex: menu: #availableListMenu: keystroke: nil) enableDragNDrop. allPluginsList hResizing: #spaceFill; vResizing: #spaceFill; borderWidth: 0. box := AlignmentMorph newColumn. box addMorphBack: (TextMorph new contents: 'Plugins not built' asText allBold; lock); setBalloonText: 'List of plugins that are available to build but not yet chosen. Drag to either other list or use menu option to move in bulk'. box addMorphBack: allPluginsList. sysWin addMorph: box fullFrame: (LayoutFrame fractions: (0 @ 0 corner: 1 / 3 @ 1) offsets: (0 @ verticalOffset corner: 0 @ -100)). "make the list for plugins that will be built for internal linking" internalPluginsList := (PluggableListMorph on: self list: #internalModules selected: #currentInternalModuleIndex changeSelected: #currentInternalModuleIndex: menu: #internalListMenu: keystroke: nil) enableDragNDrop. internalPluginsList hResizing: #spaceFill; vResizing: #spaceFill; borderWidth: 0. box := AlignmentMorph newColumn. box addMorphBack: (TextMorph new contents: 'Internal Plugins' asText allBold; lock); setBalloonText: 'List of plugins chosen to be built internally'. box addMorphBack: internalPluginsList. sysWin addMorph: box fullFrame: (LayoutFrame fractions: (1 / 3 @ 0 corner: 2 / 3 @ 1) offsets: (0 @ verticalOffset corner: 0 @ -100)). "make the list for plugins to be built externally (ie as DLLs, SO or whatever suits the platform" externalPluginsList := (PluggableListMorph on: self list: #externalModules selected: #currentExternalModuleIndex changeSelected: #currentExternalModuleIndex: menu: #externalListMenu: keystroke: nil) enableDragNDrop. externalPluginsList hResizing: #spaceFill; vResizing: #spaceFill; borderWidth: 0. box := AlignmentMorph newColumn. box addMorphBack: (TextMorph new contents: 'External Plugins' asText allBold; lock); setBalloonText: 'List of plugins chosen to be built externally'. box addMorphBack: externalPluginsList. sysWin addMorph: box fullFrame: (LayoutFrame fractions: (2 / 3 @ 0 corner: 1 @ 1) offsets: (0 @ verticalOffset corner: 0 @ -100)). sysWin addMorph: (PluggableTextMorph on: logger text: nil accept: nil readSelection: nil menu: nil) fullFrame: (LayoutFrame fractions: (0 @ 1 corner: 1 @ 1) offsets: (0 @ -100 corner: 0 @ 0)). ^ sysWin! ! !VMMakerTool methodsFor: 'settings' stamp: 'nk 4/5/2005 23:31'! checkOK "check as many settings as we can and report true if all seems ok" (interpreterClassMorph accept; hasUnacceptedEdits) ifTrue:[^false]. (platformPathMorph accept; hasUnacceptedEdits) ifTrue:[^false]. (platformNameMorph accept; hasUnacceptedEdits) ifTrue:[^false]. (generatedPathMorph accept; hasUnacceptedEdits) ifTrue:[^false]. [vmMaker platformPluginsDirectory; crossPlatformPluginsDirectory] on: VMMakerException do: [:ex| self inform: ex messageText. ^ false]. ^ true! ! !VMMakerTool methodsFor: 'path access' stamp: 'tpr 3/27/2002 15:19'! cleanoutSrcDir "remove the entire generated src tree, ready for a nice clean build" vmMaker deleteEntireGeneratedTree! ! !VMMakerTool methodsFor: 'configurations' stamp: 'dtl 12/17/2010 14:24'! configFileName "Answer the full path to the most recently loaded configuration file, or a default if no configuration file was previously loaded." ^ configFileName ifNil: [configFileName := FileDirectory default pathName , FileDirectory slash , 'vmmaker.config']! ! !VMMakerTool methodsFor: 'list access'! currentAvailableModuleIndex allPluginsSelection ifNil:[^0]. ^allPluginsSelection! ! !VMMakerTool methodsFor: 'list access' stamp: 'nk 12/16/2002 08:49'! currentAvailableModuleIndex: anInteger allPluginsSelection := anInteger. self changed: #currentAvailableModuleIndex! ! !VMMakerTool methodsFor: 'list access'! currentExternalModuleIndex externalPluginsSelection ifNil:[^0]. ^externalPluginsSelection! ! !VMMakerTool methodsFor: 'list access' stamp: 'nk 12/16/2002 08:49'! currentExternalModuleIndex: anInteger externalPluginsSelection := anInteger. self changed: #currentExternalModuleIndex! ! !VMMakerTool methodsFor: 'list access'! currentInternalModuleIndex internalPluginsSelection ifNil:[^0]. ^internalPluginsSelection! ! !VMMakerTool methodsFor: 'list access' stamp: 'nk 12/16/2002 08:49'! currentInternalModuleIndex: anInteger internalPluginsSelection := anInteger. self changed: #currentInternalModuleIndex! ! !VMMakerTool methodsFor: 'drag and drop' stamp: 'tpr 10/12/2001 15:27'! dragPassengerFor: item inMorph: dragSource (dragSource isKindOf: PluggableListMorph) ifFalse: [^item]. ^item contents! ! !VMMakerTool methodsFor: 'drag and drop'! dragTransferTypeForMorph: dragSource ^(dragSource isKindOf: PluggableListMorph) ifTrue: [dragSource getListSelector]! ! !VMMakerTool methodsFor: 'window construction' stamp: 'dtl 3/14/2010 18:22'! entryRowWithLabel: label labelWidth: lWidth balloonText: balloonText getFieldText: getTextSelector setFieldText: setTextSelector buttonLabel: buttonLabel buttonAction: buttonAction buttonBalloonText: buttonBalloonText | row tm | row := Morph new color: Color transparent; hResizing: #spaceFill; vResizing: #spaceFill; extent: 550 @ 40; layoutPolicy: ProportionalLayout new; borderWidth: 2; setBalloonText: balloonText translated; yourself. row addMorph: (TextMorph new contents: label translated asText allBold) lock fullFrame: (LayoutFrame fractions: (0 @ 0 corner: 0 @ 1) offsets: (3 @ 3 corner: lWidth @ -3)). row addMorph: ((tm := PluggableTextMorph on: self text: getTextSelector accept: setTextSelector) hideVScrollBarIndefinitely: true; acceptOnCR: true) fullFrame: (LayoutFrame fractions: (0 @ 0 corner: 1 @ 1) offsets: (lWidth + 10 @ 0 corner: (lWidth / 1.8 + 10) negated @ 0)). "Make the background a solid color so that eventual bleed from the labels doesn't make the entire input field unreadable. Happens when the bold font is significantly wider than the non-bold font or when the spacing of the font doesn't match the guess above" tm color: (Color gray: 0.9). buttonAction ifNotNil: [row addMorph: (SimpleButtonMorph new target: self; label: buttonLabel translated; actionSelector: buttonAction; hResizing: #spaceFill; setBalloonText: buttonBalloonText translated) fullFrame: (LayoutFrame fractions: (1 @ 0 corner: 1 @ 1) offsets: ((lWidth / 1.8 + 5) negated @ 3 corner: -5 @ -3))]. ^ row! ! !VMMakerTool methodsFor: 'menus' stamp: 'nk 4/5/2005 20:25'! externalListMenu: aMenu aMenu addTranslatedList:#( ('make all external' makeAllPluginsExternal) ('make all internal' makeAllPluginsInternal) ('make all available' makeAllPluginsAvailable) - ('browse plugin' browseSelectedExternalPlugin) - ('generate plugin' generateSelectedExternalPlugin)). ^ aMenu! ! !VMMakerTool methodsFor: 'list access' stamp: 'tpr 10/10/2001 12:36'! externalListSelectionAt: index "return the boolean to say if the external plugin at index is selected" ^externalPluginsSelectionsArray at: index! ! !VMMakerTool methodsFor: 'list access' stamp: 'tpr 10/10/2001 12:37'! externalListSelectionAt: index put: bool "set the boolean to say if the external plugin at index is selected" ^externalPluginsSelectionsArray at: index put: bool! ! !VMMakerTool methodsFor: 'list access'! externalModules ^vmMaker externalModules! ! !VMMakerTool methodsFor: 'path access' stamp: 'dtl 8/24/2009 07:26'! findPlatformsPath | dir | dir := self selectDirectory. dir ifNil: [^nil]. self platformsPathText: dir pathName! ! !VMMakerTool methodsFor: 'path access' stamp: 'tpr 3/12/2002 14:10'! findPlatformsPathFrom: fd | path | Utilities informUserDuring:[:bar| path := self findPlatformsPathFrom: fd informing: bar. ]. ^path! ! !VMMakerTool methodsFor: 'path access' stamp: 'ar 3/10/2002 14:54'! findPlatformsPathFrom: fd informing: bar | dirNames possiblePath | bar value: 'Searching in ', fd pathName. dirNames := fd directoryNames. (dirNames includes: 'platforms') ifTrue:[ possiblePath := fd pathName, fd pathNameDelimiter asString, 'platforms'. (self confirm: 'Found a platforms directory at ', possiblePath,' Do you want me to use it?') ifTrue:[^possiblePath]. ]. dirNames do:[:dd| possiblePath := self findPlatformsPathFrom: (fd directoryNamed: dd) informing: bar. possiblePath ifNotNil:[^possiblePath]. ]. ^nil! ! !VMMakerTool methodsFor: 'generate sources' stamp: 'tpr 10/21/2001 11:00'! generateAll "tell the vmMaker to build all the sources" self checkOK ifTrue: [[vmMaker generateEntire] on: VMMakerException do: [:ex| self inform: ex messageText]]! ! !VMMakerTool methodsFor: 'generate sources' stamp: 'tpr 10/21/2001 11:01'! generateCore "tell the vmMaker to build all the core vm sources" self checkOK ifTrue: [[vmMaker generateMainVM] on: VMMakerException do: [:ex| self inform: ex messageText]]! ! !VMMakerTool methodsFor: 'generate sources' stamp: 'tpr 10/21/2001 11:02'! generateExternal "tell the vmMaker to build all the externally linked plugin sources" self checkOK ifTrue: [[vmMaker generateExternalPlugins] on: VMMakerException do: [:ex | self inform: ex messageText]]! ! !VMMakerTool methodsFor: 'generate sources' stamp: 'tpr 10/21/2001 11:03'! generateSelectedExternalPlugin | plugin | plugin := self externalModules at: self currentExternalModuleIndex ifAbsent: [^self]. self checkOK ifTrue: [[vmMaker generateExternalPlugin: plugin] on: VMMakerException do: [:ex| self inform: ex messageText]] ! ! !VMMakerTool methodsFor: 'generate sources' stamp: 'tpr 10/21/2001 11:03'! generateSelectedInternalPlugin | plugin | plugin := self internalModules at: self currentInternalModuleIndex ifAbsent: [^self]. self checkOK ifTrue: [[vmMaker generateInternalPlugin: plugin] on: VMMakerException do: [:ex| self inform: ex messageText]] ! ! !VMMakerTool methodsFor: 'menus' stamp: 'tpr 10/14/2001 20:11'! helpText (StringHolder new contents: self class comment) openLabel: 'VMMakerTool help' ! ! !VMMakerTool methodsFor: 'generate sources' stamp: 'tpr 5/28/2008 19:39'! inform: aProblemString "log the problem in the transcript window" logger show: aProblemString; cr! ! !VMMakerTool methodsFor: 'initialisation' stamp: 'ar 3/10/2002 15:09'! initialExtent ^600@450! ! !VMMakerTool methodsFor: 'list access'! initialModules ^vmMaker availableModules! ! !VMMakerTool methodsFor: 'initialisation' stamp: 'ar 3/10/2002 15:06'! initialize logger := TranscriptStream new. vmMaker := VMMaker default. vmMaker logger: logger. vmMaker addDependent: self. allPluginsSelectionsArray := Array new: self availableModules size withAll: false. internalPluginsSelectionsArray := Array new. externalPluginsSelectionsArray := Array new.! ! !VMMakerTool methodsFor: 'menus' stamp: 'nk 4/5/2005 20:25'! internalListMenu: aMenu aMenu addTranslatedList:#( ('make all external' makeAllPluginsExternal) ('make all internal' makeAllPluginsInternal) ('make all available' makeAllPluginsAvailable) - ('browse plugin' browseSelectedInternalPlugin) - ('generate plugin' generateSelectedInternalPlugin)). ^ aMenu! ! !VMMakerTool methodsFor: 'list access' stamp: 'tpr 10/10/2001 12:36'! internalListSelectionAt: index "return the boolean to say if the internal plugin at index is selected" ^internalPluginsSelectionsArray at: index! ! !VMMakerTool methodsFor: 'list access' stamp: 'tpr 10/10/2001 12:37'! internalListSelectionAt: index put: bool "set the boolean to say if the internal plugin at index is selected" ^internalPluginsSelectionsArray at: index put: bool! ! !VMMakerTool methodsFor: 'list access'! internalModules ^vmMaker internalModules! ! !VMMakerTool methodsFor: 'path access' stamp: 'svp 11/14/2002 21:11'! interpreterClassName "return a Text for the path to the generated sources" ^[vmMaker interpreterClass name asString] on: VMMakerException do:[:ex| ex return:''].! ! !VMMakerTool methodsFor: 'path access' stamp: 'tpr 5/28/2008 19:51'! interpreterClassName: aText "set the interpreter class name" [vmMaker interpreterClassName: aText asString] on: VMMakerException do: [:ex| self inform:ex messageText. ^false]. ^true! ! !VMMakerTool methodsFor: 'deprecated' stamp: 'dtl 5/27/2010 21:31'! isFor64BitVM "This selector may be used by obsolete instances of VMMakerTool. The 64-bit setting of VMMaker is no longer functionally relevant, but this method is retained to prevent problems with existing VMMakerTool instances that may exist in some images."! ! !VMMakerTool methodsFor: 'list access' stamp: 'tpr 10/12/2001 15:29'! listForMorph: aMorph "work out which list is the one associated with this morph" allPluginsList = aMorph ifTrue:[^allPluginsList getListSelector]. internalPluginsList = aMorph ifTrue:[^internalPluginsList getListSelector]. externalPluginsList =aMorph ifTrue:[^externalPluginsList getListSelector]. ^nil! ! !VMMakerTool methodsFor: 'list access'! listMorphs ^Array with: allPluginsList with: internalPluginsList with: externalPluginsList! ! !VMMakerTool methodsFor: 'configurations' stamp: 'dtl 12/19/2010 22:50'! loadConfig ((Smalltalk hasClassNamed: #UIManager) ifTrue: [ "Newer images use UIManager" (Smalltalk at: #UIManager) default chooseFileMatching: #('config' ) label: 'Select VMMaker configuration...'] ifFalse: [ "UIManager not present, use original StandardFileMenu implementation " (((Smalltalk at: #StandardFileMenu) oldFileMenu: FileDirectory default withPattern: '*.config') startUpWithCaption: 'Select VMMaker configuration...') ifNotNilDo: [ :fileResult | fileResult directory fullNameFor: fileResult name]]) ifNotNilDo: [ :file | [vmMaker := VMMaker forConfigurationFile: file. vmMaker logger: logger. vmMaker platformDirectory] on: Error do: [self inform: 'Possible problem with path settings or platform name?']. configFileName := file. "set default config file name to the most recently loaded file" self updateAllViews]! ! !VMMakerTool methodsFor: 'menus' stamp: 'tpr 10/16/2001 09:58'! makeAllPluginsAvailable vmMaker makeAllModulesAvailable! ! !VMMakerTool methodsFor: 'menus' stamp: 'tpr 10/16/2001 09:58'! makeAllPluginsExternal vmMaker makeAllModulesExternal! ! !VMMakerTool methodsFor: 'menus' stamp: 'tpr 10/16/2001 09:58'! makeAllPluginsInternal vmMaker makeAllModulesInternal! ! !VMMakerTool methodsFor: 'drag and drop' stamp: 'tpr 10/21/2001 11:19'! moveItem: transferedMorph from: sourceListMorph to: destListMorph "As part of a drag operation we have to move the item carried by the transfer morph from a source list to a destination list" "work out which list is involved and add the item to it" | destlist srclist | "no need to do anything if we drop on the same place from which we dragged" sourceListMorph = destListMorph ifTrue: [^ false]. (destlist := self listForMorph: destListMorph) ifNil: [^ false]. (srclist := self listForMorph: sourceListMorph) ifNil: [^ false]. vmMaker movePlugin: transferedMorph contents from: srclist to: destlist. self changed: sourceListMorph getListSelector. self changed: destListMorph getListSelector. ^ true! ! !VMMakerTool methodsFor: 'menus' stamp: 'rww 9/25/2001 01:02'! perform: selector orSendTo: otherTarget "Selector was just chosen from a menu by a user. If can respond, then perform it on myself. If not, send it to otherTarget, presumably the editPane from which the menu was invoked." (self respondsTo: selector) ifTrue: [^ self perform: selector] ifFalse: [^ otherTarget perform: selector]! ! !VMMakerTool methodsFor: 'path access'! platformNameText "return a Text for the platform name" ^vmMaker platformName asText! ! !VMMakerTool methodsFor: 'menus' stamp: 'tpr 5/28/2008 19:56'! platformNameText: aText "set the platform name - this will almost certainly mean replacing the vmMaker with one suited to the platform so we do it anyway." | prevVMMaker | prevVMMaker := vmMaker. "make a new vmmaker and ensure I depend on it correctly" vmMaker := VMMaker forPlatform: aText string. vmMaker logger: logger. vmMaker addDependent: self. prevVMMaker removeDependent: self. "configure the new vmmaker to match the old one" [vmMaker loadConfiguration: prevVMMaker configurationInfo. vmMaker platformDirectory] on: VMMakerException do: [:ex| self inform: ex messageText. ^ false]. ^ true! ! !VMMakerTool methodsFor: 'menus' stamp: 'nk 4/5/2005 23:05'! platformsListMenu "create a menu of all known platforms" | choice platnames | platnames := vmMaker platformRootDirectory directoryNames copyWithoutAll: #('Cross' 'CVS' '.svn'). choice := (PopUpMenu labelArray: platnames lines: #()) startUp. choice = 0 ifTrue: [^self]. self platformNameText: (platnames at: choice) asText! ! !VMMakerTool methodsFor: 'path access' stamp: 'tpr 10/21/2001 11:24'! platformsPathText "return a Text for the path to the platform sources" [^vmMaker platformRootDirectory fullName asText] on: VMMakerException do:[^'Problem with directory name for platform code: enter correct path or consult help text' asText]! ! !VMMakerTool methodsFor: 'path access' stamp: 'tpr 5/28/2008 19:55'! platformsPathText: aText "set the path to the platform sources" [^vmMaker platformRootDirectoryName: aText asString] on: VMMakerException do:[:ex| self inform:'Problem with this directory name; check the path settings, permissions or spelling?'. ex return: false]! ! !VMMakerTool methodsFor: 'menus' stamp: 'nk 4/5/2005 20:27'! release vmMaker ifNotNil: [ vmMaker removeDependent: self ]. super release.! ! !VMMakerTool methodsFor: 'menus' stamp: 'dtl 10/23/2009 19:48'! rescanPlugins vmMaker reinitializePluginsLists! ! !VMMakerTool methodsFor: 'configurations' stamp: 'dtl 12/21/2010 10:59'! saveConfig "write info about the current configuration to a file." ((Smalltalk hasClassNamed: #UIManager) ifTrue: [ "Newer images use UIManager" ((Smalltalk at: #UIManager) default request: 'Save VMMaker configuration...' initialAnswer: self configFileName) ifNotNilDo: [:f | | file path | ('*.config' match: f) ifTrue: [file := f] ifFalse: [file := f , '.config']. "If path is not valid, the image has probably been moved to a new location or to a different platform. Assume this is the case, and change the path to the current default." path := file copyUpToLast: FileDirectory pathNameDelimiter. (FileDirectory default directoryExists: path) ifTrue: [file] ifFalse: [file copyReplaceAll: path with: FileDirectory default pathName]]] ifFalse: [ "UIManager not present, use original StandardFileMenu implementation" (((Smalltalk at: #StandardFileMenu) newFileMenu: FileDirectory default withPattern: '*.config') startUpWithCaption: 'Save VMMaker configuration...') ifNotNilDo: [ :fileResult | ('*.config' match: fileResult name) ifFalse: [fileResult name: fileResult name , '.config']. fileResult directory fullNameFor: fileResult name]]) ifNotNilDo: [ :file | vmMaker saveConfigurationTo: file. configFileName := file]! ! !VMMakerTool methodsFor: 'path access' stamp: 'dtl 8/24/2009 07:25'! selectDirectory "Newer images should use UIManager, but UIManager is not available on older images. Provide backward compatibility." (Smalltalk hasClassNamed: #UIManager) ifTrue: [^(Smalltalk at: #UIManager) default perform: #chooseDirectory] ifFalse: [^(Smalltalk at: #FileList2) perform: #modalFolderSelector]. self error: 'directory selector dialog not available'! ! !VMMakerTool methodsFor: 'path access' stamp: 'ar 5/4/2002 21:06'! sourcePathText "return a Text for the path to the generated sources" ^[vmMaker sourceDirectory fullName asText] on: VMMakerException do:[:ex| ex return:''].! ! !VMMakerTool methodsFor: 'path access'! sourcePathText: aText "set the path to the generated sources" ^vmMaker sourceDirectoryName: aText asString! ! !VMMakerTool methodsFor: 'deprecated' stamp: 'dtl 5/27/2010 21:33'! toggle64BitVM "This selector may be used by obsolete instances of VMMakerTool. The 64-bit setting of VMMaker is no longer functionally relevant, but this method is retained to prevent problems with existing VMMakerTool instances that may exist in some images."! ! !VMMakerTool methodsFor: 'initialisation' stamp: 'tpr 10/12/2001 18:06'! update: anObject "some related object has changed. Try to handle it" anObject == #reinitialize ifTrue: [self updateAllViews]! ! !VMMakerTool methodsFor: 'initialisation' stamp: 'tpr 10/12/2001 18:06'! updateAllViews self changed: #platformsPathText; changed: #platformNameText; changed: #sourcePathText; changed: #availableModules; changed: #internalModules; changed: #externalModules! ! !VMMakerTool methodsFor: 'drag and drop' stamp: 'nk 4/5/2005 23:14'! wantsDroppedMorph: transferMorph event: anEvent inMorph: destinationLM "We are only interested in TransferMorphs as wrappers for information. If their content is really interesting for us, will determined later in >>acceptDroppingMorph:event:." "only want drops on the lists" (transferMorph isKindOf: HandleMorph) ifTrue: [ ^false ]. (transferMorph isKindOf: TransferMorph) ifFalse: [ ^false ]. transferMorph source model = self ifFalse:[^false]. ^self listMorphs includes: destinationLM! ! !String class methodsFor: '*VMMaker-plugin generation' stamp: 'acg 9/19/1999 00:21'! ccg: cg prolog: aBlock expr: aString index: anInteger ^cg ccgLoad: aBlock expr: aString asCharPtrFrom: anInteger andThen: (cg ccgValBlock: 'isBytes')! ! !String class methodsFor: '*VMMaker-plugin generation' stamp: 'acg 9/18/1999 17:10'! ccgDeclareCForVar: aSymbolOrString ^'char *', aSymbolOrString! ! !String methodsFor: '*VMMaker-Translation to C' stamp: 'EstebanLorenzano 12/6/2010 19:19'! replaceLastOccurrence: oldSubstring with: newSubstring "Answer a copy with the last occurrence of oldSubstring replaced by newSubstring." " 'int i' replaceLastOccurrence: 'i' with: 'i2' " " 'void *v' replaceLastOccurrence: 'v' with: 'v2' " " 'int intxintxintx' replaceLastOccurrence: 'i' with: 'I2' " " 'int intxintxintx' replaceLastOccurrence: 'FOO' with: 'BAR' " " 'int intxintxintx' replaceLastOccurrence: '' with: 'BAZ' " ^ self class streamContents: [:ws | | pos rs | rs := ReadStream on: self. pos := self findLastOccurrenceOfString: oldSubstring startingAt: 1. pos > 0 ifTrue: [ws nextPutAll: (rs next: pos - 1); nextPutAll: newSubstring. rs next: oldSubstring size]. ws nextPutAll: rs upToEnd]! ! !Integer methodsFor: '*VMMaker-interpreter simulator' stamp: 'eem 2/19/2009 18:33'! asUnsignedInteger self assert: self >= 0. ^self! ! !Integer methodsFor: '*VMMaker-interpreter simulator' stamp: 'nk 4/3/2004 12:46'! coerceTo: cTypeString sim: interpreter | unitSize | cTypeString last = $* ifTrue: [ "C pointer" unitSize := cTypeString caseOf: { ['char *'] -> [1]. ['int *'] -> [4]. ['float *'] -> [4]. ['unsigned *'] -> [4]. ['float *'] -> [4]. } otherwise: [ (cTypeString beginsWith: 'char') ifTrue: [1] ifFalse: [4] ]. ^(CArray basicNew) interpreter: interpreter address: self unitSize: unitSize; yourself. ]. ^ self "C number (int, char, float, etc)"! ! !Integer methodsFor: '*VMMaker-interpreter simulator' stamp: 'eem 5/21/2010 11:09'! hex8 "Print the receiver in base 16 with prefixed base, using at least 8 digits. DO NOT CHANGE THIS!! The Cog VMMaker depends on this. Consider using storeStringBase: 16 length: 11 padded: true instead." "16r3333 hex8" | hex | hex := self hex. "16rNNN" ^hex size < 11 ifTrue: [hex copyReplaceFrom: 4 to: 3 with: ('00000000' copyFrom: 1 to: 11-hex size)] ifFalse: [hex]! ! !Integer methodsFor: '*VMMaker-interpreter simulator' stamp: 'eem 3/19/2009 16:15'! signedBitShift: anInteger "For historical reasons Slang generates an unsigned shift from all of the shift operators >>, << & bitShift:. These are too deeply entrenched to try and redefine the semantics. So instead we provide a signed bitShift: that signals to Slang that its argument should be cast to signed, not to unsigned, when being shifted." ^self bitShift: anInteger! ! !Integer methodsFor: '*VMMaker-interpreter simulator' stamp: 'eem 2/15/2009 10:17'! signedIntFromLong "Self is a signed or unsigned 32-bit integer" | sign | self < 0 ifTrue: [^self]. sign := self bitAnd: 16r80000000. sign = 0 ifTrue: [^ self]. ^ self - sign - sign! ! !Integer methodsFor: '*VMMaker-interpreter simulator' stamp: 'eem 3/2/2009 18:32'! signedIntFromShort "Self is an unsigned 16-bit integer in twos-comp form" | shortBits | shortBits := self bitAnd: 16rFFFF. ^(self bitAnd: 16r8000) "sign bit" = 0 ifTrue: [shortBits] ifFalse: [shortBits - 16r10000]! ! !Integer methodsFor: '*VMMaker-interpreter simulator' stamp: 'di 7/14/2004 12:27'! signedIntToLong "Produces a 32-bit value in twos-comp form. Sorry no error checking" self >= 0 ifTrue: [^ self] ifFalse: [^ self + 16r80000000 + 16r80000000] ! ! !Integer methodsFor: '*VMMaker-interpreter simulator' stamp: 'eem 3/2/2009 17:03'! signedIntToShort "Produces a 16-bit value (0-65k) in twos-comp form. Sorry no error checking" ^self bitAnd: 16rFFFF! ! !Float class methodsFor: '*VMMaker-plugin generation' stamp: 'bf 3/16/2000 19:06'! ccg: cg emitLoadFor: aString from: anInteger on: aStream cg emitLoad: aString asFloatValueFrom: anInteger on: aStream! ! !Float class methodsFor: '*VMMaker-plugin generation' stamp: 'acg 10/5/1999 06:05'! ccg: cg generateCoerceToOopFrom: aNode on: aStream cg generateCoerceToFloatObjectFrom: aNode on: aStream! ! !Float class methodsFor: '*VMMaker-plugin generation' stamp: 'acg 10/5/1999 06:10'! ccg: cg generateCoerceToValueFrom: aNode on: aStream cg generateCoerceToFloatValueFrom: aNode on: aStream! ! !Float class methodsFor: '*VMMaker-plugin generation' stamp: 'acg 9/18/1999 17:08'! ccg: cg prolog: aBlock expr: aString index: anInteger ^cg ccgLoad: aBlock expr: aString asFloatValueFrom: anInteger! ! !Float class methodsFor: '*VMMaker-plugin generation' stamp: 'acg 9/20/1999 11:22'! ccgCanConvertFrom: anObject ^anObject class == self! ! !Float class methodsFor: '*VMMaker-plugin generation' stamp: 'acg 9/17/1999 01:09'! ccgDeclareCForVar: aSymbolOrString ^'double ', aSymbolOrString! ! Object subclass: #CArray instanceVariableNames: 'interpreter arrayBaseAddress ptrOffset unitSize' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-InterpreterSimulation'! !CArray commentStamp: '' prior: 0! For Simulating the Interpreter only. Coercing an Integer to a pointer (eg. cCoerce:to: 'char *') returns a CArray. A CArray responds to at: and at:put: by reading/writing from the memory of the interpreter that sent the cCoerce:to: message in the first place. A CArray responds to arithmetic by returning the new address. Since longAt: sends // to its given address this is where the CArray converts back to a Integer for the memory fetch to work.! CArray subclass: #BalloonArray instanceVariableNames: 'simArray' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-InterpreterSimulation'! !BalloonArray commentStamp: '' prior: 0! BalloonArray keeps a shadow copy of its raw memory data in a Smalltalk array. This allows support for C's inhomogeneous access, returning floats where Floats were stored, and negative ints where they were stored. This ruse only works, of course where we have control over all the access.! !BalloonArray methodsFor: 'memory access' stamp: 'di 7/16/2004 12:14'! at: index | value | value := simArray at: index+1. "Debug only..." value ifNil: [self error: 'attempt to read an uninitialized field'. ^ super at: index "Maybe it was set in Squeak. Return the raw value"]. (self bitsOf: value) ~= (super at: index) ifTrue: [self error: 'inconsistent values']. ^ value! ! !BalloonArray methodsFor: 'memory access' stamp: 'di 7/16/2004 11:28'! at: index put: value super at: index put: (self bitsOf: value). ^ simArray at: index + 1 put: value. ! ! !BalloonArray methodsFor: 'memory access' stamp: 'di 7/15/2004 13:34'! bitsOf: value "Convert pos and neg ints and floats to 32-bit representations expected by C" value isInteger ifTrue: [value >= 0 ifTrue: [^ value]. ^ value + 16r80000000 + 16r80000000]. value isFloat ifTrue: [^ value asIEEE32BitWord]. self error: 'unexpected value for 32 bits'. ^ 0! ! !BalloonArray methodsFor: 'memory access' stamp: 'di 7/15/2004 16:04'! floatAt: index | value | value := self at: index. value isFloat ifFalse: [value = 0 ifTrue: [^ 0.0]. self error: 'non-float was stored'. ^ Float fromIEEE32Bit: value]. ^ value! ! !BalloonArray methodsFor: 'memory access' stamp: 'di 7/15/2004 13:00'! floatAt: index put: value value isFloat ifFalse: [self error: 'inconsistent values']. ^ self at: index put: value! ! !BalloonArray methodsFor: 'memory access' stamp: 'di 7/15/2004 13:02'! intAt: index | value | value := self at: index. value isInteger ifFalse: [self error: 'inconsistent values']. ^ value! ! !BalloonArray methodsFor: 'memory access' stamp: 'di 7/15/2004 13:01'! intAt: index put: value value isInteger ifFalse: [self error: 'inconsistent values']. ^ self at: index put: value! ! !BalloonArray methodsFor: 'memory access' stamp: 'di 7/15/2004 13:17'! setSimArray: anArray simArray := anArray! ! !CArray methodsFor: 'int arithmetic' stamp: 'ajh 8/20/2002 00:35'! * n ^ self ptrAddress * n! ! !CArray methodsFor: 'int arithmetic' stamp: 'ajh 8/20/2002 01:43'! + n ^ self ptrAddress + n! ! !CArray methodsFor: 'pointer arithmetic' stamp: 'ajh 8/20/2002 01:34'! += increment ptrOffset := ptrOffset + increment! ! !CArray methodsFor: 'int arithmetic' stamp: 'ajh 8/20/2002 01:43'! - n ^ self ptrAddress - n! ! !CArray methodsFor: 'pointer arithmetic' stamp: 'ajh 8/20/2002 01:35'! -= decrement ptrOffset := ptrOffset - decrement! ! !CArray methodsFor: 'int arithmetic' stamp: 'ajh 8/20/2002 00:35'! // n ^ self ptrAddress // n! ! !CArray methodsFor: 'int arithmetic' stamp: 'ajh 8/20/2002 00:35'! << n ^ self ptrAddress bitShift: n! ! !CArray methodsFor: 'int arithmetic' stamp: 'ajh 8/20/2002 00:35'! >> n ^ self ptrAddress bitShift: 0 - n! ! !CArray methodsFor: 'converting' stamp: 'ajh 8/20/2002 01:29'! adaptToNumber: rcvr andSend: selector ^ rcvr perform: selector with: self asInteger! ! !CArray methodsFor: 'converting' stamp: 'di 7/15/2004 16:55'! asCArrayAccessor ^ (CArrayAccessor on: self) += -1 "Defeat the +1 offset in the accessor"! ! !CArray methodsFor: 'converting' stamp: 'ajh 8/20/2002 01:10'! asInteger ^ self ptrAddress! ! !CArray methodsFor: 'accessing' stamp: 'di 7/6/2004 09:32'! at: offset ptrOffset = 0 ifFalse: [self error: 'only expect base address to receive at: message']. unitSize = 1 ifTrue: [^ interpreter byteAt: arrayBaseAddress + offset]. unitSize = 4 ifTrue: [^ interpreter long32At: arrayBaseAddress + (offset * 4)]. self halt: 'Can''t handle unitSize ', unitSize printString ! ! !CArray methodsFor: 'accessing' stamp: 'di 7/19/2004 12:01'! at: offset put: val ptrOffset = 0 ifFalse: [self error: 'only expect base address to receive at:put: message']. unitSize = 1 ifTrue: [^ interpreter byteAt: arrayBaseAddress + offset put: val]. unitSize = 4 ifTrue: [^ interpreter long32At: arrayBaseAddress + (offset * 4) put: val]. self halt: 'Can''t handle unitSize ', unitSize printString ! ! !CArray methodsFor: 'int arithmetic' stamp: 'ajh 8/20/2002 00:35'! bitAnd: n ^ self ptrAddress bitAnd: n! ! !CArray methodsFor: 'int arithmetic' stamp: 'ajh 8/20/2002 00:35'! bitOr: n ^ self ptrAddress bitOr: n! ! !CArray methodsFor: 'int arithmetic' stamp: 'ajh 8/20/2002 00:35'! bitShift: n ^ self ptrAddress bitShift: n! ! !CArray methodsFor: 'converting' stamp: 'tpr 3/23/2005 12:36'! coerceTo: cTypeString sim: interpreterSimulator cTypeString = 'int' ifTrue: [^ self ptrAddress]. cTypeString = 'float *' ifTrue: [^ self asCArrayAccessor asFloatAccessor]. cTypeString = 'int *' ifTrue: [^ self asCArrayAccessor asIntAccessor]. cTypeString = 'unsigned' ifTrue: [^ self ptrAddress]. ^ self! ! !CArray methodsFor: 'converting' stamp: 'ajh 8/20/2002 01:23'! doesNotUnderstand: message ^ self asInteger perform: message selector withArguments: message arguments! ! !CArray methodsFor: 'accessing' stamp: 'di 7/16/2004 12:45'! floatAt: index ^ Float fromIEEE32Bit: (self at: index)! ! !CArray methodsFor: 'accessing' stamp: 'di 7/16/2004 12:45'! floatAt: index put: value ^ self at: index put: value asIEEE32BitWord! ! !CArray methodsFor: 'accessing' stamp: 'di 7/16/2004 12:45'! intAt: index ^ (self at: index) signedIntFromLong! ! !CArray methodsFor: 'accessing' stamp: 'di 7/16/2004 12:45'! intAt: index put: signedInt ^ self at: index put: signedInt signedIntToLong! ! !CArray methodsFor: 'private' stamp: 'ajh 8/20/2002 00:30'! interpreter: interpreterSimulator address: arrayAddress unitSize: numBytes interpreter := interpreterSimulator. arrayBaseAddress := arrayAddress. unitSize := numBytes. ptrOffset := 0. ! ! !CArray methodsFor: 'private' stamp: 'ajh 8/20/2002 00:36'! ptrAddress ^ arrayBaseAddress + ptrOffset! ! Object subclass: #CCodeGenerator instanceVariableNames: 'translationDict inlineList constants variables variableDeclarations scopeStack methods preparedMethodList variablesSetCache headerFiles globalVariableUsage useSymbolicConstants generateDeadCode doNotRemoveMethodList asArgumentTranslationDict vmClass currentMethod' classVariableNames: 'UseRightShiftForDivide' poolDictionaries: '' category: 'VMMaker-Translation to C'! !CCodeGenerator commentStamp: 'tpr 5/2/2003 14:30' prior: 0! This class oversees the translation of a subset of Smalltalk to C, allowing the comforts of Smalltalk during development and the efficiency and portability of C for the resulting interpreter. See VMMaker for more useful info! !CCodeGenerator class methodsFor: 'class initialization' stamp: 'jm 8/19/1998 10:03'! initialize "CCodeGenerator initialize" UseRightShiftForDivide := true. "If UseRightShiftForDivide is true, the translator will generate a right-shift when it encounters a division by a constant that is a small power of two. For example, 'x / 8' will generate '((int) x >> 3)'. The coercion to int is done to make it clear that the C compiler should generate a signed shift." "Note: The Kernighan and Ritchie 2nd Edition C manual, p. 49, leaves the semantics of right-shifting a negative number open to the discretion of the compiler implementor. However, it strongly suggests that most compilers should generate an arithmetic right shift (i.e., shifting in the sign bit), which is the same as dividing by a power of two. If your compiler does not generate or simulate an arithmetic shift, then make this class variable false and re-translate." ! ! !CCodeGenerator class methodsFor: 'removing from system' stamp: 'jm 5/16/1998 10:26'! removeCompilerMethods "Before removing the C code generator classes from the system, use this method to remove the compiler node methods that support it. This avoids leaving dangling references to C code generator classes in the compiler node classes." ParseNode withAllSubclasses do: [ :nodeClass | nodeClass removeCategory: 'C translation'. ]. Smalltalk at: #AbstractSound ifPresent: [:abstractSound | abstractSound class removeCategory: 'primitive generation']. ! ! !CCodeGenerator methodsFor: 'public' stamp: 'TPR 3/2/2000 11:22'! addAllClassVarsFor: aClass "Add the class variables for the given class (and its superclasses) to the code base as constants." | allClasses | allClasses := aClass withAllSuperclasses. allClasses do: [:c | self addClassVarsFor: c]. ! ! !CCodeGenerator methodsFor: 'public' stamp: 'tpr 2/27/2004 19:07'! addClass: aClass "Add the variables and methods of the given class to the code base." | source | self checkClassForNameConflicts: aClass. self addClassVarsFor: aClass. "ikp..." self addPoolVarsFor: aClass. variables addAll: aClass instVarNames. self retainMethods: aClass requiredMethodNames. 'Adding Class ' , aClass name , '...' displayProgressAt: Sensor cursorPoint from: 0 to: aClass selectors size during: [:bar | aClass selectors doWithIndex: [:sel :i | bar value: i. source := aClass sourceCodeAt: sel. self addMethod: ((Compiler new parse: source in: aClass notifying: nil) asTranslationMethodOfClass: self translationMethodClass)]]. aClass declareCVarsIn: self! ! !CCodeGenerator methodsFor: 'public' stamp: 'ar 7/8/2003 11:16'! addClassVarsFor: aClass "Add the class variables for the given class to the code base as constants." | val node | aClass classPool associationsDo: [:assoc | val := assoc value. (useSymbolicConstants and:[self isCLiteral: val]) ifTrue:[node := TDefineNode new setName: assoc key asString value: assoc value] ifFalse:[node := TConstantNode new setValue: assoc value]. constants at: assoc key asString put: node]. ! ! !CCodeGenerator methodsFor: 'public' stamp: 'ar 2/14/1999 01:08'! addHeaderFile: aString "Add a header file. The argument must be a quoted string!!" headerFiles addLast: aString.! ! !CCodeGenerator methodsFor: 'utilities'! addMethod: aTMethod "Add the given method to the code base." (methods includesKey: aTMethod selector) ifTrue: [ self error: 'Method name conflict: ', aTMethod selector. ]. methods at: aTMethod selector put: aTMethod.! ! !CCodeGenerator methodsFor: 'public' stamp: 'ar 2/3/2001 17:55'! addMethodsForPrimitives: classAndSelectorList | sel aClass source verbose meth | classAndSelectorList do: [:classAndSelector | aClass := Smalltalk at: (classAndSelector at: 1). self addAllClassVarsFor: aClass. "TPR - should pool vars also be added here?" "find the method in either the class or the metaclass" sel := classAndSelector at: 2. (aClass includesSelector: sel) ifTrue: [source := aClass sourceCodeAt: sel] ifFalse: [source := aClass class sourceCodeAt: sel]. "compile the method source and convert to a suitable translation method " meth := (Compiler new parse: source in: aClass notifying: nil) asTranslationMethodOfClass: self translationMethodClass. (aClass includesSelector: sel) ifTrue: [meth definingClass: aClass] ifFalse: [meth definingClass: aClass class]. meth primitive > 0 ifTrue:[meth preparePrimitiveName]. "for old-style array accessing: meth covertToZeroBasedArrayReferences." meth replaceSizeMessages. self addMethod: meth]. "method preparation" verbose := false. self prepareMethods. verbose ifTrue: [self printUnboundCallWarnings. self printUnboundVariableReferenceWarnings. Transcript cr]. "code generation" self doInlining: true. methods do:[:m| "if this method is supposed to be a primitive (rather than a helper routine), add assorted prolog and epilog items" m primitive > 0 ifTrue: [m preparePrimitivePrologue]].! ! !CCodeGenerator methodsFor: 'public' stamp: 'ar 7/8/2003 11:16'! addPoolVarsFor: aClass "Add the pool variables for the given class to the code base as constants." | val node | aClass sharedPools do: [:pool | pool bindingsDo: [:assoc | val := assoc value. (useSymbolicConstants and:[self isCLiteral: val]) ifTrue:[node := TDefineNode new setName: assoc key asString value: assoc value] ifFalse:[node := TConstantNode new setValue: assoc value]. constants at: assoc key asString put: node]].! ! !CCodeGenerator methodsFor: 'utilities' stamp: 'dtl 7/2/2008 16:46'! builtin: sel "Answer true if the given selector is one of the builtin selectors." ^ sel = #error: or: [(self memoryAccessSelectors includes: sel) or: [translationDict includesKey: sel]]! ! !CCodeGenerator methodsFor: 'utilities'! cCodeForMethod: selector "Answer a string containing the C code for the given method." "Example: ((CCodeGenerator new initialize addClass: TestCClass1; prepareMethods) cCodeForMethod: #ifTests)" | m s | m := self methodNamed: selector. m = nil ifTrue: [ self error: 'method not found in code base: ', selector ]. s := (ReadWriteStream on: ''). m emitCCodeOn: s generator: self. ^ s contents! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'ar 3/16/2002 15:33'! cFunctionNameFor: aSelector "Create a C function name from the given selector by omitting colons and prefixing with the plugin name if the method is exported." ^aSelector copyWithout: $:! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'ikp 8/3/2004 20:16'! cLiteralFor: anObject "Return a string representing the C literal value for the given object." (anObject isKindOf: Integer) ifTrue: [ (anObject < 16r7FFFFFFF) ifTrue: [^ anObject printString] ifFalse: [^ anObject printString , ObjectMemory unsignedIntegerSuffix "ikp"]]. (anObject isKindOf: String) ifTrue: [^ '"', anObject, '"' ]. (anObject isKindOf: Float) ifTrue: [^ anObject printString ]. anObject == nil ifTrue: [^ 'null' ]. anObject == true ifTrue: [^ '1' ]. "ikp" anObject == false ifTrue: [^ '0' ]. "ikp" (anObject isKindOf: Character) ifTrue:[^anObject asString printString]. "ar" self error: "ikp" 'Warning: A Smalltalk literal could not be translated into a C constant: ', anObject printString. ^'"XXX UNTRANSLATABLE CONSTANT XXX"'! ! !CCodeGenerator methodsFor: 'error notification' stamp: 'tpr 6/11/2003 16:36'! checkClassForNameConflicts: aClass "Verify that the given class does not have constant, variable, or method names that conflict with those of previously added classes. Raise an error if a conflict is found, otherwise just return." "check for constant name collisions" aClass classPool associationsDo: [ :assoc | (constants includesKey: assoc key asString) ifTrue: [ self error: 'Constant was defined in a previously added class: ', assoc key. ]. ]. "ikp..." aClass sharedPools do: [:pool | pool bindingsDo: [ :assoc | (constants includesKey: assoc key asString) ifTrue: [ self error: 'Constant was defined in a previously added class: ', assoc key. ]. ]. ]. "check for instance variable name collisions" aClass instVarNames do: [ :varName | (variables includes: varName) ifTrue: [ self error: 'Instance variable was defined in a previously added class: ', varName. ]. ]. "check for method name collisions" aClass selectors do: [ :sel | (methods includesKey: sel) ifTrue: [ self error: 'Method was defined in a previously added class: ', sel. ]. ].! ! !CCodeGenerator methodsFor: 'utilities'! checkForGlobalUsage: vars in: aTMethod | item | vars do: [:var | "TPR - why the use of globalsAsSet here instead of globalVariables? JMM - globalVariables is not initialized yet, variables is an OrderedCollection, globalsAsSet returns variables as needed set" (self globalsAsSet includes: var) ifTrue: ["find the set of method names using this global var" item := globalVariableUsage at: var ifAbsent: [globalVariableUsage at: var put: Set new]. "add this method name to that set" item add: aTMethod selector]]. aTMethod referencesGlobalStructMakeZero! ! !CCodeGenerator methodsFor: 'public' stamp: 'ikp 9/26/97 14:48'! codeString "Return a string containing all the C code for the code base. Used for testing." | stream | stream := ReadWriteStream on: (String new: 1000). self emitCCodeOn: stream doInlining: true doAssertions: true. ^stream contents! ! !CCodeGenerator methodsFor: 'inlining' stamp: 'dtl 6/7/2008 16:57'! collectInlineList "Make a list of methods that should be inlined." "Details: The method must not include any inline C, since the translator cannot currently map variable names in inlined C code. The #inline: directive may be used to override this for cases in which the C code or declarations are harmless. Methods to be inlined must be small or called from only one place." | methodsNotToInline callsOf inlineIt hasCCode nodeCount senderCount sel | methodsNotToInline := Set new: methods size. "build dictionary to record the number of calls to each method" callsOf := Dictionary new: methods size * 2. methods keys do: [ :s | callsOf at: s put: 0 ]. "For each method, scan its parse tree once to: 1. determine if the method contains C code or declarations 2. determine how many nodes it has 3. increment the sender counts of the methods it calls 4. determine if it includes any C declarations or code" inlineList := Set new: methods size * 2. methods do: [ :m | inlineIt := #dontCare. (translationDict includesKey: m selector) ifTrue: [ hasCCode := true. ] ifFalse: [ hasCCode := m declarations size > 0. nodeCount := 0. m parseTree nodesDo: [ :node | node isSend ifTrue: [ sel := node selector. (sel = #cCode: or: [sel = #cCode:inSmalltalk:]) ifTrue: [ hasCCode := true ]. senderCount := callsOf at: sel ifAbsent: [ nil ]. nil = senderCount ifFalse: [ callsOf at: sel put: senderCount + 1. ]. ]. nodeCount := nodeCount + 1. ]. inlineIt := m extractInlineDirective. "may be true, false, or #dontCare" ]. (inlineIt ~= true and: [hasCCode or: [inlineIt = false]]) ifTrue: [ "Don't inline if method has C code or if it contains a negative inline directive. If it contains a positive inline directive, permit inlining even if C code is present." methodsNotToInline add: m selector. ] ifFalse: [ ((nodeCount < 40) or: [inlineIt = true]) ifTrue: [ "inline if method has no C code and is either small or contains inline directive" inlineList add: m selector. ]. ]. ]. callsOf associationsDo: [ :assoc | ((assoc value = 1) and: [(methodsNotToInline includes: assoc key) not]) ifTrue: [ inlineList add: assoc key. ]. ].! ! !CCodeGenerator methodsFor: 'accessing' stamp: 'eem 7/2/2008 16:01'! currentMethod ^currentMethod! ! !CCodeGenerator methodsFor: 'accessing' stamp: 'eem 7/2/2008 16:01'! currentMethod: aTMethod currentMethod := aTMethod! ! !CCodeGenerator methodsFor: 'public' stamp: 'ar 3/16/2002 18:00'! declareModuleName: nameString "add the declaration of a module name, version and local/external tag" self var: #moduleName declareC:'const char *moduleName = #ifdef SQUEAK_BUILTIN_PLUGIN "', nameString,' (i)" #else "', nameString,' (e)" #endif '.! ! !CCodeGenerator methodsFor: 'inlining' stamp: 'qwaq 5/21/2010 12:17'! doBasicInlining: inlineFlag "Inline the bodies of all methods that are suitable for inlining. This method does only the basic inlining suitable for both the core VM and plugins - no bytecode inlining etc" | pass progress | self collectInlineList. pass := 0. progress := true. [progress] whileTrue: [ "repeatedly attempt to inline methods until no further progress is made" progress := false. ('Inlining pass ', (pass := pass + 1) printString, '...') displayProgressAt: Sensor cursorPoint from: 0 to: methods size during: [:bar | (self sortMethods: methods) doWithIndex: [:m :i | bar value: i. currentMethod := m. (m tryToInlineMethodsIn: self) ifTrue: [progress := true]]]]. ! ! !CCodeGenerator methodsFor: 'inlining' stamp: 'dtl 9/8/2008 23:48'! doInlining: inlineFlag "Inline the bodies of all methods that are suitable for inlining." "Modified slightly for the core VM translator, since the first level of inlining for the interpret loop must be performed in order that the instruction implementations can easily discover their addresses. Remember to inline the bytecode routines as well" inlineFlag ifFalse: [ self inlineDispatchesInMethodNamed: #interpret localizingVars: #(). ^ self]. self doBasicInlining: inlineFlag. self inlineCaseStatementBranchesInMethodNamed: #interpret localizingVars: #(). 'Inlining bytecodes' displayProgressAt: Sensor cursorPoint from: 1 to: 2 during: [:bar | self inlineDispatchesInMethodNamed: #interpret localizingVars: #(currentBytecode localIP localSP localHomeContext localReturnContext localReturnValue). bar value: 1. self removeMethodsReferingToGlobals: #( currentBytecode localIP localSP localHomeContext) except: #(interpret). bar value: 2]. "make receiver on the next line false to generate code for all methods, even those that are inlined or unused" true ifTrue: [ (methods includesKey: #interpret) ifTrue: [ "only prune when generating the interpreter itself" self pruneUnreachableMethods]]. ! ! !CCodeGenerator methodsFor: 'utilities' stamp: ' 2/7/08 14:57'! emitBuiltinConstructAsArgumentFor: msgNode on: aStream level: level "If the given selector is in the translation dictionary, translate it into a target code construct and return true. Otherwise, do nothing and return false." | action | action := asArgumentTranslationDict at: msgNode selector ifAbsent: [translationDict at: msgNode selector ifAbsent: [ ^false ]]. self perform: action with: msgNode with: aStream with: level. ^true! ! !CCodeGenerator methodsFor: 'utilities'! emitBuiltinConstructFor: msgNode on: aStream level: level "If the given selector is in the translation dictionary, translate it into a target code construct and return true. Otherwise, do nothing and return false." | action | action := translationDict at: msgNode selector ifAbsent: [ ^false ]. self perform: action with: msgNode with: aStream with: level. ^true! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'dtl 1/28/2007 13:52'! emitCCodeOn: aStream doAssertions: assertionFlag "Emit C code for all methods in the code base onto the given stream. All inlined method calls should already have been expanded." self emitCHeaderOn: aStream. self emitCConstantsOn: aStream. self emitCFunctionPrototypes: preparedMethodList on: aStream. self emitCVariablesOn: aStream. 'Writing Translated Code...' displayProgressAt: Sensor cursorPoint from: 0 to: methods size during: [:bar | preparedMethodList doWithIndex: [ :m :i | bar value: i. m emitCCodeOn: aStream generator: self. ]]. self emitExportsOn: aStream. ! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'dtl 1/28/2007 14:10'! emitCCodeOn: aStream doInlining: inlineFlag doAssertions: assertionFlag "Emit C code for all methods in the code base onto the given stream. All inlined method calls should already have been expanded." self prepareMethodsInlined: inlineFlag doAssertions: assertionFlag. ^ self emitCCodeOn: aStream doAssertions: assertionFlag ! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'jmv 10/26/2009 08:54'! emitCConstantsOn: aStream "Store the global variable declarations on the given stream." | unused constList node | unused := constants keys asSet. methods do: [ :meth | meth parseTree nodesDo: [ :n | n isConstant ifTrue: [ unused remove: n name ifAbsent: []]]]. constList := constants keys reject: [ :any | unused includes: any]. aStream nextPutAll: '/*** Constants ***/'; cr. constList asSortedCollection do: [ :varName | node := constants at: varName. node name isEmpty ifFalse: [ aStream nextPutAll: '#define '. aStream nextPutAll: node name. aStream space. aStream nextPutAll: (self cLiteralFor: node value). aStream cr ]. ]. aStream cr.! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'dtl 11/9/2006 06:22'! emitCExpression: aParseNode on: aStream "Emit C code for the expression described by the given parse node." aParseNode isLeaf ifTrue: [ "omit parens" aParseNode asExpression emitCCodeOn: aStream level: 0 generator: self. ] ifFalse: [ aStream nextPut: $(. aParseNode asExpression emitCCodeOn: aStream level: 0 generator: self. aStream nextPut: $). ].! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'tpr 3/7/2003 19:55'! emitCFunctionPrototypes: methodList on: aStream "Store prototype declarations for all non-inlined methods on the given stream." | exporting | aStream nextPutAll: '/*** Function Prototypes ***/'; cr. exporting := false. methodList do: [:m | m export ifTrue: [exporting ifFalse: [aStream nextPutAll: '#pragma export on'; cr. exporting := true]] ifFalse: [exporting ifTrue: [aStream nextPutAll: '#pragma export off'; cr. exporting := false]]. m emitCFunctionPrototype: aStream generator: self. aStream nextPutAll: ';'; cr]. exporting ifTrue: [aStream nextPutAll: '#pragma export off'; cr]! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'dtl 12/20/2009 23:39'! emitCHeaderForPrimitivesOn: aStream "Write a C file header for compiled primitives onto the given stream." aStream nextPutAll: '/* Automatically generated from Squeak ('; nextPutAll: VMMaker versionString; nextPutAll: ') on '. Time dateAndTimeNow do: [:e | aStream nextPutAll: e asString; nextPut: Character space]. aStream nextPutAll: '*/'; cr; cr; nextPutAll: '#include "sq.h"'; cr; cr. "Additional header files" headerFiles do:[:hdr| aStream nextPutAll:'#include '; nextPutAll: hdr; cr]. aStream nextPutAll: ' #include "sqMemoryAccess.h" /*** Imported Functions/Variables ***/ extern sqInt stackValue(sqInt); extern sqInt stackIntegerValue(sqInt); extern sqInt successFlag; /* allows accessing Strings in both C and Smalltalk */ #define asciiValue(c) c '. aStream cr.! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'dtl 4/6/2010 00:14'! emitCHeaderOn: aStream "Write a C file header onto the given stream." aStream nextPutAll: '/* '. aStream nextPutAll: VMMaker headerNotice. aStream nextPutAll: ' */'; cr. self emitGlobalStructFlagOn: aStream. aStream nextPutAll: '#include "sq.h"'; cr. "Additional header files" headerFiles do:[:hdr| aStream nextPutAll:'#include '; nextPutAll: hdr; cr]. "Default definitions for optional functions, provided for backward compatibility" self emitDefaultMacrosOn: aStream. aStream nextPutAll: ' #include "sqMemoryAccess.h" sqInt printCallStack(void); void defaultErrorProc(char *s) { /* Print an error message and exit. */ static sqInt printingStack = false; printf("\n%s\n\n", s); if (!!printingStack) { /* flag prevents recursive error when trying to print a broken stack */ printingStack = true; printCallStack(); } exit(-1); } '. aStream cr.! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'dtl 11/9/2006 06:42'! emitCTestBlock: aBlockNode on: aStream "Emit C code for the given block node to be used as a loop test." aBlockNode statements size > 1 ifTrue: [ aBlockNode emitCCodeOn: aStream level: 0 generator: self. ] ifFalse: [ aBlockNode statements first asExpression emitCCodeOn: aStream level: 0 generator: self. ].! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'tpr 4/12/2006 11:40'! emitCVariablesOn: aStream "Store the global variable declarations on the given stream." | varString | aStream nextPutAll: '/*** Variables ***/'; cr. variables asSortedCollection do: [:var | varString := var asString. self isGeneratingPluginCode ifTrue: [varString = 'interpreterProxy' ifTrue: ["quite special..." aStream cr; nextPutAll: '#ifdef SQUEAK_BUILTIN_PLUGIN'. aStream cr; nextPutAll: 'extern'. aStream cr; nextPutAll: '#endif'; cr] ifFalse: [aStream nextPutAll: 'static ']]. (variableDeclarations includesKey: varString) ifTrue: [aStream nextPutAll: (variableDeclarations at: varString) , ';'; cr] ifFalse: ["default variable declaration" aStream nextPutAll: 'sqInt ' , varString , ';'; cr]]. aStream cr! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'dtl 4/6/2010 00:13'! emitDefaultMacrosOn: aStream "Emit macros to provide default implementations of certain functions used by the interpreter. If not previously defined in config.h they will be defined here. The definitions will be available to any module that includes sqMemoryAccess.h. The default macros are chosen for backward compatibility with existing platform support code." aStream cr; nextPutAll: '#ifndef allocateMemoryMinimumImageFileHeaderSize'; cr; nextPutAll: ' /* Called by Interpreter>>allocateMemory:minimum:imageFile:headerSize: */'; cr; nextPutAll: ' /* Default definition if not previously defined in config.h */'; cr; nextPutAll: ' #define allocateMemoryMinimumImageFileHeaderSize(', 'heapSize, minimumMemory, fileStream, headerSize) \'; cr; nextPutAll: ' sqAllocateMemory(minimumMemory, heapSize)'; cr; nextPutAll: '#endif'; cr; cr; nextPutAll: '#ifndef sqImageFileReadEntireImage'; cr; nextPutAll: ' /* Called by Interpreter>>sqImage:read:size:length: */'; cr; nextPutAll: ' /* Default definition if not previously defined in config.h */'; cr; nextPutAll: ' #define sqImageFileReadEntireImage(memoryAddress, ', 'elementSize, length, fileStream) \'; cr; nextPutAll: ' sqImageFileRead(memoryAddress, elementSize, length, fileStream)'; cr; nextPutAll: '#endif'; cr; cr; nextPutAll: '#ifndef error'; cr; nextPutAll: ' /* error() function called from Interpreter */'; cr; nextPutAll: ' /* Default definition if not previously defined in config.h */'; cr; nextPutAll: ' #define error(str) defaultErrorProc(str)'; cr; nextPutAll: '#endif'; cr; cr; nextPutAll: '#ifndef ioMicroSecondClock'; cr; nextPutAll: ' /* Called by Interpreter>>primitiveMicrosecondClock and GC methods */'; cr; nextPutAll: ' /* Default definition if not previously defined in config.h */'; cr; nextPutAll: ' #define ioMicroSecondClock ioMSecs'; cr; nextPutAll: '#endif'; cr; cr; nextPutAll: '#ifndef ioUtcWithOffset'; cr; nextPutAll: ' /* Called by Interpreter>>primitiveUtcWithOffset */'; cr; nextPutAll: ' /* Default definition if not previously defined in config.h */'; cr; nextPutAll: ' #define ioUtcWithOffset(clock, offset) setMicroSecondsandOffset(clock, offset)'; cr; nextPutAll: '#endif'; cr. self flag: #setMicroSeconds:andOffset: "referenced by these macros" ! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'dtl 5/27/2010 21:40'! emitDefineBytesPerWordOn: aStream "Define word size dependent constants. These are mirrored by class variables in ObjectMemory. The macro definitions here are used at compile time to permit building a VM for either 32-bit or 64-bit object memory from a single generated code base. If SQ_VI_BYTES_PER_WORD is defined as 8 (e.g. in config.h), then a VM for 64-bit image will be built. Otherwise, a VM for 32-bit image is built." aStream cr; nextPutAll: '/*'; cr; nextPutAll: ' * define SQ_VI_BYTES_PER_WORD 8 for a 64-bit word size VM'; cr; nextPutAll: ' * and default to SQ_VI_BYTES_PER_WORD 4 for a 32-bit word size VM'; cr; nextPutAll: ' */'; cr; nextPutAll: '#ifndef SQ_VI_BYTES_PER_WORD'; cr; nextPutAll: '# define SQ_VI_BYTES_PER_WORD '; print: 4; cr; "default to word size 4" nextPutAll: '#endif'; cr; cr; nextPutAll: '#define BYTES_PER_WORD SQ_VI_BYTES_PER_WORD'; cr; nextPutAll: '#define BASE_HEADER_SIZE SQ_VI_BYTES_PER_WORD'; cr; "Define various constants that depend on BytesPerWord" nextPutAll: '#if (BYTES_PER_WORD == 4) // 32-bit object memory'; cr; nextPutAll: '# define WORD_MASK 0xffffffff'; cr; "(1 bitShift: BytesPerWord*8) - 1" nextPutAll: '# define SHIFT_FOR_WORD 2'; cr; "(BytesPerWord log: 2) rounded" nextPutAll: '# define SMALL_CONTEXT_SIZE 92'; cr; "ContextFixedSizePlusHeader + 16 * BytesPerWord" "Large contexts have 56 indexable fileds. Max with single header word." "However note that in 64 bits, for now, large contexts have 3-word headers" nextPutAll: '# define LARGE_CONTEXT_SIZE 252'; cr; "ContextFixedSizePlusHeader + 56 * BytesPerWord." nextPutAll: '# define SIZE_MASK 0xfc'; cr; "Base header word bit field" nextPutAll: '# define LONG_SIZE_MASK 0xfffffffc'; cr; "Base header word bit field" nextPutAll: '# define SIZE_4_BIT 0'; cr; nextPutAll: '# define MARK_BIT 0x80000000'; cr; "Top bit, 1 bitShift: BytesPerWord*8 - 1" nextPutAll: '# define ROOT_BIT 0x40000000'; cr; "Next-to-top bit, 1 bitShift: BytesPerWord*8 - 2" nextPutAll: '# define ALL_BUT_MARK_BIT 0x7fffffff'; cr; "WordMask - MarkBit." nextPutAll: '# define ALL_BUT_ROOT_BIT 0xbfffffff'; cr; "WordMask - RootBit" nextPutAll: '# define ALL_BUT_TYPE_MASK 0xfffffffc'; cr; "WordMask - TypeMask" nextPutAll: '# define ALL_BUT_MARK_BIT_AND_TYPE_MASK 0x7ffffffc'; cr; "AllButTypeMask - MarkBit" nextPutAll: '# define ALL_BUT_HASH_BITS 0xe001ffff'; cr; nextPutAll: '#else // 64-bit object memory'; cr; nextPutAll: '# define WORD_MASK 0xffffffffffffffff'; cr; nextPutAll: '# define SHIFT_FOR_WORD 3'; cr; nextPutAll: '# define SMALL_CONTEXT_SIZE 184'; cr; nextPutAll: '# define LARGE_CONTEXT_SIZE 504'; cr; nextPutAll: '# define SIZE_MASK 0xf8'; cr; "Lose the 4 bit in temp 64-bit chunk format" nextPutAll: '# define LONG_SIZE_MASK 0xfffffffffffffff8'; cr; "The 4 bit is excluded from SIZE_MASK for 64-bit object memory, but need it" "for ST size, so define SIZE_4_BIT." nextPutAll: '# define SIZE_4_BIT 4'; cr; nextPutAll: '# define MARK_BIT 0x8000000000000000'; cr; nextPutAll: '# define ROOT_BIT 0x4000000000000000'; cr; nextPutAll: '# define ALL_BUT_MARK_BIT 0x7fffffffffffffff'; cr; nextPutAll: '# define ALL_BUT_ROOT_BIT 0xbfffffffffffffff'; cr; nextPutAll: '# define ALL_BUT_TYPE_MASK 0xfffffffffffffffc'; cr; nextPutAll: '# define ALL_BUT_MARK_BIT_AND_TYPE_MASK 0x7ffffffffffffffc'; cr; nextPutAll: '# define ALL_BUT_HASH_BITS 0xffffffffe001ffff'; cr; nextPutAll: '#endif // (BYTES_PER_WORD == 4)'; cr ! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'dtl 4/6/2010 00:15'! emitDefineMemoryAccessInImageOn: aStream "If MemoryAccess is present in the image, then define MEMORY_ACCESS_IN_IMAGE as a C preprocessor macro. When MEMORY_ACCESS_IN_IMAGE is defined, the traditional C preprocessor macros for low level memory access are ignored and will be replaced by directly translated (and inlined) SLANG versions of the same. This enables visibility of the memory access functions for debuggers and profilers." (Smalltalk classNamed: #MemoryAccess) ifNotNilDo: [:ma | ma isEnabled ifTrue: [aStream nextPutAll: '#define MEMORY_ACCESS_IN_IMAGE 1'; cr]]! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'tpr 1/10/2003 16:17'! emitExportsOn: aStream "Store all the exported primitives in a form to be used by the internal named prim system" aStream nextPutAll:' void* vm_exports[][3] = {'. self exportedPrimitiveNames do:[:primName| aStream cr; nextPutAll:' {"", "'; nextPutAll: primName; nextPutAll:'", (void*)'; nextPutAll: primName; nextPutAll:'},'. ]. aStream nextPutAll:' {NULL, NULL, NULL} }; '.! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'ikp 9/10/2003 05:53'! emitGlobalStructFlagOn: aStream "Default: do nothing. Overridden in CCGenGlobalStruct." ! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'dtl 4/6/2010 00:16'! emitVmmVersionOn: aStream "Emit a version string macro suitable for identifying source code version of this interpreter. This is expected to be used in conjunction with a similar identifier for platform source code version, such the the VM can identify the source code version for its platform source and matching VMMaker source." aStream nextPutAll: '#define VMMAKER_VERSION "'; nextPutAll: VMMaker versionString; nextPut: $"; cr ! ! !CCodeGenerator methodsFor: 'public' stamp: 'dtl 2/5/2007 07:45'! exportedPrimitiveNames "Return an array of all exported primitives" ^methods select:[:m| m export] thenCollect:[:m| m selectorForCodeGeneration copyWithout: $:]. ! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 10/5/2009 13:48'! generateAddressOf: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPut: $(; nextPut: $&. self emitCExpression: msgNode args first on: aStream. aStream nextPut: $)! ! !CCodeGenerator methodsFor: 'C translation'! generateAnd: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' && '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'ar 10/3/1998 13:45'! generateAsFloat: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll:'((double) '. self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' )'.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 2/15/2009 16:38'! generateAsInteger: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll:'((sqInt)'. self emitCExpression: msgNode receiver on: aStream. aStream nextPut: $)! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 1/3/2009 10:22'! generateAsSymbol: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream. The receiver is expected to be a TConstantNode." aStream nextPutAll: (self cFunctionNameFor: msgNode receiver nameOrValue)! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 2/15/2009 16:38'! generateAsUnsignedInteger: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll:'((usqInt)'. self emitCExpression: msgNode receiver on: aStream. aStream nextPut: $)! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 6/24/2010 09:33'! generateAt: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPut: $[. msgNode args first emitCCodeAsExpressionOn: aStream level: level + 1 generator: self. aStream nextPut: $]! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 6/24/2010 09:33'! generateAtPut: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPut: $[. msgNode args first emitCCodeAsExpressionOn: aStream level: level + 1 generator: self. aStream nextPutAll: '] = '. self emitCExpression: msgNode args last on: aStream! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 5/18/2010 21:38'! generateBaseHeaderSize: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: 'BASE_HEADER_SIZE' ! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 7/8/2008 20:21'! generateBetweenAnd: msgNode on: aStream indent: level "Generate the C code for the between:and: message onto the given stream." aStream nextPutAll: '(('. self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' >= '. self emitCExpression: msgNode args first on: aStream. aStream nextPutAll: ') && ('. self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' <= '. self emitCExpression: msgNode args second on: aStream. aStream nextPutAll: '))'! ! !CCodeGenerator methodsFor: 'C translation'! generateBitAnd: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' & '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 7/16/2009 13:46'! generateBitInvert32: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPut: $~. self emitCExpression: msgNode receiver on: aStream! ! !CCodeGenerator methodsFor: 'C translation'! generateBitOr: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' | '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'ikp 8/4/2004 16:29'! generateBitShift: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." | arg rcvr | arg := msgNode args first. rcvr := msgNode receiver. arg isConstant ifTrue: [ "bit shift amount is a constant" aStream nextPutAll: '((usqInt) '. self emitCExpression: rcvr on: aStream. arg value < 0 ifTrue: [ aStream nextPutAll: ' >> ', arg value negated printString. ] ifFalse: [ aStream nextPutAll: ' << ', arg value printString. ]. aStream nextPutAll: ')'. ] ifFalse: [ "bit shift amount is an expression" aStream nextPutAll: '(('. self emitCExpression: arg on: aStream. aStream nextPutAll: ' < 0) ? ((usqInt) '. self emitCExpression: rcvr on: aStream. aStream nextPutAll: ' >> -'. self emitCExpression: arg on: aStream. aStream nextPutAll: ') : ((usqInt) '. self emitCExpression: rcvr on: aStream. aStream nextPutAll: ' << '. self emitCExpression: arg on: aStream. aStream nextPutAll: '))'. ].! ! !CCodeGenerator methodsFor: 'C translation'! generateBitXor: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' ^ '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 5/18/2010 21:33'! generateBytesPerWord: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: 'BYTES_PER_WORD' ! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 2/11/2009 13:53'! generateCCoercion: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '(('. aStream nextPutAll: msgNode args last value. aStream nextPutAll: ') '. self emitCExpression: msgNode args first on: aStream. aStream nextPut: $) ! ! !CCodeGenerator methodsFor: 'accessing' stamp: 'ar 7/8/2003 11:26'! generateDeadCode "Answer whether we should generate 'dead code' branches. This can be useful for hacking the VM when used in conjunction with #useSymbolicConstants, e.g., for code like: DoAssertionChecks ifTrue:[ ... ]. we will generate #define DoAssertionChecks 0 ... if(DoAssertionChecks) { ... }. allowing us to change the #define (or redefine it as a variable) for later use." ^generateDeadCode! ! !CCodeGenerator methodsFor: 'accessing' stamp: 'ar 7/8/2003 11:26'! generateDeadCode: aBool "Indicate whether we should generate 'dead code' branches." generateDeadCode := aBool! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'ikp 6/9/2004 16:14'! generateDivide: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." | rcvr arg divisor | rcvr := msgNode receiver. arg := msgNode args first. (arg isConstant and: [UseRightShiftForDivide and: [(divisor := arg value) isInteger and: [divisor isPowerOfTwo and: [divisor > 0 and: [divisor <= (1 bitShift: 31)]]]]]) ifTrue: [ "use signed (arithmetic) right shift instead of divide" aStream nextPutAll: '((sqInt) '. self emitCExpression: rcvr on: aStream. aStream nextPutAll: ' >> ', (divisor log: 2) asInteger printString. aStream nextPutAll: ')'. ] ifFalse: [ self emitCExpression: rcvr on: aStream. aStream nextPutAll: ' / '. self emitCExpression: arg on: aStream]. ! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 11/9/2006 06:24'! generateDoWhileFalse: msgNode on: aStream indent: level "Generate do {stmtList} while(!!(cond))" | stmts testStmt | stmts := msgNode receiver statements asOrderedCollection. testStmt := stmts removeLast. msgNode receiver setStatements: stmts. aStream nextPutAll: 'do {'; cr. msgNode receiver emitCCodeOn: aStream level: level + 1 generator: self. level timesRepeat: [ aStream tab ]. aStream nextPutAll: '} while(!!('. testStmt asExpression emitCCodeOn: aStream level: 0 generator: self. aStream nextPutAll: '))'.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 11/9/2006 06:24'! generateDoWhileTrue: msgNode on: aStream indent: level "Generate do {stmtList} while(cond)" | stmts testStmt | stmts := msgNode receiver statements asOrderedCollection. testStmt := stmts removeLast. msgNode receiver setStatements: stmts. aStream nextPutAll: 'do {'; cr. msgNode receiver emitCCodeOn: aStream level: level + 1 generator: self. level timesRepeat: [ aStream tab ]. aStream nextPutAll: '} while('. testStmt asExpression emitCCodeOn: aStream level: 0 generator: self. aStream nextPutAll: ')'.! ! !CCodeGenerator methodsFor: 'C translation'! generateEqual: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' == '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation'! generateGreaterThan: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' > '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation'! generateGreaterThanOrEqual: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' >= '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation' stamp: ' 2/7/08 14:57'! generateIfFalse: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." (self nilOrBooleanConstantReceiverOf: msgNode) ifNil: [aStream nextPutAll: 'if (!!('. msgNode receiver emitCCodeAsExpressionOn: aStream level: level + 1 generator: self. aStream nextPutAll: ')) {'; cr. msgNode args last emitCCodeOn: aStream level: level + 1 generator: self. level timesRepeat: [aStream tab]. aStream nextPut: $}] ifNotNil: [:const | const ifFalse: [msgNode args first emitCCodeOn: aStream level: level generator: self]]! ! !CCodeGenerator methodsFor: 'C translation' stamp: ' 2/7/08 14:57'! generateIfFalseAsArgument: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." (self nilOrBooleanConstantReceiverOf: msgNode) ifNil: [aStream nextPutAll: '(!!('. msgNode receiver emitCCodeAsArgumentOn: aStream level: 0 generator: self. aStream nextPut: $); crtab: level + 1; nextPut: $?; space. msgNode args last emitCCodeAsArgumentOn: aStream level: level + 2 generator: self. aStream crtab: level + 1; nextPutAll: ': 0)'] ifNotNil: [:const| const ifFalse: [msgNode args first emitCCodeAsArgumentOn: aStream level: level generator: self]]! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 10/24/2010 16:15'! generateIfFalseIfTrue: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." (self nilOrBooleanConstantReceiverOf: msgNode) ifNil: [aStream nextPutAll: 'if ('. msgNode receiver emitCCodeAsExpressionOn: aStream level: level generator: self. aStream nextPutAll: ') {'; cr. msgNode args last emitCCodeOn: aStream level: level + 1 generator: self. aStream tab: level; nextPut: $}; nextPutAll: ' else {'; cr. msgNode args first emitCCodeOn: aStream level: level + 1 generator: self. aStream tab: level; nextPut: $}] ifNotNil: [:const | (const ifTrue: [msgNode args last] ifFalse: [msgNode args first]) emitCCodeOn: aStream level: level generator: self]! ! !CCodeGenerator methodsFor: 'C translation' stamp: ' 2/7/08 14:57'! generateIfFalseIfTrueAsArgument: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." (self nilOrBooleanConstantReceiverOf: msgNode) ifNil: [aStream nextPut: $(. msgNode receiver emitCCodeAsArgumentOn: aStream level: level generator: self. aStream crtab: level + 1; nextPut: $?; space. msgNode args last emitCCodeAsArgumentOn: aStream level: level + 2 generator: self. aStream crtab: level + 1; nextPut: $:; space. msgNode args first emitCCodeAsArgumentOn: aStream level: level + 2 generator: self. aStream nextPut: $)] ifNotNil: [:const| (const ifTrue: [msgNode args last] ifFalse: [msgNode args first]) emitCCodeAsArgumentOn: aStream level: level generator: self]! ! !CCodeGenerator methodsFor: 'C translation' stamp: ' 2/7/08 14:57'! generateIfTrue: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." (self nilOrBooleanConstantReceiverOf: msgNode) ifNil: [aStream nextPutAll: 'if ('. msgNode receiver emitCCodeAsExpressionOn: aStream level: level generator: self. aStream nextPutAll: ') {'; cr. msgNode args first emitCCodeOn: aStream level: level + 1 generator: self. level timesRepeat: [ aStream tab ]. aStream nextPut: $}] ifNotNil: [:const | const ifTrue: [msgNode args first emitCCodeOn: aStream level: level generator: self]]! ! !CCodeGenerator methodsFor: 'C translation' stamp: ' 2/7/08 14:57'! generateIfTrueAsArgument: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." (self nilOrBooleanConstantReceiverOf: msgNode) ifNil: [aStream nextPut: $(. msgNode receiver emitCCodeAsArgumentOn: aStream level: level generator: self. aStream crtab: level + 1; nextPut: $?; space. msgNode args first emitCCodeAsArgumentOn: aStream level: level + 2 generator: self. aStream crtab: level + 1; nextPutAll: ': 0)'] ifNotNil: [:const| const ifTrue: [msgNode args first emitCCodeAsArgumentOn: aStream level: level generator: self]]! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 10/24/2010 16:14'! generateIfTrueIfFalse: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." (self nilOrBooleanConstantReceiverOf: msgNode) ifNil: [aStream nextPutAll: 'if ('. msgNode receiver emitCCodeAsExpressionOn: aStream level: level generator: self. aStream nextPutAll: ') {'; cr. msgNode args first emitCCodeOn: aStream level: level + 1 generator: self. aStream tab: level; nextPut: $}; nextPutAll: ' else {'; cr. msgNode args last emitCCodeOn: aStream level: level + 1 generator: self. aStream tab: level; nextPut: $}] ifNotNil: [:const | (const ifTrue: [msgNode args first] ifFalse: [msgNode args last]) emitCCodeOn: aStream level: level generator: self]! ! !CCodeGenerator methodsFor: 'C translation' stamp: ' 2/7/08 14:57'! generateIfTrueIfFalseAsArgument: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." (self nilOrBooleanConstantReceiverOf: msgNode) ifNil: [aStream nextPut: $(. msgNode receiver emitCCodeAsArgumentOn: aStream level: level generator: self. aStream crtab: level + 1; nextPut: $?; space. msgNode args first emitCCodeAsArgumentOn: aStream level: level + 2 generator: self. aStream crtab: level + 1; nextPut: $:; space. msgNode args last emitCCodeAsArgumentOn: aStream level: level + 2 generator: self. aStream nextPut: $)] ifNotNil: [:const| (const ifTrue: [msgNode args first] ifFalse: [msgNode args last]) emitCCodeAsArgumentOn: aStream level: level generator: self]! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 9/16/2009 18:06'! generateInlineCCode: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream. There are two forms, self cCode: aString ... and self cCode: aBlock." msgNode args first isConstant ifTrue: [aStream nextPutAll: msgNode args first value] ifFalse: [msgNode args first emitCCodeOn: aStream level: level generator: self]! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 12/14/2009 21:16'! generateInlineCCodeAsArgument: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream. There are two forms, self cCode: aString ... and self cCode: aBlock." msgNode args first isConstant ifTrue: [aStream nextPutAll: msgNode args first value] ifFalse: [msgNode args first emitCCodeAsArgumentOn: aStream level: level generator: self]! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 2/24/2009 14:54'! generateInlineCPreprocessorDirective: msgNode on: aStream indent: level "Generate the C preprocessor directive for this message onto the given stream." aStream cr; nextPutAll: msgNode args first value! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 11/9/2006 19:47'! generateInlineCppDirective: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream cr; nextPutAll: '# ', msgNode args first value.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 11/12/2006 17:30'! generateInlineCppIfDef: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." | comment | aStream cr; nextPutAll: '# ifdef ', msgNode args first value. comment := msgNode args third value. (comment isKindOf: String) ifTrue: [aStream nextPutAll: ' // ', comment] ifFalse: ["nil argument, ignore it"]. aStream cr. msgNode isExpression ifTrue: [aStream tab: level + 1; nextPut: $(. msgNode args fourth asExpression emitCCodeOn: aStream level: level + 1 generator: self. aStream nextPut: $); cr] ifFalse: [msgNode args fourth emitCCodeOn: aStream level: level generator: self]. aStream nextPutAll: '# endif // ', msgNode args first value; cr; tab: level! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 11/12/2006 17:30'! generateInlineCppIfDefElse: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." | comment alternateBlock alternateBlockIsNil | aStream cr; nextPutAll: '# ifdef ', msgNode args first value. comment := msgNode args third value. (comment isKindOf: String) ifTrue: [aStream nextPutAll: ' // ', comment] ifFalse: ["nil argument, ignore it"]. aStream cr. msgNode isExpression ifTrue: [aStream tab: level + 1; nextPut: $(. msgNode args fourth asExpression emitCCodeOn: aStream level: level + 1 generator: self. aStream nextPut: $); cr] ifFalse: [msgNode args fourth emitCCodeOn: aStream level: level generator: self]. alternateBlock := msgNode args fifth. alternateBlockIsNil := true. "check for nil #else clause" alternateBlock nodesDo: [:n | (n ~= alternateBlock and: [n name ~= 'nil']) ifTrue: [alternateBlockIsNil := false ]]. (alternateBlockIsNil) ifFalse: [aStream nextPutAll: '# else'; cr. msgNode isExpression ifTrue: [aStream tab: level + 1; nextPut: $(. alternateBlock asExpression emitCCodeOn: aStream level: level + 1 generator: self. aStream nextPut: $); cr] ifFalse: [alternateBlock emitCCodeOn: aStream level: level generator: self]]. aStream nextPutAll: '# endif // ', msgNode args first value; cr; tab: level ! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 5/17/2010 15:18'! generateInlineCppIfElse: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." | comment alternateBlock alternateBlockIsNil | aStream cr; nextPutAll: '# if (', msgNode args first value, ')'. comment := msgNode args third value. (comment isKindOf: String) ifTrue: [aStream nextPutAll: ' // ', comment] ifFalse: ["nil argument, ignore it"]. aStream cr. msgNode isExpression ifTrue: [aStream tab: level + 1; nextPut: $(. msgNode args fourth asExpression emitCCodeOn: aStream level: level + 1 generator: self. aStream nextPut: $); cr] ifFalse: [msgNode args fourth emitCCodeOn: aStream level: level generator: self]. alternateBlock := msgNode args fifth. alternateBlockIsNil := true. "check for nil #else clause" alternateBlock nodesDo: [:n | (n ~= alternateBlock and: [n name ~= 'nil']) ifTrue: [alternateBlockIsNil := false ]]. (alternateBlockIsNil) ifFalse: [aStream nextPutAll: '# else'; cr. msgNode isExpression ifTrue: [aStream tab: level + 1; nextPut: $(. alternateBlock asExpression emitCCodeOn: aStream level: level + 1 generator: self. aStream nextPut: $); cr] ifFalse: [alternateBlock emitCCodeOn: aStream level: level generator: self]]. aStream nextPutAll: '# endif // ', msgNode args first value; cr; tab: level ! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 9/25/2010 10:13'! generateInlineDirective: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '/* inline: '. aStream nextPutAll: msgNode args first value asString. aStream nextPutAll: ' */'. ! ! !CCodeGenerator methodsFor: 'C translation'! generateIntegerObjectOf: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '(('. self emitCExpression: msgNode args first on: aStream. aStream nextPutAll: ' << 1) | 1)'.! ! !CCodeGenerator methodsFor: 'C translation'! generateIntegerValueOf: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '('. self emitCExpression: msgNode args first on: aStream. aStream nextPutAll: ' >> 1)'.! ! !CCodeGenerator methodsFor: 'C translation'! generateIsIntegerObject: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '('. self emitCExpression: msgNode args first on: aStream. aStream nextPutAll: ' & 1)'.! ! !CCodeGenerator methodsFor: 'C translation'! generateIsNil: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' == '. aStream nextPutAll: (self cLiteralFor: nil).! ! !CCodeGenerator methodsFor: 'C translation'! generateLessThan: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' < '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation'! generateLessThanOrEqual: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' <= '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation'! generateMax: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '(('. self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' < '. self emitCExpression: msgNode args first on: aStream. aStream nextPutAll: ') ? '. self emitCExpression: msgNode args first on: aStream. aStream nextPutAll: ' : '. self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ')'.! ! !CCodeGenerator methodsFor: 'C translation'! generateMin: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '(('. self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' < '. self emitCExpression: msgNode args first on: aStream. aStream nextPutAll: ') ? '. self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' : '. self emitCExpression: msgNode args first on: aStream. aStream nextPutAll: ')'.! ! !CCodeGenerator methodsFor: 'C translation'! generateMinus: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' - '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation'! generateModulo: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' % '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 7/8/2008 17:47'! generateNegated: msgNode on: aStream indent: level "Generate the C code for teh negated message onto the given stream." aStream nextPut: $-. self emitCExpression: msgNode receiver on: aStream! ! !CCodeGenerator methodsFor: 'C translation'! generateNot: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '!!'. self emitCExpression: msgNode receiver on: aStream.! ! !CCodeGenerator methodsFor: 'C translation'! generateNotEqual: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' !!= '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation'! generateNotNil: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' !!= '. aStream nextPutAll: (self cLiteralFor: nil).! ! !CCodeGenerator methodsFor: 'C translation'! generateOr: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' || '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 1/18/2009 23:34'! generatePerform: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode args first on: aStream. aStream nextPut: $(. (msgNode args copyFrom: 2 to: msgNode args size) do:[:arg| self emitCExpression: arg on: aStream. ] separatedBy:[aStream nextPutAll:', ']. aStream nextPut: $)! ! !CCodeGenerator methodsFor: 'C translation'! generatePlus: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' + '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'ATG 4/8/2004 15:03'! generatePreDecrement: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." | varNode | varNode := msgNode receiver. varNode isVariable ifFalse: [ self error: 'preDecrement can only be applied to variables' ]. aStream nextPutAll: '--'. aStream nextPutAll: (self returnPrefixFromVariable: varNode name). ! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'ikp 9/11/2003 20:08'! generatePreIncrement: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." | varNode | varNode := msgNode receiver. varNode isVariable ifFalse: [ self error: 'preIncrement can only be applied to variables' ]. aStream nextPutAll: '++'. aStream nextPutAll: (self returnPrefixFromVariable: varNode name). ! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'ar 2/15/1999 21:43'! generateRaisedTo: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll:'pow('. self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ','. self emitCExpression: msgNode args first on: aStream. aStream nextPutAll:')'.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 10/24/2010 15:41'! generateSequentialAnd: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' && ('. self emitCTestBlock: msgNode args first on: aStream. aStream nextPut: $)! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 10/24/2010 15:41'! generateSequentialOr: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." "Note: PP 2.3 compiler produces two arguments for or:, presumably to help with inlining later. Taking the last agument should do the correct thing even if your compiler is different." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' || ('. self emitCTestBlock: msgNode args last on: aStream. aStream nextPutAll: ')'! ! !CCodeGenerator methodsFor: 'C translation'! generateSharedCodeDirective: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '/* common code: '. aStream nextPutAll: msgNode args first value. aStream nextPutAll: ' */'. ! ! !CCodeGenerator methodsFor: 'C translation'! generateShiftLeft: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' << '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'ikp 8/4/2004 18:25'! generateShiftRight: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '((usqInt) '. self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ')'. aStream nextPutAll: ' >> '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 3/19/2009 16:17'! generateSignedBitShift: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." | arg | (arg := msgNode args first) isConstant ifTrue: "bit shift amount is a constant" [aStream nextPut: $(; nextPutAll: '(signed)'. self emitCExpression: msgNode receiver on: aStream. arg value < 0 ifTrue: [aStream nextPutAll: ' >> ', arg value negated printString] ifFalse: [aStream nextPutAll: ' << ', arg value printString]. aStream nextPut: $)] ifFalse: "bit shift amount is an expression" [aStream nextPutAll: '(('. self emitCExpression: arg on: aStream. aStream nextPutAll: ' < 0) ? ('; nextPutAll: '(signed)'. self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' >> -'. self emitCExpression: arg on: aStream. aStream nextPutAll: ') : ('; nextPutAll: '(signed)'. self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' << '. self emitCExpression: arg on: aStream. aStream nextPutAll: '))']! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 3/5/2009 10:27'! generateSignedIntFromLong: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '((sqInt) '. self emitCExpression: msgNode receiver on: aStream. aStream nextPut: $) ! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 3/2/2009 20:48'! generateSignedIntFromShort: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '((short)'. self emitCExpression: msgNode receiver on: aStream. aStream nextPut: $) ! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 3/5/2009 10:28'! generateSignedIntToLong: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '((usqInt) '. self emitCExpression: msgNode receiver on: aStream. aStream nextPut: $) ! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 3/5/2009 10:28'! generateSignedIntToShort: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: '((usqInt) (short)'. self emitCExpression: msgNode receiver on: aStream. aStream nextPut: $) ! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 2/26/2009 10:18'! generateSmalltalkMetaError: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." aStream nextPutAll: 'error("'; nextPutAll: msgNode selector; nextPutAll: '")'! ! !CCodeGenerator methodsFor: 'C translation'! generateTimes: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: ' * '. self emitCExpression: msgNode args first on: aStream.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'eem 7/8/2008 17:40'! generateToByDo: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." | iterationVar step negative | (msgNode args last args size = 1) ifFalse: [ self error: 'wrong number of block arguments'. ]. iterationVar := msgNode args last args first. aStream nextPutAll: 'for (', iterationVar, ' = '. self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: '; ', iterationVar. negative := ((step := msgNode args at: 2) isConstant and: [step value < 0]) or: [step isSend and: [step selector == #negated and: [step receiver isConstant and: [step receiver value >= 0]]]]. aStream nextPutAll: (negative ifTrue: [' >= '] ifFalse: [' <= ']). self emitCExpression: msgNode args first on: aStream. aStream nextPutAll: '; ', iterationVar, ' += '. self emitCExpression: step on: aStream. aStream nextPutAll: ') {'; cr. msgNode args last emitCCodeOn: aStream level: level + 1 generator: self. level timesRepeat: [ aStream tab ]. aStream nextPutAll: '}'.! ! !CCodeGenerator methodsFor: 'C translation'! generateToDo: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." | iterationVar | (msgNode args last args size = 1) ifFalse: [ self error: 'wrong number of block arguments'. ]. iterationVar := msgNode args last args first. aStream nextPutAll: 'for (', iterationVar, ' = '. self emitCExpression: msgNode receiver on: aStream. aStream nextPutAll: '; ', iterationVar, ' <= '. self emitCExpression: msgNode args first on: aStream. aStream nextPutAll: '; ', iterationVar, '++) {'; cr. msgNode args last emitCCodeOn: aStream level: level + 1 generator: self. level timesRepeat: [ aStream tab ]. aStream nextPutAll: '}'.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'tpr 7/26/2003 10:23'! generateTouch: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream - which is to say absolutely nothing" ! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'acg 12/22/1999 01:41'! generateWhileFalse: msgNode on: aStream indent: level "Generate C code for a loop in one of the following formats, as appropriate: while(!!(cond)) { stmtList } do {stmtList} while(!!(cond)) while(1) {stmtListA; if (cond) break; stmtListB}" msgNode receiver statements size <= 1 ifTrue: [^self generateWhileFalseLoop: msgNode on: aStream indent: level]. msgNode args first isNilStmtListNode ifTrue: [^self generateDoWhileFalse: msgNode on: aStream indent: level]. ^self generateWhileForeverBreakTrueLoop: msgNode on: aStream indent: level! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'acg 12/22/1999 01:41'! generateWhileFalseLoop: msgNode on: aStream indent: level "Generate while(!!(cond)) {stmtList}." aStream nextPutAll: 'while (!!('. self emitCTestBlock: msgNode receiver on: aStream. aStream nextPutAll: ')) {'; cr. msgNode args first isNilStmtListNode ifFalse: [msgNode args first emitCCodeOn: aStream level: level + 1 generator: self]. level timesRepeat: [ aStream tab ]. aStream nextPutAll: '}'.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 11/9/2006 06:28'! generateWhileForeverBreakFalseLoop: msgNode on: aStream indent: level "Generate while(1) {stmtListA; if(!!(cond)) break; stmtListB}." | stmts testStmt | stmts := msgNode receiver statements asOrderedCollection. testStmt := stmts removeLast. msgNode receiver setStatements: stmts. level - 1 timesRepeat: [ aStream tab ]. aStream nextPutAll: 'while (1) {'; cr. msgNode receiver emitCCodeOn: aStream level: level + 1 generator: self. (level + 1) timesRepeat: [ aStream tab ]. aStream nextPutAll: 'if (!!('. testStmt asExpression emitCCodeOn: aStream level: 0 generator: self. aStream nextPutAll: ')) break;'; cr. msgNode args first emitCCodeOn: aStream level: level + 1 generator: self. level timesRepeat: [ aStream tab ]. aStream nextPutAll: '}'.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 11/9/2006 06:28'! generateWhileForeverBreakTrueLoop: msgNode on: aStream indent: level "Generate while(1) {stmtListA; if(cond) break; stmtListB}." | stmts testStmt | stmts := msgNode receiver statements asOrderedCollection. testStmt := stmts removeLast. msgNode receiver setStatements: stmts. level - 1 timesRepeat: [ aStream tab ]. aStream nextPutAll: 'while (1) {'; cr. msgNode receiver emitCCodeOn: aStream level: level + 1 generator: self. (level + 1) timesRepeat: [ aStream tab ]. aStream nextPutAll: 'if ('. testStmt asExpression emitCCodeOn: aStream level: 0 generator: self. aStream nextPutAll: ') break;'; cr. msgNode args first emitCCodeOn: aStream level: level + 1 generator: self. level timesRepeat: [ aStream tab ]. aStream nextPutAll: '}'.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'acg 12/22/1999 01:41'! generateWhileTrue: msgNode on: aStream indent: level "Generate C code for a loop in one of the following formats, as appropriate: while(cond) { stmtList } do {stmtList} while(cond) while(1) {stmtListA; if (!!(cond)) break; stmtListB}" msgNode receiver statements size <= 1 ifTrue: [^self generateWhileTrueLoop: msgNode on: aStream indent: level]. msgNode args first isNilStmtListNode ifTrue: [^self generateDoWhileTrue: msgNode on: aStream indent: level]. ^self generateWhileForeverBreakFalseLoop: msgNode on: aStream indent: level! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'acg 12/22/1999 01:38'! generateWhileTrueLoop: msgNode on: aStream indent: level "Generate while(cond) {stmtList}." aStream nextPutAll: 'while ('. self emitCTestBlock: msgNode receiver on: aStream. aStream nextPutAll: ') {'; cr. msgNode args first isNilStmtListNode ifFalse: [msgNode args first emitCCodeOn: aStream level: level + 1 generator: self]. level timesRepeat: [ aStream tab ]. aStream nextPutAll: '}'.! ! !CCodeGenerator methodsFor: 'public'! globalsAsSet "Used by the inliner to avoid name clashes with global variables." ((variablesSetCache == nil) or: [variablesSetCache size ~= variables size]) ifTrue: [ variablesSetCache := variables asSet. ]. ^ variablesSetCache! ! !CCodeGenerator methodsFor: 'public' stamp: 'dtl 10/17/2010 19:12'! initialize translationDict := Dictionary new. inlineList := Array new. constants := Dictionary new: 100. variables := OrderedCollection new: 100. variableDeclarations := Dictionary new: 100. methods := Dictionary new: 500. self initializeCTranslationDictionary. headerFiles := OrderedCollection new. globalVariableUsage := Dictionary new. useSymbolicConstants := true. generateDeadCode := true. scopeStack := OrderedCollection new.! ! !CCodeGenerator methodsFor: 'C translation' stamp: 'dtl 10/17/2010 19:54'! initializeCTranslationDictionary "Initialize the dictionary mapping message names to actions for C code generation." | pairs | translationDict := Dictionary new: 200. pairs := #( #& #generateAnd:on:indent: #| #generateOr:on:indent: #and: #generateSequentialAnd:on:indent: #or: #generateSequentialOr:on:indent: #not #generateNot:on:indent: #+ #generatePlus:on:indent: #- #generateMinus:on:indent: #negated #generateNegated:on:indent: #* #generateTimes:on:indent: #/ #generateDivide:on:indent: #// #generateDivide:on:indent: #\\ #generateModulo:on:indent: #<< #generateShiftLeft:on:indent: #>> #generateShiftRight:on:indent: #min: #generateMin:on:indent: #max: #generateMax:on:indent: #between:and: #generateBetweenAnd:on:indent: #bitAnd: #generateBitAnd:on:indent: #bitOr: #generateBitOr:on:indent: #bitXor: #generateBitXor:on:indent: #bitShift: #generateBitShift:on:indent: #signedBitShift: #generateSignedBitShift:on:indent: #bitInvert32 #generateBitInvert32:on:indent: #< #generateLessThan:on:indent: #<= #generateLessThanOrEqual:on:indent: #= #generateEqual:on:indent: #> #generateGreaterThan:on:indent: #>= #generateGreaterThanOrEqual:on:indent: #~= #generateNotEqual:on:indent: #== #generateEqual:on:indent: #~~ #generateNotEqual:on:indent: #isNil #generateIsNil:on:indent: #notNil #generateNotNil:on:indent: #whileTrue: #generateWhileTrue:on:indent: #whileFalse: #generateWhileFalse:on:indent: #whileTrue #generateDoWhileTrue:on:indent: #whileFalse #generateDoWhileFalse:on:indent: #to:do: #generateToDo:on:indent: #to:by:do: #generateToByDo:on:indent: #ifTrue: #generateIfTrue:on:indent: #ifFalse: #generateIfFalse:on:indent: #ifTrue:ifFalse: #generateIfTrueIfFalse:on:indent: #ifFalse:ifTrue: #generateIfFalseIfTrue:on:indent: #at: #generateAt:on:indent: #at:put: #generateAtPut:on:indent: #basicAt: #generateAt:on:indent: #basicAt:put: #generateAtPut:on:indent: #integerValueOf: #generateIntegerValueOf:on:indent: #integerObjectOf: #generateIntegerObjectOf:on:indent: #isIntegerObject: #generateIsIntegerObject:on:indent: #cCode: #generateInlineCCode:on:indent: #cCode:inSmalltalk: #generateInlineCCode:on:indent: #cPreprocessorDirective: #generateInlineCPreprocessorDirective:on:indent: #preprocessorExpression: #generateInlineCppDirective:on:indent: #isDefined:inSmalltalk:comment:ifTrue: #generateInlineCppIfDef:on:indent: #isDefined:inSmalltalk:comment:ifTrue:ifFalse: #generateInlineCppIfDefElse:on:indent: #isDefinedTrueExpression:inSmalltalk:comment:ifTrue:ifFalse: #generateInlineCppIfElse:on:indent: #cCoerce:to: #generateCCoercion:on:indent: #cCoerceSimple:to: #generateCCoercion:on:indent: #addressOf: #generateAddressOf:on:indent: #signedIntFromLong #generateSignedIntFromLong:on:indent: #signedIntToLong #generateSignedIntToLong:on:indent: #signedIntFromShort #generateSignedIntFromShort:on:indent: #signedIntToShort #generateSignedIntToShort:on:indent: #preIncrement #generatePreIncrement:on:indent: #preDecrement #generatePreDecrement:on:indent: #inline: #generateInlineDirective:on:indent: #asFloat #generateAsFloat:on:indent: #asInteger #generateAsInteger:on:indent: #asUnsignedInteger #generateAsUnsignedInteger:on:indent: #asSymbol #generateAsSymbol:on:indent: #anyMask: #generateBitAnd:on:indent: #raisedTo: #generateRaisedTo:on:indent: #touch: #generateTouch:on:indent: #bytesPerWord #generateBytesPerWord:on:indent: #baseHeaderSize #generateBaseHeaderSize:on:indent: #sharedCodeNamed:inCase: #generateSharedCodeDirective:on:indent: #perform: #generatePerform:on:indent: #perform:with: #generatePerform:on:indent: #perform:with:with: #generatePerform:on:indent: #perform:with:with:with: #generatePerform:on:indent: #perform:with:with:with:with: #generatePerform:on:indent: #perform:with:with:with:with:with: #generatePerform:on:indent: #shouldNotImplement #generateSmalltalkMetaError:on:indent: #shouldBeImplemented #generateSmalltalkMetaError:on:indent: ). 1 to: pairs size by: 2 do: [:i | translationDict at: (pairs at: i) put: (pairs at: i + 1)]. pairs := #( #ifTrue: #generateIfTrueAsArgument:on:indent: #ifFalse: #generateIfFalseAsArgument:on:indent: #ifTrue:ifFalse: #generateIfTrueIfFalseAsArgument:on:indent: #ifFalse:ifTrue: #generateIfFalseIfTrueAsArgument:on:indent: #cCode: #generateInlineCCodeAsArgument:on:indent: #cCode:inSmalltalk: #generateInlineCCodeAsArgument:on:indent: ). asArgumentTranslationDict := Dictionary new: 8. 1 to: pairs size by: 2 do: [:i | asArgumentTranslationDict at: (pairs at: i) put: (pairs at: i + 1)]. ! ! !CCodeGenerator methodsFor: 'inlining' stamp: 'dtl 6/21/2008 12:54'! inlineCaseStatementBranchesInMethodNamed: selector localizingVars: varsList "Inline case statement branches in the method with the given name." (self methodNamed: selector) ifNotNilDo: [:m | m inlineCaseStatementBranchesIn: self localizingVars: varsList]! ! !CCodeGenerator methodsFor: 'inlining' stamp: 'ar 7/8/2003 11:27'! inlineDispatchesInMethodNamed: selector localizingVars: varsList "Inline dispatches (case statements) in the method with the given name." | m varString | m := self methodNamed: selector. m = nil ifFalse: [ m inlineCaseStatementBranchesIn: self localizingVars: varsList. m parseTree nodesDo: [ :n | n isCaseStmt ifTrue: [ n customizeShortCasesForDispatchVar: 'currentBytecode' in: self method: m. ]. ]. ]. variables := variables asOrderedCollection. varsList do: [ :v | varString := v asString. variables remove: varString ifAbsent: []. (variableDeclarations includesKey: varString) ifTrue: [ m declarations at: v asString put: (variableDeclarations at: varString). variableDeclarations removeKey: varString. ]. ]. ! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'ar 7/8/2003 11:04'! isCLiteral: anObject (anObject isKindOf: Integer) ifTrue: [^true]. (anObject isKindOf: String) ifTrue: [^true]. (anObject isKindOf: Float) ifTrue: [^true]. anObject == nil ifTrue: [^true]. anObject == true ifTrue: [^true]. "ikp" anObject == false ifTrue: [^true]. "ikp" (anObject isKindOf: Character) ifTrue:[^true]. "ar" ^false! ! !CCodeGenerator methodsFor: 'utilities' stamp: 'ar 10/7/1998 17:53'! isGeneratingPluginCode ^false! ! !CCodeGenerator methodsFor: 'public' stamp: 'JMM 11/28/2002 11:52'! isGlobalStructureBuild ^false! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'eem 2/9/2009 20:41'! isNonArgumentImplicitReceiverVariableName: aString ^(self typeOfVariable: aString) == #implicit or: [vmClass ifNil: [#('interpreterProxy' 'self') includes: aString] ifNotNil: [vmClass isNonArgumentImplicitReceiverVariableName: aString]]! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'eem 12/15/2008 18:38'! isPointerToStructVariableName: varName "" ^self isTypePointerToStruct: (self typeOfVariable: varName)! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'eem (auto rename) 12/15/2008 18:38'! isTypePointerToStruct: type "" ^vmClass notNil and: [vmClass isTypePointerToStruct: type]! ! !CCodeGenerator methodsFor: 'utilities'! localizeGlobalVariables | candidates procedure | "find all globals used in only one method" candidates := globalVariableUsage select: [:e | e size = 1]. variables removeAllFoundIn: candidates keys. "move any suitable global to be local to the single method using it" candidates keysAndValuesDo: [:key :targets | targets do: [:name | procedure := methods at: name. procedure locals add: key. variableDeclarations at: key ifPresent: [:v | procedure declarations at: key put: v. variableDeclarations removeKey: key]]].! ! !CCodeGenerator methodsFor: 'inlining'! mayInline: sel "Answer true if the method with the given selector may be inlined." ^ inlineList includes: sel! ! !CCodeGenerator methodsFor: 'utilities' stamp: 'dtl 7/3/2008 12:16'! memoryAccessSelectors "Answer the selectors used for low level memory access. These are traditionally implemented as C preprocessor macros (or static inlined functions) in the external support code, but may also be implemented as Smalltalk methods for translation to C." ^ { #byteAt: . #byteAt:put: . #shortAt: . #shortAt:put: . #intAt: . #intAt:put: . #longAt: . #longAt:put: . #byteAtPointer: . #byteAtPointer:put: . #shortAtPointer: . #shortAtPointer:put: . #intAtPointer: . #intAtPointer:put: . #longAtPointer: . #longAtPointer:put: }! ! !CCodeGenerator methodsFor: 'utilities'! methodNamed: selector "Answer the method in the code base with the given selector." ^ methods at: selector ifAbsent: [ nil ]! ! !CCodeGenerator methodsFor: 'inlining' stamp: 'ls 10/10/1999 13:55'! methodStatsString "Return a string describing the size, # of locals, and # of senders of each method. Note methods that have inline C code or C declarations." | methodsWithCCode sizesOf callsOf hasCCode nodeCount senderCount s calls registers selr m | methodsWithCCode := Set new: methods size. sizesOf := Dictionary new: methods size * 2. "selector -> nodeCount" callsOf := Dictionary new: methods size * 2. "selector -> senderCount" "For each method, scan its parse tree once to: 1. determine if the method contains C code or declarations 2. determine how many nodes it has 3. increment the sender counts of the methods it calls 4. determine if it includes any C declarations or code" methods do: [ :m0 | m := m0. (translationDict includesKey: m selector) ifTrue: [ hasCCode := true. ] ifFalse: [ hasCCode := m declarations size > 0. nodeCount := 0. m parseTree nodesDo: [ :node | node isSend ifTrue: [ selr := node selector. selr = #cCode: ifTrue: [ hasCCode := true ]. senderCount := callsOf at: selr ifAbsent: [ 0 ]. callsOf at: selr put: senderCount + 1. ]. nodeCount := nodeCount + 1. ]. ]. hasCCode ifTrue: [ methodsWithCCode add: m selector ]. sizesOf at: m selector put: nodeCount. ]. s := WriteStream on: (String new: 5000). methods keys asSortedCollection do: [ :sel | m := methods at: sel. registers := m locals size + m args size. calls := callsOf at: sel ifAbsent: [0]. registers > 11 ifTrue: [ s nextPutAll: sel; tab. s nextPutAll: (sizesOf at: sel) printString; tab. s nextPutAll: calls printString; tab. s nextPutAll: registers printString; tab. (methodsWithCCode includes: sel) ifTrue: [ s nextPutAll: 'CCode' ]. s cr. ]. ]. ^ s contents! ! !CCodeGenerator methodsFor: 'utilities'! methodsReferringToGlobal: v "Return a collection of methods that refer to the given global variable." | out | out := OrderedCollection new. methods associationsDo: [ :assoc | (assoc value freeVariableReferences includes: v) ifTrue: [ out add: assoc key. ]. ]. ^ out! ! !CCodeGenerator methodsFor: 'utilities'! methodsThatCanInvoke: aSelectorList "Return a set of methods that can invoke one of the given selectors, either directly or via a sequence of intermediate methods." | out todo sel mSelector | out := Set new. todo := aSelectorList copy asOrderedCollection. [todo isEmpty] whileFalse: [ sel := todo removeFirst. out add: sel. methods do: [ :m | (m allCalls includes: sel) ifTrue: [ mSelector := m selector. ((out includes: mSelector) or: [todo includes: mSelector]) ifFalse: [ todo add: mSelector. ]. ]. ]. ]. ^ out ! ! !CCodeGenerator methodsFor: 'utilities' stamp: 'ar 7/8/2003 11:16'! nilOrBooleanConstantReceiverOf: sendNode "Answer nil or the boolean constant that is the receiver of the given message send. Used to suppress conditional code when the condition is a translation-time constant." | rcvr val | generateDeadCode ifTrue:[^nil]. rcvr := sendNode receiver. rcvr isConstant ifTrue: [ val := rcvr value. ((val == true) or: [val == false]) ifTrue: [^ val]]. ^ nil ! ! !CCodeGenerator methodsFor: 'utilities'! prepareMethods "Prepare methods for browsing." | globals | globals := Set new: 200. globals addAll: variables. methods do: [ :m | (m locals, m args) do: [ :var | (globals includes: var) ifTrue: [ self error: 'Local variable name may mask global when inlining: ', var. ]. (methods includesKey: var) ifTrue: [ self error: 'Local variable name may mask method when inlining: ', var. ]. ]. m bindClassVariablesIn: constants. m prepareMethodIn: self. ].! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'dtl 1/28/2007 14:10'! prepareMethodsInlined: inlineFlag doAssertions: assertionFlag "Prepare to emit C code for all methods in the code base. All inlined method calls should be expanded. Answer a list of methods to be emitted as C code." | verbose methodList | "method preparation" verbose := false. self prepareMethods. verbose ifTrue: [ self printUnboundCallWarnings. self printUnboundVariableReferenceWarnings. Transcript cr. ]. assertionFlag ifFalse: [ self removeAssertions ]. self doInlining: inlineFlag. "code generation" methodList := methods asSortedCollection: [ :m1 :m2 | m1 selector < m2 selector ]. "clean out no longer valid variable names and then handle any global variable usage in each method" methodList do: [:m | self checkForGlobalUsage: m removeUnusedTemps in: m]. self localizeGlobalVariables. ^ preparedMethodList := methodList ! ! !CCodeGenerator methodsFor: 'private' stamp: 'sma 3/3/2000 12:08'! printArray: array on: aStream | first | first := true. 1 to: array size do: [:i | first ifTrue: [first := false] ifFalse: [aStream nextPutAll: ', ']. i \\ 16 = 1 ifTrue: [aStream cr]. self printInt: (array at: i) on: aStream]! ! !CCodeGenerator methodsFor: 'private' stamp: 'sma 3/3/2000 12:13'! printInt: int on: aStream aStream print: int. (int between: -2147483648 and: 2147483647) ifFalse: [(int between: 2147483648 and: 4294967295) ifTrue: [aStream nextPut: $U] ifFalse: [aStream nextPut: $L]]! ! !CCodeGenerator methodsFor: 'error notification'! printUnboundCallWarnings "Print a warning message for every unbound method call in the code base." | knownSelectors undefinedCalls | undefinedCalls := Dictionary new. knownSelectors := translationDict keys asSet. knownSelectors add: #error:. methods do: [ :m | knownSelectors add: m selector ]. methods do: [ :m | m allCalls do: [ :sel | (knownSelectors includes: sel) ifFalse: [ (undefinedCalls includesKey: sel) ifTrue: [ (undefinedCalls at: sel) add: m selector ] ifFalse: [ undefinedCalls at: sel put: (OrderedCollection with: m selector) ]. ]. ]. ]. Transcript cr. undefinedCalls keys asSortedCollection do: [ :undefined | Transcript show: undefined, ' -- undefined method sent by:'; cr. (undefinedCalls at: undefined) do: [ :caller | Transcript tab; show: caller; cr. ]. ].! ! !CCodeGenerator methodsFor: 'error notification'! printUnboundVariableReferenceWarnings "Print a warning message for every unbound variable reference in the code base." | undefinedRefs globalVars knownVars | undefinedRefs := Dictionary new. globalVars := Set new: 100. globalVars addAll: variables. methods do: [ :m | knownVars := globalVars copy. m args do: [ :var | knownVars add: var ]. m locals do: [ :var | knownVars add: var ]. m freeVariableReferences do: [ :varName | (knownVars includes: varName) ifFalse: [ (undefinedRefs includesKey: varName) ifTrue: [ (undefinedRefs at: varName) add: m selector ] ifFalse: [ undefinedRefs at: varName put: (OrderedCollection with: m selector) ]. ]. ]. ]. Transcript cr. undefinedRefs keys asSortedCollection do: [ :var | Transcript show: var, ' -- undefined variable used in:'; cr. (undefinedRefs at: var) do: [ :sel | Transcript tab; show: sel; cr. ]. ].! ! !CCodeGenerator methodsFor: 'inlining' stamp: 'ar 2/3/2001 17:08'! pruneMethods: selectorList "Explicitly prune some methods" selectorList do:[:sel| methods removeKey: sel ifAbsent:[]].! ! !CCodeGenerator methodsFor: 'inlining' stamp: 'tpr 3/2/2004 11:09'! pruneUnreachableMethods "Remove any methods that are not reachable. Retain methods needed by the translated classes - see implementors of requiredMethodNames" | newMethods | "add all the exported methods and all the called methods to the dNRML" methods do: [ :m | m export ifTrue:[doNotRemoveMethodList add: m selector]. doNotRemoveMethodList addAll: m allCalls]. "build a new dictionary of methods from the collection of all the ones to keep" newMethods := Dictionary new: doNotRemoveMethodList size. doNotRemoveMethodList do:[:sel| methods at: sel ifPresent:[:meth| newMethods at: sel put: meth]]. methods := newMethods! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'eem 7/2/2008 14:21'! pushScope: variableToType "" while: aBlock scopeStack addLast: variableToType. ^aBlock ensure: [scopeStack removeLast]! ! !CCodeGenerator methodsFor: 'inlining' stamp: 'ikp 9/26/97 14:50'! removeAssertions "Remove all assertions in method bodies. This is for the benefit of inlining, which fails to recognise and disregard empty method bodies when checking the inlinability of sends." | newMethods | newMethods := Dictionary new. 'Removing assertions...' displayProgressAt: Sensor cursorPoint from: 0 to: methods size during: [ :bar | methods doWithIndex: [ :m :i | bar value: i. m isAssertion ifFalse: [ newMethods at: m selector put: m. m removeAssertions]]]. methods := newMethods.! ! !CCodeGenerator methodsFor: 'inlining' stamp: 'dtl 6/21/2008 09:21'! removeMethodsReferingToGlobals: varList except: methodNames "Remove any methods (presumably inlined) that still contain references to the given obsolete global variables." | varListAsStrings mVars | varListAsStrings := varList collect: [ :sym | sym asString ]. (methods keys copyWithoutAll: methodNames) do: [ :sel | mVars := (self methodNamed: sel) freeVariableReferences asSet. (mVars includesAnyOf: varListAsStrings) ifTrue: [methods removeKey: sel ifAbsent: []]] ! ! !CCodeGenerator methodsFor: 'utilities'! reportRecursiveMethods "Report in transcript all methods that can call themselves directly or indirectly or via a chain of N intermediate methods." | visited calls newCalls sel called | methods do: [: m | visited := translationDict keys asSet. calls := m allCalls asOrderedCollection. 5 timesRepeat: [ newCalls := Set new: 50. [calls isEmpty] whileFalse: [ sel := calls removeFirst. sel = m selector ifTrue: [ Transcript show: m selector, ' is recursive'; cr. ] ifFalse: [ (visited includes: sel) ifFalse: [ called := self methodNamed: sel. called = nil ifFalse: [ newCalls addAll: called allCalls ]. ]. visited add: sel. ]. ]. calls := newCalls asOrderedCollection. ]. ].! ! !CCodeGenerator methodsFor: 'inlining' stamp: 'tpr 2/27/2004 18:49'! retainMethods: aListOfMethodsToKeep "add aListOfMethodsToKeep to doNotRemoveMethodList so that they will not be pruned" doNotRemoveMethodList ifNil:[doNotRemoveMethodList := Set new:100]. doNotRemoveMethodList addAll: aListOfMethodsToKeep. ^aListOfMethodsToKeep! ! !CCodeGenerator methodsFor: 'utilities' stamp: 'JMM 4/16/2002 22:39'! returnPrefixFromVariable: aName ^aName! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'eem (auto rename) 12/16/2008 08:46'! selectorReturnsPointerToStruct: selector "" | tMethod | ^vmClass notNil and: [(tMethod := methods at: selector ifAbsent: []) notNil and: [vmClass isTypePointerToStruct: tMethod returnType]]! ! !CCodeGenerator methodsFor: 'utilities' stamp: 'eem 5/20/2010 20:46'! sortMethods: aTMethodCollection "We need to define this since different Squeak versions answer different results for asSortedCollection and if sort order changes, generated code changes too." ^aTMethodCollection asSortedCollection: [:a :b| a selector caseSensitiveLessOrEqual: b selector]! ! !CCodeGenerator methodsFor: 'public' stamp: 'ikp 9/26/97 14:50'! storeCodeOnFile: fileName doInlining: inlineFlag "Store C code for this code base on the given file." self storeCodeOnFile: fileName doInlining: inlineFlag doAssertions: true! ! !CCodeGenerator methodsFor: 'public' stamp: 'tpr 9/26/2001 07:28'! storeCodeOnFile: fileName doInlining: inlineFlag doAssertions: assertionFlag "Store C code for this code base on the given file." | stream | stream := CrLfFileStream forceNewFileNamed: fileName. stream ifNil: [Error signal: 'Could not open C code file: ', fileName]. self emitCCodeOn: stream doInlining: inlineFlag doAssertions: assertionFlag. stream close! ! !CCodeGenerator methodsFor: 'public' stamp: 'dtl 5/27/2010 21:41'! storeHeaderOnFile: fileName "Store C header code for this interpreter on the given file." | aStream | aStream := CrLfFileStream forceNewFileNamed: fileName. aStream ifNil: [Error signal: 'Could not open C header file: ', fileName]. aStream nextPutAll: '/* '; nextPutAll: VMMaker headerNotice; nextPutAll: ' */'; cr; cr. self emitVmmVersionOn: aStream. self emitDefineBytesPerWordOn: aStream. self emitDefineMemoryAccessInImageOn: aStream. aStream cr. aStream close ! ! !CCodeGenerator methodsFor: 'utilities' stamp: 'TPR 3/2/2000 11:45'! translationMethodClass "return the class used to produce C translation methods from MethodNodes" ^TMethod! ! !CCodeGenerator methodsFor: 'C code generator' stamp: 'eem 2/9/2009 20:39'! typeOfVariable: varName "" scopeStack reverseDo: [:dict| (dict includesKey: varName) ifTrue: [^dict at: varName]]. ^variableDeclarations at: varName ifAbsent: nil! ! !CCodeGenerator methodsFor: 'utilities' stamp: 'ar 7/17/1999 15:06'! unreachableMethods "Return a collection of methods that are never invoked." | sent out | sent := Set new. methods do: [ :m | m export ifTrue:[sent add: m selector]. sent addAll: m allCalls. ]. out := OrderedCollection new. methods keys do: [ :sel | (sent includes: sel) ifFalse: [ out add: sel ]. ]. ^ out! ! !CCodeGenerator methodsFor: 'accessing' stamp: 'ar 7/8/2003 11:23'! useSymbolicConstants "Answer whether we should generate symbolic constants instead of their actual values" ^useSymbolicConstants! ! !CCodeGenerator methodsFor: 'accessing' stamp: 'ar 7/8/2003 11:23'! useSymbolicConstants: aBool "Indicate whether we should generate symbolic constants instead of their actual values" useSymbolicConstants := aBool! ! !CCodeGenerator methodsFor: 'public' stamp: 'eem 7/16/2009 14:07'! var: varName declareC: declarationString "Record the given C declaration for a global variable." (declarationString includesSubString: varName) ifFalse: [self error: 'declaration omits variable name. probably an error. use e.g. var:type:']. variableDeclarations at: varName asString put: declarationString.! ! !CCodeGenerator methodsFor: 'public' stamp: 'tpr 12/29/2005 15:59'! var: varName type: type "Use this in preference to #var:declareC: whenver possible since it avoids typing the varname twice and thus avoids the potential for a typo. See also #var:type:array:" self var: varName declareC: type , ' ' , varName! ! !CCodeGenerator methodsFor: 'public' stamp: 'tpr 12/29/2005 16:00'! var: varName type: type array: array "use this in preference to #var:declareC: when possible. This produces a C statment of the form int * fooArray[]={1,2,3} See also #var:type: for simple var decls" self var: varName declareC: (String streamContents: [:s | s nextPutAll: type. s space. s nextPutAll: varName. s nextPutAll: '[] = {'. self printArray: array on: s. s nextPut: $}])! ! CCodeGenerator subclass: #CCodeGeneratorGlobalStructure instanceVariableNames: 'localStructDef' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Translation to C'! !CCodeGeneratorGlobalStructure commentStamp: 'tpr 5/23/2003 11:17' prior: 0! This subclass of CCodeGenerator adds support for sticking most global variables into a large global array. This in turn means that suitably minded C compilers can do a better job of accessing those variables; in particular the Mac OS use of PPC and Acorn use of ARM benfits by a substantial margin. Only simple globals are currently put in the array. Someday we might try adding pointers to the various arrays etc.! !CCodeGeneratorGlobalStructure methodsFor: 'C code generator'! buildSortedVariablesCollection "Build sorted vars, end result will be sorted collection based on static usage, perhaps cache lines will like this!!" | globalNames sorted | globalNames := Bag new: globalVariableUsage size. globalVariableUsage keysAndValuesDo: [:k :v | (variableDeclarations includesKey: k) ifFalse: [globalNames add: k withOccurrences: v size]]. variableDeclarations keysDo: [:e | globalNames add: e withOccurrences: 0]. sorted := SortedCollection sortBlock: [:a :b | (globalNames occurrencesOf: a) > (globalNames occurrencesOf: b)]. sorted addAll: variables. ^sorted! ! !CCodeGeneratorGlobalStructure methodsFor: 'utilities'! checkForGlobalUsage: vars in: aTMethod "override to handle global struct needs" super checkForGlobalUsage: vars in: aTMethod. "if localStructDef is false, we don't ever need to include a reference to it in a function" localStructDef ifFalse:[^self]. vars asSet do: [:var | "if any var is global and in the global var struct tell the TMethod it will be refering to the struct" ((self globalsAsSet includes: var ) and: [self placeInStructure: var ]) ifTrue: [aTMethod referencesGlobalStructIncrementBy: (vars occurrencesOf: var)]]! ! !CCodeGeneratorGlobalStructure methodsFor: 'C code generator' stamp: 'tpr 10/29/2002 14:00'! emitCCodeOn: aStream doInlining: inlineFlag doAssertions: assertionFlag super emitCCodeOn: aStream doInlining: inlineFlag doAssertions: assertionFlag. "if the machine needs the globals structure defined locally in the interp.c file, don't add the folowing function" localStructDef ifFalse:[self emitStructureInitFunctionOn: aStream]! ! !CCodeGeneratorGlobalStructure methodsFor: 'C code generator' stamp: 'dtl 12/4/2010 11:51'! emitCVariablesOn: aStream "Store the global variable declarations on the given stream. break logic into vars for structure and vars for non-structure" | varString structure nonstruct target | structure := WriteStream on: (String new: 32768). nonstruct := WriteStream on: (String new: 32768). aStream nextPutAll: '/*** Variables ***/'; cr. structure nextPutAll: 'static struct foo {'; cr. self buildSortedVariablesCollection do: [ :var | varString := var asString. target := (self placeInStructure: var) ifTrue: [structure] ifFalse: [nonstruct]. (self isGeneratingPluginCode) ifTrue:[ varString = 'interpreterProxy' ifTrue:[ "quite special..." aStream cr; nextPutAll: '#ifdef SQUEAK_BUILTIN_PLUGIN'. aStream cr; nextPutAll: 'extern'. aStream cr; nextPutAll: '#endif'; cr. ] ifFalse:[aStream nextPutAll:'static ']. ]. (variableDeclarations includesKey: varString) ifTrue: [ target nextPutAll: (variableDeclarations at: varString), ';'; cr. ] ifFalse: [ "default variable declaration" target nextPutAll: 'sqInt ', varString, ';'; cr. ]. ]. structure nextPutAll: ' } fum;';cr. "if the machine needs the fum structure defining locally, do it now" localStructDef ifTrue:[structure nextPutAll: 'struct foo * foo = &fum;';cr;cr]. aStream nextPutAll: structure contents. aStream nextPutAll: nonstruct contents. aStream cr.! ! !CCodeGeneratorGlobalStructure methodsFor: 'C code generator' stamp: 'ikp 9/10/2003 05:55'! emitGlobalStructFlagOn: aStream "Define SQ_USE_GLOBAL_STRUCT before including the header." aStream nextPutAll: '#define SQ_USE_GLOBAL_STRUCT 1'; cr; cr! ! !CCodeGeneratorGlobalStructure methodsFor: 'C code generator' stamp: 'tpr 10/9/2002 15:40'! emitStructureInitFunctionOn: aStream "For the VM using a global struct for most of the global vars (useful for ARM and PPC so far), append the initGlobalStructure() function" aStream cr; nextPutAll: 'void initGlobalStructure(void) {foo = &fum;}'; cr! ! !CCodeGeneratorGlobalStructure methodsFor: 'C code generator' stamp: 'tpr 10/29/2002 15:01'! globalStructDefined: aBool localStructDef := aBool! ! !CCodeGeneratorGlobalStructure methodsFor: 'C code generator' stamp: 'tpr 10/29/2002 16:11'! initialize super initialize. localStructDef := false! ! !CCodeGeneratorGlobalStructure methodsFor: 'public'! isGlobalStructureBuild ^true! ! !CCodeGeneratorGlobalStructure methodsFor: 'utilities'! localizeGlobalVariables "TPR - remove all the global vars destined for the structure that are only used once - not worth the space, actually what will happen is the folding code will fold these variables into the method" super localizeGlobalVariables. globalVariableUsage := globalVariableUsage select: [:e | e size > 1]. ! ! !CCodeGeneratorGlobalStructure methodsFor: 'C code generator' stamp: 'tpr 12/22/2005 16:03'! placeInStructure: var "See if we should put this array into a structure This has hard coded vars, should go somewhere else!! The variables listed are hardcoded as C in the interpreter thus they don't get resolved via TVariableNode logic Also let's ignore variables that have special definitions that require initialization, and the function def which has problems" | check | check := variableDeclarations at: var ifAbsent: ['']. (check includes: $=) ifTrue: [^false]. (check includes: $() ifTrue: [^false]. (#( 'showSurfaceFn' 'memory' 'extraVMMemory' 'interpreterProxy') includes: var) ifTrue: [^false]. ^true. ! ! !CCodeGeneratorGlobalStructure methodsFor: 'C code generator'! returnPrefixFromVariable: aName ^((self globalsAsSet includes: aName) and: [self placeInStructure: aName]) ifTrue: ['foo->',aName] ifFalse: [aName]! ! CCodeGenerator subclass: #VMPluginCodeGenerator instanceVariableNames: 'pluginName' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Translation to C'! !VMPluginCodeGenerator commentStamp: '' prior: 0! I generate code that can be loaded dynamically from external libraries (e.g., DSOs on Unix or DLLs on Windows)! VMPluginCodeGenerator subclass: #SmartSyntaxPluginCodeGenerator instanceVariableNames: 'debugFlag' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-SmartSyntaxPlugins'! !SmartSyntaxPluginCodeGenerator commentStamp: 'tpr 5/5/2003 16:03' prior: 0! Subclass of CCodeGenerator, used in connection with TestInterpreterPlugin to generate named primitives with type coercion specifications. See the plugins implemeted as subclasses of TestInterpreterPlugin! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:32'! ccgLoad: aBlock expr: aString asBooleanValueFrom: anInteger "Answer codestring for boolean coercion (with validating side-effect) of object, as described in comment to ccgLoad:expr:asRawOopFrom:" ^aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'interpreterProxy booleanValueOf:'; crtab: 2; nextPutAll: '(interpreterProxy stackValue:'; nextPutAll: anInteger asString; nextPutAll: ')'])! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:29'! ccgLoad: aBlock expr: aString asCharPtrFrom: anInteger "Answer codestring for character pointer to first indexable field of object (without validating side-effect), as described in comment to ccgLoad:expr:asRawOopFrom:" ^aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'self cCoerce: (interpreterProxy firstIndexableField:'; crtab: 4; nextPutAll: '(interpreterProxy stackValue:'; nextPutAll: anInteger asString; nextPutAll: '))'; crtab: 3; nextPutAll: 'to: ''char *'''])! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:29'! ccgLoad: aBlock expr: aString asCharPtrFrom: anInteger andThen: valBlock "Answer codestring for character pointer to first indexable field of object (without validating side-effect unless specified in valBlock), as described in comment to ccgLoad:expr:asRawOopFrom:" ^(valBlock value: anInteger), '.', (aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'self cCoerce: (interpreterProxy firstIndexableField:'; crtab: 4; nextPutAll: '(interpreterProxy stackValue:'; nextPutAll: anInteger asString; nextPutAll: '))'; crtab: 3; nextPutAll: 'to: ''char *'''])) ! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:29'! ccgLoad: aBlock expr: aString asFloatValueFrom: anInteger "Answer codestring for double precision coercion (with validating side-effect) of oop, as described in comment to ccgLoad:expr:asRawOopFrom:" ^aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'interpreterProxy stackFloatValue: '; nextPutAll: anInteger asString])! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:29'! ccgLoad: aBlock expr: aString asIntPtrFrom: anInteger "Answer codestring for integer pointer to first indexable field of object (without validating side-effect), as described in comment to ccgLoad:expr:asRawOopFrom:" ^aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'self cCoerce: (interpreterProxy firstIndexableField:'; crtab: 4; nextPutAll: '(interpreterProxy stackValue:'; nextPutAll: anInteger asString; nextPutAll: '))'; crtab: 3; nextPutAll: 'to: ''int *'''])! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:29'! ccgLoad: aBlock expr: aString asIntPtrFrom: anInteger andThen: valBlock "Answer codestring for integer pointer to first indexable field of object (without validating side-effect unless specified in valBlock), as described in comment to ccgLoad:expr:asRawOopFrom:" ^(valBlock value: anInteger), '.', (aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'self cCoerce: (interpreterProxy firstIndexableField:'; crtab: 4; nextPutAll: '(interpreterProxy stackValue:'; nextPutAll: anInteger asString; nextPutAll: '))'; crtab: 3; nextPutAll: 'to: ''int *''']))! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:29'! ccgLoad: aBlock expr: aString asIntegerValueFrom: anInteger "Answer codestring for integer coercion (with validating side-effect) of oop, as described in comment to ccgLoad:expr:asRawOopFrom:" ^aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'interpreterProxy stackIntegerValue: '; nextPutAll: anInteger asString])! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 9/19/1999 20:28'! ccgLoad: aBlock expr: aString asKindOf: aClass from: anInteger ^String streamContents: [:aStream | aStream nextPutAll: 'interpreterProxy success: (interpreterProxy'; crtab: 2; nextPutAll: 'is: (interpreterProxy stackValue: '; nextPutAll: anInteger asString; nextPutAll: ')'; crtab: 2; nextPutAll: 'KindOf: '''; nextPutAll: aClass asString; nextPutAll: ''').'; crtab; nextPutAll: (self ccgLoad: aBlock expr: aString asRawOopFrom: anInteger)]! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 9/19/1999 20:28'! ccgLoad: aBlock expr: aString asMemberOf: aClass from: anInteger ^String streamContents: [:aStream | aStream nextPutAll: 'interpreterProxy success: (interpreterProxy'; crtab: 2; nextPutAll: 'is: (interpreterProxy stackValue: '; nextPutAll: anInteger asString; nextPutAll: ')'; crtab: 2; nextPutAll: 'MemberOf: '''; nextPutAll: aClass asString; nextPutAll: ''').'; crtab; nextPutAll: (self ccgLoad: aBlock expr: aString asRawOopFrom: anInteger)]! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:29'! ccgLoad: aBlock expr: exprString asNamedPtr: recordString from: anInteger "Answer codestring for integer pointer to first indexable field of object (without validating side-effect), as described in comment to ccgLoad:expr:asRawOopFrom:" ^aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'self cCoerce: (interpreterProxy firstIndexableField:'; crtab: 4; nextPutAll: '(interpreterProxy stackValue:'; nextPutAll: anInteger asString; nextPutAll: '))'; crtab: 3; nextPutAll: 'to: '''; nextPutAll: recordString; nextPutAll: ' *'''])! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:29'! ccgLoad: aBlock expr: exprString asNamedPtr: recordString from: anInteger andThen: valBlock "Answer codestring for integer pointer to first indexable field of object (without validating side-effect), as described in comment to ccgLoad:expr:asRawOopFrom:" ^(valBlock value: anInteger), '.', (aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'self cCoerce: (interpreterProxy firstIndexableField:'; crtab: 4; nextPutAll: '(interpreterProxy stackValue:'; nextPutAll: anInteger asString; nextPutAll: '))'; crtab: 3; nextPutAll: 'to: '''; nextPutAll: recordString; nextPutAll: ' *''']))! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:29'! ccgLoad: aBlock expr: aString asNonIntegerValueFrom: anInteger "Answer codestring for oop (with validating side effect), as described in comment to ccgLoad:expr:asRawOopFrom:" ^aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'interpreterProxy stackObjectValue: '; nextPutAll: anInteger asString])! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:32'! ccgLoad: aBlock expr: aString asRawOopFrom: anInteger "Answer a string for a Slang expression that will load an oop (without validation) from stack index anInteger. Apply aBlock, a BlockContext instance that when passed an expression, will return a string assigning the expression to the desired identifier, to the string before answering. aString is a Slang expression that refers to the stack value, once it has been loaded." ^aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'interpreterProxy stackValue: '; nextPutAll: anInteger asString])! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:31'! ccgLoad: aBlock expr: aString asUnsignedPtrFrom: anInteger andThen: valBlock "Answer a codestring for integer pointer to first indexable field of object (without validating side-effect unless specified in valBlock), as described in comment to ccgLoad:expr:asRawOopFrom:" ^(valBlock value: anInteger), '.', (aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'self cCoerce: (interpreterProxy firstIndexableField:'; crtab: 4; nextPutAll: '(interpreterProxy stackValue:'; nextPutAll: anInteger asString; nextPutAll: '))'; crtab: 3; nextPutAll: 'to: ''unsigned *''']))! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:31'! ccgLoad: aBlock expr: aString asUnsignedValueFrom: anInteger "Answer a codestring for positive integer coercion (with validating side-effect) of oop, as described in comment to ccgLoad:expr:asRawOopFrom:" ^aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'interpreterProxy positive32BitValueOf:'; crtab: 2; nextPutAll: '(interpreterProxy stackValue:'; nextPutAll: anInteger asString; nextPutAll: ')'])! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:31'! ccgLoad: aBlock expr: aString asWBCharPtrFrom: anInteger "Answer codestring for char pointer to first indexable field of object (with validating side-effect), as described in comment to ccgLoad:expr:asRawOopFrom:" ^aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'self cCoerce: (interpreterProxy arrayValueOf:'; crtab: 4; nextPutAll: '(interpreterProxy stackValue:'; nextPutAll: anInteger asString; nextPutAll: '))'; crtab: 3; nextPutAll: 'to: ''char *'''])! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:31'! ccgLoad: aBlock expr: aString asWBFloatPtrFrom: anInteger "Answer codestring for single-precision float pointer to first indexable field of object (with validating side-effect), as described in comment to ccgLoad:expr:asRawOopFrom:" ^aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'self cCoerce: (interpreterProxy arrayValueOf:'; crtab: 4; nextPutAll: '(interpreterProxy stackValue:'; nextPutAll: anInteger asString; nextPutAll: '))'; crtab: 3; nextPutAll: 'to: ''float *'''])! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 12/17/1999 07:31'! ccgLoad: aBlock expr: aString asWBIntPtrFrom: anInteger "Answer codestring for integer pointer to first indexable field of object (with validating side-effect), as described in comment to ccgLoad:expr:asRawOopFrom:" ^aBlock value: (String streamContents: [:aStream | aStream nextPutAll: 'self cCoerce: (interpreterProxy arrayValueOf:'; crtab: 4; nextPutAll: '(interpreterProxy stackValue:'; nextPutAll: anInteger asString; nextPutAll: '))'; crtab: 3; nextPutAll: 'to: ''int *'''])! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'ar 4/4/2006 21:10'! ccgSetBlock: aString ^[:expr | aString, ' := ', expr]! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'acg 9/19/1999 13:05'! ccgTVarBlock: anInteger ^[:expr | '(thisContext tempAt: 1) tempAt: ', anInteger asString, ' put: (', expr, ')']! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'coercing' stamp: 'EstebanLorenzano 12/6/2010 19:19'! ccgValBlock: valString ^[:index | String streamContents: [:aStream | aStream nextPutAll: 'interpreterProxy success: (interpreterProxy '; nextPutAll: valString; nextPutAll: ': (interpreterProxy stackValue: '; nextPutAll: index asString; nextPutAll: '))']]! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'linking' stamp: 'acg 9/17/1999 01:43'! emitLoad: aString asBooleanValueFrom: anInteger on: aStream aStream nextPutAll: aString; nextPutAll: ' = interpreterProxy->booleanValueOf('; crtab: 2; nextPutAll: 'interpreterProxy->stackValue('; nextPutAll: anInteger asString; nextPutAll: '))'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'linking' stamp: 'acg 9/17/1999 01:43'! emitLoad: aString asCharPtrFrom: anInteger on: aStream aStream nextPutAll: aString; nextPutAll: ' = (char *) interpreterProxy->firstIndexableField('; crtab: 2; nextPutAll: 'interpreterProxy->stackValueOf('; nextPutAll: anInteger asString; nextPutAll: '))'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'linking' stamp: 'acg 9/17/1999 01:43'! emitLoad: aString asFloatPtrFrom: anInteger on: aStream aStream nextPutAll: aString; nextPutAll: ' = (float *) interpreterProxy->firstIndexableField('; crtab: 2; nextPutAll: 'interpreterProxy->stackValueOf('; nextPutAll: anInteger asString; nextPutAll: '))'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'linking' stamp: 'acg 9/17/1999 01:43'! emitLoad: aString asFloatValueFrom: anInteger on: aStream aStream nextPutAll: aString; nextPutAll: ' = interpreterProxy->stackFloatValue('; nextPutAll: anInteger asString; nextPutAll: ')'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'linking' stamp: 'acg 9/17/1999 01:43'! emitLoad: aString asIntPtrFrom: anInteger on: aStream aStream nextPutAll: aString; nextPutAll: ' = (int *) interpreterProxy->firstIndexableField('; crtab: 2; nextPutAll: 'interpreterProxy->stackValueOf('; nextPutAll: anInteger asString; nextPutAll: '))'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'linking' stamp: 'acg 9/17/1999 01:43'! emitLoad: aString asIntegerValueFrom: anInteger on: aStream aStream nextPutAll: aString; nextPutAll: ' = interpreterProxy stackIntegerValue('; nextPutAll: anInteger asString; nextPutAll: ')'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'linking' stamp: 'acg 9/17/1999 01:42'! emitLoad: aString asKindOf: aClass from: anInteger on: aStream self emitLoad: aString asNakedOopFrom: anInteger on: aStream. aStream crtab; nextPutAll: 'interpreterProxy->success(interpreterProxy->isKindOf('; nextPutAll: aString; nextPutAll: ', '''; nextPutAll: aClass asString; nextPutAll: '''))'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'linking' stamp: 'bf 3/16/2000 19:20'! emitLoad: aString asMemberOf: aClass from: anInteger on: aStream self emitLoad: aString asNakedOopFrom: anInteger on: aStream. aStream crtab; nextPutAll: 'interpreterProxy->success(interpreterProxy->isMemberOf('; nextPutAll: aString; nextPutAll: ', '''; nextPutAll: aClass asString; nextPutAll: '''))'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'linking' stamp: 'acg 9/18/1999 14:23'! emitLoad: aString asNakedOopFrom: anInteger on: aStream aStream nextPutAll: aString; nextPutAll: ' = interpreterProxy stackValue('; nextPutAll: anInteger asString; nextPutAll: ')'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'linking' stamp: 'acg 9/17/1999 01:44'! emitLoad: aString asNonIntegerValueFrom: anInteger on: aStream aStream nextPutAll: aString; nextPutAll: ' = interpreterProxy stackObjectValue('; nextPutAll: anInteger asString; nextPutAll: ')'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'linking' stamp: 'acg 9/17/1999 01:44'! emitLoad: aString asUnsignedValueFrom: anInteger on: aStream aStream nextPutAll: aString; nextPutAll: ' = interpreterProxy->positive32BitValueOf('; crtab: 2; nextPutAll: 'interpreterProxy->stackValue('; nextPutAll: anInteger asString; nextPutAll: '))'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:08'! generateAsBooleanObj: aNode on: aStream indent: anInteger aStream nextPutAll: '('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ') ? interpreterProxy->trueObject(): interpreterProxy->falseObject()'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:09'! generateAsCBoolean: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->booleanValueOf('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:09'! generateAsCDouble: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->floatValueOf('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 21:53'! generateAsCInt: aNode on: aStream indent: anInteger self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ' >> 1'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:09'! generateAsCUnsigned: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->positive32BitValueOf('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:10'! generateAsCharPtr: aNode on: aStream indent: anInteger aStream nextPutAll: '(char *) interpreterProxy->firstIndexableField('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:10'! generateAsFloatObj: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->floatObjectOf('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'TPR 2/25/2000 16:21'! generateAsIfVar: aNode on: aStream indent: anInteger | cName fName class index | cName := String streamContents: [:scStr | self emitCExpression: aNode args first on: scStr]. class := Smalltalk at: (cName asSymbol) ifAbsent: [nil]. (class isNil not and: [class isBehavior]) ifFalse: [^self error: 'first arg must identify class']. fName := aNode args second value. index := class allInstVarNames indexOf: fName ifAbsent: [^self error: 'second arg must be instVar']. aStream nextPutAll: 'interpreterProxy->fetchPointerofObject('; nextPutAll: (index - 1) asString; nextPutAll: ','. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'TPR 2/25/2000 16:41'! generateAsIfVarAsValue: aNode on: aStream indent: anInteger | cName fName class index fetchNode | cName := String streamContents: [:scStr | self emitCExpression: aNode args first on: scStr]. class := Smalltalk at: (cName asSymbol) ifAbsent: [nil]. (class isNil not and: [class isBehavior]) ifFalse: [^self error: 'first arg must identify class']. fName := aNode args second value. index := class allInstVarNames indexOf: fName ifAbsent: [^self error: 'second arg must be instVar']. fetchNode := TSendNode new setSelector: #fetchPointer:ofObject: receiver: (TVariableNode new setName: 'interpreterProxy') arguments: (Array with: (TConstantNode new setValue: index - 1) with: aNode receiver). cName := aNode args third nameOrValue. class := Smalltalk at: (cName asSymbol) ifAbsent: [nil]. (class isNil not and: [class isBehavior]) ifFalse: [^self error: 'third arg must identify class']. class ccg: self generateCoerceToValueFrom: fetchNode on: aStream ! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'TPR 2/25/2000 16:41'! generateAsIfVarPut: aNode on: aStream indent: anInteger | cName fName class index | cName := String streamContents: [:scStr | self emitCExpression: aNode args first on: scStr]. class := Smalltalk at: (cName asSymbol) ifAbsent: [nil]. (class isNil not and: [class isBehavior]) ifFalse: [^self error: 'first arg must identify class']. fName := aNode args second value. index := class allInstVarNames indexOf: fName ifAbsent: [^self error: 'second arg must be instVar']. aStream nextPutAll: 'interpreterProxy->storePointerofObjectwithValue('; nextPutAll: (index - 1) asString; nextPutAll: ','. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ','. self emitCExpression: aNode args third on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:10'! generateAsIntPtr: aNode on: aStream indent: anInteger aStream nextPutAll: '(int *) interpreterProxy->firstIndexableField('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 12/17/1999 07:23'! generateAsOop: aNode on: aStream indent: anInteger | cName class | cName := aNode args first nameOrValue. class := Smalltalk at: (cName asSymbol) ifAbsent: [nil]. (class isNil not and: [class isBehavior]) ifFalse: [^self error: 'first arg must identify class']. class ccg: self generateCoerceToOopFrom: aNode receiver on: aStream! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:10'! generateAsPositiveIntegerObj: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->positive32BitIntegerFor('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/19/1999 20:47'! generateAsSmallIntegerObj: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->integerObjectOf('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 12/17/1999 07:22'! generateAsValue: aNode on: aStream indent: anInteger | cName class | cName := aNode args first nameOrValue. class := Smalltalk at: (cName asSymbol) ifAbsent: [nil]. (class isNil not and: [class isBehavior]) ifFalse: [^self error: 'first arg must identify class']. class ccg: self generateCoerceToValueFrom: aNode receiver on: aStream! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'dtl 5/19/2010 21:35'! generateCPtrAsOop: aNode on: aStream indent: anInteger aStream nextPutAll: '('. aStream nextPutAll: 'oopForPointer( '. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ' ) - BASE_HEADER_SIZE)'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:11'! generateClass: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->fetchClassOf('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'asOop:/asValue:' stamp: 'acg 12/25/1999 10:00'! generateCoerceToBooleanObjectFrom: aNode on: aStream aStream nextPutAll: '('. self emitCExpression: aNode on: aStream. aStream nextPutAll: '? interpreterProxy->trueObject(): interpreterProxy->falseObject())'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'asOop:/asValue:' stamp: 'acg 10/5/1999 06:07'! generateCoerceToBooleanValueFrom: aNode on: aStream aStream nextPutAll: 'interpreterProxy->booleanValueOf('. self emitCExpression: aNode on: aStream. aStream nextPutAll: ')'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'asOop:/asValue:' stamp: 'acg 10/5/1999 06:03'! generateCoerceToFloatObjectFrom: aNode on: aStream aStream nextPutAll: 'interpreterProxy->floatObjectOf('. self emitCExpression: aNode on: aStream. aStream nextPutAll: ')'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'asOop:/asValue:' stamp: 'acg 10/5/1999 05:53'! generateCoerceToFloatValueFrom: aNode on: aStream aStream nextPutAll: 'interpreterProxy->floatValueOf('. self emitCExpression: aNode on: aStream. aStream nextPutAll: ')'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'asOop:/asValue:' stamp: 'dtl 5/19/2010 21:34'! generateCoerceToObjectFromPtr: aNode on: aStream "This code assumes no named instance variables" aStream nextPutAll: 'oopForPointer('. self emitCExpression: aNode on: aStream. aStream nextPutAll: ') - BASE_HEADER_SIZE'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'asOop:/asValue:' stamp: 'acg 10/5/1999 05:57'! generateCoerceToPtr: aString fromObject: aNode on: aStream "This code assumes no named instance variables" aStream nextPutAll: '(('; nextPutAll: aString; nextPutAll: ') interpreterProxy->firstIndexableField('. self emitCExpression: aNode on: aStream. aStream nextPutAll: '))'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'asOop:/asValue:' stamp: 'acg 10/5/1999 06:03'! generateCoerceToSmallIntegerObjectFrom: aNode on: aStream aStream nextPutAll: 'interpreterProxy->integerObjectOf('. self emitCExpression: aNode on: aStream. aStream nextPutAll: ')'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'asOop:/asValue:' stamp: 'acg 10/5/1999 05:59'! generateCoerceToSmallIntegerValueFrom: aNode on: aStream aStream nextPutAll: 'interpreterProxy->integerValueOf('. self emitCExpression: aNode on: aStream. aStream nextPutAll: ')'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'asOop:/asValue:' stamp: 'acg 10/5/1999 06:03'! generateCoerceToUnsignedObjectFrom: aNode on: aStream aStream nextPutAll: 'interpreterProxy->positive32BitIntegerFor('. self emitCExpression: aNode on: aStream. aStream nextPutAll: ')'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'asOop:/asValue:' stamp: 'acg 10/5/1999 06:00'! generateCoerceToUnsignedValueFrom: aNode on: aStream aStream nextPutAll: 'interpreterProxy->positive32BitValueOf('. self emitCExpression: aNode on: aStream. aStream nextPutAll: ')'! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'debug code' stamp: 'sr 4/8/2000 00:52'! generateDebugCode ^ debugFlag! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'debug code' stamp: 'sr 4/8/2000 00:52'! generateDebugCode: aBool debugFlag := aBool! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'sr 4/8/2000 02:38'! generateDebugCode: aNode on: aStream indent: level "Generate the C debug code for this message onto the given stream, if compiled in debugMode." self generateDebugCode ifTrue: [aStream nextPutAll: '/* DebugCode... */'; cr. aNode args first emitCCodeOn: aStream level: level generator: self. aStream tab: level. aStream nextPutAll: '/* ...DebugCode */'] ifFalse: [aStream nextPutAll: '/* missing DebugCode */']! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:11'! generateField: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->fetchPointerofObject('. self emitCExpression: aNode args first on: aStream. aStream nextPutAll: ','. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 23:40'! generateFieldPut: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->storePointerofObjectwithValue('. self emitCExpression: aNode args first on: aStream. aStream nextPutAll: ','. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ','. self emitCExpression: aNode args second on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/16/1999 08:02'! generateFromStack: aNode on: aStream indent: anInteger | idList | aNode args first isConstant ifFalse: [^self error: 'arg must be constant']. idList := aNode args first value. (1 to: idList size) do: [:i | aStream nextPutAll: (idList at: i); nextPutAll: ' = interpreterProxy->stackValue('; nextPutAll: (idList size - i) asString; nextPutAll: ')'] separatedBy: [aStream nextPut: $;; crtab: anInteger]. ! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/19/1999 20:50'! generateIsBytes: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->isBytes('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/19/1999 20:50'! generateIsFloat: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->isFloatObject('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/19/1999 20:49'! generateIsIndexable: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->isIndexable('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/19/1999 20:49'! generateIsInteger: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->isIntegerValue('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:13'! generateIsIntegerOop: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->isIntegerObject('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:13'! generateIsIntegerValue: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->isIntegerValue('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:20'! generateIsKindOf: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->isKindOf('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ','''. self emitCExpression: aNode args first on: aStream. aStream nextPutAll: ''')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:20'! generateIsMemberOf: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->isMemberOf('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ','''. self emitCExpression: aNode args first on: aStream. aStream nextPutAll: ''')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:14'! generateIsPointers: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->isPointers('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:14'! generateIsWords: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->isWords('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:13'! generateIsWordsOrBytes: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->isWordsOrBytes('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/19/1999 01:56'! generateNext: msgNode on: aStream indent: level "Generate the C code for this message onto the given stream." | varNode | varNode := msgNode receiver. varNode isVariable ifFalse: [ self error: 'next can only be applied to variables' ]. aStream nextPutAll: '*'. aStream nextPutAll: varNode name. aStream nextPutAll: '++' ! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 12/31/1999 16:37'! generateRemapOopIn: aNode on: aStream indent: level "Generate the C code for this message onto the given stream." | idList | idList := aNode args first nameOrValue. idList class == Array ifFalse: [idList := Array with: idList]. idList do: [:each | aStream nextPutAll: 'interpreterProxy->pushRemappableOop('; nextPutAll: each asString; nextPutAll: ');'] separatedBy: [aStream crtab: level]. aStream cr. aNode args second emitCCodeOn: aStream level: level generator: self. level timesRepeat: [aStream tab]. idList reversed do: [:each | aStream nextPutAll: each asString; nextPutAll: ' = interpreterProxy->popRemappableOop()'] separatedBy: [aStream nextPut: $;; crtab: level].! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:15'! generateStAt: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->stObjectat('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ','. self emitCExpression: aNode args first on: aStream. aStream nextPutAll: ')' ! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 9/15/1999 22:17'! generateStAtPut: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->stObjectatput('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ','. self emitCExpression: aNode args first on: aStream. aStream nextPutAll: ','. self emitCExpression: aNode args second on: aStream. aStream nextPutAll: ')' ! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'acg 1/1/2000 22:41'! generateStSize: aNode on: aStream indent: anInteger aStream nextPutAll: 'interpreterProxy->stSizeOf('. self emitCExpression: aNode receiver on: aStream. aStream nextPutAll: ')'.! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'initialize' stamp: 'sr 4/8/2000 00:53'! initialize super initialize. debugFlag := false! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'translating builtins' stamp: 'tpr 12/21/2005 17:25'! initializeCTranslationDictionary "Initialize the dictionary mapping message names to actions for C code generation." | pairs | super initializeCTranslationDictionary. pairs := #( #asCInt #generateAsCInt:on:indent: #asCUnsigned #generateAsCUnsigned:on:indent: #asCBoolean #generateAsCBoolean:on:indent: #asCDouble #generateAsCDouble:on:indent: #asSmallIntegerObj #generateAsSmallIntegerObj:on:indent: #asPositiveIntegerObj #generateAsPositiveIntegerObj:on:indent: #asBooleanObj #generateAsBooleanObj:on:indent: #asFloatObj #generateAsFloatObj:on:indent: #asIf:var: #generateAsIfVar:on:indent: #asIf:var:asValue: #generateAsIfVarAsValue:on:indent: #asIf:var:put: #generateAsIfVarPut:on:indent: #field: #generateField:on:indent: #field:put: #generateFieldPut:on:indent: #class #generateClass:on:indent: #stSize #generateStSize:on:indent: #stAt: #generateStAt:on:indent: #stAt:put: #generateStAtPut:on:indent: #asCharPtr #generateAsCharPtr:on:indent: #asIntPtr #generateAsIntPtr:on:indent: #cPtrAsOop #generateCPtrAsOop:on:indent: #next #generateNext:on:indent: #asOop: #generateAsOop:on:indent: #asValue: #generateAsValue:on:indent: #isFloat #generateIsFloat:on:indent: #isIndexable #generateIsIndexable:on:indent: #isIntegerOop #generateIsIntegerOop:on:indent: #isIntegerValue #generateIsIntegerValue:on:indent: #FloatOop #generateIsFloatValue:on:indent: #isWords #generateIsWords:on:indent: #isWordsOrBytes #generateIsWordsOrBytes:on:indent: #isPointers #generateIsPointers:on:indent: #isNil #generateIsNil:on:indent: #isMemberOf: #generateIsMemberOf:on:indent: #isKindOf: #generateIsKindOf:on:indent: #fromStack: #generateFromStack:on:indent: #clone #generateClone:on:indent #new #generateNew:on:indent #new: #generateNewSize:on:indent #superclass #generateSuperclass:on:indent: #remapOop:in: #generateRemapOopIn:on:indent: #debugCode: #generateDebugCode:on:indent: ). 1 to: pairs size by: 2 do: [:i | translationDict at: (pairs at: i) put: (pairs at: i + 1)]. ! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'initialize' stamp: 'tpr 6/9/2003 16:40'! translationMethodClass "return the class used to produce C translation methods from MethodNodes" ^SmartSyntaxPluginTMethod! ! !SmartSyntaxPluginCodeGenerator methodsFor: 'transforming' stamp: 'ar 3/10/2000 17:59'! var: varName as: aClass "Record the given C declaration for a global variable" variableDeclarations at: varName asString put: (aClass ccgDeclareCForVar: varName)! ! !VMPluginCodeGenerator methodsFor: 'inlining' stamp: 'tpr 2/24/2004 20:30'! doInlining: inlineFlag "do inlining for a plugin" ^self doBasicInlining: inlineFlag! ! !VMPluginCodeGenerator methodsFor: 'C code generator' stamp: 'tpr 4/10/2002 18:28'! emitCHeaderForPrimitivesOn: aStream "Write a C file header for compiled primitives onto the given stream." self emitCHeaderOn: aStream. aStream nextPutAll: ' /*** Proxy Functions ***/ #define stackValue(i) (interpreterProxy->stackValue(i)) #define stackIntegerValue(i) (interpreterProxy->stackIntegerValue(i)) #define successFlag (!!interpreterProxy->failed()) #define success(bool) (interpreterProxy->success(bool)) #define arrayValueOf(oop) (interpreterProxy->arrayValueOf(oop)) #define checkedIntegerValueOf(oop) (interpreterProxy->checkedIntegerValueOf(oop)) #define fetchArrayofObject(idx,oop) (interpreterProxy->fetchArrayofObject(idx,oop)) #define fetchFloatofObject(idx,oop) (interpreterProxy->fetchFloatofObject(idx,oop)) #define fetchIntegerofObject(idx,oop) (interpreterProxy->fetchIntegerofObject(idx,oop)) #define floatValueOf(oop) (interpreterProxy->floatValueOf(oop)) #define pop(n) (interpreterProxy->pop(n)) #define pushInteger(n) (interpreterProxy->pushInteger(n)) #define sizeOfSTArrayFromCPrimitive(cPtr) (interpreterProxy->sizeOfSTArrayFromCPrimitive(cPtr)) #define storeIntegerofObjectwithValue(idx,oop,value) (interpreterProxy->storeIntegerofObjectwithValue(idx,oop,value)) #define primitiveFail() interpreterProxy->primitiveFail() /* allows accessing Strings in both C and Smalltalk */ #define asciiValue(c) c '. aStream cr.! ! !VMPluginCodeGenerator methodsFor: 'C code generator' stamp: 'tpr 4/3/2006 13:19'! emitCHeaderOn: aStream "Write a C file header onto the given stream." aStream nextPutAll: '/* '. aStream nextPutAll: VMMaker headerNotice. aStream nextPutAll: ' */';cr. aStream nextPutAll:' #include #include #include #include #include /* Default EXPORT macro that does nothing (see comment in sq.h): */ #define EXPORT(returnType) returnType /* Do not include the entire sq.h file but just those parts needed. */ /* The virtual machine proxy definition */ #include "sqVirtualMachine.h" /* Configuration options */ #include "sqConfig.h" /* Platform specific definitions */ #include "sqPlatformSpecific.h" #define true 1 #define false 0 #define null 0 /* using ''null'' because nil is predefined in Think C */ #ifdef SQUEAK_BUILTIN_PLUGIN #undef EXPORT // was #undef EXPORT(returnType) but screws NorCroft cc #define EXPORT(returnType) static returnType #endif '. "Additional header files" headerFiles do:[:hdr| aStream nextPutAll:'#include '; nextPutAll: hdr; cr]. aStream nextPutAll: ' #include "sqMemoryAccess.h" '. aStream cr.! ! !VMPluginCodeGenerator methodsFor: 'C code generator' stamp: 'tpr 1/10/2003 16:09'! emitExportsOn: aStream "Store all the exported primitives in a form to be used by internal plugins" | prefix | aStream nextPutAll:' #ifdef SQUEAK_BUILTIN_PLUGIN';cr. aStream nextPutAll:' void* ', pluginName,'_exports[][3] = {'. prefix := '"', pluginName,'"'. self exportedPrimitiveNames do:[:primName| aStream cr; nextPutAll:' {'; nextPutAll: prefix; nextPutAll:', "'; nextPutAll: primName; nextPutAll:'", (void*)'; nextPutAll: primName; nextPutAll:'},'. ]. aStream nextPutAll:' {NULL, NULL, NULL} }; '. aStream nextPutAll:' #endif /* ifdef SQ_BUILTIN_PLUGIN */ '.! ! !VMPluginCodeGenerator methodsFor: 'public' stamp: 'ar 7/8/2003 10:53'! generateCodeStringForPrimitives "TPR - moved down from CCodeGenerator" | s methodList | s := ReadWriteStream on: (String new: 1000). methodList := methods asSortedCollection: [:m1 :m2 | m1 selector < m2 selector]. self emitCHeaderForPrimitivesOn: s. self emitCConstantsOn: s. self emitCVariablesOn: s. self emitCFunctionPrototypes: methodList on: s. methodList do: [:m | m emitCCodeOn: s generator: self]. self emitExportsOn: s. ^ s contents ! ! !VMPluginCodeGenerator methodsFor: 'testing' stamp: 'ar 10/7/1998 17:54'! isGeneratingPluginCode ^true! ! !VMPluginCodeGenerator methodsFor: 'C code generator' stamp: 'eem 11/7/2009 10:03'! isTypePointerToStruct: type "" ^pluginClass notNil and: [[pluginClass isTypePointerToStruct: type] on: MessageNotUnderstood do: [:ex| ex message selector == #isTypePointerToStruct: ifTrue: [^false]. ex pass]]! ! !VMPluginCodeGenerator methodsFor: 'public' stamp: 'tpr 1/10/2003 16:20'! localizeGlobalVariables "TPR - we don't do this for plugins"! ! !VMPluginCodeGenerator methodsFor: 'public' stamp: 'tpr 1/10/2003 16:18'! pluginName: aString "TPR - moved from CCodeGenerator" "Set the plugin name when generating plugins." pluginName := aString.! ! !VMPluginCodeGenerator methodsFor: 'private' stamp: 'ar 4/4/2006 21:15'! storeVirtualMachineProxyHeader: categoryList on: fileName "Store the interpreter definitions on the given file" | stream | stream := FileStream newFileNamed: fileName. stream nextPutAll: '#ifndef _SqueakVM_H #define _SqueakVM_H /* Increment the following number if you change the order of functions listed or if you remove functions */ #define VM_PROXY_MAJOR 1 /* Increment the following number if you add functions at the end */ #define VM_PROXY_MINOR 0 typedef struct VirtualMachine { int (*minorVersion) (void); int (*majorVersion) (void); '. categoryList do:[:assoc| stream cr; crtab; nextPutAll:'/* InterpreterProxy methodsFor: ''',assoc key, ''' */'; cr; crtab. assoc value asSortedCollection do:[:sel| (methods at: sel) emitProxyFunctionPrototype: stream generator: self. stream nextPutAll: ';'; crtab]]. stream nextPutAll:' } VirtualMachine; #endif /* _SqueakVM_H */ '. stream close.! ! !VMPluginCodeGenerator methodsFor: 'private' stamp: 'tpr 4/12/2006 12:29'! storeVirtualMachineProxyImplementation: categoryList on: fileName "Store the interpreter definitions on the given file" | stream | stream := FileStream newFileNamed: fileName. stream nextPutAll:' #include #include #include #include #include #include "sqVirtualMachine.h"'; cr;cr. stream nextPutAll:'/*** Function prototypes ***/'. categoryList do:[:assoc| stream cr; cr; nextPutAll:'/* InterpreterProxy methodsFor: ''',assoc key, ''' */'; cr. assoc value asSortedCollection do:[:sel| (methods at: sel) emitCFunctionPrototype: stream generator: self. stream nextPutAll: ';'; cr]]. stream cr; nextPutAll:'struct VirtualMachine *VM = NULL;'; cr. stream cr; nextPutAll: 'static int majorVersion(void) { return VM_PROXY_MAJOR; } static int minorVersion(void) { return VM_PROXY_MINOR; } struct VirtualMachine* sqGetInterpreterProxy(void) { if(VM) return VM; VM = (struct VirtualMachine *) calloc(1, sizeof(VirtualMachine)); /* Initialize Function pointers */ VM->majorVersion = majorVersion; VM->minorVersion = minorVersion; '. categoryList do:[:assoc| stream cr; crtab; nextPutAll:'/* InterpreterProxy methodsFor: ''',assoc key, ''' */'; crtab. assoc value asSortedCollection do:[:sel| stream nextPutAll:'VM->'; nextPutAll: (self cFunctionNameFor: sel); nextPutAll:' = '; nextPutAll: (self cFunctionNameFor: sel); nextPutAll:';'; crtab]]. stream cr; crtab; nextPutAll:'return VM;'; cr; nextPutAll:'}'; cr. stream close.! ! Object subclass: #CObjectAccessor instanceVariableNames: 'object offset' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-InterpreterSimulation'! !CObjectAccessor commentStamp: '' prior: 0! I am used to simulate the indexed access to any object during plugin simulation.! CObjectAccessor subclass: #CArrayAccessor instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-InterpreterSimulation'! !CArrayAccessor commentStamp: '' prior: 0! I am used to simulate the indexed access to arrays during plugin simulation.! !CArrayAccessor methodsFor: 'comparing' stamp: 'yo 2/9/2001 11:23'! < other ^ (object == other object) and: [offset < other offset].! ! !CArrayAccessor methodsFor: 'comparing' stamp: 'yo 2/9/2001 11:24'! <= other ^ (object == other object) and: [offset <= other offset].! ! !CArrayAccessor methodsFor: 'comparing' stamp: 'yo 2/9/2001 11:24'! > other ^ (object == other object) and: [offset > other offset].! ! !CArrayAccessor methodsFor: 'comparing' stamp: 'yo 2/9/2001 11:24'! >= other ^ (object == other object) and: [offset >= other offset].! ! !CArrayAccessor methodsFor: 'accessing' stamp: 'ar 10/9/1998 21:56'! at: index ^object at: index + offset + 1! ! !CArrayAccessor methodsFor: 'accessing' stamp: 'ar 10/9/1998 21:56'! at: index put: value ^object at: index + offset + 1 put: value! ! !CArrayAccessor methodsFor: 'accessing' stamp: 'ar 12/31/2001 01:36'! byteAt: index ^object byteAt: index + offset + 1! ! !CArrayAccessor methodsFor: 'accessing' stamp: 'acg 9/19/1999 01:50'! cPtrAsOop offset = 0 ifFalse: [self error: 'offset must be zero']. ^object! ! !CArrayAccessor methodsFor: 'accessing' stamp: 'ar 8/2/2007 18:00'! long32At: index | idx | idx := (offset + index) // 4 + 1. "Note: This is a special hack for BitBlt." (idx = (object basicSize + 1)) ifTrue:[^0]. ^object basicAt: idx! ! !CArrayAccessor methodsFor: 'accessing' stamp: 'ar 8/2/2007 18:01'! long32At: index put: value ^object basicAt: (offset + index) // 4 + 1 put: value! ! !CArrayAccessor methodsFor: 'accessing' stamp: 'ar 10/10/1998 16:26'! longAt: index | idx | idx := (offset + index) // 4 + 1. "Note: This is a special hack for BitBlt." (idx = (object basicSize + 1)) ifTrue:[^0]. ^object basicAt: idx! ! !CArrayAccessor methodsFor: 'accessing' stamp: 'ar 10/10/1998 16:26'! longAt: index put: value ^object basicAt: (offset + index) // 4 + 1 put: value! ! !CArrayAccessor methodsFor: 'accessing' stamp: 'acg 9/19/1999 01:48'! next |val| val := self at: 0. offset := offset + 1. ^val! ! !CArrayAccessor methodsFor: 'accessing' stamp: 'acg 9/19/1999 01:46'! size ^object size! ! CArrayAccessor subclass: #CPluggableAccessor instanceVariableNames: 'readBlock writeBlock' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-InterpreterSimulation'! !CPluggableAccessor commentStamp: 'tpr 5/5/2003 11:49' prior: 0! This class adds generalized block parameter access to C objects for vm simulation! !CPluggableAccessor methodsFor: 'accessing' stamp: 'ar 11/24/1998 20:45'! at: index ^readBlock value: object value: index + offset + 1! ! !CPluggableAccessor methodsFor: 'accessing' stamp: 'ar 11/24/1998 20:45'! at: index put: value ^writeBlock value: object value: index + offset + 1 value: value! ! !CPluggableAccessor methodsFor: 'initialize' stamp: 'di 7/14/2004 11:55'! atBlock: rBlock atPutBlock: wBlock readBlock := rBlock. writeBlock := wBlock! ! !CPluggableAccessor methodsFor: 'initialize' stamp: 'ar 11/24/1998 20:51'! readBlock: rBlock writeBlock: wBlock readBlock := rBlock. writeBlock := wBlock! ! !CObjectAccessor class methodsFor: 'instance creation' stamp: 'ar 9/16/1998 21:36'! on: anObject ^self new setObject: anObject! ! !CObjectAccessor methodsFor: 'pointer arithmetic' stamp: 'ar 10/9/1998 21:57'! + increment ^self clone += increment! ! !CObjectAccessor methodsFor: 'pointer arithmetic' stamp: 'ar 10/9/1998 21:57'! += increment offset := offset + increment! ! !CObjectAccessor methodsFor: 'pointer arithmetic' stamp: 'ar 10/9/1998 21:58'! - decrement ^self clone -= decrement! ! !CObjectAccessor methodsFor: 'pointer arithmetic' stamp: 'ar 10/9/1998 21:58'! -= decrement offset := offset - decrement! ! !CObjectAccessor methodsFor: 'converting' stamp: 'di 7/14/2004 17:36'! asFloatAccessor ^ self asPluggableAccessor atBlock: [:obj :index | obj floatAt: index] atPutBlock: [:obj :index :value | obj floatAt: index put: value]! ! !CObjectAccessor methodsFor: 'converting' stamp: 'di 7/14/2004 17:36'! asIntAccessor ^ self asPluggableAccessor atBlock: [:obj :index | obj intAt: index] atPutBlock: [:obj :index :value | obj intAt: index put: value]! ! !CObjectAccessor methodsFor: 'converting' stamp: 'acg 9/20/1999 11:08'! asOop: aClass (aClass ccgCanConvertFrom: object) ifFalse: [^self error: 'incompatible object for autocoercion']. ^object! ! !CObjectAccessor methodsFor: 'converting' stamp: 'di 7/14/2004 11:55'! asPluggableAccessor ^ (CPluggableAccessor on: object) += offset! ! !CObjectAccessor methodsFor: 'converting' stamp: 'ar 11/24/1998 20:51'! asPluggableAccessor: accessorArray ^((CPluggableAccessor on: object) += offset) readBlock: accessorArray first writeBlock: accessorArray last! ! !CObjectAccessor methodsFor: 'accessing' stamp: 'ar 10/9/1998 21:56'! at: index ^object instVarAt: index + offset + 1! ! !CObjectAccessor methodsFor: 'accessing' stamp: 'ar 10/9/1998 21:56'! at: index put: value ^object instVarAt: index + offset + 1 put: value! ! !CObjectAccessor methodsFor: 'converting' stamp: 'di 7/14/2004 17:38'! coerceTo: cTypeString sim: interpreterSimulator cTypeString = 'float *' ifTrue: [^ self asFloatAccessor]. cTypeString = 'int *' ifTrue: [^ self asIntAccessor]. ^ self! ! !CObjectAccessor methodsFor: 'private' stamp: 'ar 11/3/1998 22:37'! getObject ^object! ! !CObjectAccessor methodsFor: 'accessing' stamp: 'di 7/14/2004 12:13'! isCObjectAccessor ^ true! ! !CObjectAccessor methodsFor: 'accessing' stamp: 'yo 2/9/2001 11:23'! object ^ object! ! !CObjectAccessor methodsFor: 'accessing' stamp: 'yo 2/9/2001 11:23'! offset ^ offset ! ! !CObjectAccessor methodsFor: 'printing' stamp: 'ar 9/16/1998 21:38'! printOn: aStream super printOn: aStream. aStream nextPutAll:' on: '; print: object.! ! !CObjectAccessor methodsFor: 'printing' stamp: 'MPW 1/1/1901 22:01'! printOnStream: aStream super printOnStream: aStream. aStream print:' on: '; write: object.! ! !CObjectAccessor methodsFor: 'private' stamp: 'ar 10/9/1998 21:56'! setObject: anObject object := anObject. offset := 0.! ! Object subclass: #InterpreterPlugin instanceVariableNames: 'interpreterProxy moduleName' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! InterpreterPlugin class instanceVariableNames: 'timeStamp'! !InterpreterPlugin commentStamp: 'tpr 5/5/2003 11:43' prior: 0! This class provides the basic framework for creating VM plugins. Most of the useful methods are on the class side; particularly take note of the messages like #shouldBeTranslated and #requiresPlatformFiles.! InterpreterPlugin class instanceVariableNames: 'timeStamp'! InterpreterPlugin subclass: #ADPCMCodecPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !ADPCMCodecPlugin commentStamp: 'tpr 3/24/2004 14:48' prior: 0! This is a kludgy interface to the translated primitive code in ADPCMCodec. The translate.... method gathers the code and writes it to a file. No methods in this class actually implement the codec.! !ADPCMCodecPlugin class methodsFor: 'translation' stamp: 'tpr 4/9/2002 16:14'! translateInDirectory: directory doInlining: inlineFlag "handle a special case code string rather than generated code" "Not currently hooked into the timeStamp mechanism for VMMaker since this would mean replicating code from InterpreterPlugin; waiting for a more elegant solution to appear. In the meantime this means that this plugin will always get regenerated even if the file is uptodate" | cg | self initialize. cg := self buildCodeGeneratorUpTo: InterpreterPlugin. cg addMethodsForPrimitives: ADPCMCodec translatedPrimitives. inlineFlag ifTrue:[ "now remove a few which will be inlined but not pruned" cg pruneMethods: #(indexForDeltaFrom:to: nextBits: nextBits:put:)]. self storeString: cg generateCodeStringForPrimitives onFileNamed: (directory fullNameFor: self moduleName, '.c'). ^cg exportedPrimitiveNames asArray ! ! InterpreterPlugin subclass: #B3DAcceleratorPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !B3DAcceleratorPlugin commentStamp: '' prior: 0! B3DAcceleratorPlugin translate! !B3DAcceleratorPlugin class methodsFor: 'translation' stamp: 'tpr 5/23/2001 17:08'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !B3DAcceleratorPlugin class methodsFor: 'translation' stamp: 'ar 4/19/2001 02:21'! moduleName ^'B3DAcceleratorPlugin'! ! !B3DAcceleratorPlugin class methodsFor: 'translation' stamp: 'tpr 7/4/2001 15:12'! requiresCrossPlatformFiles "default is ok for most, any plugin needing platform specific files must say so" ^true! ! !B3DAcceleratorPlugin class methodsFor: 'translation' stamp: 'tpr 3/20/2001 12:16'! requiresPlatformFiles "default is ok for most, any plugin needing platform specific files must say so" ^true! ! !B3DAcceleratorPlugin methodsFor: 'primitive support' stamp: 'ar (auto pragmas dtl 2010-09-27) 9/6/2000 22:14'! fetchLightSource: index ofObject: anArray "Fetch the primitive light source from the given array. Note: No checks are done within here - that happened in stackLightArrayValue:" | lightOop | lightOop := interpreterProxy fetchPointer: index ofObject: anArray. ^interpreterProxy firstIndexableField: lightOop! ! !B3DAcceleratorPlugin methodsFor: 'initialize-release' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/26/2000 17:23'! initialiseModule ^self b3dxInitialize! ! !B3DAcceleratorPlugin methodsFor: 'primitives-textures' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:50'! primitiveAllocateTexture | h w d result renderer | interpreterProxy methodArgumentCount = 4 ifFalse:[^interpreterProxy primitiveFail]. h := interpreterProxy stackIntegerValue: 0. w := interpreterProxy stackIntegerValue: 1. d := interpreterProxy stackIntegerValue: 2. renderer := interpreterProxy stackIntegerValue: 3. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxAllocateTexture(renderer, w, h, d)' inSmalltalk:[-1]. result = -1 ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: 5. "args+rcvr" ^interpreterProxy pushInteger: result.! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:51'! primitiveClearDepthBuffer | result handle | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxClearDepthBuffer(handle)'. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 1. "pop args; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:51'! primitiveClearViewport | result handle pv rgba | interpreterProxy methodArgumentCount = 3 ifFalse:[^interpreterProxy primitiveFail]. pv := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). rgba := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 1). handle := interpreterProxy stackIntegerValue: 2. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxClearViewport(handle, rgba, pv)'. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 3. "pop args; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-textures' stamp: 'ar (auto pragmas 12/08) 9/9/2000 16:08'! primitiveCompositeTexture | result translucent y x w h texHandle rendererHandle | interpreterProxy methodArgumentCount = 7 ifFalse:[^interpreterProxy primitiveFail]. translucent := interpreterProxy booleanValueOf: (interpreterProxy stackValue: 0). h := interpreterProxy stackIntegerValue: 1. w := interpreterProxy stackIntegerValue: 2. y := interpreterProxy stackIntegerValue: 3. x := interpreterProxy stackIntegerValue: 4. texHandle := interpreterProxy stackIntegerValue: 5. rendererHandle := interpreterProxy stackIntegerValue: 6. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxCompositeTexture(rendererHandle, texHandle, x, y, w, h, translucent)' inSmalltalk:[false]. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 7. "args" ! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 9/5/2002 16:53'! primitiveCreateRenderer "NOTE: This primitive is obsolete but should be supported for older images" | h w y x result allowHardware allowSoftware | interpreterProxy methodArgumentCount = 6 ifFalse:[^interpreterProxy primitiveFail]. h := interpreterProxy stackIntegerValue: 0. w := interpreterProxy stackIntegerValue: 1. y := interpreterProxy stackIntegerValue: 2. x := interpreterProxy stackIntegerValue: 3. allowHardware := interpreterProxy booleanValueOf: (interpreterProxy stackValue: 4). allowSoftware := interpreterProxy booleanValueOf: (interpreterProxy stackValue: 5). interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxCreateRenderer(allowSoftware, allowHardware, x, y, w, h)'. result < 0 ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: 7. ^interpreterProxy pushInteger: result.! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 9/5/2002 16:52'! primitiveCreateRendererFlags | flags h w y x result | interpreterProxy methodArgumentCount = 5 ifFalse:[^interpreterProxy primitiveFail]. h := interpreterProxy stackIntegerValue: 0. w := interpreterProxy stackIntegerValue: 1. y := interpreterProxy stackIntegerValue: 2. x := interpreterProxy stackIntegerValue: 3. flags := interpreterProxy stackIntegerValue: 4. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxCreateRendererFlags(x, y, w, h, flags)'. result < 0 ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: 6. ^interpreterProxy pushInteger: result.! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 5/14/2001 20:59'! primitiveDestroyRenderer | handle result | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxDestroyRenderer(handle)' inSmalltalk:[false]. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 1. "pop arg; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-textures' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:50'! primitiveDestroyTexture | handle result renderer | interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. renderer := interpreterProxy stackIntegerValue: 1. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxDestroyTexture(renderer, handle)' inSmalltalk:[false]. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 2. "pop arg; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:52'! primitiveFinishRenderer | handle result | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxFinishRenderer(handle)' inSmalltalk:[false]. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 1. "pop arg; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:52'! primitiveFlushRenderer | handle result | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxFlushRenderer(handle)' inSmalltalk:[false]. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 1. "pop arg; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 9/10/2000 00:04'! primitiveGetIntProperty | handle prop result | interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. prop := interpreterProxy stackIntegerValue: 0. handle := interpreterProxy stackIntegerValue: 1. result := self cCode:'b3dxGetIntProperty(handle, prop)'. interpreterProxy pop: 3. "args+rcvr" ^interpreterProxy pushInteger: result! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/16/2001 17:46'! primitiveGetRendererColorMasks | handle result masks array arrayOop | interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. array := interpreterProxy stackObjectValue: 0. handle := interpreterProxy stackIntegerValue: 1. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy fetchClassOf: array) = interpreterProxy classArray ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: array) = 4 ifFalse:[^interpreterProxy primitiveFail]. result := self cCode:'b3dxGetRendererColorMasks(handle, masks)' inSmalltalk:[false]. result ifFalse:[^interpreterProxy primitiveFail]. arrayOop := array. 0 to: 3 do:[:i| interpreterProxy pushRemappableOop: arrayOop. result := interpreterProxy positive32BitIntegerFor: (masks at: i). arrayOop := interpreterProxy popRemappableOop. interpreterProxy storePointer: i ofObject: arrayOop withValue: result]. ^interpreterProxy pop: 2. "pop args return receiver"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 5/14/2001 21:41'! primitiveGetRendererSurfaceDepth | handle result | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxGetRendererSurfaceDepth(handle)' inSmalltalk:[-1]. result < 0 ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: 2. "args+rcvr" ^interpreterProxy pushInteger: result! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 5/14/2001 21:09'! primitiveGetRendererSurfaceHandle | handle result | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxGetRendererSurfaceHandle(handle)' inSmalltalk:[-1]. result < 0 ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: 2. "args+rcvr" ^interpreterProxy pushInteger: result! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 5/14/2001 21:41'! primitiveGetRendererSurfaceHeight | handle result | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxGetRendererSurfaceHeight(handle)' inSmalltalk:[-1]. result < 0 ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: 2. "args+rcvr" ^interpreterProxy pushInteger: result! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 5/14/2001 21:41'! primitiveGetRendererSurfaceWidth | handle result | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxGetRendererSurfaceWidth(handle)' inSmalltalk:[-1]. result < 0 ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: 2. "args+rcvr" ^interpreterProxy pushInteger: result! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 5/14/2001 21:00'! primitiveIsOverlayRenderer | handle result | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxIsOverlayRenderer(handle)' inSmalltalk:[false]. interpreterProxy pop: 2. "args+rcvr" ^interpreterProxy pushBool: result.! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 3/26/2006 22:39'! primitiveRenderVertexBuffer | idxCount vtxCount vtxArray idxArray texHandle primType result flags handle | interpreterProxy methodArgumentCount = 8 ifFalse:[^interpreterProxy primitiveFail]. idxCount := interpreterProxy stackIntegerValue: 0. vtxCount := interpreterProxy stackIntegerValue: 2. texHandle := interpreterProxy stackIntegerValue: 4. flags := interpreterProxy stackIntegerValue: 5. primType := interpreterProxy stackIntegerValue: 6. handle := interpreterProxy stackIntegerValue: 7. interpreterProxy failed ifTrue:[^nil]. vtxArray := self stackPrimitiveVertexArray: 3 ofSize: vtxCount. idxArray := self stackPrimitiveIndexArray: 1 ofSize: idxCount validate: true forVertexSize: vtxCount. (vtxArray == nil or:[idxArray == nil or:[primType < 1 or:[primType > 6 or:[interpreterProxy failed]]]]) ifTrue:[^interpreterProxy primitiveFail]. result := self cCode:'b3dxRenderVertexBuffer(handle, primType, flags, texHandle, vtxArray, vtxCount, idxArray, idxCount)' inSmalltalk:[false]. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 8. "pop args; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:52'! primitiveRendererVersion interpreterProxy methodArgumentCount = 0 ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy pop: 1. ^interpreterProxy pushInteger: 1.! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 4/19/2001 02:19'! primitiveSetBufferRect "Primitive. Set the buffer rectangle (e.g., the pixel area on screen) to use for this renderer. The viewport is positioned within the buffer rectangle." | h w y x result handle | interpreterProxy methodArgumentCount = 5 ifFalse:[^interpreterProxy primitiveFail]. h := interpreterProxy stackIntegerValue: 0. w := interpreterProxy stackIntegerValue: 1. y := interpreterProxy stackIntegerValue: 2. x := interpreterProxy stackIntegerValue: 3. handle := interpreterProxy stackIntegerValue: 4. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxSetBufferRect(handle, x, y, w, h)'. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 5. "pop args; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/15/2001 16:11'! primitiveSetFog | result handle rgba density fogType stop start | interpreterProxy methodArgumentCount = 6 ifFalse:[^interpreterProxy primitiveFail]. rgba := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). stop := interpreterProxy floatValueOf: (interpreterProxy stackValue: 1). start := interpreterProxy floatValueOf: (interpreterProxy stackValue: 2). density := interpreterProxy floatValueOf: (interpreterProxy stackValue: 3). fogType := interpreterProxy stackIntegerValue: 4. handle := interpreterProxy stackIntegerValue: 5. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxSetFog(handle, fogType, density, start, stop, rgba)'. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 6. "pop args; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 9/10/2000 00:05'! primitiveSetIntProperty | handle prop result value | interpreterProxy methodArgumentCount = 3 ifFalse:[^interpreterProxy primitiveFail]. value := interpreterProxy stackIntegerValue: 0. prop := interpreterProxy stackIntegerValue: 1. handle := interpreterProxy stackIntegerValue: 2. result := self cCode:'b3dxSetIntProperty(handle, prop, value)'. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 3. "args; return rcvr" ! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:52'! primitiveSetLights | lightArray lightCount light handle | interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. lightArray := self stackLightArrayValue: 0. handle := interpreterProxy stackIntegerValue: 1. interpreterProxy failed ifTrue:[^nil]. (self b3dxDisableLights: handle) ifFalse:[^interpreterProxy primitiveFail]. lightArray == nil ifTrue:[^nil]. lightCount := interpreterProxy slotSizeOf: lightArray. "For each enabled light source" 0 to: lightCount-1 do:[:i| light := self fetchLightSource: i ofObject: lightArray. (self cCode:'b3dxLoadLight(handle, i, light)' inSmalltalk:[false]) ifFalse:[^interpreterProxy primitiveFail]. ]. ^interpreterProxy pop: 2. "args; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:52'! primitiveSetMaterial | material handle | interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. material := self stackMaterialValue: 0. handle := interpreterProxy stackIntegerValue: 1. (self cCode:'b3dxLoadMaterial(handle, material)' inSmalltalk:[false]) ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 2. "args; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas dtl 2010-09-27) 9/9/2000 15:52'! primitiveSetTransform "Transform an entire vertex buffer using the supplied modelview and projection matrix." | projectionMatrix modelViewMatrix handle | interpreterProxy methodArgumentCount = 3 ifFalse:[^interpreterProxy primitiveFail]. projectionMatrix := self stackMatrix: 0. modelViewMatrix := self stackMatrix: 1. handle := interpreterProxy stackIntegerValue: 2. interpreterProxy failed ifTrue:[^nil]. self cCode: 'b3dxSetTransform(handle, modelViewMatrix, projectionMatrix)'. ^interpreterProxy pop: 3. "Leave rcvr on stack"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 4/20/2001 01:47'! primitiveSetVerboseLevel | result level | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. level := interpreterProxy stackIntegerValue: 0. result := self cCode:'b3dxSetVerboseLevel(level)'. interpreterProxy pop: 2. "args+rcvr" ^interpreterProxy pushInteger: result! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:53'! primitiveSetViewport | h w y x result handle | interpreterProxy methodArgumentCount = 5 ifFalse:[^interpreterProxy primitiveFail]. h := interpreterProxy stackIntegerValue: 0. w := interpreterProxy stackIntegerValue: 1. y := interpreterProxy stackIntegerValue: 2. x := interpreterProxy stackIntegerValue: 3. handle := interpreterProxy stackIntegerValue: 4. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxSetViewport(handle, x, y, w, h)'. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 5. "pop args; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-renderer' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:53'! primitiveSwapRendererBuffers | handle result | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxSwapRendererBuffers(handle)' inSmalltalk:[false]. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 1. "pop arg; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-textures' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:50'! primitiveTextureByteSex | handle result renderer | interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. renderer := interpreterProxy stackIntegerValue: 1. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxTextureByteSex(renderer, handle)' inSmalltalk:[-1]. result < 0 ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: 3. ^interpreterProxy pushBool: result.! ! !B3DAcceleratorPlugin methodsFor: 'primitives-textures' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:50'! primitiveTextureDepth | handle result renderer | interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. renderer := interpreterProxy stackIntegerValue: 1. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxActualTextureDepth(renderer, handle)' inSmalltalk:[-1]. result < 0 ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: 3. ^interpreterProxy pushInteger: result.! ! !B3DAcceleratorPlugin methodsFor: 'primitives-textures' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/16/2001 17:46'! primitiveTextureGetColorMasks | handle result masks array renderer arrayOop | interpreterProxy methodArgumentCount = 3 ifFalse:[^interpreterProxy primitiveFail]. array := interpreterProxy stackObjectValue: 0. handle := interpreterProxy stackIntegerValue: 1. renderer := interpreterProxy stackIntegerValue: 2. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy fetchClassOf: array) = interpreterProxy classArray ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: array) = 4 ifFalse:[^interpreterProxy primitiveFail]. result := self cCode:'b3dxTextureColorMasks(renderer, handle, masks)' inSmalltalk:[false]. result ifFalse:[^interpreterProxy primitiveFail]. arrayOop := array. 0 to: 3 do:[:i| interpreterProxy pushRemappableOop: arrayOop. result := interpreterProxy positive32BitIntegerFor: (masks at: i). arrayOop := interpreterProxy popRemappableOop. interpreterProxy storePointer: i ofObject: arrayOop withValue: result]. ^interpreterProxy pop: 3. "pop args return receiver"! ! !B3DAcceleratorPlugin methodsFor: 'primitives-textures' stamp: 'ar (auto pragmas 12/08) 5/14/2001 20:01'! primitiveTextureSurfaceHandle | handle result renderer | interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. handle := interpreterProxy stackIntegerValue: 0. renderer := interpreterProxy stackIntegerValue: 1. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxTextureSurfaceHandle(renderer, handle)' inSmalltalk:[-1]. result < 0 ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: 3. ^interpreterProxy pushInteger: result! ! !B3DAcceleratorPlugin methodsFor: 'primitives-textures' stamp: 'ar (auto pragmas 12/08) 9/9/2000 15:50'! primitiveTextureUpload | h w d result form bits ppw bitsPtr handle renderer | interpreterProxy methodArgumentCount = 3 ifFalse:[^interpreterProxy primitiveFail]. form := interpreterProxy stackValue: 0. ((interpreterProxy isPointers: form) and:[(interpreterProxy slotSizeOf: form) >= 4]) ifFalse:[^interpreterProxy primitiveFail]. bits := interpreterProxy fetchPointer: 0 ofObject: form. w := interpreterProxy fetchInteger: 1 ofObject: form. h := interpreterProxy fetchInteger: 2 ofObject: form. d := interpreterProxy fetchInteger: 3 ofObject: form. ppw := 32 // d. (interpreterProxy isWords: bits) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: bits) = (w + ppw - 1 // ppw * h) ifFalse:[^interpreterProxy primitiveFail]. bitsPtr := interpreterProxy firstIndexableField: bits. handle := interpreterProxy stackIntegerValue: 1. renderer := interpreterProxy stackIntegerValue: 2. interpreterProxy failed ifTrue:[^nil]. result := self cCode:'b3dxUploadTexture(renderer, handle, w, h, d, bitsPtr)' inSmalltalk:[false]. result ifFalse:[^interpreterProxy primitiveFail]. ^interpreterProxy pop: 3. "args; return rcvr"! ! !B3DAcceleratorPlugin methodsFor: 'initialize-release' stamp: 'ar (auto pragmas 12/08) 5/26/2000 17:23'! shutdownModule ^self b3dxShutdown! ! !B3DAcceleratorPlugin methodsFor: 'primitive support' stamp: 'ar (auto pragmas 12/08) 3/26/2006 22:39'! stackLightArrayValue: stackIndex "Load an Array of B3DPrimitiveLights from the given stack index" | oop array arraySize | array := interpreterProxy stackObjectValue: stackIndex. array = nil ifTrue:[^nil]. array = interpreterProxy nilObject ifTrue:[^nil]. (interpreterProxy fetchClassOf: array) = interpreterProxy classArray ifFalse:[^interpreterProxy primitiveFail]. arraySize := interpreterProxy slotSizeOf: array. 0 to: arraySize-1 do:[:i| oop := interpreterProxy fetchPointer: i ofObject: array. (interpreterProxy isIntegerObject: oop) ifTrue:[^interpreterProxy primitiveFail]. ((interpreterProxy isWords: oop) and:[(interpreterProxy slotSizeOf: oop) = 32]) ifFalse:[^interpreterProxy primitiveFail]. ]. ^array! ! !B3DAcceleratorPlugin methodsFor: 'primitive support' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/26/2006 22:38'! stackMaterialValue: stackIndex "Load a B3DMaterial from the given stack index" | oop | oop := interpreterProxy stackObjectValue: stackIndex. oop = nil ifTrue:[^nil]. oop = interpreterProxy nilObject ifTrue:[^nil]. ((interpreterProxy isWords: oop) and:[(interpreterProxy slotSizeOf: oop) = 17]) ifTrue:[^interpreterProxy firstIndexableField: oop]. ^nil! ! !B3DAcceleratorPlugin methodsFor: 'primitive support' stamp: 'ar (auto pragmas dtl 2010-09-27) 9/6/2000 22:14'! stackMatrix: index "Load a 4x4 transformation matrix from the interpreter stack. Return a pointer to the matrix data if successful, nil otherwise." | oop | oop := interpreterProxy stackObjectValue: index. oop = nil ifTrue:[^nil]. oop = interpreterProxy nilObject ifTrue:[^nil]. ((interpreterProxy isWords: oop) and:[(interpreterProxy slotSizeOf: oop) = 16]) ifTrue:[^interpreterProxy firstIndexableField: oop]. ^nil! ! !B3DAcceleratorPlugin methodsFor: 'primitive support' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/26/2000 12:37'! stackPrimitiveIndexArray: stackIndex ofSize: nItems validate: aBool forVertexSize: maxIndex "Load a primitive index array from the interpreter stack. If aBool is true then check that all the indexes are in the range (1,maxIndex). Return a pointer to the index data if successful, nil otherwise." | oop oopSize idxPtr index | oop := interpreterProxy stackObjectValue: stackIndex. oop = nil ifTrue:[^nil]. (interpreterProxy isWords: oop) ifFalse:[^nil]. oopSize := interpreterProxy slotSizeOf: oop. oopSize < nItems ifTrue:[^nil]. idxPtr := self cCoerce: (interpreterProxy firstIndexableField: oop) to:'int *'. aBool ifTrue:[ 0 to: nItems-1 do:[:i| index := idxPtr at: i. (index < 0 or:[index > maxIndex]) ifTrue:[^nil]]]. ^idxPtr! ! !B3DAcceleratorPlugin methodsFor: 'primitive support' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/26/2006 22:40'! stackPrimitiveVertex: index "Load a primitive vertex from the interpreter stack. Return a pointer to the vertex data if successful, nil otherwise." | oop | oop := interpreterProxy stackObjectValue: index. oop = nil ifTrue:[^nil]. ((interpreterProxy isWords: oop) and:[(interpreterProxy slotSizeOf: oop) = 16]) ifTrue:[^interpreterProxy firstIndexableField: oop]. ^nil! ! !B3DAcceleratorPlugin methodsFor: 'primitive support' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/26/2006 22:40'! stackPrimitiveVertexArray: index ofSize: nItems "Load a primitive vertex array from the interpreter stack. Return a pointer to the vertex data if successful, nil otherwise." | oop oopSize | oop := interpreterProxy stackObjectValue: index. oop = nil ifTrue:[^nil]. (interpreterProxy isWords: oop) ifTrue:[ oopSize := interpreterProxy slotSizeOf: oop. (oopSize >= nItems * 16 and:[oopSize \\ 16 = 0]) ifTrue:[^interpreterProxy firstIndexableField: oop]]. ^nil! ! InterpreterPlugin subclass: #BMPReadWriterPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !BMPReadWriterPlugin commentStamp: 'tpr 5/5/2003 16:45' prior: 0! A plugin to provide fast read and write of .bmp files! !BMPReadWriterPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas dtl 2010-09-27) 8/1/2006 09:54'! primitiveRead24BmpLine | width formBitsIndex formBitsOop pixelLineOop formBitsSize formBits pixelLineSize pixelLine | interpreterProxy methodArgumentCount = 4 ifFalse:[^interpreterProxy primitiveFail]. width := interpreterProxy stackIntegerValue: 0. width <= 0 ifTrue:[^interpreterProxy primitiveFail]. formBitsIndex := interpreterProxy stackIntegerValue: 1. formBitsOop := interpreterProxy stackObjectValue: 2. pixelLineOop := interpreterProxy stackObjectValue: 3. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isWords: formBitsOop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isBytes: pixelLineOop) ifFalse:[^interpreterProxy primitiveFail]. formBitsSize := interpreterProxy slotSizeOf: formBitsOop. formBits := interpreterProxy firstIndexableField: formBitsOop. pixelLineSize := interpreterProxy slotSizeOf: pixelLineOop. pixelLine := interpreterProxy firstIndexableField: pixelLineOop. (formBitsIndex + width <= formBitsSize and:[width*3 <= pixelLineSize]) ifFalse:[^interpreterProxy primitiveFail]. "do the actual work" self cCode:' formBits += formBitsIndex-1; while(width--) { unsigned int rgb; rgb = (*pixelLine++); rgb += (*pixelLine++) << 8; rgb += (*pixelLine++) << 16; if(rgb) rgb |= 0xFF000000; else rgb |= 0xFF000001; *formBits++ = rgb; } ' inSmalltalk:[formBits. pixelLine. ^interpreterProxy primitiveFail]. interpreterProxy pop: 4. "args" ! ! !BMPReadWriterPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas dtl 2010-09-27) 8/1/2006 09:53'! primitiveWrite24BmpLine | width formBitsIndex formBitsOop pixelLineOop formBitsSize formBits pixelLineSize pixelLine | interpreterProxy methodArgumentCount = 4 ifFalse:[^interpreterProxy primitiveFail]. width := interpreterProxy stackIntegerValue: 0. width <= 0 ifTrue:[^interpreterProxy primitiveFail]. formBitsIndex := interpreterProxy stackIntegerValue: 1. formBitsOop := interpreterProxy stackObjectValue: 2. pixelLineOop := interpreterProxy stackObjectValue: 3. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isWords: formBitsOop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isBytes: pixelLineOop) ifFalse:[^interpreterProxy primitiveFail]. formBitsSize := interpreterProxy slotSizeOf: formBitsOop. formBits := interpreterProxy firstIndexableField: formBitsOop. pixelLineSize := interpreterProxy slotSizeOf: pixelLineOop. pixelLine := interpreterProxy firstIndexableField: pixelLineOop. (formBitsIndex + width <= formBitsSize and:[width*3 <= pixelLineSize]) ifFalse:[^interpreterProxy primitiveFail]. "do the actual work. Read 32 bit at a time from formBits, and store the low order 24 bits or each word into pixelLine in little endian order." self cCode:' formBits += formBitsIndex-1; while(width--) { unsigned int rgb; rgb = *formBits++; (*pixelLine++) = (rgb ) & 0xFF; (*pixelLine++) = (rgb >> 8 ) & 0xFF; (*pixelLine++) = (rgb >> 16) & 0xFF; } ' inSmalltalk:[formBits. pixelLine. ^interpreterProxy primitiveFail]. interpreterProxy pop: 4. "args" ! ! InterpreterPlugin subclass: #BalloonEngineBase instanceVariableNames: 'workBuffer objBuffer getBuffer aetBuffer spanBuffer engine formArray engineStopped geProfileTime dispatchedValue dispatchReturnValue objUsed doProfileStats copyBitsFn loadBBFn bbPluginName' classVariableNames: 'EdgeInitTable EdgeStepTable FillTable WideLineFillTable WideLineWidthTable' poolDictionaries: 'BalloonEngineConstants' category: 'VMMaker-Plugins'! !BalloonEngineBase commentStamp: 'tpr 5/5/2003 11:45' prior: 0! This is the main class for the Balloon graphics Engine. BalloonEnginePlugin should be translated but its superclass should not since it is incorporated within that class's translation process. Nor should the simulation subclass be translated! !BalloonEngineBase class methodsFor: 'documentation' stamp: 'ar 11/7/1998 03:33'! a1EngineOutline "The following is a brief outline on how the engine works. In general, we're using a pretty straight-forward active edge approach, e.g., we classify all edges into three different states: a) Waiting for processing b) Active (e.g., being processed) c) Finished Before the engine starts all edges are sorted by their y-value in a so-called 'global edge table' (furthermore referred to as GET) and processed in top to bottom order (the edges are also sorted by x-value but this is only for simplifying the insertion when adding edges). Then, we start at the first visible scan line and execute the following steps: 1) Move all edges starting at the current scan line from state a) to state b) This step requires the GET to be sorted so that we only need to check the first edges of the GET. After the initial state of the edge (e.g., it's current pixel value and data required for incremental updates) the edges are then inserted in the 'active edge table' (called AET). The sort order in the AET is defined by the pixel position of each edge at the current scan line and thus edges are kept in increasing x-order. This step does occur for every edge only once and is therefore not the most time-critical part of the approach. 2) Draw the current scan line This step includes two sub-parts. In the first part, the scan line is assembled. This involves walking through the AET and drawing the pixels between each two neighbour edges. Since each edge can have two associated fills (a 'left' and a 'right' fill) we need to make sure that edges falling on the same pixel position do not affect the painted image. This issue is discussed in the aetScanningProblems documentation. Wide edges (e.g., edges having an associated width) are also handled during this step. Wide edges are always preferred over interior fills - this ensures that the outline of an object cannot be overdrawn by any interior fill of a shape that ends very close to the edge (for more information see wideEdges documentation). After the scan is assembled it is blitted to the screen. This only happens all 'aaLevel' scan lines (for further information see the antiAliasing documentation). This second step is done at each scan line in the image, and is usually the most time-critical part. 3) Update all currently active edges Updating the active edges basically means either to remove the edge from the AET (if it is at the end y value) or incrementally computing the pixel value for the next scan line. Based on the information gathered in the first step, this part should be executed as fast as possible - it happens for each edge in the AET at each scan line and may be the bottleneck if many edges are involved in the drawing operations (see the TODO list; part of it probably deals with the issue). " ^self error:'Comment only'! ! !BalloonEngineBase class methodsFor: 'documentation' stamp: 'ar 11/7/1998 03:55'! a2AntiAliasing "The engine currently used a very simple, but efficient anti-aliasing scheme. It is based on a square unweighted filter of size 1, 2, or 4 resulting in three levels of anti-aliasing: * No anti-aliasing (filter size 1) This simply draws each pixel 'as is' on the screen * Slight anti-aliasing (filter size 2) Doubles the rasterization size in each direction and assembles the pixel value as the medium of the four sub-pixels falling into the full pixel * Full anti-aliasing (filter size 4) Quadruples the rasterization in each direction and assembles the pixel value as the medium of the sixteen sub-pixels falling into the full pixel The reason for using these three AA levels is simply efficiency of computing. Since the above filters (1x1, 2x2, 4x4) have all power of two elements (1, 4, and 16) we can compute the weighted sum of the final pixel by computing destColor := destColor + (srcColor // subPixels) And, since we're only working on 32bit destination buffer we do not need to compute the components of each color separately but can neatly put the entire color into a single formula: destPixel32 := destPixel32 + ((srcPixel32 bitAnd: aaMask) >> aaShift). with aaMask = 16rFFFFFFFF for aaLevel = 1, aaMask = 16rFCFCFCFC for aaLevel = 2, aaMask = 16rF0F0F0F0 for aaLevel = 4 and aaShift = 0, 2, or 4 for the different levels. However, while the above is efficient to compute, it also drops accuracy. So, for the 4x4 anti-aliasing we're effectively only using the high 4 bits of each color component. While is generally not a problem (we add 16 sub-pixels into this value) there is a simple arithmetic difficulty because the above cannot fill the entire range of values, e.g., 16 * (255 // 16) = 16 * 15 = 240 and not 255 as expected. We solve this problem by replicating the top n (n=0, 2, 4) bits of each component as the low bits in an adjustment step before blitting to scan line to the screen. This has the nice effect that a zero pixel value (e.g., transparent) will remain zero, a white pixel (as computed above) will result in a value of 255 for each component (defining opaque white) and each color inbetween linearly mapped between 0 and 255. " ^self error:'Comment only'! ! !BalloonEngineBase class methodsFor: 'documentation' stamp: 'ar 11/7/1998 03:35'! a3RasterizationRules ^self error:'Comment only'! ! !BalloonEngineBase class methodsFor: 'documentation' stamp: 'ar 11/7/1998 03:35'! a4WideEdges! ! !BalloonEngineBase class methodsFor: 'documentation' stamp: 'ar 11/7/1998 03:36'! a5AETScanningProblems "Due to having two fill entries (one left and one right) there can be problems while scanning the active edge table. In general, the AET should look like the following (ri - regions, ei - edges, fi - fills): | \ | r1 | r2 \ r3 | r4 | \ | e1 e2 e3 with: f(r1) = fLeft(e1) = 0 (empty fill, denoted -) f(r2) = fRight(e1) = fLeft(e2) (denoted x) f(r3) = fRight(e2) = fLeft(e3) (denoted o) f(r4) = fRight(e3) = 0 However, due to integer arithmetic used during computations the AET may look like the following: X \| | | \ | | \ | r1 | r2 \ r3 | r4 | \ | e1 e2 e3 In this case, the starting point of e1 and e2 have the same x value at the first scan line but e2 has been sorted before e1 (Note: This can happen in *many* cases - the above is just a very simple example). Given the above outlined fill relations we have a problem. So, for instance, using the left/right fills as defined by the edges would lead to the effect that in the first scan line region r3 is actually filled with the right fill of e1 while it should actually be filled with the right fill of e2. This leads to noticable artifacts in the image and increasing resolution does not help. What we do here is defining an arbitrary sort order between fills (you can think of it as a depth value but the only thing that matters is that you can order the fills by this number and that the empty fill is always sorted at the end), and toggle the fills between an 'active' and an 'inactive' state at each edge. This is done as follows: For each edge ei in the AET do: * if fLeft(ei) isActive then removeActive(fLeft(ei)) else addActive(fLeft(ei)) * if fRight(ei) isActive then removeActive(fRight(ei)) else addActive(fRight(ei)) * draw the span from ei to ei+1 with currentActive where addActive adds the fill to the list of currently active fills, removeActive() removes the fill from the active list and currentActive returns the fill AS DEFINED BY THE SORT ORDER from the list of active fills. Note that this does not change anything in the first example above because the list will only contain one entry (besides the empty fill). In the second case however, it will lead to the following sequence: * toggle fLeft(e2) = f(r2) = 'x' - makes fLeft(e2) active - activeList = 'x' * toggle fRight(e2) = f(r3) = 'o' - makes fRight(e2) active - activeList = 'xo' * draw span from e2 to e1 Depending on the sort order between 'x' and 'o' the region will be drawn with either one of the fills. It is significant to note here that the occurence of such a problem is generally only *very* few pixels large (in the above example zero pixels) and will therefore not be visually noticable. In any case, there is a unique decision for the fill to use here and that is what we need if the problem did not happen accidentally (e.g., someone has manually changed one fill of an edge but not the fill of the opposite edge). * toggle fLeft(e1) = f(r1) = '-' - makes fLeft(r1) visible - activeList = 'xo-' [Note: empty fills are a special case. They can be ignored since they sort last and the activeList can return the empty fill if it is itself empty]. * toggle fRight(e1) = f(r2) = 'x' - makes fRight(e1) invisible - activeList = 'o-' * draw span from e2 to e3 Since the active list contains (besides the empty fill) only one fill value this will be used. Fortunately, this is the correct fill because it is the fill we had initially defined for the region r2. An interesting side effect of the above is that there is no such notion as a 'left' or 'right' fill anymore. Another (not-so-nice) side effect is that the entire AET has to be scanned from the beginning even if only the last few edges actually affect the visible region. PS. I need to find a way of clipping the edges for this. More on it later... " ^self error:'Comment only'! ! !BalloonEngineBase class methodsFor: 'documentation' stamp: 'ar 11/8/1998 00:06'! a6StuffTODO "This is an unordered list of things to do: BalloonEnginePlugin>>stepToFirstBezierIn:at: 1) Check if reducing maxSteps from 2*deltaY to deltaY brings a *significant* performance improvement. In theory this should make for double step performance but will cost in quality. Might be that the AA stuff will compensate for this - but I'm not really sure. BalloonEngineBase>>dispatchOn:in: 1) Check what dispatches cost most and must be inlined by an #inlinedDispatchOn:in: Probably this will be stepping and eventually wide line stuff but we'll see. BalloonEngineBase 1) Check which variables should become inst vars, if any. This will remove an indirection during memory access and might allow a couple of optimizations by the C compiler. Anti-Aliasing: 1) Check if we can use a weighted 3x3 filter function of the form 1 2 1 2 4 2 1 2 1 Which should be *extremely* nice for fonts (it's sharpening edges). The good thing about the above is that it sums up to 16 (as in the 4x4 case) but I don't know how to keep a history without needing two extra scan lines. 2) Check if we can - somehow - integrate more general filters. 3) Unroll the loops during AA so we can copy and mask aaLevel pixels in each step between start and end. This should speed up filling by a factor of 2-4 (in particular for difficult stuff like radial gradients). Clipping 1) Find a way of clipping edges left of the clip rectangle or at least ignoring most of them after the first scan line. The AET scanning problems discuss the issue but it should be possible to keep the color list between spans (if not empty) and speed up drawing at the very right (such as in the Winnie Pooh example where a lot of stuff is between the left border and the clipping rect. 2) Check if we can determine empty states of the color list and an edge that is longer than anything left of it. This should work in theory but might be relatively expensive to compute. " ^self error:'Comment only'! ! !BalloonEngineBase class methodsFor: 'translation' stamp: 'ikp 6/14/2004 15:19'! declareCVarsIn: cg "Buffers" cg var: #workBuffer type: #'int*'. cg var: #objBuffer type: #'int*'. cg var: #getBuffer type: #'int*'. cg var: #aetBuffer type: #'int*'. cg var: #spanBuffer type: #'unsigned int*'. cg var: #edgeTransform declareC: 'float edgeTransform[6]'. cg var: #doProfileStats declareC: 'int doProfileStats = 0'. cg var: 'bbPluginName' declareC:'char bbPluginName[256] = "BitBltPlugin"'. "Functions" cg var: 'copyBitsFn' type: 'void *'. cg var: 'loadBBFn' type: 'void *'.! ! !BalloonEngineBase class methodsFor: 'class initialization' stamp: 'ar 11/7/1998 22:26'! initialize "BalloonEngineBase initialize" "BalloonEnginePlugin translateDoInlining: true." EdgeInitTable := self initializeEdgeInitTable. EdgeStepTable := self initializeEdgeStepTable. WideLineWidthTable := self initializeWideLineWidthTable. WideLineFillTable := self initializeWideLineFillTable. FillTable := self initializeFillTable.! ! !BalloonEngineBase class methodsFor: 'class initialization' stamp: 'ar 11/4/1998 21:52'! initializeEdgeInitTable "BalloonEngineBase initialize" ^#( errorWrongIndex errorWrongIndex errorWrongIndex errorWrongIndex stepToFirstLine stepToFirstWideLine stepToFirstBezier stepToFirstWideBezier )! ! !BalloonEngineBase class methodsFor: 'class initialization' stamp: 'ar 11/4/1998 21:52'! initializeEdgeStepTable "BalloonEngineBase initialize" ^#( errorWrongIndex errorWrongIndex errorWrongIndex errorWrongIndex stepToNextLine stepToNextWideLine stepToNextBezier stepToNextWideBezier )! ! !BalloonEngineBase class methodsFor: 'class initialization' stamp: 'ar 11/25/1998 19:46'! initializeFillTable "BalloonEngineBase initialize" ^#( errorWrongIndex "Type zero - undefined" errorWrongIndex "Type one - external fill" fillLinearGradient "Linear gradient fill" fillRadialGradient "Radial gradient fill" fillBitmapSpan "Clipped bitmap fill" fillBitmapSpan "Repeated bitmap fill" )! ! !BalloonEngineBase class methodsFor: 'class initialization' stamp: 'ar 11/4/1998 23:03'! initializeWideLineFillTable "BalloonEngineBase initialize" ^#( errorWrongIndex errorWrongIndex returnWideLineFill returnWideBezierFill )! ! !BalloonEngineBase class methodsFor: 'class initialization' stamp: 'ar 11/4/1998 23:03'! initializeWideLineWidthTable "BalloonEngineBase initialize" ^#( errorWrongIndex errorWrongIndex returnWideLineWidth returnWideBezierWidth )! ! !BalloonEngineBase class methodsFor: 'accessing' stamp: 'ar 5/11/2000 23:48'! moduleName ^'B2DPlugin'! ! !BalloonEngineBase class methodsFor: 'translation' stamp: 'tpr 5/14/2001 12:14'! shouldBeTranslated "BalloonEnginePlugin should be translated but its superclasse should not since it is incorporated within this class's translation process. Nor should the simulation subclass be translated" ^self == BalloonEnginePlugin! ! !BalloonEngineBase class methodsFor: 'accessing' stamp: 'ar 11/11/1998 21:56'! simulatorClass ^BalloonEngineSimulation! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 00:34'! aaColorMaskGet ^workBuffer at: GWAAColorMask! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 00:34'! aaColorMaskPut: value ^workBuffer at: GWAAColorMask put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 00:34'! aaColorShiftGet ^workBuffer at: GWAAColorShift! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 00:34'! aaColorShiftPut: value ^workBuffer at: GWAAColorShift put: value! ! !BalloonEngineBase methodsFor: 'displaying' stamp: 'ar (auto pragmas 12/08) 11/9/1998 00:53'! aaFirstPixelFrom: leftX to: rightX "Common function to compute the first full pixel for AA drawing" | firstPixel | firstPixel := (leftX + self aaLevelGet - 1) bitAnd: (self aaLevelGet - 1) bitInvert32. firstPixel > rightX ifTrue:[^rightX] ifFalse:[^firstPixel]! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 00:34'! aaHalfPixelGet ^workBuffer at: GWAAHalfPixel! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 00:35'! aaHalfPixelPut: value ^workBuffer at: GWAAHalfPixel put: value! ! !BalloonEngineBase methodsFor: 'displaying' stamp: 'ar (auto pragmas 12/08) 11/9/1998 00:53'! aaLastPixelFrom: leftX to: rightX "Common function to compute the last full pixel for AA drawing" ^(rightX - 1) bitAnd: (self aaLevelGet - 1) bitInvert32.! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 00:35'! aaLevelGet ^workBuffer at: GWAALevel! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 00:35'! aaLevelPut: value ^workBuffer at: GWAALevel put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 00:35'! aaScanMaskGet ^workBuffer at: GWAAScanMask! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 00:35'! aaScanMaskPut: value ^workBuffer at: GWAAScanMask put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 00:35'! aaShiftGet ^workBuffer at: GWAAShift! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 00:36'! aaShiftPut: value ^workBuffer at: GWAAShift put: value! ! !BalloonEngineBase methodsFor: 'other' stamp: 'ar 11/9/1998 02:06'! accurateLengthOf: deltaX with: deltaY "Return the accurate length of the vector described by deltaX and deltaY" | length2 | deltaX = 0 ifTrue:[deltaY < 0 ifTrue:[^0-deltaY] ifFalse:[^deltaY]]. deltaY = 0 ifTrue:[deltaX < 0 ifTrue:[^0-deltaX] ifFalse:[^deltaX]]. length2 := (deltaX * deltaX) + (deltaY * deltaY). ^self computeSqrt: length2! ! !BalloonEngineBase methodsFor: 'GET processing' stamp: 'ar (auto pragmas 12/08) 11/1/1998 01:07'! addEdgeToGET: edge (self allocateGETEntry: 1) ifFalse:[^0]. "Install edge in the GET" getBuffer at: self getUsedGet put: edge. self getUsedPut: self getUsedGet + 1.! ! !BalloonEngineBase methodsFor: 'displaying' stamp: 'ar (auto pragmas 12/08) 11/9/1998 00:50'! adjustAALevel "NOTE: This method is (hopefully) obsolete due to unrolling the fill loops to deal with full pixels." "Adjust the span buffers values by the appropriate color offset for anti-aliasing. We do this by replicating the top bits of each color in the lower bits. The idea is that we can scale each color value uniquely from 0 to 255 and thus fill the entire range of colors." | adjustShift adjustMask x0 x1 pixelValue | adjustShift := 8 - self aaColorShiftGet. adjustMask := self aaColorMaskGet bitInvert32. x0 := self spanStartGet >> self aaShiftGet. x1 := self spanEndGet >> self aaShiftGet. [x0 < x1] whileTrue:[ pixelValue := spanBuffer at: x0. spanBuffer at: x0 put: (pixelValue bitOr: (pixelValue >> adjustShift bitAnd: adjustMask)). x0 := x0 + 1].! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:27'! aetStartGet ^workBuffer at: GWAETStart! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:29'! aetStartPut: value ^workBuffer at: GWAETStart put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:27'! aetUsedGet ^workBuffer at: GWAETUsed! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:29'! aetUsedPut: value ^workBuffer at: GWAETUsed put: value! ! !BalloonEngineBase methodsFor: 'allocating' stamp: 'ar 10/29/1998 18:37'! allocateAETEntry: nSlots "Allocate n slots in the active edge table" ^self needAvailableSpace: nSlots! ! !BalloonEngineBase methodsFor: 'allocating' stamp: 'ar (auto pragmas 12/08) 10/28/1998 21:06'! allocateGETEntry: nSlots "Allocate n slots in the global edge table" | srcIndex dstIndex | "First allocate nSlots in the AET" (self allocateAETEntry: nSlots) ifFalse:[^false]. self aetUsedGet = 0 ifFalse:["Then move the AET upwards" srcIndex := self aetUsedGet. dstIndex := self aetUsedGet + nSlots. 1 to: self aetUsedGet do:[:i| aetBuffer at: (dstIndex := dstIndex - 1) put: (aetBuffer at: (srcIndex := srcIndex - 1))]. ]. aetBuffer := aetBuffer + nSlots. ^true! ! !BalloonEngineBase methodsFor: 'allocating' stamp: 'ar (auto pragmas 12/08) 10/28/1998 21:16'! allocateObjEntry: nSlots "Allocate n slots in the object buffer" | srcIndex dstIndex | "First allocate nSlots in the GET" (self allocateGETEntry: nSlots) ifFalse:[^false]. self getUsedGet = 0 ifFalse:["Then move the GET upwards" srcIndex := self getUsedGet. dstIndex := self getUsedGet + nSlots. 1 to: self getUsedGet do:[:i| getBuffer at: (dstIndex := dstIndex - 1) put: (getBuffer at: (srcIndex := srcIndex - 1))]. ]. getBuffer := getBuffer + nSlots. ^true! ! !BalloonEngineBase methodsFor: 'allocating' stamp: 'ar 10/29/1998 18:37'! allocateStackEntry: nSlots "AET and Stack allocation are symmetric" ^self needAvailableSpace: nSlots! ! !BalloonEngineBase methodsFor: 'allocating' stamp: 'ar 10/30/1998 19:24'! allocateStackFillEntry ^self wbStackPush: self stackFillEntryLength! ! !BalloonEngineBase methodsFor: 'testing' stamp: 'ar 11/9/1998 15:34'! areEdgeFillsValid: edge ^((self objectHeaderOf: edge) bitAnd: GEEdgeFillsInvalid) = 0! ! !BalloonEngineBase methodsFor: 'displaying' stamp: 'ar (auto pragmas 12/08) 11/14/1998 19:31'! clearSpanBuffer "Clear the current span buffer. The span buffer is only cleared in the area that has been used by the previous scan line." | x0 x1 | x0 := self spanStartGet >> self aaShiftGet. x1 := self spanEndGet >> self aaShiftGet + 1. x0 < 0 ifTrue:[x0 := 0]. x1 > self spanSizeGet ifTrue:[x1 := self spanSizeGet]. [x0 < x1] whileTrue:[ spanBuffer at: x0 put: 0. x0 := x0 + 1]. self spanStartPut: self spanSizeGet. self spanEndPut: 0.! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/29/1998 00:43'! clearSpanBufferGet ^workBuffer at: GWClearSpanBuffer! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/29/1998 00:44'! clearSpanBufferPut: value ^workBuffer at: GWClearSpanBuffer put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 18:46'! clipMaxXGet ^workBuffer at: GWClipMaxX! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 18:46'! clipMaxXPut: value ^workBuffer at: GWClipMaxX put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 18:46'! clipMaxYGet ^workBuffer at: GWClipMaxY! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 18:46'! clipMaxYPut: value ^workBuffer at: GWClipMaxY put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 18:46'! clipMinXGet ^workBuffer at: GWClipMinX! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 18:47'! clipMinXPut: value ^workBuffer at: GWClipMinX put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 18:47'! clipMinYGet ^workBuffer at: GWClipMinY! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 18:47'! clipMinYPut: value ^workBuffer at: GWClipMinY put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar (auto pragmas dtl 2010-09-27) 11/24/1998 21:36'! colorTransform ^self cCoerce: workBuffer + GWColorTransform to:'float *'! ! !BalloonEngineBase methodsFor: 'other' stamp: 'ar 11/7/1998 14:26'! computeSqrt: length2 length2 < 32 ifTrue:[^self smallSqrtTable at: length2] ifFalse:[^(length2 asFloat sqrt + 0.5) asInteger]! ! !BalloonEngineBase methodsFor: 'private' stamp: 'ikp 6/14/2004 15:14'! copyBitsFrom: x0 to: x1 at: yValue copyBitsFn = 0 ifTrue: [ "We need copyBits here so try to load it implicitly" self initialiseModule ifFalse: [^false]. ]. ^self cCode: '((sqInt (*)(sqInt, sqInt, sqInt))copyBitsFn)(x0, x1, yValue)'! ! !BalloonEngineBase methodsFor: 'GET processing' stamp: 'ar (auto pragmas 12/08) 11/25/1998 00:41'! createGlobalEdgeTable "Create the global edge table" | object end | object := 0. end := objUsed. [object < end] whileTrue:[ "Note: addEdgeToGET: may fail on insufficient space but that's not a problem here" (self isEdge: object) ifTrue:[ "Check if the edge starts below fillMaxY." (self edgeYValueOf: object) >= self fillMaxYGet ifFalse:[ self checkedAddEdgeToGET: object. ]. ]. object := object + (self objectLengthOf: object). ].! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:27'! currentYGet ^workBuffer at: GWCurrentY! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 21:27'! currentYPut: value ^workBuffer at: GWCurrentY put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 11/24/1998 20:28'! currentZGet ^workBuffer at: GWCurrentZ! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 11/24/1998 20:29'! currentZPut: value ^workBuffer at: GWCurrentZ put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/29/1998 16:23'! destOffsetXGet ^workBuffer at: GWDestOffsetX! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/29/1998 16:24'! destOffsetXPut: value ^workBuffer at: GWDestOffsetX put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/29/1998 16:23'! destOffsetYGet ^workBuffer at: GWDestOffsetY! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/29/1998 16:24'! destOffsetYPut: value ^workBuffer at: GWDestOffsetY put: value! ! !BalloonEngineBase methodsFor: 'displaying' stamp: 'ar (auto pragmas 12/08) 5/12/2000 16:42'! displaySpanBufferAt: y "Display the span buffer at the current scan line." | targetX0 targetX1 targetY | "self aaLevelGet > 1 ifTrue:[self adjustAALevel]." targetX0 := self spanStartGet >> self aaShiftGet. targetX0 < self clipMinXGet ifTrue:[targetX0 := self clipMinXGet]. targetX1 := (self spanEndGet + self aaLevelGet - 1) >> self aaShiftGet. targetX1 > self clipMaxXGet ifTrue:[targetX1 := self clipMaxXGet]. targetY := y >> self aaShiftGet. (targetY < self clipMinYGet or:[targetY >= self clipMaxYGet or:[ targetX1 < self clipMinXGet or:[targetX0 >= self clipMaxXGet]]]) ifTrue:[^0]. self copyBitsFrom: targetX0 to: targetX1 at: targetY.! ! !BalloonEngineBase methodsFor: 'displaying' stamp: 'ar (auto pragmas 12/08) 11/25/1998 02:34'! drawWideEdge: edge from: leftX "Draw the given edge starting from leftX with the edge's fill. Return the end value of the drawing operation." | rightX fill type lineWidth | "Not for the moment" type := self edgeTypeOf: edge. dispatchedValue := edge. self dispatchOn: type in: WideLineWidthTable. lineWidth := dispatchReturnValue. self dispatchOn: type in: WideLineFillTable. fill := self makeUnsignedFrom: dispatchReturnValue. fill = 0 ifTrue:[^leftX]. "Check if this line is only partially visible" "self assert:(self isFillColor: fill)." rightX := leftX + lineWidth. self fillSpan: fill from: leftX to: rightX. ^rightX! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/9/1998 15:35'! edgeFillsInvalidate: edge ^self objectTypeOf: edge put: ((self objectTypeOf: edge) bitOr: GEEdgeFillsInvalid)! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/9/1998 15:35'! edgeFillsValidate: edge ^self objectTypeOf: edge put: ((self objectTypeOf: edge) bitAnd: GEEdgeFillsInvalid bitInvert32)! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/24/1998 22:04'! edgeLeftFillOf: edge ^self obj: edge at: GEFillIndexLeft! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/24/1998 22:04'! edgeLeftFillOf: edge put: value ^self obj: edge at: GEFillIndexLeft put: value! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/24/1998 22:04'! edgeNumLinesOf: edge ^self obj: edge at: GENumLines! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/24/1998 22:04'! edgeNumLinesOf: edge put: value ^self obj: edge at: GENumLines put: value! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/24/1998 22:05'! edgeRightFillOf: edge ^self obj: edge at: GEFillIndexRight! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/24/1998 22:05'! edgeRightFillOf: edge put: value ^self obj: edge at: GEFillIndexRight put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar (auto pragmas dtl 2010-09-27) 11/24/1998 21:36'! edgeTransform ^self cCoerce: workBuffer + GWEdgeTransform to:'float *'! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/9/1998 15:35'! edgeTypeOf: edge "Return the edge type (e.g., witout the wide edge flag)" ^(self objectTypeOf: edge) >> 1! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/24/1998 22:05'! edgeXValueOf: edge ^self obj: edge at: GEXValue! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/24/1998 22:05'! edgeXValueOf: edge put: value ^self obj: edge at: GEXValue put: value! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/24/1998 22:05'! edgeYValueOf: edge ^self obj: edge at: GEYValue! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/24/1998 22:06'! edgeYValueOf: edge put: value ^self obj: edge at: GEYValue put: value! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/24/1998 22:06'! edgeZValueOf: edge ^self obj: edge at: GEZValue! ! !BalloonEngineBase methodsFor: 'accessing edges' stamp: 'ar 11/24/1998 22:06'! edgeZValueOf: edge put: value ^self obj: edge at: GEZValue put: value! ! !BalloonEngineBase methodsFor: 'private' stamp: 'ar 5/13/2000 14:55'! errorWrongIndex "Ignore dispatch errors when translating to C (since we have no entry point for #error in the VM proxy)" self cCode:'' inSmalltalk:[self error:'BalloonEngine: Fatal dispatch error']! ! !BalloonEngineBase methodsFor: 'other' stamp: 'ar 11/8/1998 14:33'! estimatedLengthOf: deltaX with: deltaY "Estimate the length of the vector described by deltaX and deltaY. This method may be extremely inaccurate - use it only if you know exactly that this doesn't matter. Otherwise use #accurateLengthOf:width:" | absDx absDy | deltaX >= 0 ifTrue:[absDx := deltaX] ifFalse:[absDx := 0 - deltaX]. deltaY >= 0 ifTrue:[absDy := deltaY] ifFalse:[absDy := 0 - deltaY]. absDx > absDy ifTrue:[^absDx + (absDy // 2)] ifFalse:[^absDy + (absDx // 2)] ! ! !BalloonEngineBase methodsFor: 'displaying' stamp: 'ar (auto pragmas 12/08) 11/25/1998 15:12'! fillAllFrom: leftX to: rightX "Fill the span buffer from leftX to rightX with the given fill." | fill startX stopX | fill := self topFill. startX := leftX. stopX := self topRightX. [stopX < rightX] whileTrue:[ fill := self makeUnsignedFrom: self topFill. fill = 0 ifFalse:[ (self fillSpan: fill from: startX to: stopX) ifTrue:[^true]]. self quickRemoveInvalidFillsAt: stopX. startX := stopX. stopX := self topRightX]. fill := self makeUnsignedFrom: self topFill. fill = 0 ifFalse:[^self fillSpan: fill from: startX to: rightX]. ^false! ! !BalloonEngineBase methodsFor: 'displaying' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 14:20'! fillBitmapSpan: bits from: leftX to: rightX "Fill the span buffer between leftEdge and rightEdge using the given bits. Note: We always start from zero - this avoids using huge bitmap buffers if the bitmap is to be displayed at the very far right hand side and also gives us a chance of using certain bitmaps (e.g., those with depth 32) directly." | x0 x1 x bitX colorMask colorShift baseShift fillValue | x0 := leftX. x1 := rightX. bitX := -1. "Hack for pre-increment" self aaLevelGet = 1 ifTrue:["Speedy version for no anti-aliasing" [x0 < x1] whileTrue:[ fillValue := (self cCoerce: bits to: 'int *') at: (bitX := bitX + 1). spanBuffer at: x0 put: fillValue. x0 := x0 + 1. ]. ] ifFalse:["Generic version with anti-aliasing" colorMask := self aaColorMaskGet. colorShift := self aaColorShiftGet. baseShift := self aaShiftGet. [x0 < x1] whileTrue:[ x := x0 >> baseShift. fillValue := (self cCoerce: bits to: 'int *') at: (bitX := bitX + 1). fillValue := (fillValue bitAnd: colorMask) >> colorShift. spanBuffer at: x put: (spanBuffer at: x) + fillValue. x0 := x0 + 1. ]. ]. x1 > self spanEndGet ifTrue:[self spanEndPut: x1]. x1 > self spanEndAAGet ifTrue:[self spanEndAAPut: x1].! ! !BalloonEngineBase methodsFor: 'displaying' stamp: 'ar (auto pragmas 12/08) 11/8/1998 03:30'! fillColorSpan: pixelValue32 from: leftX to: rightX "Fill the span buffer between leftEdge and rightEdge with the given pixel value." | x0 x1 | "Use a unrolled version for anti-aliased fills..." self aaLevelGet = 1 ifFalse:[^self fillColorSpanAA: pixelValue32 x0: leftX x1: rightX]. x0 := leftX. x1 := rightX. "Unroll the inner loop four times, since we're only storing data." [x0 + 4 < x1] whileTrue:[ spanBuffer at: x0 put: pixelValue32. spanBuffer at: x0+1 put: pixelValue32. spanBuffer at: x0+2 put: pixelValue32. spanBuffer at: x0+3 put: pixelValue32. x0 := x0+4. ]. [x0 < x1] whileTrue:[ spanBuffer at: x0 put: pixelValue32. x0 := x0 + 1. ].! ! !BalloonEngineBase methodsFor: 'displaying' stamp: 'ar (auto pragmas 12/08) 11/9/1998 00:52'! fillColorSpanAA: pixelValue32 x0: leftX x1: rightX "This is the inner loop for solid color fills with anti-aliasing. This loop has been unrolled for speed and quality into three parts: a) copy all pixels that fall into the first full pixel. b) copy aaLevel pixels between the first and the last full pixel c) copy all pixels that fall in the last full pixel" | colorMask baseShift x idx firstPixel lastPixel aaLevel pv32 | "Not now -- maybe later" "Compute the pixel boundaries." firstPixel := self aaFirstPixelFrom: leftX to: rightX. lastPixel := self aaLastPixelFrom: leftX to: rightX. aaLevel := self aaLevelGet. baseShift := self aaShiftGet. x := leftX. "Part a: Deal with the first n sub-pixels" x < firstPixel ifTrue:[ pv32 := (pixelValue32 bitAnd: self aaColorMaskGet) >> self aaColorShiftGet. [x < firstPixel] whileTrue:[ idx := x >> baseShift. spanBuffer at: idx put: (spanBuffer at: idx) + pv32. x := x + 1. ]. ]. "Part b: Deal with the full pixels" x < lastPixel ifTrue:[ colorMask := (self aaColorMaskGet >> self aaShiftGet) bitOr: 16rF0F0F0F0. pv32 := (pixelValue32 bitAnd: colorMask) >> self aaShiftGet. [x < lastPixel] whileTrue:[ idx := x >> baseShift. spanBuffer at: idx put: (spanBuffer at: idx) + pv32. x := x + aaLevel. ]. ]. "Part c: Deal with the last n sub-pixels" x < rightX ifTrue:[ pv32 := (pixelValue32 bitAnd: self aaColorMaskGet) >> self aaColorShiftGet. [x < rightX] whileTrue:[ idx := x >> baseShift. spanBuffer at: idx put: (spanBuffer at: idx) + pv32. x := x + 1. ]. ].! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:27'! fillMaxXGet ^workBuffer at: GWFillMaxX! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:29'! fillMaxXPut: value ^workBuffer at: GWFillMaxX put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:27'! fillMaxYGet ^workBuffer at: GWFillMaxY! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:30'! fillMaxYPut: value ^workBuffer at: GWFillMaxY put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:27'! fillMinXGet ^workBuffer at: GWFillMinX! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:30'! fillMinXPut: value ^workBuffer at: GWFillMinX put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:27'! fillMinYGet ^workBuffer at: GWFillMinY! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:30'! fillMinYPut: value ^workBuffer at: GWFillMinY put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:27'! fillOffsetXGet ^workBuffer at: GWFillOffsetX! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:30'! fillOffsetXPut: value ^workBuffer at: GWFillOffsetX put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:27'! fillOffsetYGet ^workBuffer at: GWFillOffsetY! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:30'! fillOffsetYPut: value ^workBuffer at: GWFillOffsetY put: value! ! !BalloonEngineBase methodsFor: 'FILL processing' stamp: 'ar (auto pragmas 12/08) 11/24/1998 22:42'! fillSorts: fillEntry1 before: fillEntry2 "Return true if fillEntry1 should be drawn before fillEntry2" | diff | "First check the depth value" diff := (self stackFillDepth: fillEntry1) - (self stackFillDepth: fillEntry2). diff = 0 ifFalse:[^diff > 0]. "See the class comment for aetScanningProblems" ^(self cCoerce: (self makeUnsignedFrom: (self stackFillValue: fillEntry1)) to:'unsigned') < (self cCoerce: (self makeUnsignedFrom: (self stackFillValue: fillEntry2)) to: 'unsigned')! ! !BalloonEngineBase methodsFor: 'displaying' stamp: 'ikp (auto pragmas 12/08) 8/9/2004 18:22'! fillSpan: fill from: leftX to: rightX "Fill the span buffer from leftX to rightX with the given fill. Clip before performing any operations. Return true if the fill must be handled by some Smalltalk code." | x0 x1 type | fill = 0 ifTrue:[^false]. "Nothing to do" "Start from spEnd - we must not paint pixels twice at a scan line" leftX < self spanEndAAGet ifTrue:[x0 := self spanEndAAGet] ifFalse:[x0 := leftX]. rightX > (self spanSizeGet << self aaShiftGet) ifTrue:[x1 := (self spanSizeGet << self aaShiftGet)] ifFalse:[x1 := rightX]. "Clip left and right values" x0 < self fillMinXGet ifTrue:[x0 := self fillMinXGet]. x1 > self fillMaxXGet ifTrue:[x1 := self fillMaxXGet]. "Adjust start and end values of span" x0 < self spanStartGet ifTrue:[self spanStartPut: x0]. x1 > self spanEndGet ifTrue:[self spanEndPut: x1]. x1 > self spanEndAAGet ifTrue:[self spanEndAAPut: x1]. x0 >= x1 ifTrue:[^false]. "Nothing to do" (self isFillColor: fill) ifTrue:[ self fillColorSpan: fill from: x0 to: x1. ] ifFalse:[ "Store the values for the dispatch" self lastExportedFillPut: fill. self lastExportedLeftXPut: x0. self lastExportedRightXPut: x1. type := self fillTypeOf: fill. type <= 1 ifTrue:[^true]. self dispatchOn: type in: FillTable. ]. ^false! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 11/7/1998 22:25'! fillTypeOf: fill ^((self objectTypeOf: fill) bitAnd: GEPrimitiveFillMask) >> 8! ! !BalloonEngineBase methodsFor: 'AET processing' stamp: 'ar 11/24/1998 22:47'! findNextAETEdgeFrom: leftEdge | depth rightEdge | depth := self edgeZValueOf: leftEdge. [self aetStartGet < self aetUsedGet] whileTrue:[ rightEdge := aetBuffer at: self aetStartGet. (self edgeZValueOf: rightEdge) >= depth ifTrue:[^rightEdge]. self aetStartPut: self aetStartGet + 1. ]. ^nil! ! !BalloonEngineBase methodsFor: 'GET processing' stamp: 'ar 11/9/1998 15:36'! findNextExternalEntryFromGET "Check the global edge table for any entries that cannot be handled by the engine itself. If there are any, return true. Otherwise, initialize the the edge and add it to the AET" | yValue edge type | yValue := self currentYGet. "As long as we have entries in the GET" [self getStartGet < self getUsedGet] whileTrue:[ edge := getBuffer at: self getStartGet. (self edgeYValueOf: edge) > yValue ifTrue:[^false]. "No more edges to add" type := self objectTypeOf: edge. (type bitAnd: GEPrimitiveWideMask) = GEPrimitiveEdge ifTrue:[^true]. "This is an external edge" "Note: We must make sure not to do anything with the edge if there is not enough room in the AET" (self needAvailableSpace: 1) ifFalse:[^false]. "No more room" "Process the edge in the engine itself" self dispatchOn: type in: EdgeInitTable. "Insert the edge into the AET" self insertEdgeIntoAET: edge. self getStartPut: self getStartGet + 1. ]. "No entries in GET" ^false! ! !BalloonEngineBase methodsFor: 'AET processing' stamp: 'ar (auto pragmas 12/08) 11/25/1998 23:21'! findNextExternalFillFromAET "Scan the active edge table. If there is any fill that cannot be handled by the engine itself, return true. Otherwise handle the fills and return false." | leftEdge rightEdge leftX rightX | "self currentYGet >= 680 ifTrue:[ self printAET. self halt. ]." leftX := rightX := self fillMaxXGet. [self aetStartGet < self aetUsedGet] whileTrue:[ leftEdge := rightEdge := aetBuffer at: self aetStartGet. "TODO: We should check if leftX from last operation is greater than leftX from next edge. Currently, we rely here on spanEndAA from the span buffer fill." leftX := rightX := self edgeXValueOf: leftEdge. leftX >= self fillMaxXGet ifTrue:[^false]. "Nothing more visible" self quickRemoveInvalidFillsAt: leftX. "Check if we need to draw the edge" (self isWide: leftEdge) ifTrue:[ self toggleWideFillOf: leftEdge. "leftX := rightX := self drawWideEdge: leftEdge from: leftX." ]. (self areEdgeFillsValid: leftEdge) ifTrue:[ self toggleFillsOf: leftEdge. "Adjust the fills" engineStopped ifTrue:[^false]. ]. self aetStartPut: self aetStartGet + 1. self aetStartGet < self aetUsedGet ifTrue:[ rightEdge := aetBuffer at: self aetStartGet. rightX := self edgeXValueOf: rightEdge. rightX >= self fillMinXGet ifTrue:["This is the visible portion" self fillAllFrom: leftX to: rightX. "Fetch the currently active fill" "fill := self makeUnsignedFrom: self topFill. fill = 0 ifFalse:[self fillSpan: fill from: leftX to: rightX max: self topRightX]" ]. ]. ]. "Note: Due to pre-clipping we may have to draw remaining stuff with the last fill" rightX < self fillMaxXGet ifTrue:[ self fillAllFrom: rightX to: self fillMaxXGet. "fill := self makeUnsignedFrom: self topFill. fill = 0 ifFalse:[self fillSpan: fill from: rightX to: self fillMaxXGet max: self topRightX]." ]. ^false! ! !BalloonEngineBase methodsFor: 'AET processing' stamp: 'ar (auto pragmas 12/08) 11/9/1998 15:36'! findNextExternalUpdateFromAET "Check the active edge table for any entries that cannot be handled by the engine itself. If there are any, return true. Otherwise, step the the edge to the next y value." | edge count type | [self aetStartGet < self aetUsedGet] whileTrue:[ edge := aetBuffer at: self aetStartGet. count := (self edgeNumLinesOf: edge) - 1. count = 0 ifTrue:[ "Edge at end -- remove it" self removeFirstAETEntry ] ifFalse:[ "Store remaining lines back" self edgeNumLinesOf: edge put: count. type := self objectTypeOf: edge. (type bitAnd: GEPrimitiveWideMask) = GEPrimitiveEdge ifTrue:[^true]. "This is an external edge" self dispatchOn: type in: EdgeStepTable. self resortFirstAETEntry. self aetStartPut: self aetStartGet+1. ]. ]. ^false! ! !BalloonEngineBase methodsFor: 'FILL processing' stamp: 'ar 11/25/1998 15:47'! findStackFill: fillIndex depth: depth | index | index := 0. [index < self stackFillSize and:[ (self stackFillValue: index) ~= fillIndex or:[ (self stackFillDepth: index) ~= depth]]] whileTrue:[index := index + self stackFillEntryLength]. index >= self stackFillSize ifTrue:[^-1] ifFalse:[^index]. ! ! !BalloonEngineBase methodsFor: 'testing' stamp: 'ar 10/31/1998 17:06'! finishedProcessing "Return true if processing is finished" ^self stateGet = GEStateCompleted! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/29/1998 17:08'! firstPointListGet ^workBuffer at: GWPointListFirst! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/29/1998 17:08'! firstPointListPut: value ^workBuffer at: GWPointListFirst put: value! ! !BalloonEngineBase methodsFor: 'allocating' stamp: 'ar 10/30/1998 19:24'! freeStackFillEntry self wbStackPop: self stackFillEntryLength.! ! !BalloonEngineBase methodsFor: 'GET processing' stamp: 'ar (auto pragmas 12/08) 10/28/1998 21:07'! getSorts: edge1 before: edge2 "Return true if the edge at index i should sort before the edge at index j." | diff | edge1 = edge2 ifTrue:[^true]. "First, sort by Y" diff := (self edgeYValueOf: edge1) - (self edgeYValueOf: edge2). diff = 0 ifFalse:[^diff < 0]. "Then, by X" diff := (self edgeXValueOf: edge1) - (self edgeXValueOf: edge2). ^diff < 0! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:27'! getStartGet ^workBuffer at: GWGETStart! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:30'! getStartPut: value ^workBuffer at: GWGETStart put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:27'! getUsedGet ^workBuffer at: GWGETUsed! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:31'! getUsedPut: value ^workBuffer at: GWGETUsed put: value! ! !BalloonEngineBase methodsFor: 'testing' stamp: 'ar 11/24/1998 19:39'! hasColorTransform ^self hasColorTransformGet ~= 0! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 11/24/1998 21:36'! hasColorTransformGet ^workBuffer at: GWHasColorTransform! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 11/24/1998 21:36'! hasColorTransformPut: value ^workBuffer at: GWHasColorTransform put: value! ! !BalloonEngineBase methodsFor: 'testing' stamp: 'ar 11/24/1998 19:38'! hasEdgeTransform ^self hasEdgeTransformGet ~= 0! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 11/24/1998 21:36'! hasEdgeTransformGet ^workBuffer at: GWHasEdgeTransform! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 11/24/1998 21:35'! hasEdgeTransformPut: value ^workBuffer at: GWHasEdgeTransform put: value! ! !BalloonEngineBase methodsFor: 'FILL processing' stamp: 'ar (auto pragmas 12/08) 11/25/1998 15:48'! hideFill: fillIndex depth: depth "Make the fill style with the given index invisible" | index newTopIndex newTop newDepth newRightX | index := self findStackFill: fillIndex depth: depth. index = -1 ifTrue:[^false]. index = 0 ifTrue:[ self freeStackFillEntry. ^true]. "Fill is visible - replace it with the last entry on the stack" self stackFillValue: index put: (self stackFillValue: 0). self stackFillDepth: index put: (self stackFillDepth: 0). self stackFillRightX: index put: (self stackFillRightX: 0). self freeStackFillEntry. (self stackFillSize <= self stackFillEntryLength) ifTrue:[^true]. "Done" "Find the new top fill" newTopIndex := 0. index := self stackFillEntryLength. [index < self stackFillSize] whileTrue:[ (self fillSorts: index before: newTopIndex) ifTrue:[newTopIndex := index]. index := index + self stackFillEntryLength. ]. (newTopIndex + self stackFillEntryLength = self stackFillSize) ifTrue:[^true]. "Top fill not changed" newTop := self stackFillValue: newTopIndex. self stackFillValue: newTopIndex put: self topFillValue. self topFillValuePut: newTop. newDepth := self stackFillDepth: newTopIndex. self stackFillDepth: newTopIndex put: self topFillDepth. self topFillDepthPut: newDepth. newRightX := self stackFillRightX: newTopIndex. self stackFillRightX: newTopIndex put: self topFillRightX. self topFillRightXPut: newRightX. ^true! ! !BalloonEngineBase methodsFor: 'transforming' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 14:20'! incrementPoint: point by: delta point at: 0 put: (point at: 0) + delta. point at: 1 put: (point at: 1) + delta.! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 11/9/1998 15:36'! incrementStat: statIndex by: value ^workBuffer at: statIndex put: (workBuffer at: statIndex) + value! ! !BalloonEngineBase methodsFor: 'AET processing' stamp: 'ar (auto pragmas 12/08) 10/28/1998 21:07'! indexForInsertingIntoAET: edge "Find insertion point for the given edge in the AET" | initialX index | initialX := self edgeXValueOf: edge. index := 0. [index < self aetUsedGet and:[ (self edgeXValueOf: (aetBuffer at: index)) < initialX]] whileTrue:[index := index + 1]. [index < self aetUsedGet and:[ (self edgeXValueOf: (aetBuffer at: index)) = initialX and:[ (self getSorts: (aetBuffer at: index) before: edge)]]] whileTrue:[index := index + 1]. ^index! ! !BalloonEngineBase methodsFor: 'other' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 14:20'! initColorTransform | transform | transform := self colorTransform. transform at: 0 put: (self cCoerce: 1.0 to: 'float'). transform at: 1 put: (self cCoerce: 0.0 to: 'float'). transform at: 2 put: (self cCoerce: 1.0 to: 'float'). transform at: 3 put: (self cCoerce: 0.0 to: 'float'). transform at: 4 put: (self cCoerce: 1.0 to: 'float'). transform at: 5 put: (self cCoerce: 0.0 to: 'float'). transform at: 6 put: (self cCoerce: 1.0 to: 'float'). transform at: 7 put: (self cCoerce: 0.0 to: 'float'). self hasColorTransformPut: 0.! ! !BalloonEngineBase methodsFor: 'other' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 14:20'! initEdgeTransform | transform | transform := self edgeTransform. transform at: 0 put: (self cCoerce: 1.0 to: 'float'). transform at: 1 put: (self cCoerce: 0.0 to: 'float'). transform at: 2 put: (self cCoerce: 0.0 to: 'float'). transform at: 3 put: (self cCoerce: 0.0 to: 'float'). transform at: 4 put: (self cCoerce: 1.0 to: 'float'). transform at: 5 put: (self cCoerce: 0.0 to: 'float'). self hasEdgeTransformPut: 0.! ! !BalloonEngineBase methodsFor: 'initialize-release' stamp: 'tpr (auto pragmas 12/08) 4/7/2004 21:10'! initialiseModule loadBBFn := interpreterProxy ioLoadFunction: 'loadBitBltFrom' From: bbPluginName. copyBitsFn := interpreterProxy ioLoadFunction: 'copyBitsFromtoat' From: bbPluginName. ^(loadBBFn ~= 0 and:[copyBitsFn ~= 0])! ! !BalloonEngineBase methodsFor: 'GET processing' stamp: 'di (auto pragmas 12/08) 7/14/2004 13:09'! initializeGETProcessing "Initialization stuff that needs to be done before any processing can take place." "Make sure aaLevel is initialized" self setAALevel: self aaLevelGet. self clipMinXGet < 0 ifTrue:[self clipMinXPut: 0]. self clipMaxXGet > self spanSizeGet ifTrue:[self clipMaxXPut: self spanSizeGet]. "Convert clipRect to aaLevel" self fillMinXPut: self clipMinXGet << self aaShiftGet. self fillMinYPut: self clipMinYGet << self aaShiftGet. self fillMaxXPut: self clipMaxXGet << self aaShiftGet. self fillMaxYPut: self clipMaxYGet << self aaShiftGet. "Reset GET and AET" self getUsedPut: 0. self aetUsedPut: 0. getBuffer := objBuffer + objUsed. aetBuffer := objBuffer + objUsed. "Create the global edge table" self createGlobalEdgeTable. engineStopped ifTrue:[^nil]. self getUsedGet = 0 ifTrue:[ "Nothing to do" self currentYPut: self fillMaxYGet. ^0]. "Sort entries in the GET" self sortGlobalEdgeTable. "Find the first y value to be processed" self currentYPut: (self edgeYValueOf: (getBuffer at: 0)). self currentYGet < self fillMinYGet ifTrue:[self currentYPut: self fillMinYGet]. "Load and clear the span buffer" self spanStartPut: 0. self spanEndPut: (self spanSizeGet << self aaShiftGet) - 1. self clearSpanBuffer. "@@: Is this really necessary?!!"! ! !BalloonEngineBase methodsFor: 'AET processing' stamp: 'ar (auto pragmas 12/08) 10/28/1998 19:52'! insertEdgeIntoAET: edge "Insert the edge with the given index from the global edge table into the active edge table. The edge has already been stepped to the initial yValue -- thus remainingLines and rasterX are both set." | index | "Check for the number of lines remaining" (self edgeNumLinesOf: edge) <= 0 ifTrue:[^nil]. "Nothing to do" "Find insertion point" index := self indexForInsertingIntoAET: edge. "And insert edge" self insertToAET: edge beforeIndex: index.! ! !BalloonEngineBase methodsFor: 'AET processing' stamp: 'ar (auto pragmas 12/08) 10/28/1998 21:07'! insertToAET: edge beforeIndex: index "Insert the given edge into the AET." | i | "Make sure we have space in the AET" (self allocateAETEntry: 1) ifFalse:[^nil]. "Insufficient space in AET" i := self aetUsedGet-1. [i < index] whileFalse:[ aetBuffer at: i+1 put: (aetBuffer at: i). i := i - 1. ]. aetBuffer at: index put: edge. self aetUsedPut: self aetUsedGet + 1.! ! !BalloonEngineBase methodsFor: 'testing' stamp: 'ar 10/29/1998 19:36'! isEdge: edge | type | type := self objectTypeOf: edge. type > GEPrimitiveEdgeMask ifTrue:[^false]. ^((self objectTypeOf: edge) bitAnd: GEPrimitiveEdgeMask) ~= 0! ! !BalloonEngineBase methodsFor: 'testing' stamp: 'ar 11/7/1998 21:28'! isFill: fill ^(self isFillColor: fill) or:[self isRealFill: fill]! ! !BalloonEngineBase methodsFor: 'testing' stamp: 'ar 10/29/1998 19:31'! isFillColor: fill ^((self makeUnsignedFrom: fill) bitAnd: 16rFF000000) ~= 0! ! !BalloonEngineBase methodsFor: 'testing' stamp: 'ar 11/25/1998 00:43'! isObject: obj ^obj >= 0 and:[obj < objUsed]! ! !BalloonEngineBase methodsFor: 'testing' stamp: 'ar 11/7/1998 21:28'! isRealFill: fill ^((self objectTypeOf: fill) bitAnd: GEPrimitiveFillMask) ~= 0! ! !BalloonEngineBase methodsFor: 'testing' stamp: 'ar 10/31/1998 23:12'! isStackEntry: entry ^entry >= self wbTopGet and:[entry < self wbSizeGet]! ! !BalloonEngineBase methodsFor: 'testing' stamp: 'ar 10/30/1998 17:38'! isStackIndex: index ^index >= 0 and:[index < self wbStackSize]! ! !BalloonEngineBase methodsFor: 'testing' stamp: 'ar 11/9/1998 15:36'! isWide: object ^((self objectTypeOf: object) bitAnd: GEPrimitiveWide) ~= 0! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:28'! lastExportedEdgeGet ^workBuffer at: GWLastExportedEdge! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 20:11'! lastExportedEdgePut: value ^workBuffer at: GWLastExportedEdge put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 14:24'! lastExportedFillGet ^workBuffer at: GWLastExportedFill! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 14:24'! lastExportedFillPut: value ^workBuffer at: GWLastExportedFill put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 16:51'! lastExportedLeftXGet ^workBuffer at: GWLastExportedLeftX! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 16:51'! lastExportedLeftXPut: value ^workBuffer at: GWLastExportedLeftX put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 16:51'! lastExportedRightXGet ^workBuffer at: GWLastExportedRightX! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/28/1998 16:51'! lastExportedRightXPut: value ^workBuffer at: GWLastExportedRightX put: value! ! !BalloonEngineBase methodsFor: 'loading state' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 14:20'! loadArrayTransformFrom: transformOop into: destPtr length: n "Load a transformation from the given array." | value | 0 to: n-1 do:[:i| value := interpreterProxy fetchPointer: i ofObject: transformOop. ((interpreterProxy isIntegerObject: value) or:[interpreterProxy isFloatObject: value]) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isIntegerObject: value) ifTrue:[destPtr at: i put: (self cCoerce: (interpreterProxy integerValueOf: value) asFloat to:'float')] ifFalse:[destPtr at: i put: (self cCoerce: (interpreterProxy floatValueOf: value) to: 'float')]. ].! ! !BalloonEngineBase methodsFor: 'private' stamp: 'ikp 6/14/2004 15:14'! loadBitBltFrom: bbObj loadBBFn = 0 ifTrue: [ "We need copyBits here so try to load it implicitly" self initialiseModule ifFalse:[^false]. ]. ^self cCode: '((sqInt (*)(sqInt))loadBBFn)(bbObj)'! ! !BalloonEngineBase methodsFor: 'loading state' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 14:20'! loadColorTransformFrom: transformOop "Load a 2x3 transformation matrix from the given oop. Return true if the matrix is not nil, false otherwise" | okay transform | transform := self colorTransform. self hasColorTransformPut: 0. okay := self loadTransformFrom: transformOop into: transform length: 8. okay ifFalse:[^false]. self hasColorTransformPut: 1. "Scale transform to be in 0-256 range" transform at: 1 put: (transform at: 1) * (self cCoerce: 256.0 to:'float'). transform at: 3 put: (transform at: 3) * (self cCoerce: 256.0 to:'float'). transform at: 5 put: (transform at: 5) * (self cCoerce: 256.0 to:'float'). transform at: 7 put: (transform at: 7) * (self cCoerce: 256.0 to:'float'). ^okay! ! !BalloonEngineBase methodsFor: 'loading state' stamp: 'ar (auto pragmas dtl 2010-09-27) 11/11/1998 22:21'! loadEdgeStateFrom: edgeOop | edge | edge := self lastExportedEdgeGet. (interpreterProxy slotSizeOf: edgeOop) < ETBalloonEdgeDataSize ifTrue:[^interpreterProxy primitiveFail]. self edgeXValueOf: edge put: (interpreterProxy fetchInteger: ETXValueIndex ofObject: edgeOop). self edgeYValueOf: edge put: (interpreterProxy fetchInteger: ETYValueIndex ofObject: edgeOop). self edgeZValueOf: edge put: (interpreterProxy fetchInteger: ETZValueIndex ofObject: edgeOop). self edgeNumLinesOf: edge put: (interpreterProxy fetchInteger: ETLinesIndex ofObject: edgeOop). ^edge! ! !BalloonEngineBase methodsFor: 'loading state' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 14:21'! loadEdgeTransformFrom: transformOop "Load a 2x3 transformation matrix from the given oop. Return true if the matrix is not nil, false otherwise" | transform okay | self hasEdgeTransformPut: 0. transform := self edgeTransform. okay := self loadTransformFrom: transformOop into: transform length: 6. interpreterProxy failed ifTrue:[^nil]. okay ifFalse:[^false]. self hasEdgeTransformPut: 1. "Add the fill offset to the matrix" transform at: 2 put: (self cCoerce: (transform at: 2) + self destOffsetXGet asFloat to:'float'). transform at: 5 put: (self cCoerce: (transform at: 5) + self destOffsetYGet asFloat to:'float'). ^true! ! !BalloonEngineBase methodsFor: 'loading state' stamp: 'ar 12/5/2003 20:07'! loadFormsFrom: arrayOop "Check all the forms from arrayOop." | formOop bmBits bmBitsSize bmWidth bmHeight bmDepth ppw bmRaster | (interpreterProxy isArray: arrayOop) ifFalse:[^false]. formArray := arrayOop. 0 to: (interpreterProxy slotSizeOf: formArray) - 1 do:[:i| formOop := interpreterProxy fetchPointer: i ofObject: formArray. (interpreterProxy isIntegerObject: formOop) ifTrue:[^false]. (interpreterProxy isPointers: formOop) ifFalse:[^false]. (interpreterProxy slotSizeOf: formOop) < 5 ifTrue:[^false]. bmBits := interpreterProxy fetchPointer: 0 ofObject: formOop. (interpreterProxy fetchClassOf: bmBits) == interpreterProxy classBitmap ifFalse:[^false]. bmBitsSize := interpreterProxy slotSizeOf: bmBits. bmWidth := interpreterProxy fetchInteger: 1 ofObject: formOop. bmHeight := interpreterProxy fetchInteger: 2 ofObject: formOop. bmDepth := interpreterProxy fetchInteger: 3 ofObject: formOop. interpreterProxy failed ifTrue:[^false]. (bmWidth >= 0 and:[bmHeight >= 0]) ifFalse:[^false]. ppw := 32 // bmDepth. bmRaster := bmWidth + (ppw-1) // ppw. bmBitsSize = (bmRaster * bmHeight) ifFalse:[^false]. ]. ^true! ! !BalloonEngineBase methodsFor: 'loading state' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 14:21'! loadPoint: pointArray from: pointOop "Load the contents of pointOop into pointArray" | value | (interpreterProxy fetchClassOf: pointOop) = interpreterProxy classPoint ifFalse:[^interpreterProxy primitiveFail]. value := interpreterProxy fetchPointer: 0 ofObject: pointOop. ((interpreterProxy isIntegerObject: value) or:[interpreterProxy isFloatObject: value]) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isIntegerObject: value) ifTrue:[pointArray at: 0 put: (interpreterProxy integerValueOf: value)] ifFalse:[pointArray at: 0 put: (interpreterProxy floatValueOf: value) asInteger]. value := interpreterProxy fetchPointer: 1 ofObject: pointOop. ((interpreterProxy isIntegerObject: value) or:[interpreterProxy isFloatObject: value]) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isIntegerObject: value) ifTrue:[pointArray at: 1 put: (interpreterProxy integerValueOf: value)] ifFalse:[pointArray at: 1 put: (interpreterProxy floatValueOf: value) asInteger]. ! ! !BalloonEngineBase methodsFor: 'primitives-rendering' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/12/2000 16:40'! loadRenderingState "Load the entire state from the interpreter for the rendering primitives" | edgeOop fillOop state | interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. fillOop := interpreterProxy stackObjectValue: 0. edgeOop := interpreterProxy stackObjectValue: 1. engine := interpreterProxy stackObjectValue: 2. interpreterProxy failed ifTrue:[^false]. (self quickLoadEngineFrom: engine) ifFalse:[^false]. "Load span buffer and bitBlt" (self loadSpanBufferFrom: (interpreterProxy fetchPointer: BESpanIndex ofObject: engine)) ifFalse:[^false]. (self loadBitBltFrom: (interpreterProxy fetchPointer: BEBitBltIndex ofObject: engine)) ifFalse:[^false]. (self loadFormsFrom: (interpreterProxy fetchPointer: BEFormsIndex ofObject: engine)) ifFalse:[^false]. "Check edgeOop and fillOop" (interpreterProxy slotSizeOf: edgeOop) < ETBalloonEdgeDataSize ifTrue:[^false]. (interpreterProxy slotSizeOf: fillOop) < FTBalloonFillDataSize ifTrue:[^false]. "Note: Rendering can only take place if we're not in one of the intermediate (e.g., external) states." state := self stateGet. (state = GEStateWaitingForEdge or:[ state = GEStateWaitingForFill or:[ state = GEStateWaitingChange]]) ifTrue:[^false]. ^true! ! !BalloonEngineBase methodsFor: 'loading state' stamp: 'ar (auto pragmas dtl 2010-09-27) 10/28/1998 00:46'! loadSpanBufferFrom: spanOop "Load the span buffer from the given oop." (interpreterProxy fetchClassOf: spanOop) = (interpreterProxy classBitmap) ifFalse:[^false]. spanBuffer := interpreterProxy firstIndexableField: spanOop. "Leave last entry unused to avoid complications" self spanSizePut: (interpreterProxy slotSizeOf: spanOop) - 1. ^true! ! !BalloonEngineBase methodsFor: 'loading state' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 14:21'! loadTransformFrom: transformOop into: destPtr length: n "Load a transformation from transformOop into the float array defined by destPtr. The transformation is assumed to be either an array or a FloatArray of length n." transformOop = interpreterProxy nilObject ifTrue:[^false]. (interpreterProxy isIntegerObject: transformOop) ifTrue:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: transformOop) = n ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isWords: transformOop) ifTrue:[self loadWordTransformFrom: transformOop into: destPtr length: n] ifFalse:[self loadArrayTransformFrom: transformOop into: destPtr length: n]. ^true! ! !BalloonEngineBase methodsFor: 'loading state' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 14:21'! loadWordTransformFrom: transformOop into: destPtr length: n "Load a float array transformation from the given oop" | srcPtr | srcPtr := self cCoerce: (interpreterProxy firstIndexableField: transformOop) to: 'float *'. 0 to: n-1 do:[:i| destPtr at: i put: (srcPtr at: i)].! ! !BalloonEngineBase methodsFor: 'loading state' stamp: 'ar (auto pragmas dtl 2010-09-27) 7/11/2004 13:42'! loadWorkBufferFrom: wbOop "Load the working buffer from the given oop" (interpreterProxy isIntegerObject: wbOop) ifTrue:[^false]. (interpreterProxy isWords: wbOop) ifFalse:[^false]. (interpreterProxy slotSizeOf: wbOop) < GWMinimalSize ifTrue:[^false]. self workBufferPut: wbOop. self magicNumberGet = GWMagicNumber ifFalse:[^false]. "Sanity checks" (self wbSizeGet = (interpreterProxy slotSizeOf: wbOop)) ifFalse:[^false]. self objStartGet = GWHeaderSize ifFalse:[^false]. "Load buffers" objBuffer := workBuffer + self objStartGet. getBuffer := objBuffer + self objUsedGet. aetBuffer := getBuffer + self getUsedGet. "Make sure we don't exceed the work buffer" GWHeaderSize + self objUsedGet + self getUsedGet + self aetUsedGet > self wbSizeGet ifTrue:[^false]. ^true! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:28'! magicNumberGet ^workBuffer at: GWMagicIndex! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:39'! magicNumberPut: value ^workBuffer at: GWMagicIndex put: value! ! !BalloonEngineBase methodsFor: 'private' stamp: 'ar 10/28/1998 20:58'! makeUnsignedFrom: someIntegerValue ^someIntegerValue! ! !BalloonEngineBase methodsFor: 'initialize-release' stamp: 'ar (auto pragmas 12/08) 5/16/2000 19:57'! moduleUnloaded: aModuleName "The module with the given name was just unloaded. Make sure we have no dangling references." (aModuleName strcmp: bbPluginName) = 0 ifTrue:[ "BitBlt just shut down. How nasty." loadBBFn := 0. copyBitsFn := 0. ].! ! !BalloonEngineBase methodsFor: 'AET processing' stamp: 'ar (auto pragmas 12/08) 10/28/1998 01:39'! moveAETEntryFrom: index edge: edge x: xValue "The entry at index is not in the right position of the AET. Move it to the left until the position is okay." | newIndex | newIndex := index. [newIndex > 0 and:[(self edgeXValueOf: (aetBuffer at: newIndex-1)) > xValue]] whileTrue:[ aetBuffer at: newIndex put: (aetBuffer at: newIndex-1). newIndex := newIndex - 1]. aetBuffer at: newIndex put: edge.! ! !BalloonEngineBase methodsFor: 'allocating' stamp: 'ar 11/25/1998 02:19'! needAvailableSpace: nSlots "Check if we have n slots available" GWHeaderSize + objUsed + self getUsedGet + self aetUsedGet + nSlots > self wbTopGet ifTrue:[ self stopBecauseOf: GErrorNoMoreSpace. ^false ]. ^true! ! !BalloonEngineBase methodsFor: 'testing' stamp: 'ar 11/25/1998 00:21'! needsFlush ^self needsFlushGet ~= 0! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 11/25/1998 00:20'! needsFlushGet ^workBuffer at: GWNeedsFlush! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 11/25/1998 00:20'! needsFlushPut: value ^workBuffer at: GWNeedsFlush put: value! ! !BalloonEngineBase methodsFor: 'accessing objects' stamp: 'ar 11/24/1998 22:22'! obj: object at: index ^objBuffer at: object + index! ! !BalloonEngineBase methodsFor: 'accessing objects' stamp: 'ar 11/24/1998 22:22'! obj: object at: index put: value ^objBuffer at: object + index put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:28'! objStartGet ^workBuffer at: GWObjStart! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:32'! objStartPut: value ^workBuffer at: GWObjStart put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:28'! objUsedGet ^workBuffer at: GWObjUsed! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:32'! objUsedPut: value ^workBuffer at: GWObjUsed put: value! ! !BalloonEngineBase methodsFor: 'accessing objects' stamp: 'ar 11/24/1998 22:02'! objectHeaderOf: obj ^self makeUnsignedFrom:(self obj: obj at: GEObjectType)! ! !BalloonEngineBase methodsFor: 'accessing objects' stamp: 'ar 11/24/1998 22:03'! objectIndexOf: obj ^self obj: obj at: GEObjectIndex! ! !BalloonEngineBase methodsFor: 'accessing objects' stamp: 'ar 11/24/1998 22:03'! objectIndexOf: obj put: value ^self obj: obj at: GEObjectIndex put: value! ! !BalloonEngineBase methodsFor: 'accessing objects' stamp: 'ar 11/24/1998 22:03'! objectLengthOf: obj ^self obj: obj at: GEObjectLength! ! !BalloonEngineBase methodsFor: 'accessing objects' stamp: 'ar 11/24/1998 22:03'! objectLengthOf: obj put: value ^self obj: obj at: GEObjectLength put: value! ! !BalloonEngineBase methodsFor: 'accessing objects' stamp: 'ar 11/24/1998 22:03'! objectTypeOf: obj ^(self makeUnsignedFrom:(self obj: obj at: GEObjectType)) bitAnd: GEPrimitiveTypeMask! ! !BalloonEngineBase methodsFor: 'accessing objects' stamp: 'ar 11/24/1998 22:03'! objectTypeOf: obj put: value ^self obj: obj at: GEObjectType put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar (auto pragmas dtl 2010-09-27) 10/28/1998 16:33'! point1Get ^self cCoerce: workBuffer + GWPoint1 to:'int *'! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar (auto pragmas dtl 2010-09-27) 10/28/1998 16:34'! point2Get ^self cCoerce: workBuffer + GWPoint2 to:'int *'! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar (auto pragmas dtl 2010-09-27) 10/28/1998 16:34'! point3Get ^self cCoerce: workBuffer + GWPoint3 to:'int *'! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar (auto pragmas dtl 2010-09-27) 11/1/1998 03:13'! point4Get ^self cCoerce: workBuffer + GWPoint4 to:'int *'! ! !BalloonEngineBase methodsFor: 'displaying' stamp: 'ar (auto pragmas 12/08) 11/8/1998 15:13'! postDisplayAction "We have just blitted a scan line to the screen. Do whatever seems to be a good idea here." "Note: In the future we may check the time needed for this scan line and interrupt processing to give the Smalltalk code a chance to run at a certain time." "Check if there is any more work to do." (self getStartGet >= self getUsedGet and:[self aetUsedGet = 0]) ifTrue:[ "No more entries to process" self statePut: GEStateCompleted. ]. (self currentYGet >= self fillMaxYGet) ifTrue:[ "Out of clipping range" self statePut: GEStateCompleted. ].! ! !BalloonEngineBase methodsFor: 'primitives-other' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:06'! primitiveAbortProcessing interpreterProxy methodArgumentCount = 0 ifFalse:[^interpreterProxy primitiveFail]. engine := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine) ifFalse:[^interpreterProxy primitiveFail]. self statePut: GEStateCompleted. self storeEngineStateInto: engine.! ! !BalloonEngineBase methodsFor: 'primitives-incremental' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/13/2000 14:58'! primitiveAddActiveEdgeEntry "Note: No need to load either bitBlt or spanBuffer" | edgeOop edge | doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. edgeOop := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateWaitingForEdge) ifFalse:[^interpreterProxy primitiveFail]. edge := self loadEdgeStateFrom: edgeOop. interpreterProxy failed ifTrue:[^nil]. (self needAvailableSpace: 1) ifFalse:[^interpreterProxy primitiveFail]. (self edgeNumLinesOf: edge) > 0 ifTrue:[ self insertEdgeIntoAET: edge. ]. engineStopped ifTrue:[^interpreterProxy primitiveFail]. self statePut: GEStateAddingFromGET. "Back to adding edges from GET" self storeEngineStateInto: engine. interpreterProxy pop: 1. "Leave rcvr on stack" doProfileStats ifTrue:[ self incrementStat: GWCountAddAETEntry by: 1. self incrementStat: GWTimeAddAETEntry by: (interpreterProxy ioMicroMSecs - geProfileTime)]. ! ! !BalloonEngineBase methodsFor: 'primitives-incremental' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/13/2000 14:59'! primitiveChangedActiveEdgeEntry "Note: No need to load either bitBlt or spanBuffer" | edgeOop edge | doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. edgeOop := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateWaitingChange) ifFalse:[^interpreterProxy primitiveFail]. edge := self loadEdgeStateFrom: edgeOop. interpreterProxy failed ifTrue:[^nil]. (self edgeNumLinesOf: edge) = 0 ifTrue:[ self removeFirstAETEntry] ifFalse:[ self resortFirstAETEntry. self aetStartPut: self aetStartGet + 1]. self statePut: GEStateUpdateEdges. "Back to updating edges" self storeEngineStateInto: engine. interpreterProxy pop: 1. "Leave rcvr on stack" doProfileStats ifTrue:[ self incrementStat: GWCountChangeAETEntry by: 1. self incrementStat: GWTimeChangeAETEntry by: (interpreterProxy ioMicroMSecs - geProfileTime)]. ! ! !BalloonEngineBase methodsFor: 'primitives-other' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:37'! primitiveCopyBuffer | buf1 buf2 diff src dst | interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. buf2 := interpreterProxy stackObjectValue: 0. buf1 := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. "Make sure the old buffer is properly initialized" (self loadWorkBufferFrom: buf1) ifFalse:[^interpreterProxy primitiveFail]. "Make sure the buffers are of the same type" (interpreterProxy fetchClassOf: buf1) = (interpreterProxy fetchClassOf: buf2) ifFalse:[^interpreterProxy primitiveFail]. "Make sure buf2 is at least of the size of buf1" diff := (interpreterProxy slotSizeOf: buf2) - (interpreterProxy slotSizeOf: buf1). diff < 0 ifTrue:[^interpreterProxy primitiveFail]. "Okay - ready for copying. First of all just copy the contents up to wbTop" src := workBuffer. dst := interpreterProxy firstIndexableField: buf2. 0 to: self wbTopGet-1 do:[:i| dst at: i put: (src at: i). ]. "Adjust wbSize and wbTop in the new buffer" dst at: GWBufferTop put: self wbTopGet + diff. dst at: GWSize put: self wbSizeGet + diff. "Now copy the entries from wbTop to wbSize" src := src + self wbTopGet. dst := dst + self wbTopGet + diff. 0 to: (self wbSizeGet - self wbTopGet - 1) do:[:i| dst at: i put: (src at: i). ]. "Okay, done. Check the new buffer by loading the state from it" (self loadWorkBufferFrom: buf2) ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy pop: 2. "Leave rcvr on stack" ! ! !BalloonEngineBase methodsFor: 'primitives-incremental' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/13/2000 14:59'! primitiveDisplaySpanBuffer "Note: Must load bitBlt and spanBuffer" doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. interpreterProxy methodArgumentCount = 0 ifFalse:[^interpreterProxy primitiveFail]. engine := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateBlitBuffer) ifFalse:[^interpreterProxy primitiveFail]. "Load span buffer and bitBlt" (self loadSpanBufferFrom: (interpreterProxy fetchPointer: BESpanIndex ofObject: engine)) ifFalse:[^interpreterProxy primitiveFail]. (self loadBitBltFrom: (interpreterProxy fetchPointer: BEBitBltIndex ofObject: engine)) ifFalse:[^interpreterProxy primitiveFail]. (self currentYGet bitAnd: self aaScanMaskGet) = self aaScanMaskGet ifTrue:[ self displaySpanBufferAt: self currentYGet. self postDisplayAction. ]. self finishedProcessing ifFalse:[ self aetStartPut: 0. self currentYPut: self currentYGet + 1. self statePut: GEStateUpdateEdges]. self storeEngineStateInto: engine. doProfileStats ifTrue:[ self incrementStat: GWCountDisplaySpan by: 1. self incrementStat: GWTimeDisplaySpan by: (interpreterProxy ioMicroMSecs - geProfileTime)]. ! ! !BalloonEngineBase methodsFor: 'primitives-other' stamp: 'ar (auto pragmas 12/08) 5/11/2000 23:05'! primitiveDoProfileStats "Turn on/off profiling. Return the old value of the flag." | oldValue newValue | oldValue := doProfileStats. newValue := interpreterProxy stackObjectValue: 0. newValue := interpreterProxy booleanValueOf: newValue. interpreterProxy failed ifFalse:[ doProfileStats := newValue. interpreterProxy pop: 2. "Pop rcvr, arg" interpreterProxy pushBool: oldValue. ].! ! !BalloonEngineBase methodsFor: 'primitives-other' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/13/2000 14:59'! primitiveFinishedProcessing | finished | doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. interpreterProxy methodArgumentCount = 0 ifFalse:[^interpreterProxy primitiveFail]. engine := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine) ifFalse:[^interpreterProxy primitiveFail]. finished := self finishedProcessing. self storeEngineStateInto: engine. interpreterProxy pop: 1. interpreterProxy pushBool: finished. doProfileStats ifTrue:[ self incrementStat: GWCountFinishTest by: 1. self incrementStat: GWTimeFinishTest by: (interpreterProxy ioMicroMSecs - geProfileTime)]. ! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:08'! primitiveGetAALevel interpreterProxy methodArgumentCount = 0 ifFalse:[^interpreterProxy primitiveFail]. engine := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine) ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy pop: 1. interpreterProxy pushInteger: self aaLevelGet.! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:10'! primitiveGetClipRect | rectOop pointOop | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. rectOop := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isPointers: rectOop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: rectOop) < 2 ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pushRemappableOop: rectOop. pointOop := interpreterProxy makePointwithxValue: self clipMinXGet yValue: self clipMinYGet. rectOop := interpreterProxy popRemappableOop. interpreterProxy storePointer: 0 ofObject: rectOop withValue: pointOop. interpreterProxy pushRemappableOop: rectOop. pointOop := interpreterProxy makePointwithxValue: self clipMaxXGet yValue: self clipMaxYGet. rectOop := interpreterProxy popRemappableOop. interpreterProxy storePointer: 1 ofObject: rectOop withValue: pointOop. interpreterProxy pop: 2. interpreterProxy push: rectOop.! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:37'! primitiveGetCounts | statOop stats | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. statOop := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isWords: statOop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: statOop) < 9 ifTrue:[^interpreterProxy primitiveFail]. stats := interpreterProxy firstIndexableField: statOop. stats at: 0 put: (stats at: 0) + (workBuffer at: GWCountInitializing). stats at: 1 put: (stats at: 1) + (workBuffer at: GWCountFinishTest). stats at: 2 put: (stats at: 2) + (workBuffer at: GWCountNextGETEntry). stats at: 3 put: (stats at: 3) + (workBuffer at: GWCountAddAETEntry). stats at: 4 put: (stats at: 4) + (workBuffer at: GWCountNextFillEntry). stats at: 5 put: (stats at: 5) + (workBuffer at: GWCountMergeFill). stats at: 6 put: (stats at: 6) + (workBuffer at: GWCountDisplaySpan). stats at: 7 put: (stats at: 7) + (workBuffer at: GWCountNextAETEntry). stats at: 8 put: (stats at: 8) + (workBuffer at: GWCountChangeAETEntry). interpreterProxy pop: 1. "Leave rcvr on stack"! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:14'! primitiveGetDepth interpreterProxy methodArgumentCount = 0 ifFalse:[^interpreterProxy primitiveFail]. engine := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine) ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy pop: 1. interpreterProxy pushInteger: self currentZGet.! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:10'! primitiveGetFailureReason "Return the reason why the last operation failed." interpreterProxy methodArgumentCount = 0 ifFalse:[^interpreterProxy primitiveFail]. engine := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. "Note -- don't call loadEngineFrom here because this will override the stopReason with Zero" (interpreterProxy isIntegerObject: engine) ifTrue:[^false]. (interpreterProxy isPointers: engine) ifFalse:[^false]. (interpreterProxy slotSizeOf: engine) < BEBalloonEngineSize ifTrue:[^false]. (self loadWorkBufferFrom: (interpreterProxy fetchPointer: BEWorkBufferIndex ofObject: engine)) ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy pop: 1. interpreterProxy pushInteger: self stopReasonGet.! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:11'! primitiveGetOffset | pointOop | interpreterProxy methodArgumentCount = 0 ifFalse:[^interpreterProxy primitiveFail]. engine := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine) ifFalse:[^interpreterProxy primitiveFail]. pointOop := interpreterProxy makePointwithxValue: self destOffsetXGet yValue: self destOffsetYGet. interpreterProxy pop: 1. interpreterProxy push: pointOop.! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:37'! primitiveGetTimes | statOop stats | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. statOop := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isWords: statOop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: statOop) < 9 ifTrue:[^interpreterProxy primitiveFail]. stats := interpreterProxy firstIndexableField: statOop. stats at: 0 put: (stats at: 0) + (workBuffer at: GWTimeInitializing). stats at: 1 put: (stats at: 1) + (workBuffer at: GWTimeFinishTest). stats at: 2 put: (stats at: 2) + (workBuffer at: GWTimeNextGETEntry). stats at: 3 put: (stats at: 3) + (workBuffer at: GWTimeAddAETEntry). stats at: 4 put: (stats at: 4) + (workBuffer at: GWTimeNextFillEntry). stats at: 5 put: (stats at: 5) + (workBuffer at: GWTimeMergeFill). stats at: 6 put: (stats at: 6) + (workBuffer at: GWTimeDisplaySpan). stats at: 7 put: (stats at: 7) + (workBuffer at: GWTimeNextAETEntry). stats at: 8 put: (stats at: 8) + (workBuffer at: GWTimeChangeAETEntry). interpreterProxy pop: 1. "Leave rcvr on stack"! ! !BalloonEngineBase methodsFor: 'primitives-other' stamp: 'ar (auto pragmas 12/08) 7/11/2004 13:42'! primitiveInitializeBuffer | wbOop size | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. wbOop := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isWords: wbOop) ifFalse:[^interpreterProxy primitiveFail]. (size := interpreterProxy slotSizeOf: wbOop) < GWMinimalSize ifTrue:[^interpreterProxy primitiveFail]. self workBufferPut: wbOop. objBuffer := workBuffer + GWHeaderSize. self magicNumberPut: GWMagicNumber. self wbSizePut: size. self wbTopPut: size. self statePut: GEStateUnlocked. self objStartPut: GWHeaderSize. self objUsedPut: 4. "Dummy fill object" self objectTypeOf: 0 put: GEPrimitiveFill. self objectLengthOf: 0 put: 4. self objectIndexOf: 0 put: 0. self getStartPut: 0. self getUsedPut: 0. self aetStartPut: 0. self aetUsedPut: 0. self stopReasonPut: 0. self needsFlushPut: 0. self clipMinXPut: 0. self clipMaxXPut: 0. self clipMinYPut: 0. self clipMaxYPut: 0. self currentZPut: 0. self resetGraphicsEngineStats. self initEdgeTransform. self initColorTransform. interpreterProxy pop: 2. interpreterProxy push: wbOop.! ! !BalloonEngineBase methodsFor: 'primitives-incremental' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/13/2000 14:59'! primitiveInitializeProcessing "Note: No need to load bitBlt but must load spanBuffer" doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. interpreterProxy methodArgumentCount = 0 ifFalse:[^interpreterProxy primitiveFail]. engine := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. "Load span buffer for clear operation" (self loadSpanBufferFrom: (interpreterProxy fetchPointer: BESpanIndex ofObject: engine)) ifFalse:[^interpreterProxy primitiveFail]. self initializeGETProcessing. engineStopped ifTrue:[^interpreterProxy primitiveFail]. self statePut: GEStateAddingFromGET. "Initialized" interpreterProxy failed ifFalse:[self storeEngineStateInto: engine]. doProfileStats ifTrue:[ self incrementStat: GWCountInitializing by: 1. self incrementStat: GWTimeInitializing by: (interpreterProxy ioMicroMSecs - geProfileTime)]. ! ! !BalloonEngineBase methodsFor: 'primitives-incremental' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/13/2000 14:59'! primitiveMergeFillFrom "Note: No need to load bitBlt but must load spanBuffer" | fillOop bitsOop value | doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. fillOop := interpreterProxy stackObjectValue: 0. bitsOop := interpreterProxy stackObjectValue: 1. engine := interpreterProxy stackObjectValue: 2. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateWaitingForFill) ifFalse:[^interpreterProxy primitiveFail]. "Load span buffer for merging the fill" (self loadSpanBufferFrom: (interpreterProxy fetchPointer: BESpanIndex ofObject: engine)) ifFalse:[^interpreterProxy primitiveFail]. "Check bitmap" (interpreterProxy fetchClassOf: bitsOop) = interpreterProxy classBitmap ifFalse:[^interpreterProxy primitiveFail]. "Check fillOop" (interpreterProxy slotSizeOf: fillOop) < FTBalloonFillDataSize ifTrue:[^interpreterProxy primitiveFail]. "Check if this was the fill we have exported" value := interpreterProxy fetchInteger: FTIndexIndex ofObject: fillOop. (self objectIndexOf: self lastExportedFillGet) = value ifFalse:[^interpreterProxy primitiveFail]. value := interpreterProxy fetchInteger: FTMinXIndex ofObject: fillOop. self lastExportedLeftXGet = value ifFalse:[^interpreterProxy primitiveFail]. value := interpreterProxy fetchInteger: FTMaxXIndex ofObject: fillOop. self lastExportedRightXGet = value ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: bitsOop) < (self lastExportedRightXGet - self lastExportedLeftXGet) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy failed ifTrue:[^nil]. self fillBitmapSpan: (interpreterProxy firstIndexableField: bitsOop) from: self lastExportedLeftXGet to: self lastExportedRightXGet. self statePut: GEStateScanningAET. "Back to scanning AET" self storeEngineStateInto: engine. interpreterProxy pop: 2. "Leave rcvr on stack" doProfileStats ifTrue:[ self incrementStat: GWCountMergeFill by: 1. self incrementStat: GWTimeMergeFill by: (interpreterProxy ioMicroMSecs - geProfileTime)]. ! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:12'! primitiveNeedsFlush | needFlush | interpreterProxy methodArgumentCount = 0 ifFalse:[^interpreterProxy primitiveFail]. engine := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine) ifFalse:[^interpreterProxy primitiveFail]. needFlush := self needsFlush. self storeEngineStateInto: engine. interpreterProxy pop: 1. interpreterProxy pushBool: needFlush. ! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:14'! primitiveNeedsFlushPut | needFlush | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. needFlush := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. needFlush := interpreterProxy booleanValueOf: needFlush. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine) ifFalse:[^interpreterProxy primitiveFail]. needFlush == true ifTrue:[self needsFlushPut: 1] ifFalse:[self needsFlushPut: 0]. self storeEngineStateInto: engine. interpreterProxy pop: 1. "Leave rcvr on stack" ! ! !BalloonEngineBase methodsFor: 'primitives-incremental' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/13/2000 14:59'! primitiveNextActiveEdgeEntry "Note: No need to load either bitBlt or spanBuffer" | edgeOop hasEdge edge | doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. edgeOop := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateUpdateEdges or: GEStateCompleted) ifFalse:[^interpreterProxy primitiveFail]. hasEdge := false. self stateGet = GEStateCompleted ifFalse:[ hasEdge := self findNextExternalUpdateFromAET. hasEdge ifTrue:[ edge := aetBuffer at: self aetStartGet. self storeEdgeStateFrom: edge into: edgeOop. "Do not advance to the next aet entry yet" "self aetStartPut: self aetStartGet + 1." self statePut: GEStateWaitingChange. "Wait for changed edge" ] ifFalse:[self statePut: GEStateAddingFromGET]. "Start over" ]. interpreterProxy failed ifTrue:[^nil]. self storeEngineStateInto: engine. interpreterProxy pop: 2. interpreterProxy pushBool: hasEdge not. doProfileStats ifTrue:[ self incrementStat: GWCountNextAETEntry by: 1. self incrementStat: GWTimeNextAETEntry by: (interpreterProxy ioMicroMSecs - geProfileTime)]. ! ! !BalloonEngineBase methodsFor: 'primitives-incremental' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/13/2000 14:59'! primitiveNextFillEntry "Note: No need to load bitBlt but must load spanBuffer" | fillOop hasFill | doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. fillOop := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateScanningAET) ifFalse:[^interpreterProxy primitiveFail]. "Load span buffer for internal handling of fills" (self loadSpanBufferFrom: (interpreterProxy fetchPointer: BESpanIndex ofObject: engine)) ifFalse:[^interpreterProxy primitiveFail]. (self loadFormsFrom: (interpreterProxy fetchPointer: BEFormsIndex ofObject: engine)) ifFalse:[^interpreterProxy primitiveFail]. "Check if we have to clear the span buffer before proceeding" (self clearSpanBufferGet = 0) ifFalse:[ (self currentYGet bitAnd: self aaScanMaskGet) = 0 ifTrue:[self clearSpanBuffer]. self clearSpanBufferPut: 0]. hasFill := self findNextExternalFillFromAET. engineStopped ifTrue:[^interpreterProxy primitiveFail]. hasFill ifTrue:[self storeFillStateInto: fillOop]. interpreterProxy failed ifFalse:[ hasFill ifTrue:[ self statePut: GEStateWaitingForFill] ifFalse:[ self wbStackClear. self spanEndAAPut: 0. self statePut: GEStateBlitBuffer]. self storeEngineStateInto: engine. interpreterProxy pop: 2. interpreterProxy pushBool: hasFill not. doProfileStats ifTrue:[ self incrementStat: GWCountNextFillEntry by: 1. self incrementStat: GWTimeNextFillEntry by: (interpreterProxy ioMicroMSecs - geProfileTime)]. ].! ! !BalloonEngineBase methodsFor: 'primitives-incremental' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/13/2000 15:00'! primitiveNextGlobalEdgeEntry "Note: No need to load either bitBlt or spanBuffer" | edgeOop hasEdge edge | doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. edgeOop := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateAddingFromGET) ifFalse:[^interpreterProxy primitiveFail]. hasEdge := self findNextExternalEntryFromGET. hasEdge ifTrue:[ edge := getBuffer at: self getStartGet. self storeEdgeStateFrom: edge into: edgeOop. self getStartPut: self getStartGet + 1]. interpreterProxy failed ifTrue:[^nil]. hasEdge ifTrue:[ self statePut: GEStateWaitingForEdge] "Wait for adding edges" ifFalse:[ "Start scanning the AET" self statePut: GEStateScanningAET. self clearSpanBufferPut: 1. "Clear span buffer at next entry" self aetStartPut: 0. self wbStackClear]. self storeEngineStateInto: engine. interpreterProxy pop: 2. interpreterProxy pushBool: hasEdge not. doProfileStats ifTrue:[ self incrementStat: GWCountNextGETEntry by: 1. self incrementStat: GWTimeNextGETEntry by: (interpreterProxy ioMicroMSecs - geProfileTime)]. ! ! !BalloonEngineBase methodsFor: 'primitives-other' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:08'! primitiveRegisterExternalEdge | rightFillIndex leftFillIndex initialZ initialY initialX index edge | interpreterProxy methodArgumentCount = 6 ifFalse:[^interpreterProxy primitiveFail]. rightFillIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). leftFillIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 1). initialZ := interpreterProxy stackIntegerValue: 2. initialY := interpreterProxy stackIntegerValue: 3. initialX := interpreterProxy stackIntegerValue: 4. index := interpreterProxy stackIntegerValue: 5. engine := interpreterProxy stackObjectValue: 6. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. (self allocateObjEntry: GEBaseEdgeSize) ifFalse:[^interpreterProxy primitiveFail]. "Make sure the fills are okay" (self isFillOkay: leftFillIndex) ifFalse:[^interpreterProxy primitiveFail]. (self isFillOkay: rightFillIndex) ifFalse:[^interpreterProxy primitiveFail]. edge := objUsed. objUsed := edge + GEBaseEdgeSize. "Install type and length" self objectTypeOf: edge put: GEPrimitiveEdge. self objectLengthOf: edge put: GEBaseEdgeSize. self objectIndexOf: edge put: index. "Install remaining stuff" self edgeXValueOf: edge put: initialX. self edgeYValueOf: edge put: initialY. self edgeZValueOf: edge put: initialZ. self edgeLeftFillOf: edge put: (self transformColor: leftFillIndex). self edgeRightFillOf: edge put: (self transformColor: rightFillIndex). engineStopped ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy failed ifFalse:[ self storeEngineStateInto: engine. interpreterProxy pop: 6. "Leave rcvr on stack" ].! ! !BalloonEngineBase methodsFor: 'primitives-other' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:14'! primitiveRegisterExternalFill | index fill | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. index := interpreterProxy stackIntegerValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. "Note: We *must* not allocate any fill with index 0" fill := 0. [fill = 0] whileTrue:[ (self allocateObjEntry: GEBaseEdgeSize) ifFalse:[^interpreterProxy primitiveFail]. fill := objUsed. objUsed := fill + GEBaseFillSize. "Install type and length" self objectTypeOf: fill put: GEPrimitiveFill. self objectLengthOf: fill put: GEBaseFillSize. self objectIndexOf: fill put: index. ]. interpreterProxy failed ifFalse:[ self storeEngineStateInto: engine. interpreterProxy pop: 2. interpreterProxy pushInteger: fill. ].! ! !BalloonEngineBase methodsFor: 'primitives-rendering' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:08'! primitiveRenderImage "Start/Proceed rendering the entire image" self loadRenderingState ifFalse:[^interpreterProxy primitiveFail]. self proceedRenderingScanline. "Finish this scan line" engineStopped ifTrue:[^self storeRenderingState]. self proceedRenderingImage. "And go on as usual" self storeRenderingState.! ! !BalloonEngineBase methodsFor: 'primitives-rendering' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:07'! primitiveRenderScanline "Start rendering the entire image" self loadRenderingState ifFalse:[^interpreterProxy primitiveFail]. self proceedRenderingScanline. "Finish the current scan line" self storeRenderingState.! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:12'! primitiveSetAALevel | level | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. level := interpreterProxy stackIntegerValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. self setAALevel: level. self storeEngineStateInto: engine. interpreterProxy pop: 1. "Leace rcvr on stack"! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:38'! primitiveSetBitBltPlugin "Primitive. Set the BitBlt plugin to use." | pluginName length ptr needReload | pluginName := interpreterProxy stackValue: 0. "Must be string to work" (interpreterProxy isBytes: pluginName) ifFalse:[^interpreterProxy primitiveFail]. length := interpreterProxy byteSizeOf: pluginName. length >= 256 ifTrue:[^interpreterProxy primitiveFail]. ptr := interpreterProxy firstIndexableField: pluginName. needReload := false. 0 to: length-1 do:[:i| "Compare and store the plugin to be used" (bbPluginName at: i) = (ptr at: i) ifFalse:[ bbPluginName at: i put: (ptr at: i). needReload := true]]. (bbPluginName at: length) = 0 ifFalse:[ bbPluginName at: length put: 0. needReload := true]. needReload ifTrue:[ self initialiseModule ifFalse:[^interpreterProxy primitiveFail]]. interpreterProxy pop: 1. "Return receiver"! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:05'! primitiveSetClipRect | rectOop | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. rectOop := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isPointers: rectOop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: rectOop) < 2 ifTrue:[^interpreterProxy primitiveFail]. self loadPoint: self point1Get from: (interpreterProxy fetchPointer: 0 ofObject: rectOop). self loadPoint: self point2Get from: (interpreterProxy fetchPointer: 1 ofObject: rectOop). interpreterProxy failed ifFalse:[ self clipMinXPut: (self point1Get at: 0). self clipMinYPut: (self point1Get at: 1). self clipMaxXPut: (self point2Get at: 0). self clipMaxYPut: (self point2Get at: 1). self storeEngineStateInto: engine. interpreterProxy pop: 1. "Leave rcvr on stack" ].! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:11'! primitiveSetColorTransform | transformOop | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. transformOop := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. self loadColorTransformFrom: transformOop. interpreterProxy failed ifFalse:[ self storeEngineStateInto: engine. interpreterProxy pop: 1. "Leave rcvr on stack" ].! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:06'! primitiveSetDepth | depth | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. depth := interpreterProxy stackIntegerValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. self currentZPut: depth. interpreterProxy failed ifFalse:[ self storeEngineStateInto: engine. interpreterProxy pop: 1. "Leave rcvr on stack" ].! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:14'! primitiveSetEdgeTransform | transformOop | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. transformOop := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. self loadEdgeTransformFrom: transformOop. interpreterProxy failed ifFalse:[ self storeEngineStateInto: engine. interpreterProxy pop: 1. "Leave rcvr on stack" ].! ! !BalloonEngineBase methodsFor: 'primitives-access' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:13'! primitiveSetOffset | pointOop | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. pointOop := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy fetchClassOf: pointOop) = interpreterProxy classPoint ifFalse:[^interpreterProxy primitiveFail]. self loadPoint: self point1Get from: pointOop. interpreterProxy failed ifFalse:[ self destOffsetXPut: (self point1Get at: 0). self destOffsetYPut: (self point1Get at: 1). self storeEngineStateInto: engine. interpreterProxy pop: 1. "Leave rcvr on stack" ].! ! !BalloonEngineBase methodsFor: 'primitives-rendering' stamp: 'ar (auto pragmas 12/08) 5/13/2000 15:00'! proceedRenderingImage "This is the main rendering entry" | external | [self finishedProcessing] whileFalse:[ doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. external := self findNextExternalEntryFromGET. doProfileStats ifTrue:[ self incrementStat: GWCountNextGETEntry by: 1. self incrementStat: GWTimeNextGETEntry by: (interpreterProxy ioMicroMSecs - geProfileTime)]. engineStopped ifTrue:[^self statePut: GEStateAddingFromGET]. external ifTrue:[ self statePut: GEStateWaitingForEdge. ^self stopBecauseOf: GErrorGETEntry. ]. self aetStartPut: 0. self wbStackClear. self clearSpanBufferPut: 1. doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. (self clearSpanBufferGet ~= 0 and:[(self currentYGet bitAnd: self aaScanMaskGet) = 0]) ifTrue:[self clearSpanBuffer]. self clearSpanBufferPut: 0. external := self findNextExternalFillFromAET. doProfileStats ifTrue:[ self incrementStat: GWCountNextFillEntry by: 1. self incrementStat: GWTimeNextFillEntry by: (interpreterProxy ioMicroMSecs - geProfileTime)]. engineStopped ifTrue:[^self statePut: GEStateScanningAET]. external ifTrue:[ self statePut: GEStateWaitingForFill. ^self stopBecauseOf: GErrorFillEntry. ]. self wbStackClear. self spanEndAAPut: 0. doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. (self currentYGet bitAnd: self aaScanMaskGet) = self aaScanMaskGet ifTrue:[ self displaySpanBufferAt: self currentYGet. self postDisplayAction. ]. doProfileStats ifTrue:[ self incrementStat: GWCountDisplaySpan by: 1. self incrementStat: GWTimeDisplaySpan by: (interpreterProxy ioMicroMSecs - geProfileTime)]. engineStopped ifTrue:[^self statePut: GEStateBlitBuffer]. self finishedProcessing ifTrue:[^0]. self aetStartPut: 0. self currentYPut: self currentYGet + 1. doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. external := self findNextExternalUpdateFromAET. doProfileStats ifTrue:[ self incrementStat: GWCountNextAETEntry by: 1. self incrementStat: GWTimeNextAETEntry by: (interpreterProxy ioMicroMSecs - geProfileTime)]. engineStopped ifTrue:[^self statePut: GEStateUpdateEdges]. external ifTrue:[ self statePut: GEStateWaitingChange. ^self stopBecauseOf: GErrorAETEntry. ]. ].! ! !BalloonEngineBase methodsFor: 'primitives-rendering' stamp: 'ar (auto pragmas 12/08) 5/13/2000 15:00'! proceedRenderingScanline "Proceed rendering the current scan line. This method may be called after some Smalltalk code has been executed inbetween." "This is the main rendering entry" | external state | state := self stateGet. state = GEStateUnlocked ifTrue:[ self initializeGETProcessing. engineStopped ifTrue:[^0]. state := GEStateAddingFromGET. ]. state = GEStateAddingFromGET ifTrue:[ doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. external := self findNextExternalEntryFromGET. doProfileStats ifTrue:[ self incrementStat: GWCountNextGETEntry by: 1. self incrementStat: GWTimeNextGETEntry by: (interpreterProxy ioMicroMSecs - geProfileTime)]. engineStopped ifTrue:[^self statePut: GEStateAddingFromGET]. external ifTrue:[ self statePut: GEStateWaitingForEdge. ^self stopBecauseOf: GErrorGETEntry. ]. self aetStartPut: 0. self wbStackClear. self clearSpanBufferPut: 1. state := GEStateScanningAET. ]. state = GEStateScanningAET ifTrue:[ doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. (self clearSpanBufferGet ~= 0 and:[(self currentYGet bitAnd: self aaScanMaskGet) = 0]) ifTrue:[self clearSpanBuffer]. self clearSpanBufferPut: 0. external := self findNextExternalFillFromAET. doProfileStats ifTrue:[ self incrementStat: GWCountNextFillEntry by: 1. self incrementStat: GWTimeNextFillEntry by: (interpreterProxy ioMicroMSecs - geProfileTime)]. engineStopped ifTrue:[^self statePut: GEStateScanningAET]. external ifTrue:[ self statePut: GEStateWaitingForFill. ^self stopBecauseOf: GErrorFillEntry. ]. state := GEStateBlitBuffer. self wbStackClear. self spanEndAAPut: 0. ]. state = GEStateBlitBuffer ifTrue:[ doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. (self currentYGet bitAnd: self aaScanMaskGet) = self aaScanMaskGet ifTrue:[ self displaySpanBufferAt: self currentYGet. self postDisplayAction. ]. doProfileStats ifTrue:[ self incrementStat: GWCountDisplaySpan by: 1. self incrementStat: GWTimeDisplaySpan by: (interpreterProxy ioMicroMSecs - geProfileTime)]. engineStopped ifTrue:[^self statePut: GEStateBlitBuffer]. self finishedProcessing ifTrue:[^0]. state := GEStateUpdateEdges. self aetStartPut: 0. self currentYPut: self currentYGet + 1. ]. state = GEStateUpdateEdges ifTrue:[ doProfileStats ifTrue:[geProfileTime := interpreterProxy ioMicroMSecs]. external := self findNextExternalUpdateFromAET. doProfileStats ifTrue:[ self incrementStat: GWCountNextAETEntry by: 1. self incrementStat: GWTimeNextAETEntry by: (interpreterProxy ioMicroMSecs - geProfileTime)]. engineStopped ifTrue:[^self statePut: GEStateUpdateEdges]. external ifTrue:[ self statePut: GEStateWaitingChange. ^self stopBecauseOf: GErrorAETEntry. ]. self statePut: GEStateAddingFromGET. ].! ! !BalloonEngineBase methodsFor: 'loading state' stamp: 'ar (auto pragmas dtl 2010-09-27) 11/25/1998 00:36'! quickLoadEngineFrom: engineOop "Load the minimal required state from the engineOop, e.g., just the work buffer." interpreterProxy failed ifTrue:[^false]. (interpreterProxy isIntegerObject: engineOop) ifTrue:[^false]. (interpreterProxy isPointers: engineOop) ifFalse:[^false]. (interpreterProxy slotSizeOf: engineOop) < BEBalloonEngineSize ifTrue:[^false]. engine := engineOop. (self loadWorkBufferFrom: (interpreterProxy fetchPointer: BEWorkBufferIndex ofObject: engineOop)) ifFalse:[^false]. self stopReasonPut: 0. objUsed := self objUsedGet. engineStopped := false. ^true! ! !BalloonEngineBase methodsFor: 'loading state' stamp: 'ar (auto pragmas dtl 2010-09-27) 10/28/1998 21:06'! quickLoadEngineFrom: oop requiredState: requiredState (self quickLoadEngineFrom: oop) ifFalse:[^false]. self stateGet = requiredState ifTrue:[^true]. self stopReasonPut: GErrorBadState. ^false! ! !BalloonEngineBase methodsFor: 'loading state' stamp: 'ar (auto pragmas dtl 2010-09-27) 10/31/1998 17:23'! quickLoadEngineFrom: oop requiredState: requiredState or: alternativeState (self quickLoadEngineFrom: oop) ifFalse:[^false]. self stateGet = requiredState ifTrue:[^true]. self stateGet = alternativeState ifTrue:[^true]. self stopReasonPut: GErrorBadState. ^false! ! !BalloonEngineBase methodsFor: 'FILL processing' stamp: 'ar 11/25/1998 15:16'! quickRemoveInvalidFillsAt: leftX "Remove any top fills if they have become invalid." self stackFillSize = 0 ifTrue:[^nil]. [self topRightX <= leftX] whileTrue:[ self hideFill: self topFill depth: self topDepth. self stackFillSize = 0 ifTrue:[^nil]. ].! ! !BalloonEngineBase methodsFor: 'GET processing' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:38'! quickSortGlobalEdgeTable: array from: i to: j "Sort elements i through j of self to be nondescending according to sortBlock." "Note: The original loop has been heavily re-written for C translation" | di dij dj tt ij k l n tmp again before | "The prefix d means the data at that index." (n := j + 1 - i) <= 1 ifTrue: [^0]. "Nothing to sort." "Sort di,dj." di := array at: i. dj := array at: j. before := self getSorts: di before: dj. "i.e., should di precede dj?" before ifFalse:[ tmp := array at: i. array at: i put: (array at: j). array at: j put: tmp. tt := di. di := dj. dj := tt]. n <= 2 ifTrue:[^0]. "More than two elements." ij := (i + j) // 2. "ij is the midpoint of i and j." dij := array at: ij. "Sort di,dij,dj. Make dij be their median." before := (self getSorts: di before: dij). "i.e. should di precede dij?" before ifTrue:[ before := (self getSorts: dij before: dj). "i.e., should dij precede dj?" before ifFalse:["i.e., should dij precede dj?" tmp := array at: j. array at: j put: (array at: ij). array at: ij put: tmp. dij := dj] ] ifFalse:[ "i.e. di should come after dij" tmp := array at: i. array at: i put: (array at: ij). array at: ij put: tmp. dij := di]. n <= 3 ifTrue:[^0]. "More than three elements." "Find k>i and l index := self aetStartGet. self aetUsedPut: self aetUsedGet - 1. [index < self aetUsedGet] whileTrue:[ aetBuffer at: index put: (aetBuffer at: index + 1). index := index + 1. ].! ! !BalloonEngineBase methodsFor: 'other' stamp: 'ar (auto pragmas 12/08) 11/7/1998 14:26'! resetGraphicsEngineStats workBuffer at: GWTimeInitializing put: 0. workBuffer at: GWTimeFinishTest put: 0. workBuffer at: GWTimeNextGETEntry put: 0. workBuffer at: GWTimeAddAETEntry put: 0. workBuffer at: GWTimeNextFillEntry put: 0. workBuffer at: GWTimeMergeFill put: 0. workBuffer at: GWTimeDisplaySpan put: 0. workBuffer at: GWTimeNextAETEntry put: 0. workBuffer at: GWTimeChangeAETEntry put: 0. workBuffer at: GWCountInitializing put: 0. workBuffer at: GWCountFinishTest put: 0. workBuffer at: GWCountNextGETEntry put: 0. workBuffer at: GWCountAddAETEntry put: 0. workBuffer at: GWCountNextFillEntry put: 0. workBuffer at: GWCountMergeFill put: 0. workBuffer at: GWCountDisplaySpan put: 0. workBuffer at: GWCountNextAETEntry put: 0. workBuffer at: GWCountChangeAETEntry put: 0. workBuffer at: GWBezierMonotonSubdivisions put: 0. workBuffer at: GWBezierHeightSubdivisions put: 0. workBuffer at: GWBezierOverflowSubdivisions put: 0. workBuffer at: GWBezierLineConversions put: 0. ! ! !BalloonEngineBase methodsFor: 'AET processing' stamp: 'ar (auto pragmas 12/08) 10/28/1998 21:07'! resortFirstAETEntry | edge xValue leftEdge | self aetStartGet = 0 ifTrue:[^nil]. "Nothing to resort" edge := aetBuffer at: self aetStartGet. xValue := self edgeXValueOf: edge. leftEdge := aetBuffer at: (self aetStartGet - 1). (self edgeXValueOf: leftEdge) <= xValue ifTrue:[^nil]. "Okay" self moveAETEntryFrom: self aetStartGet edge: edge x: xValue.! ! !BalloonEngineBase methodsFor: 'other' stamp: 'ar (auto pragmas 12/08) 11/7/1998 14:26'! setAALevel: level "Set the anti-aliasing level. Three levels are supported: 1 - No antialiasing 2 - 2x2 unweighted anti-aliasing 4 - 4x4 unweighted anti-aliasing. " | aaLevel | level >= 4 ifTrue:[aaLevel := 4]. (level >= 2) & (level < 4) ifTrue:[aaLevel := 2]. level < 2 ifTrue:[aaLevel := 1]. self aaLevelPut: aaLevel. aaLevel = 1 ifTrue:[ self aaShiftPut: 0. self aaColorMaskPut: 16rFFFFFFFF. self aaScanMaskPut: 0. ]. aaLevel = 2 ifTrue:[ self aaShiftPut: 1. self aaColorMaskPut: 16rFCFCFCFC. self aaScanMaskPut: 1. ]. aaLevel = 4 ifTrue:[ self aaShiftPut: 2. self aaColorMaskPut: 16rF0F0F0F0. self aaScanMaskPut: 3. ]. self aaColorShiftPut: self aaShiftGet * 2. self aaHalfPixelPut: self aaShiftGet. ! ! !BalloonEngineBase methodsFor: 'FILL processing' stamp: 'ar (auto pragmas 12/08) 11/25/1998 14:38'! showFill: fillIndex depth: depth rightX: rightX (self allocateStackFillEntry) ifFalse:[^nil]. "Insufficient space" self stackFillValue: 0 put: fillIndex. self stackFillDepth: 0 put: depth. self stackFillRightX: 0 put: rightX. self stackFillSize = self stackFillEntryLength ifTrue:[^nil]. "No need to update" (self fillSorts: 0 before: self stackFillSize - self stackFillEntryLength) ifTrue:[ "New top fill" self stackFillValue: 0 put: self topFillValue. self stackFillDepth: 0 put: self topFillDepth. self stackFillRightX: 0 put: self topFillRightX. self topFillValuePut: fillIndex. self topFillDepthPut: depth. self topFillRightXPut: rightX. ].! ! !BalloonEngineBase methodsFor: 'other' stamp: 'ar (auto pragmas dtl 2010-09-27) 11/8/1998 15:25'! smallSqrtTable | theTable | ^theTable! ! !BalloonEngineBase methodsFor: 'GET processing' stamp: 'ar 10/27/1998 23:34'! sortGlobalEdgeTable "Sort the entire global edge table" self quickSortGlobalEdgeTable: getBuffer from: 0 to: self getUsedGet-1.! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:28'! spanEndAAGet ^workBuffer at: GWSpanEndAA! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:31'! spanEndAAPut: value ^workBuffer at: GWSpanEndAA put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:28'! spanEndGet ^workBuffer at: GWSpanEnd! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:31'! spanEndPut: value ^workBuffer at: GWSpanEnd put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:28'! spanSizeGet ^workBuffer at: GWSpanSize! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:31'! spanSizePut: value ^workBuffer at: GWSpanSize put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:28'! spanStartGet ^workBuffer at: GWSpanStart! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:31'! spanStartPut: value ^workBuffer at: GWSpanStart put: value! ! !BalloonEngineBase methodsFor: 'other' stamp: 'ar 11/8/1998 20:57'! squaredLengthOf: deltaX with: deltaY ^(deltaX * deltaX) + (deltaY * deltaY)! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 10/30/1998 19:08'! stackFillDepth: index ^self wbStackValue: index+1! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 10/30/1998 19:08'! stackFillDepth: index put: value ^self wbStackValue: index+1 put: value! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 11/25/1998 14:31'! stackFillEntryLength ^3! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 11/25/1998 14:35'! stackFillRightX: index ^self wbStackValue: index+2! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 11/25/1998 14:35'! stackFillRightX: index put: value ^self wbStackValue: index+2 put: value! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 10/30/1998 19:10'! stackFillSize ^self wbStackSize! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 10/30/1998 19:09'! stackFillValue: index ^self wbStackValue: index! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 10/30/1998 19:09'! stackFillValue: index put: value ^self wbStackValue: index put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:28'! stateGet ^workBuffer at: GWState! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:31'! statePut: value ^workBuffer at: GWState put: value! ! !BalloonEngineBase methodsFor: 'other' stamp: 'ar 11/25/1998 02:22'! stopBecauseOf: stopReason self stopReasonPut: stopReason. engineStopped := true.! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:28'! stopReasonGet ^workBuffer at: GWStopReason! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:31'! stopReasonPut: value ^workBuffer at: GWStopReason put: value! ! !BalloonEngineBase methodsFor: 'storing state' stamp: 'ar (auto pragmas 12/08) 11/11/1998 22:21'! storeEdgeStateFrom: edge into: edgeOop (interpreterProxy slotSizeOf: edgeOop) < ETBalloonEdgeDataSize ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy storeInteger: ETIndexIndex ofObject: edgeOop withValue: (self objectIndexOf: edge). interpreterProxy storeInteger: ETXValueIndex ofObject: edgeOop withValue: (self edgeXValueOf: edge). interpreterProxy storeInteger: ETYValueIndex ofObject: edgeOop withValue: (self currentYGet). interpreterProxy storeInteger: ETZValueIndex ofObject: edgeOop withValue: (self edgeZValueOf: edge). interpreterProxy storeInteger: ETLinesIndex ofObject: edgeOop withValue: (self edgeNumLinesOf: edge). self lastExportedEdgePut: edge.! ! !BalloonEngineBase methodsFor: 'storing state' stamp: 'ar 11/25/1998 00:36'! storeEngineStateInto: oop self objUsedPut: objUsed.! ! !BalloonEngineBase methodsFor: 'storing state' stamp: 'ar (auto pragmas 12/08) 11/11/1998 22:24'! storeFillStateInto: fillOop | fillIndex leftX rightX | fillIndex := self lastExportedFillGet. leftX := self lastExportedLeftXGet. rightX := self lastExportedRightXGet. (interpreterProxy slotSizeOf: fillOop) < FTBalloonFillDataSize ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy storeInteger: FTIndexIndex ofObject: fillOop withValue: (self objectIndexOf: fillIndex). interpreterProxy storeInteger: FTMinXIndex ofObject: fillOop withValue: leftX. interpreterProxy storeInteger: FTMaxXIndex ofObject: fillOop withValue: rightX. interpreterProxy storeInteger: FTYValueIndex ofObject: fillOop withValue: self currentYGet.! ! !BalloonEngineBase methodsFor: 'primitives-rendering' stamp: 'ar (auto pragmas 12/08) 10/31/1998 23:54'! storeRenderingState interpreterProxy failed ifTrue:[^nil]. engineStopped ifTrue:[ "Check the stop reason and store the required information" self storeStopStateIntoEdge: (interpreterProxy stackObjectValue: 1) fill: (interpreterProxy stackObjectValue: 0). ]. self storeEngineStateInto: engine. interpreterProxy pop: 3. interpreterProxy pushInteger: self stopReasonGet.! ! !BalloonEngineBase methodsFor: 'storing state' stamp: 'ar 11/9/1998 15:34'! storeStopStateIntoEdge: edgeOop fill: fillOop | reason edge | reason := self stopReasonGet. reason = GErrorGETEntry ifTrue:[ edge := getBuffer at: self getStartGet. self storeEdgeStateFrom: edge into: edgeOop. self getStartPut: self getStartGet + 1. ]. reason = GErrorFillEntry ifTrue:[ self storeFillStateInto: fillOop. ]. reason = GErrorAETEntry ifTrue:[ edge := aetBuffer at: self aetStartGet. self storeEdgeStateFrom: edge into: edgeOop. "Do not advance to the next aet entry yet" "self aetStartPut: self aetStartGet + 1." ].! ! !BalloonEngineBase methodsFor: 'FILL processing' stamp: 'ar (auto pragmas 12/08) 11/25/1998 14:38'! toggleFill: fillIndex depth: depth rightX: rightX "Make the fill style with the given index either visible or invisible" | hidden | self stackFillSize = 0 ifTrue:[ (self allocateStackFillEntry) ifTrue:[ self topFillValuePut: fillIndex. self topFillDepthPut: depth. self topFillRightXPut: rightX. ]. ] ifFalse:[ hidden := self hideFill: fillIndex depth: depth. hidden ifFalse:[self showFill: fillIndex depth: depth rightX: rightX]. ].! ! !BalloonEngineBase methodsFor: 'FILL processing' stamp: 'ar (auto pragmas 12/08) 11/25/1998 15:19'! toggleFillsOf: edge | depth fillIndex | (self needAvailableSpace: self stackFillEntryLength * 2) ifFalse:[^nil]. "Make sure we have enough space left" depth := (self edgeZValueOf: edge) << 1. fillIndex := self edgeLeftFillOf: edge. fillIndex = 0 ifFalse:[self toggleFill: fillIndex depth: depth rightX: 999999999]. fillIndex := self edgeRightFillOf: edge. fillIndex = 0 ifFalse:[self toggleFill: fillIndex depth: depth rightX: 999999999]. self quickRemoveInvalidFillsAt: (self edgeXValueOf: edge).! ! !BalloonEngineBase methodsFor: 'FILL processing' stamp: 'ar (auto pragmas 12/08) 11/25/1998 15:50'! toggleWideFillOf: edge | fill type lineWidth depth rightX index | type := self edgeTypeOf: edge. dispatchedValue := edge. self dispatchOn: type in: WideLineWidthTable. lineWidth := dispatchReturnValue. self dispatchOn: type in: WideLineFillTable. fill := dispatchReturnValue. fill = 0 ifTrue:[^nil]. (self needAvailableSpace: self stackFillEntryLength) ifFalse:[^nil]. "Make sure we have enough space left" depth := (self edgeZValueOf: edge) << 1 + 1. "So lines sort before interior fills" rightX := (self edgeXValueOf: edge) + lineWidth. index := self findStackFill: fill depth: depth. index = -1 ifTrue:[ self showFill: fill depth: depth rightX: rightX. ] ifFalse:[ (self stackFillRightX: index) < rightX ifTrue:[self stackFillRightX: index put: rightX]. ]. self quickRemoveInvalidFillsAt: (self edgeXValueOf: edge).! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 11/24/1998 22:49'! topDepth self stackFillSize = 0 ifTrue:[^-1] ifFalse:[^self topFillDepth].! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 10/30/1998 19:28'! topFill self stackFillSize = 0 ifTrue:[^0] ifFalse:[^self topFillValue].! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 10/30/1998 19:27'! topFillDepth ^self stackFillDepth: self stackFillSize - self stackFillEntryLength! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 10/30/1998 19:27'! topFillDepthPut: value ^self stackFillDepth: self stackFillSize - self stackFillEntryLength put: value! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 11/25/1998 14:36'! topFillRightX ^self stackFillRightX: self stackFillSize - self stackFillEntryLength! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 11/25/1998 14:36'! topFillRightXPut: value ^self stackFillRightX: self stackFillSize - self stackFillEntryLength put: value! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 10/30/1998 19:27'! topFillValue ^self stackFillValue: self stackFillSize - self stackFillEntryLength! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 10/30/1998 19:27'! topFillValuePut: value ^self stackFillValue: self stackFillSize - self stackFillEntryLength put: value! ! !BalloonEngineBase methodsFor: 'accessing fills' stamp: 'ar 11/25/1998 15:19'! topRightX self stackFillSize = 0 ifTrue:[^999999999] ifFalse:[^self topFillRightX].! ! !BalloonEngineBase methodsFor: 'transforming' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:42'! transformColor: fillIndex | r g b a transform alphaScale | (fillIndex = 0 or:[self isFillColor: fillIndex]) ifFalse:[^fillIndex]. b := fillIndex bitAnd: 255. g := (fillIndex >> 8) bitAnd: 255. r := (fillIndex >> 16) bitAnd: 255. a := (fillIndex >> 24) bitAnd: 255. (self hasColorTransform) ifTrue:[ transform := self colorTransform. alphaScale := (a * (transform at: 6) + (transform at: 7)) / a. r := (r * (transform at: 0) + (transform at: 1) * alphaScale) asInteger. g := (g * (transform at: 2) + (transform at: 3) * alphaScale) asInteger. b := (b * (transform at: 4) + (transform at: 5) * alphaScale) asInteger. a := a * alphaScale. r := r max: 0. r := r min: 255. g := g max: 0. g := g min: 255. b := b max: 0. b := b min: 255. a := a max: 0. a := a min: 255. ]. a < 1 ifTrue:[^0]."ALWAYS return zero for transparent fills" "If alpha is not 255 (or close thereto) then we need to flush the engine before proceeding" (a < 255 and:[self needsFlush]) ifTrue:[self stopBecauseOf: GErrorNeedFlush]. ^b + (g << 8) + (r << 16) + (a << 24)! ! !BalloonEngineBase methodsFor: 'transforming' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:43'! transformPoint: point "Transform the given point. If haveMatrix is true then use the current transformation." self hasEdgeTransform ifFalse:[ "Multiply each component by aaLevel and add a half pixel" point at: 0 put: (point at: 0) + self destOffsetXGet * self aaLevelGet. point at: 1 put: (point at: 1) + self destOffsetYGet * self aaLevelGet. ] ifTrue:[ "Note: AA adjustment is done in #transformPoint: for higher accuracy" self transformPoint: point into: point. ].! ! !BalloonEngineBase methodsFor: 'transforming' stamp: 'ar (auto pragmas 12/08) 11/1/1998 16:59'! transformPoint: srcPoint into: dstPoint "Transform srcPoint into dstPoint by using the currently loaded matrix" "Note: This method has been rewritten so that inlining works (e.g., removing the declarations and adding argument coercions at the appropriate points)" self transformPointX: ((self cCoerce: srcPoint to: 'int *') at: 0) asFloat y: ((self cCoerce: srcPoint to:'int *') at: 1) asFloat into: (self cCoerce: dstPoint to: 'int *')! ! !BalloonEngineBase methodsFor: 'transforming' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 17:23'! transformPointX: xValue y: yValue into: dstPoint "Transform srcPoint into dstPoint by using the currently loaded matrix" "Note: This should be rewritten so that inlining works (e.g., removing the declarations and adding argument coercions at the appropriate points)" | x y transform | transform := self edgeTransform. x := ((((transform at: 0) * xValue) + ((transform at: 1) * yValue) + (transform at: 2)) * self aaLevelGet asFloat) asInteger. y := ((((transform at: 3) * xValue) + ((transform at: 4) * yValue) + (transform at: 5)) * self aaLevelGet asFloat) asInteger. dstPoint at: 0 put: x. dstPoint at: 1 put: y.! ! !BalloonEngineBase methodsFor: 'transforming' stamp: 'ar (auto pragmas 12/08) 11/24/1998 19:48'! transformPoints: n "Transform n (n=1,2,3) points. If haveMatrix is true then the matrix contains the actual transformation." n > 0 ifTrue:[self transformPoint: self point1Get]. n > 1 ifTrue:[self transformPoint: self point2Get]. n > 2 ifTrue:[self transformPoint: self point3Get]. n > 3 ifTrue:[self transformPoint: self point4Get].! ! !BalloonEngineBase methodsFor: 'transforming' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:43'! transformWidth: w "Transform the given width" | deltaX deltaY dstWidth dstWidth2 | w = 0 ifTrue:[^0]. self point1Get at: 0 put: 0. self point1Get at: 1 put: 0. self point2Get at: 0 put: w * 256. self point2Get at: 1 put: 0. self point3Get at: 0 put: 0. self point3Get at: 1 put: w * 256. self transformPoints: 3. deltaX := ((self point2Get at: 0) - (self point1Get at: 0)) asFloat. deltaY := ((self point2Get at: 1) - (self point1Get at: 1)) asFloat. dstWidth := (((deltaX * deltaX) + (deltaY * deltaY)) sqrt asInteger + 128) // 256. deltaX := ((self point3Get at: 0) - (self point1Get at: 0)) asFloat. deltaY := ((self point3Get at: 1) - (self point1Get at: 1)) asFloat. dstWidth2 := (((deltaX * deltaX) + (deltaY * deltaY)) sqrt asInteger + 128) // 256. dstWidth2 < dstWidth ifTrue:[dstWidth := dstWidth2]. dstWidth = 0 ifTrue:[^1] ifFalse:[^dstWidth]! ! !BalloonEngineBase methodsFor: 'transforming' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:43'! uncheckedTransformColor: fillIndex | r g b a transform | (self hasColorTransform) ifFalse:[^fillIndex]. b := fillIndex bitAnd: 255. g := (fillIndex >> 8) bitAnd: 255. r := (fillIndex >> 16) bitAnd: 255. a := (fillIndex >> 24) bitAnd: 255. transform := self colorTransform. r := (r * (transform at: 0) + (transform at: 1)) asInteger. g := (g * (transform at: 2) + (transform at: 3)) asInteger. b := (b * (transform at: 4) + (transform at: 5)) asInteger. a := (a * (transform at: 6) + (transform at: 7)) asInteger. r := r max: 0. r := r min: 255. g := g max: 0. g := g min: 255. b := b max: 0. b := b min: 255. a := a max: 0. a := a min: 255. a < 16 ifTrue:[^0]."ALWAYS return zero for transparent fills" ^b + (g << 8) + (r << 16) + (a << 24)! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:28'! wbSizeGet ^workBuffer at: GWSize! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:37'! wbSizePut: value ^workBuffer at: GWSize put: value! ! !BalloonEngineBase methodsFor: 'accessing stack' stamp: 'ar 10/31/1998 00:43'! wbStackClear self wbTopPut: self wbSizeGet.! ! !BalloonEngineBase methodsFor: 'accessing stack' stamp: 'ar 11/9/1998 15:34'! wbStackPop: nItems self wbTopPut: self wbTopGet + nItems.! ! !BalloonEngineBase methodsFor: 'accessing stack' stamp: 'ar 10/30/1998 17:16'! wbStackPush: nItems (self allocateStackEntry: nItems) ifFalse:[^false]. self wbTopPut: self wbTopGet - nItems. ^true! ! !BalloonEngineBase methodsFor: 'accessing stack' stamp: 'ar 10/30/1998 17:17'! wbStackSize ^self wbSizeGet - self wbTopGet! ! !BalloonEngineBase methodsFor: 'accessing stack' stamp: 'ar 11/9/1998 15:34'! wbStackValue: index ^workBuffer at: self wbTopGet + index! ! !BalloonEngineBase methodsFor: 'accessing stack' stamp: 'ar 11/9/1998 15:34'! wbStackValue: index put: value ^workBuffer at: self wbTopGet + index put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 23:29'! wbTopGet ^workBuffer at: GWBufferTop! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 10/27/1998 18:32'! wbTopPut: value ^workBuffer at: GWBufferTop put: value! ! !BalloonEngineBase methodsFor: 'accessing state' stamp: 'ar 7/11/2004 13:43'! workBufferPut: wbOop workBuffer := interpreterProxy firstIndexableField: wbOop.! ! BalloonEngineBase subclass: #BalloonEnginePlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !BalloonEnginePlugin commentStamp: 'tpr 5/5/2003 11:46' prior: 0! This class adds the plugin functionality for the Balloon graphics engine. BalloonEnginePlugin should be translated but its superclass should not since it is incorporated within this class's translation process. Nor should the simulation subclass be translated! !BalloonEnginePlugin class methodsFor: 'class initialization' stamp: 'ar 11/11/1998 22:01'! declareCVarsIn: cg "Nothing to declare"! ! !BalloonEnginePlugin methodsFor: 'private' stamp: 'ar (auto pragmas 12/08) 10/30/1998 20:02'! absoluteSquared8Dot24: value "Compute the squared value of a 8.24 number with 0.0 <= value < 1.0, e.g., compute (value * value) bitShift: -24" | word1 word2 | word1 := value bitAnd: 16rFFFF. word2 := (value bitShift: -16) bitAnd: 255. ^(( (self cCoerce: (word1 * word1) to:'unsigned') bitShift: -16) + ((word1 * word2) * 2) + ((word2 * word2) bitShift: 16)) bitShift: -8! ! !BalloonEnginePlugin methodsFor: 'beziers-wide' stamp: 'ar (auto pragmas 12/08) 11/8/1998 15:18'! adjustWideBezierLeft: bezier width: lineWidth offset: lineOffset endX: endX "Adjust the wide bezier curve (dx < 0) to start/end at the right point" | lastX lastY | (self bezierUpdateDataOf: bezier) at: GBUpdateX put: (((self bezierUpdateDataOf: bezier) at: GBUpdateX) - (lineOffset * 256)). "Set the lastX/Y value of the second curve lineWidth pixels right/down" lastX := (self wideBezierUpdateDataOf: bezier) at: GBUpdateX. (self wideBezierUpdateDataOf: bezier) at: GBUpdateX put: lastX + (lineWidth - lineOffset * 256). "Set lineWidth pixels down" lastY := (self wideBezierUpdateDataOf: bezier) at: GBUpdateY. (self wideBezierUpdateDataOf: bezier) at: GBUpdateY put: lastY + (lineWidth * 256). "Record the last X value" self bezierFinalXOf: bezier put: endX - lineOffset. ! ! !BalloonEnginePlugin methodsFor: 'beziers-wide' stamp: 'ar (auto pragmas 12/08) 11/8/1998 15:18'! adjustWideBezierRight: bezier width: lineWidth offset: lineOffset endX: endX "Adjust the wide bezier curve (dx >= 0) to start/end at the right point" | lastX lastY | (self bezierUpdateDataOf: bezier) at: GBUpdateX put: (((self bezierUpdateDataOf: bezier) at: GBUpdateX) + (lineOffset * 256)). "Set the lastX/Y value of the second curve lineWidth pixels right/down" "Set lineWidth-lineOffset pixels left" lastX := (self wideBezierUpdateDataOf: bezier) at: GBUpdateX. (self wideBezierUpdateDataOf: bezier) at: GBUpdateX put: lastX - (lineWidth - lineOffset * 256). lastY := (self wideBezierUpdateDataOf: bezier) at: GBUpdateY. "Set lineWidth pixels down" (self wideBezierUpdateDataOf: bezier) at: GBUpdateY put: lastY + (lineWidth * 256). "Record the last X value" self bezierFinalXOf: bezier put: endX - lineOffset + lineWidth.! ! !BalloonEnginePlugin methodsFor: 'lines-wide' stamp: 'ar (auto pragmas 12/08) 11/9/1998 15:34'! adjustWideLine: line afterSteppingFrom: lastX to: nextX "Adjust the wide line after it has been stepped from lastX to nextX. Special adjustments of line width and start position are made here to simulate a rectangular brush" | yEntry yExit lineWidth lineOffset deltaX xDir baseWidth | "Don't inline this" "Fetch the values the adjustment decisions are based on" yEntry := (self wideLineEntryOf: line). yExit := (self wideLineExitOf: line). baseWidth := self wideLineExtentOf: line. lineOffset := self offsetFromWidth: baseWidth. lineWidth := self wideLineWidthOf: line. xDir := self lineXDirectionOf: line. deltaX := nextX - lastX. "Adjust the start of the line to fill an entire rectangle" yEntry < baseWidth ifTrue:[ xDir < 0 ifTrue:[ lineWidth := lineWidth - deltaX] "effectively adding" ifFalse:[ lineWidth := lineWidth + deltaX. self edgeXValueOf: line put: lastX]. ]. "Adjust the end of x-major lines" ((yExit + lineOffset) = 0) ifTrue:[ xDir > 0 ifTrue:[lineWidth := lineWidth - (self lineXIncrementOf: line)] ifFalse:[lineWidth := lineWidth + (self lineXIncrementOf: line). "effectively subtracting" self edgeXValueOf: line put: lastX]. ]. "Adjust the end of the line to fill an entire rectangle" (yExit + lineOffset) > 0 ifTrue:[ xDir < 0 ifTrue:[ lineWidth := lineWidth + deltaX. "effectively subtracting" self edgeXValueOf: line put: lastX] ifFalse:[ lineWidth := lineWidth - deltaX] ]. "Store the manipulated line width back" self wideLineWidthOf: line put: lineWidth.! ! !BalloonEnginePlugin methodsFor: 'allocation' stamp: 'ar 11/25/1998 00:38'! allocateBezier | bezier | (self allocateObjEntry: GBBaseSize) ifFalse:[^0]. bezier := objUsed. objUsed := bezier + GBBaseSize. self objectTypeOf: bezier put: GEPrimitiveBezier. self objectIndexOf: bezier put: 0. self objectLengthOf: bezier put: GBBaseSize. ^bezier! ! !BalloonEnginePlugin methodsFor: 'allocation' stamp: 'ar 10/30/1998 20:52'! allocateBezierStackEntry self wbStackPush: 6. ^self wbStackSize! ! !BalloonEnginePlugin methodsFor: 'allocation' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:44'! allocateBitmapFill: cmSize colormap: cmBits | fill fillSize cm | fillSize := GBMBaseSize + cmSize. (self allocateObjEntry: fillSize) ifFalse:[^0]. fill := objUsed. objUsed := fill + fillSize. self objectTypeOf: fill put: GEPrimitiveClippedBitmapFill. self objectIndexOf: fill put: 0. self objectLengthOf: fill put: fillSize. cm := self colormapOf: fill. self hasColorTransform ifTrue:[ 0 to: cmSize-1 do:[:i| cm at: i put: (self transformColor: (cmBits at: i))]. ] ifFalse:[ 0 to: cmSize-1 do:[:i| cm at: i put: (cmBits at: i)]. ]. self bitmapCmSizeOf: fill put: cmSize. ^fill! ! !BalloonEnginePlugin methodsFor: 'allocation' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:44'! allocateGradientFill: ramp rampWidth: rampWidth isRadial: isRadial | fill fillSize rampPtr | fillSize := GGBaseSize + rampWidth. (self allocateObjEntry: fillSize) ifFalse:[^0]. fill := objUsed. objUsed := fill + fillSize. isRadial ifTrue:[self objectTypeOf: fill put: GEPrimitiveRadialGradientFill] ifFalse:[self objectTypeOf: fill put: GEPrimitiveLinearGradientFill]. self objectIndexOf: fill put: 0. self objectLengthOf: fill put: fillSize. rampPtr := self gradientRampOf: fill. self hasColorTransform ifTrue:[ 0 to: rampWidth-1 do:[:i| rampPtr at: i put: (self transformColor: (ramp at: i))]. ] ifFalse:[ 0 to: rampWidth-1 do:[:i| rampPtr at: i put: (ramp at: i)]. ]. self gradientRampLengthOf: fill put: rampWidth. ^fill! ! !BalloonEnginePlugin methodsFor: 'allocation' stamp: 'ar 11/25/1998 00:39'! allocateLine | line | (self allocateObjEntry: GLBaseSize) ifFalse:[^0]. line := objUsed. objUsed := line + GLBaseSize. self objectTypeOf: line put: GEPrimitiveLine. self objectIndexOf: line put: 0. self objectLengthOf: line put: GLBaseSize. ^line! ! !BalloonEnginePlugin methodsFor: 'allocation' stamp: 'ar 11/25/1998 00:39'! allocateWideBezier | bezier | (self allocateObjEntry: GBWideSize) ifFalse:[^0]. bezier := objUsed. objUsed := bezier + GBWideSize. self objectTypeOf: bezier put: GEPrimitiveWideBezier. self objectIndexOf: bezier put: 0. self objectLengthOf: bezier put: GBWideSize. ^bezier! ! !BalloonEnginePlugin methodsFor: 'allocation' stamp: 'ar 11/25/1998 00:39'! allocateWideLine | line | (self allocateObjEntry: GLWideSize) ifFalse:[^0]. line := objUsed. objUsed := line + GLWideSize. self objectTypeOf: line put: GEPrimitiveWideLine. self objectIndexOf: line put: 0. self objectLengthOf: line put: GLWideSize. ^line! ! !BalloonEnginePlugin methodsFor: 'bezier-loading' stamp: 'ar (auto pragmas 12/08) 11/9/1998 01:56'! assureValue: val1 between: val2 and: val3 "Make sure that val1 is between val2 and val3." val2 > val3 ifTrue:[ val1 > val2 ifTrue:[^val2]. val1 < val3 ifTrue:[^val3]. ] ifFalse:[ val1 < val2 ifTrue:[^val2]. val1 > val3 ifTrue:[^val3]. ]. ^val1 ! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:20'! bezierEndXOf: bezier ^self obj: bezier at: GBEndX! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:17'! bezierEndXOf: bezier put: value ^self obj: bezier at: GBEndX put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:17'! bezierEndYOf: bezier ^self obj: bezier at: GBEndY! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:18'! bezierEndYOf: bezier put: value ^self obj: bezier at: GBEndY put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:19'! bezierFinalXOf: bezier ^self obj: bezier at: GBFinalX! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:18'! bezierFinalXOf: bezier put: value ^self obj: bezier at: GBFinalX put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar (auto pragmas 12/08) 11/24/1998 22:24'! bezierUpdateDataOf: bezier ^objBuffer + bezier + GBUpdateData! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:20'! bezierViaXOf: bezier ^self obj: bezier at: GBViaX! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:17'! bezierViaXOf: bezier put: value ^self obj: bezier at: GBViaX put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:17'! bezierViaYOf: bezier ^self obj: bezier at: GBViaY! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:18'! bezierViaYOf: bezier put: value ^self obj: bezier at: GBViaY put: value! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/24/1998 22:20'! bitmapCmSizeOf: bmFill ^self obj: bmFill at: GBColormapSize! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/24/1998 22:19'! bitmapCmSizeOf: bmFill put: value ^self obj: bmFill at: GBColormapSize put: value! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/24/1998 22:17'! bitmapDepthOf: bmFill ^self obj: bmFill at: GBBitmapDepth! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/24/1998 22:20'! bitmapDepthOf: bmFill put: value ^self obj: bmFill at: GBBitmapDepth put: value! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/24/1998 22:17'! bitmapHeightOf: bmFill ^self obj: bmFill at: GBBitmapHeight! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/24/1998 22:17'! bitmapHeightOf: bmFill put: value ^self obj: bmFill at: GBBitmapHeight put: value! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/24/1998 22:18'! bitmapRasterOf: bmFill ^self obj: bmFill at: GBBitmapRaster! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/24/1998 22:18'! bitmapRasterOf: bmFill put: value ^self obj: bmFill at: GBBitmapRaster put: value! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/24/1998 22:19'! bitmapSizeOf: bmFill ^self obj: bmFill at: GBBitmapSize! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/24/1998 22:18'! bitmapSizeOf: bmFill put: value ^self obj: bmFill at: GBBitmapSize put: value! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/27/1998 14:20'! bitmapTileFlagOf: bmFill ^self obj: bmFill at: GBTileFlag! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/27/1998 14:20'! bitmapTileFlagOf: bmFill put: value ^self obj: bmFill at: GBTileFlag put: value! ! !BalloonEnginePlugin methodsFor: 'fills-bitmaps' stamp: 'ikp (auto pragmas 12/08) 6/14/2004 15:22'! bitmapValue: bmFill bits: bits atX: xp y: yp | bmDepth bmRaster value rShift cMask r g b a | bmDepth := self bitmapDepthOf: bmFill. bmRaster := self bitmapRasterOf: bmFill. bmDepth = 32 ifTrue: [ value := (self cCoerce: bits to:'int*') at: (bmRaster * yp) + xp. (value ~= 0 and: [(value bitAnd: 16rFF000000) = 0]) ifTrue: [value := value bitOr: 16rFF000000]. ^self uncheckedTransformColor: value]. "rShift - shift value to convert from pixel to word index" rShift := self rShiftTable at: bmDepth. value := self makeUnsignedFrom: ((self cCoerce: bits to:'int*') at: (bmRaster * yp) + (xp >> rShift)). "cMask - mask out the pixel from the word" cMask := (1 << bmDepth) - 1. "rShift - shift value to move the pixel in the word to the lowest bit position" rShift := 32 - bmDepth - ((xp bitAnd: (1 << rShift - 1)) * bmDepth). value := (value >> rShift) bitAnd: cMask. bmDepth = 16 ifTrue: [ "Must convert by expanding bits" value = 0 ifFalse: [ b := (value bitAnd: 31) << 3. b := b + (b >> 5). g := (value >> 5 bitAnd: 31) << 3. g := g + (g >> 5). r := (value >> 10 bitAnd: 31) << 3. r := r + (r >> 5). a := 255. value := b + (g << 8) + (r << 16) + (a << 24)]. ] ifFalse: [ "Must convert by using color map" (self bitmapCmSizeOf: bmFill) = 0 ifTrue: [value := 0] ifFalse: [value := self makeUnsignedFrom: ((self colormapOf: bmFill) at: value)]. ]. ^self uncheckedTransformColor: value.! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/24/1998 22:18'! bitmapWidthOf: bmFill ^self obj: bmFill at: GBBitmapWidth! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar 11/24/1998 22:17'! bitmapWidthOf: bmFill put: value ^self obj: bmFill at: GBBitmapWidth put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 10/30/1998 20:53'! bzEndX: index ^self wbStackValue: self wbStackSize - index + 4! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 10/30/1998 20:53'! bzEndX: index put: value ^self wbStackValue: self wbStackSize - index + 4 put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 10/30/1998 20:53'! bzEndY: index ^self wbStackValue: self wbStackSize - index + 5! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 10/30/1998 20:53'! bzEndY: index put: value ^self wbStackValue: self wbStackSize - index + 5 put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 10/30/1998 20:54'! bzStartX: index ^self wbStackValue: self wbStackSize - index + 0! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 10/30/1998 20:54'! bzStartX: index put: value ^self wbStackValue: self wbStackSize - index + 0 put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 10/30/1998 20:53'! bzStartY: index ^self wbStackValue: self wbStackSize - index + 1! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 10/30/1998 20:54'! bzStartY: index put: value ^self wbStackValue: self wbStackSize - index + 1 put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 10/30/1998 20:53'! bzViaX: index ^self wbStackValue: self wbStackSize - index + 2! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 10/30/1998 20:54'! bzViaX: index put: value ^self wbStackValue: self wbStackSize - index + 2 put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 10/30/1998 20:53'! bzViaY: index ^self wbStackValue: self wbStackSize - index + 3! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 10/30/1998 20:54'! bzViaY: index put: value ^self wbStackValue: self wbStackSize - index + 3 put: value! ! !BalloonEnginePlugin methodsFor: 'shapes-compressed' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:45'! checkCompressedFillIndexList: fillList max: maxIndex segments: nSegs "Check the fill indexes in the run-length encoded fillList" | length runLength runValue nFills fillPtr | length := interpreterProxy slotSizeOf: fillList. fillPtr := interpreterProxy firstIndexableField: fillList. nFills := 0. 0 to: length-1 do:[:i | runLength := self shortRunLengthAt: i from: fillPtr. runValue := self shortRunValueAt: i from: fillPtr. (runValue >= 0 and:[runValue <= maxIndex]) ifFalse:[^false]. nFills := nFills + runLength. ]. ^nFills = nSegs! ! !BalloonEnginePlugin methodsFor: 'shapes-compressed' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:45'! checkCompressedFills: indexList "Check if the indexList (containing fill handles) is okay." | fillPtr length fillIndex | "First check if the oops have the right format" (interpreterProxy isWords: indexList) ifFalse:[^false]. "Then check the fill entries" length := interpreterProxy slotSizeOf: indexList. fillPtr := interpreterProxy firstIndexableField: indexList. 0 to: length-1 do:[:i | fillIndex := fillPtr at: i. "Make sure the fill is okay" (self isFillOkay: fillIndex) ifFalse:[^false]]. ^ true! ! !BalloonEnginePlugin methodsFor: 'shapes-compressed' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:45'! checkCompressedLineWidths: lineWidthList segments: nSegments "Check the run-length encoded lineWidthList matches nSegments" | length runLength nItems ptr | length := interpreterProxy slotSizeOf: lineWidthList. ptr := interpreterProxy firstIndexableField: lineWidthList. nItems := 0. 0 to: length-1 do:[:i| runLength := self shortRunLengthAt: i from: ptr. nItems := nItems + runLength. ]. ^nItems = nSegments! ! !BalloonEnginePlugin methodsFor: 'shapes-compressed' stamp: 'ar (auto pragmas 12/08) 11/8/1998 15:19'! checkCompressedPoints: points segments: nSegments "Check if the given point array can be handled by the engine." | pSize | (interpreterProxy isWords: points) ifFalse:[^false]. pSize := interpreterProxy slotSizeOf: points. "The points must be either in PointArray format or ShortPointArray format. Also, we currently handle only quadratic segments (e.g., 3 points each) and thus either pSize = nSegments * 3, for ShortPointArrays or, pSize = nSegments * 6, for PointArrays" (pSize = (nSegments * 3) or:[pSize = (nSegments * 6)]) ifFalse:[^false]. "Can't handle this" ^true! ! !BalloonEnginePlugin methodsFor: 'shapes-compressed' stamp: 'ar (auto pragmas 12/08) 11/12/1998 21:22'! checkCompressedShape: points segments: nSegments leftFills: leftFills rightFills: rightFills lineWidths: lineWidths lineFills: lineFills fillIndexList: fillIndexList "Check if the given shape can be handled by the engine. Since there are a number of requirements this is an extra method." | maxFillIndex | (self checkCompressedPoints: points segments: nSegments) ifFalse:[^false]. (self checkCompressedFills: fillIndexList) ifFalse:[^false]. maxFillIndex := interpreterProxy slotSizeOf: fillIndexList. (self checkCompressedFillIndexList: leftFills max: maxFillIndex segments: nSegments) ifFalse:[^false]. (self checkCompressedFillIndexList: rightFills max: maxFillIndex segments: nSegments) ifFalse:[^false]. (self checkCompressedFillIndexList: lineFills max: maxFillIndex segments: nSegments) ifFalse:[^false]. (self checkCompressedLineWidths: lineWidths segments: nSegments) ifFalse:[^false]. ^true! ! !BalloonEnginePlugin methodsFor: 'GET processing' stamp: 'ar (auto pragmas 12/08) 11/9/1998 15:37'! checkedAddBezierToGET: bezier "Add the bezier to the global edge table if it intersects the clipping region" | lineWidth | (self isWide: bezier) ifTrue:[lineWidth := (self wideBezierExtentOf: bezier)] ifFalse:[lineWidth := 0]. (self bezierEndYOf: bezier) + lineWidth < (self fillMinYGet) ifTrue:[^0]. "Overlaps in Y but may still be entirely right of clip region" ((self edgeXValueOf: bezier) - lineWidth >= self fillMaxXGet and:[ (self bezierEndXOf: bezier) - lineWidth >= self fillMaxXGet]) ifTrue:[^0]. self addEdgeToGET: bezier. ! ! !BalloonEnginePlugin methodsFor: 'GET processing' stamp: 'ar (auto pragmas 12/08) 11/9/1998 15:37'! checkedAddEdgeToGET: edge "Add the edge to the global edge table. For known edge types, check if the edge intersects the visible region" (self isLine: edge) ifTrue:[^self checkedAddLineToGET: edge]. (self isBezier: edge) ifTrue:[^self checkedAddBezierToGET: edge]. self addEdgeToGET: edge. ! ! !BalloonEnginePlugin methodsFor: 'GET processing' stamp: 'ar (auto pragmas 12/08) 11/9/1998 15:37'! checkedAddLineToGET: line "Add the line to the global edge table if it intersects the clipping region" | lineWidth | (self isWide: line) ifTrue:[lineWidth := (self wideLineExtentOf: line)] ifFalse:[lineWidth := 0]. (self lineEndYOf: line) + lineWidth < (self fillMinYGet) ifTrue:[^0]. "Overlaps in Y but may still be entirely right of clip region" ((self edgeXValueOf: line) - lineWidth >= self fillMaxXGet and:[ (self lineEndXOf: line) - lineWidth >= self fillMaxXGet]) ifTrue:[^0]. self addEdgeToGET: line. ! ! !BalloonEnginePlugin methodsFor: 'private' stamp: 'ar (auto pragmas dtl 2010-09-27) 11/1/1998 17:06'! circleCosTable | theTable | ^theTable! ! !BalloonEnginePlugin methodsFor: 'private' stamp: 'ar (auto pragmas dtl 2010-09-27) 11/1/1998 17:06'! circleSinTable | theTable | ^theTable! ! !BalloonEnginePlugin methodsFor: 'fills-bitmaps' stamp: 'ar (auto pragmas 12/08) 11/27/1998 14:19'! clampValue: value max: maxValue value < 0 ifTrue:[^0] ifFalse:[value >= maxValue ifTrue:[^maxValue-1] ifFalse:[^value]]! ! !BalloonEnginePlugin methodsFor: 'accessing bitmaps' stamp: 'ar (auto pragmas dtl 2010-09-27) 11/25/1998 16:39'! colormapOf: bmFill ^objBuffer + bmFill + GBColormapOffset! ! !BalloonEnginePlugin methodsFor: 'bezier-loading' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:46'! computeBezier: index splitAt: param "Split the bezier curve at the given parametric value. Note: Since this method is only invoked to make non-monoton beziers monoton we must check for the resulting y values to be *really* between the start and end value." | startX startY viaX viaY endX endY newIndex leftViaX leftViaY rightViaX rightViaY sharedX sharedY | leftViaX := startX := self bzStartX: index. leftViaY := startY := self bzStartY: index. rightViaX := viaX := self bzViaX: index. rightViaY := viaY := self bzViaY: index. endX := self bzEndX: index. endY := self bzEndY: index. "Compute intermediate points" sharedX := leftViaX := leftViaX + ((viaX - startX) asFloat * param) asInteger. sharedY := leftViaY := leftViaY + ((viaY - startY) asFloat * param) asInteger. rightViaX := rightViaX + ((endX - viaX) asFloat * param) asInteger. rightViaY := rightViaY + ((endY - viaY) asFloat * param) asInteger. "Compute new shared point" sharedX := sharedX + ((rightViaX - leftViaX) asFloat * param) asInteger. sharedY := sharedY + ((rightViaY - leftViaY) asFloat * param) asInteger. "Check the new via points" leftViaY := self assureValue: leftViaY between: startY and: sharedY. rightViaY := self assureValue: rightViaY between: sharedY and: endY. newIndex := self allocateBezierStackEntry. engineStopped ifTrue:[^0]. "Something went wrong" "Store the first part back" self bzViaX: index put: leftViaX. self bzViaY: index put: leftViaY. self bzEndX: index put: sharedX. self bzEndY: index put: sharedY. "Store the second point back" self bzStartX: newIndex put: sharedX. self bzStartY: newIndex put: sharedY. self bzViaX: newIndex put: rightViaX. self bzViaY: newIndex put: rightViaY. self bzEndX: newIndex put: endX. self bzEndY: newIndex put: endY. ^newIndex! ! !BalloonEnginePlugin methodsFor: 'bezier-loading' stamp: 'ar (auto pragmas 12/08) 11/6/1998 01:26'! computeBezierSplitAtHalf: index "Split the bezier curve at 0.5." | startX startY viaX viaY endX endY newIndex leftViaX leftViaY rightViaX rightViaY sharedX sharedY | newIndex := self allocateBezierStackEntry. engineStopped ifTrue:[^0]. "Something went wrong" leftViaX := startX := self bzStartX: index. leftViaY := startY := self bzStartY: index. rightViaX := viaX := self bzViaX: index. rightViaY := viaY := self bzViaY: index. endX := self bzEndX: index. endY := self bzEndY: index. "Compute intermediate points" leftViaX := leftViaX + ((viaX - startX) // 2). leftViaY := leftViaY + ((viaY - startY) // 2). sharedX := rightViaX := rightViaX + ((endX - viaX) // 2). sharedY := rightViaY := rightViaY + ((endY - viaY) // 2). "Compute new shared point" sharedX := sharedX + ((leftViaX - rightViaX) // 2). sharedY := sharedY + ((leftViaY - rightViaY) // 2). "Store the first part back" self bzViaX: index put: leftViaX. self bzViaY: index put: leftViaY. self bzEndX: index put: sharedX. self bzEndY: index put: sharedY. "Store the second point back" self bzStartX: newIndex put: sharedX. self bzStartY: newIndex put: sharedY. self bzViaX: newIndex put: rightViaX. self bzViaY: newIndex put: rightViaY. self bzEndX: newIndex put: endX. self bzEndY: newIndex put: endY. ^newIndex! ! !BalloonEnginePlugin methodsFor: 'beziers-wide' stamp: 'ar 11/8/1998 03:44'! computeFinalWideBezierValues: bezier width: lineWidth "Get both values from the two boundaries of the given bezier and compute the actual position/width of the line" | leftX rightX temp | leftX := ((self bezierUpdateDataOf: bezier) at: GBUpdateX) // 256. rightX := ((self wideBezierUpdateDataOf: bezier) at: GBUpdateX) // 256. leftX > rightX ifTrue:[temp := leftX. leftX := rightX. rightX := temp]. self edgeXValueOf: bezier put: leftX. (rightX - leftX) > lineWidth ifTrue:[ self wideBezierWidthOf: bezier put: (rightX - leftX). ] ifFalse:[ self wideBezierWidthOf: bezier put: lineWidth. ].! ! !BalloonEnginePlugin methodsFor: 'fills-bitmaps' stamp: 'ar (auto pragmas 12/08) 11/25/1998 19:46'! fillBitmapSpan ^self fillBitmapSpan: self lastExportedFillGet from: self lastExportedLeftXGet to: self lastExportedRightXGet at: self currentYGet! ! !BalloonEnginePlugin methodsFor: 'fills-bitmaps' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:46'! fillBitmapSpan: bmFill from: leftX to: rightX at: yValue | x x1 dsX ds dtX dt deltaX deltaY bits xp yp bmWidth bmHeight fillValue tileFlag | self aaLevelGet = 1 ifFalse:[^self fillBitmapSpanAA: bmFill from: leftX to: rightX at: yValue]. bits := self loadBitsFrom: bmFill. bits == nil ifTrue:[^nil]. bmWidth := self bitmapWidthOf: bmFill. bmHeight := self bitmapHeightOf: bmFill. tileFlag := (self bitmapTileFlagOf: bmFill) = 1. deltaX := leftX - (self fillOriginXOf: bmFill). deltaY := yValue - (self fillOriginYOf: bmFill). dsX := self fillDirectionXOf: bmFill. dtX := self fillNormalXOf: bmFill. ds := (deltaX * dsX) + (deltaY * (self fillDirectionYOf: bmFill)). dt := (deltaX * dtX) + (deltaY * (self fillNormalYOf: bmFill)). x := leftX. x1 := rightX. [x < x1] whileTrue:[ tileFlag ifTrue:[ ds := self repeatValue: ds max: bmWidth << 16. dt := self repeatValue: dt max: bmHeight << 16]. xp := ds // 16r10000. yp := dt // 16r10000. tileFlag ifFalse:[ xp := self clampValue: xp max: bmWidth. yp := self clampValue: yp max: bmHeight]. (xp >= 0 and:[yp >= 0 and:[xp < bmWidth and:[yp < bmHeight]]]) ifTrue:[ fillValue := self bitmapValue: bmFill bits: bits atX: xp y: yp. spanBuffer at: x put: fillValue. ]. ds := ds + dsX. dt := dt + dtX. x := x + 1. ].! ! !BalloonEnginePlugin methodsFor: 'fills-bitmaps' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:46'! fillBitmapSpanAA: bmFill from: leftX to: rightX at: yValue | x dsX ds dtX dt deltaX deltaY bits xp yp bmWidth bmHeight fillValue baseShift cMask cShift idx aaLevel firstPixel lastPixel tileFlag | bits := self loadBitsFrom: bmFill. bits == nil ifTrue:[^nil]. bmWidth := self bitmapWidthOf: bmFill. bmHeight := self bitmapHeightOf: bmFill. tileFlag := (self bitmapTileFlagOf: bmFill) = 1. deltaX := leftX - (self fillOriginXOf: bmFill). deltaY := yValue - (self fillOriginYOf: bmFill). dsX := self fillDirectionXOf: bmFill. dtX := self fillNormalXOf: bmFill. ds := (deltaX * dsX) + (deltaY * (self fillDirectionYOf: bmFill)). dt := (deltaX * dtX) + (deltaY * (self fillNormalYOf: bmFill)). aaLevel := self aaLevelGet. firstPixel := self aaFirstPixelFrom: leftX to: rightX. lastPixel := self aaLastPixelFrom: leftX to: rightX. baseShift := self aaShiftGet. cMask := self aaColorMaskGet. cShift := self aaColorShiftGet. x := leftX. [x < firstPixel] whileTrue:[ tileFlag ifTrue:[ ds := self repeatValue: ds max: bmWidth << 16. dt := self repeatValue: dt max: bmHeight << 16]. xp := ds // 16r10000. yp := dt // 16r10000. tileFlag ifFalse:[ xp := self clampValue: xp max: bmWidth. yp := self clampValue: yp max: bmHeight]. (xp >= 0 and:[yp >= 0 and:[xp < bmWidth and:[yp < bmHeight]]]) ifTrue:[ fillValue := self bitmapValue: bmFill bits: bits atX: xp y: yp. fillValue := (fillValue bitAnd: cMask) >> cShift. idx := x >> baseShift. spanBuffer at: idx put: (spanBuffer at: idx) + fillValue. ]. ds := ds + dsX. dt := dt + dtX. x := x + 1. ]. cMask := (self aaColorMaskGet >> self aaShiftGet) bitOr: 16rF0F0F0F0. cShift := self aaShiftGet. [x < lastPixel] whileTrue:[ tileFlag ifTrue:[ ds := self repeatValue: ds max: bmWidth << 16. dt := self repeatValue: dt max: bmHeight << 16]. xp := ds // 16r10000. yp := dt // 16r10000. tileFlag ifFalse:[ xp := self clampValue: xp max: bmWidth. yp := self clampValue: yp max: bmHeight]. (xp >= 0 and:[yp >= 0 and:[xp < bmWidth and:[yp < bmHeight]]]) ifTrue:[ fillValue := self bitmapValue: bmFill bits: bits atX: xp y: yp. fillValue := (fillValue bitAnd: cMask) >> cShift. idx := x >> baseShift. spanBuffer at: idx put: (spanBuffer at: idx) + fillValue. ]. ds := ds + (dsX << cShift). dt := dt + (dtX << cShift). x := x + aaLevel. ]. cMask := self aaColorMaskGet. cShift := self aaColorShiftGet. [x < rightX] whileTrue:[ tileFlag ifTrue:[ ds := self repeatValue: ds max: bmWidth << 16. dt := self repeatValue: dt max: bmHeight << 16]. xp := ds // 16r10000. yp := dt // 16r10000. tileFlag ifFalse:[ xp := self clampValue: xp max: bmWidth. yp := self clampValue: yp max: bmHeight]. (xp >= 0 and:[yp >= 0 and:[xp < bmWidth and:[yp < bmHeight]]]) ifTrue:[ fillValue := self bitmapValue: bmFill bits: bits atX: xp y: yp. fillValue := (fillValue bitAnd: cMask) >> cShift. idx := x >> baseShift. spanBuffer at: idx put: (spanBuffer at: idx) + fillValue. ]. ds := ds + dsX. dt := dt + dtX. x := x + 1. ]. ! ! !BalloonEnginePlugin methodsFor: 'accessing fills' stamp: 'ar 11/24/1998 22:18'! fillDirectionXOf: fill ^self obj: fill at: GFDirectionX! ! !BalloonEnginePlugin methodsFor: 'accessing fills' stamp: 'ar 11/24/1998 22:18'! fillDirectionXOf: fill put: value ^self obj: fill at: GFDirectionX put: value! ! !BalloonEnginePlugin methodsFor: 'accessing fills' stamp: 'ar 11/24/1998 22:19'! fillDirectionYOf: fill ^self obj: fill at: GFDirectionY! ! !BalloonEnginePlugin methodsFor: 'accessing fills' stamp: 'ar 11/24/1998 22:18'! fillDirectionYOf: fill put: value ^self obj: fill at: GFDirectionY put: value! ! !BalloonEnginePlugin methodsFor: 'fills-gradient' stamp: 'ar (auto pragmas 12/08) 11/8/1998 15:20'! fillLinearGradient ^self fillLinearGradient: self lastExportedFillGet from: self lastExportedLeftXGet to: self lastExportedRightXGet at: self currentYGet! ! !BalloonEnginePlugin methodsFor: 'fills-gradient' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:46'! fillLinearGradient: fill from: leftX to: rightX at: yValue "Draw a linear gradient fill." | x0 x1 ramp rampSize dsX ds x rampIndex | ramp := self gradientRampOf: fill. rampSize := self gradientRampLengthOf: fill. dsX := self fillDirectionXOf: fill. ds := ((leftX - (self fillOriginXOf: fill)) * dsX) + ((yValue - (self fillOriginYOf: fill)) * (self fillDirectionYOf: fill)). x := x0 := leftX. x1 := rightX. "Note: The inner loop has been divided into three parts for speed" "Part one: Fill everything outside the left boundary" [((rampIndex := ds // 16r10000) < 0 or:[rampIndex >= rampSize]) and:[x < x1]] whileTrue:[ x := x + 1. ds := ds + dsX]. x > x0 ifTrue:[ rampIndex < 0 ifTrue:[rampIndex := 0]. rampIndex >= rampSize ifTrue:[rampIndex := rampSize - 1]. self fillColorSpan: (self makeUnsignedFrom: (ramp at: rampIndex)) from: x0 to: x]. "Part two: Fill everything inside the boundaries" self aaLevelGet = 1 ifTrue:[ "Fast version w/o anti-aliasing" [((rampIndex := ds // 16r10000) < rampSize and:[rampIndex >= 0]) and:[x < x1]] whileTrue:[ spanBuffer at: x put: (self makeUnsignedFrom: (ramp at: rampIndex)). x := x + 1. ds := ds + dsX. ]. ] ifFalse:[x := self fillLinearGradientAA: fill ramp: ramp ds: ds dsX: dsX from: x to: rightX]. "Part three fill everything outside right boundary" x < x1 ifTrue:[ rampIndex < 0 ifTrue:[rampIndex := 0]. rampIndex >= rampSize ifTrue:[rampIndex := rampSize-1]. self fillColorSpan: (self makeUnsignedFrom: (ramp at: rampIndex)) from: x to: x1]. ! ! !BalloonEnginePlugin methodsFor: 'fills-gradient' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:46'! fillLinearGradientAA: fill ramp: ramp ds: deltaS dsX: dsX from: leftX to: rightX "This is the AA version of linear gradient filling." | colorMask colorShift baseShift rampIndex ds rampSize x idx rampValue aaLevel firstPixel lastPixel | aaLevel := self aaLevelGet. baseShift := self aaShiftGet. rampSize := self gradientRampLengthOf: fill. ds := deltaS. x := leftX. rampIndex := ds // 16r10000. firstPixel := self aaFirstPixelFrom: leftX to: rightX. lastPixel := self aaLastPixelFrom: leftX to: rightX. "Deal with the first n sub-pixels" colorMask := self aaColorMaskGet. colorShift := self aaColorShiftGet. [x < firstPixel and:[rampIndex < rampSize and:[rampIndex >= 0]]] whileTrue:[ rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. "Copy as many pixels as possible" [x < firstPixel and:[(ds//16r10000) = rampIndex]] whileTrue:[ idx := x >> baseShift. spanBuffer at: idx put: (spanBuffer at: idx) + rampValue. x := x + 1. ds := ds + dsX]. rampIndex := ds // 16r10000. ]. "Deal with the full pixels" colorMask := (self aaColorMaskGet >> self aaShiftGet) bitOr: 16rF0F0F0F0. colorShift := self aaShiftGet. [x < lastPixel and:[rampIndex < rampSize and:[rampIndex >= 0]]] whileTrue:[ rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. "Copy as many pixels as possible" [x < lastPixel and:[(ds//16r10000) = rampIndex]] whileTrue:[ idx := x >> baseShift. spanBuffer at: idx put: (spanBuffer at: idx) + rampValue. x := x + aaLevel. ds := ds + (dsX << colorShift)]. rampIndex := ds // 16r10000. ]. "Deal with the last n sub-pixels" colorMask := self aaColorMaskGet. colorShift := self aaColorShiftGet. [x < rightX and:[rampIndex < rampSize and:[rampIndex>=0]]] whileTrue:[ rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. "Copy as many pixels as possible" [x < rightX and:[(ds//16r10000) = rampIndex]] whileTrue:[ idx := x >> baseShift. spanBuffer at: idx put: (spanBuffer at: idx) + rampValue. x := x + 1. ds := ds + dsX]. rampIndex := ds // 16r10000. ]. ^x! ! !BalloonEnginePlugin methodsFor: 'accessing fills' stamp: 'ar 11/24/1998 22:18'! fillNormalXOf: fill ^self obj: fill at: GFNormalX! ! !BalloonEnginePlugin methodsFor: 'accessing fills' stamp: 'ar 11/24/1998 22:18'! fillNormalXOf: fill put: value ^self obj: fill at: GFNormalX put: value! ! !BalloonEnginePlugin methodsFor: 'accessing fills' stamp: 'ar 11/24/1998 22:18'! fillNormalYOf: fill ^self obj: fill at: GFNormalY! ! !BalloonEnginePlugin methodsFor: 'accessing fills' stamp: 'ar 11/24/1998 22:16'! fillNormalYOf: fill put: value ^self obj: fill at: GFNormalY put: value! ! !BalloonEnginePlugin methodsFor: 'accessing fills' stamp: 'ar 11/24/1998 22:17'! fillOriginXOf: fill ^self obj: fill at: GFOriginX! ! !BalloonEnginePlugin methodsFor: 'accessing fills' stamp: 'ar 11/24/1998 22:17'! fillOriginXOf: fill put: value ^self obj: fill at: GFOriginX put: value! ! !BalloonEnginePlugin methodsFor: 'accessing fills' stamp: 'ar 11/24/1998 22:17'! fillOriginYOf: fill ^self obj: fill at: GFOriginY! ! !BalloonEnginePlugin methodsFor: 'accessing fills' stamp: 'ar 11/24/1998 22:18'! fillOriginYOf: fill put: value ^self obj: fill at: GFOriginY put: value! ! !BalloonEnginePlugin methodsFor: 'fills-gradient' stamp: 'ar (auto pragmas 12/08) 11/24/1998 19:02'! fillRadialDecreasing: fill ramp: ramp deltaST: deltaST dsX: dsX dtX: dtX from: leftX to: rightX "Part 2a) Compute the decreasing part of the ramp" | ds dt rampIndex rampValue length2 x x1 nextLength | ds := (self cCoerce: deltaST to:'int*') at: 0. dt := (self cCoerce: deltaST to:'int*') at: 1. rampIndex := self accurateLengthOf: ds // 16r10000 with: dt // 16r10000. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). length2 := (rampIndex-1) * (rampIndex-1). x := leftX. x1 := rightX. x1 > (self fillOriginXOf: fill) ifTrue:[x1 := self fillOriginXOf: fill]. [x < x1] whileTrue:[ "Try to copy the current value more than just once" [x < x1 and:[(self squaredLengthOf: ds // 16r10000 with: dt // 16r10000) >= length2]] whileTrue:[ spanBuffer at: x put: rampValue. x := x + 1. ds := ds + dsX. dt := dt + dtX]. "Step to next ramp value" nextLength := self squaredLengthOf: ds // 16r10000 with: dt // 16r10000. [nextLength < length2] whileTrue:[ rampIndex := rampIndex - 1. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). length2 := (rampIndex-1) * (rampIndex-1). ]. ]. (self cCoerce: deltaST to: 'int *') at: 0 put: ds. (self cCoerce: deltaST to: 'int *') at: 1 put: dt. ^x! ! !BalloonEnginePlugin methodsFor: 'fills-gradient' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:47'! fillRadialDecreasingAA: fill ramp: ramp deltaST: deltaST dsX: dsX dtX: dtX from: leftX to: rightX "Part 2a) Compute the decreasing part of the ramp" | ds dt rampIndex rampValue length2 x nextLength x1 aaLevel colorMask colorShift baseShift index firstPixel lastPixel | ds := (self cCoerce: deltaST to:'int*') at: 0. dt := (self cCoerce: deltaST to:'int*') at: 1. aaLevel := self aaLevelGet. baseShift := self aaShiftGet. rampIndex := self accurateLengthOf: ds // 16r10000 with: dt // 16r10000. length2 := (rampIndex-1) * (rampIndex-1). x := leftX. x1 := self fillOriginXOf: fill. x1 > rightX ifTrue:[x1 := rightX]. firstPixel := self aaFirstPixelFrom: leftX to: x1. lastPixel := self aaLastPixelFrom: leftX to: x1. "Deal with the first n sub-pixels" (x < firstPixel) ifTrue:[ colorMask := self aaColorMaskGet. colorShift := self aaColorShiftGet. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. [x < firstPixel] whileTrue:[ "Try to copy the current value more than just once" [x < firstPixel and:[(self squaredLengthOf: ds // 16r10000 with: dt // 16r10000) >= length2]] whileTrue:[ index := x >> baseShift. spanBuffer at: index put: (spanBuffer at: index) + rampValue. x := x + 1. ds := ds + dsX. dt := dt + dtX]. "Step to next ramp value" nextLength := self squaredLengthOf: ds // 16r10000 with: dt // 16r10000. [nextLength < length2] whileTrue:[ rampIndex := rampIndex - 1. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. length2 := (rampIndex-1) * (rampIndex-1). ]. ]. ]. "Deal with the full pixels" (x < lastPixel) ifTrue:[ colorMask := (self aaColorMaskGet >> self aaShiftGet) bitOr: 16rF0F0F0F0. colorShift := self aaShiftGet. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. [x < lastPixel] whileTrue:[ "Try to copy the current value more than just once" [x < lastPixel and:[(self squaredLengthOf: ds // 16r10000 with: dt // 16r10000) >= length2]] whileTrue:[ index := x >> baseShift. spanBuffer at: index put: (spanBuffer at: index) + rampValue. x := x + aaLevel. ds := ds + (dsX << colorShift). dt := dt + (dtX << colorShift)]. "Step to next ramp value" nextLength := self squaredLengthOf: ds // 16r10000 with: dt // 16r10000. [nextLength < length2] whileTrue:[ rampIndex := rampIndex - 1. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. length2 := (rampIndex-1) * (rampIndex-1). ]. ]. ]. "Deal with the last n sub-pixels" (x < x1) ifTrue:[ colorMask := self aaColorMaskGet. colorShift := self aaColorShiftGet. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. [x < x1] whileTrue:[ "Try to copy the current value more than just once" [x < x1 and:[(self squaredLengthOf: ds // 16r10000 with: dt // 16r10000) >= length2]] whileTrue:[ index := x >> baseShift. spanBuffer at: index put: (spanBuffer at: index) + rampValue. x := x + 1. ds := ds + dsX. dt := dt + dtX]. "Step to next ramp value" nextLength := self squaredLengthOf: ds // 16r10000 with: dt // 16r10000. [nextLength < length2] whileTrue:[ rampIndex := rampIndex - 1. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. length2 := (rampIndex-1) * (rampIndex-1). ]. ]. ]. "Done -- store stuff back" (self cCoerce: deltaST to: 'int *') at: 0 put: ds. (self cCoerce: deltaST to: 'int *') at: 1 put: dt. ^x! ! !BalloonEnginePlugin methodsFor: 'fills-gradient' stamp: 'ar (auto pragmas 12/08) 11/8/1998 15:20'! fillRadialGradient ^self fillRadialGradient: self lastExportedFillGet from: self lastExportedLeftXGet to: self lastExportedRightXGet at: self currentYGet! ! !BalloonEnginePlugin methodsFor: 'fills-gradient' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:47'! fillRadialGradient: fill from: leftX to: rightX at: yValue "Draw a radial gradient fill." | x x1 ramp rampSize dsX ds dtX dt length2 deltaX deltaY deltaST | ramp := self gradientRampOf: fill. rampSize := self gradientRampLengthOf: fill. deltaX := leftX - (self fillOriginXOf: fill). deltaY := yValue - (self fillOriginYOf: fill). dsX := self fillDirectionXOf: fill. dtX := self fillNormalXOf: fill. ds := (deltaX * dsX) + (deltaY * (self fillDirectionYOf: fill)). dt := (deltaX * dtX) + (deltaY * (self fillNormalYOf: fill)). x := leftX. x1 := rightX. "Note: The inner loop has been divided into three parts for speed" "Part one: Fill everything outside the left boundary" length2 := (rampSize-1) * (rampSize-1). "This is the upper bound" [(self squaredLengthOf: ds // 16r10000 with: dt // 16r10000) >= length2 and:[x < x1]] whileTrue:[ x := x + 1. ds := ds + dsX. dt := dt + dtX]. x > leftX ifTrue:[self fillColorSpan: (self makeUnsignedFrom: (ramp at: rampSize-1)) from: leftX to: x]. "Part two: Fill everything inside the boundaries" deltaST := self point1Get. deltaST at: 0 put: ds. deltaST at: 1 put: dt. (x < (self fillOriginXOf: fill)) ifTrue:[ "Draw the decreasing part" self aaLevelGet = 1 ifTrue:[x := self fillRadialDecreasing: fill ramp: ramp deltaST: deltaST dsX: dsX dtX: dtX from: x to: x1] ifFalse:[x := self fillRadialDecreasingAA: fill ramp: ramp deltaST: deltaST dsX: dsX dtX: dtX from: x to: x1]. ]. x < x1 ifTrue:[ "Draw the increasing part" self aaLevelGet = 1 ifTrue:[x := self fillRadialIncreasing: fill ramp: ramp deltaST: deltaST dsX: dsX dtX: dtX from: x to: x1] ifFalse:[x := self fillRadialIncreasingAA: fill ramp: ramp deltaST: deltaST dsX: dsX dtX: dtX from: x to: x1]. ]. "Part three fill everything outside right boundary" x < rightX ifTrue:[self fillColorSpan: (self makeUnsignedFrom: (ramp at: rampSize-1)) from: x to: rightX]. ! ! !BalloonEnginePlugin methodsFor: 'fills-gradient' stamp: 'ar (auto pragmas 12/08) 11/9/1998 01:21'! fillRadialIncreasing: fill ramp: ramp deltaST: deltaST dsX: dsX dtX: dtX from: leftX to: rightX "Part 2b) Compute the increasing part of the ramp" | ds dt rampIndex rampValue length2 x x1 nextLength rampSize lastLength | ds := (self cCoerce: deltaST to:'int*') at: 0. dt := (self cCoerce: deltaST to:'int*') at: 1. rampIndex := self accurateLengthOf: ds // 16r10000 with: dt // 16r10000. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampSize := self gradientRampLengthOf: fill. length2 := (rampSize-1) * (rampSize-1). "This is the upper bound" nextLength := (rampIndex+1) * (rampIndex+1). lastLength := self squaredLengthOf: ds // 16r10000 with: dt // 16r10000. x := leftX. x1 := rightX. [x < x1 and:[lastLength < length2]] whileTrue:[ "Try to copy the current value more than once" [x < x1 and:[(self squaredLengthOf: ds // 16r10000 with: dt // 16r10000) <= nextLength]] whileTrue:[ spanBuffer at: x put: rampValue. x := x + 1. ds := ds + dsX. dt := dt + dtX]. lastLength := self squaredLengthOf: ds // 16r10000 with: dt // 16r10000. [lastLength > nextLength] whileTrue:[ rampIndex := rampIndex + 1. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). nextLength := (rampIndex+1) * (rampIndex+1). ]. ]. (self cCoerce: deltaST to: 'int *') at: 0 put: ds. (self cCoerce: deltaST to: 'int *') at: 1 put: dt. ^x! ! !BalloonEnginePlugin methodsFor: 'fills-gradient' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:47'! fillRadialIncreasingAA: fill ramp: ramp deltaST: deltaST dsX: dsX dtX: dtX from: leftX to: rightX "Part 2b) Compute the increasing part of the ramp" | ds dt rampIndex rampValue length2 x nextLength rampSize lastLength aaLevel colorMask colorShift baseShift index firstPixel lastPixel | ds := (self cCoerce: deltaST to:'int*') at: 0. dt := (self cCoerce: deltaST to:'int*') at: 1. aaLevel := self aaLevelGet. baseShift := self aaShiftGet. rampIndex := self accurateLengthOf: ds // 16r10000 with: dt // 16r10000. rampSize := self gradientRampLengthOf: fill. length2 := (rampSize-1) * (rampSize-1). "This is the upper bound" nextLength := (rampIndex+1) * (rampIndex+1). lastLength := self squaredLengthOf: ds // 16r10000 with: dt // 16r10000. x := leftX. firstPixel := self aaFirstPixelFrom: leftX to: rightX. lastPixel := self aaLastPixelFrom: leftX to: rightX. "Deal with the first n subPixels" (x < firstPixel and:[lastLength < length2]) ifTrue:[ colorMask := self aaColorMaskGet. colorShift := self aaColorShiftGet. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. [x < firstPixel and:[lastLength < length2]] whileTrue:[ "Try to copy the current value more than once" [x < firstPixel and:[(self squaredLengthOf: ds // 16r10000 with: dt // 16r10000) <= nextLength]] whileTrue:[ index := x >> baseShift. spanBuffer at: index put: (spanBuffer at: index) + rampValue. x := x + 1. ds := ds + dsX. dt := dt + dtX]. lastLength := self squaredLengthOf: ds // 16r10000 with: dt // 16r10000. [lastLength > nextLength] whileTrue:[ rampIndex := rampIndex + 1. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. nextLength := (rampIndex+1) * (rampIndex+1). ]. ]. ]. "Deal with the full pixels" (x < lastPixel and:[lastLength < length2]) ifTrue:[ colorMask := (self aaColorMaskGet >> self aaShiftGet) bitOr: 16rF0F0F0F0. colorShift := self aaShiftGet. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. [x < lastPixel and:[lastLength < length2]] whileTrue:[ "Try to copy the current value more than once" [x < lastPixel and:[(self squaredLengthOf: ds // 16r10000 with: dt // 16r10000) <= nextLength]] whileTrue:[ index := x >> baseShift. spanBuffer at: index put: (spanBuffer at: index) + rampValue. x := x + aaLevel. ds := ds + (dsX << colorShift). dt := dt + (dtX << colorShift)]. lastLength := self squaredLengthOf: ds // 16r10000 with: dt // 16r10000. [lastLength > nextLength] whileTrue:[ rampIndex := rampIndex + 1. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. nextLength := (rampIndex+1) * (rampIndex+1). ]. ]. ]. "Deal with last n sub-pixels" (x < rightX and:[lastLength < length2]) ifTrue:[ colorMask := self aaColorMaskGet. colorShift := self aaColorShiftGet. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. [x < rightX and:[lastLength < length2]] whileTrue:[ "Try to copy the current value more than once" [x < rightX and:[(self squaredLengthOf: ds // 16r10000 with: dt // 16r10000) <= nextLength]] whileTrue:[ index := x >> baseShift. spanBuffer at: index put: (spanBuffer at: index) + rampValue. x := x + 1. ds := ds + dsX. dt := dt + dtX]. lastLength := self squaredLengthOf: ds // 16r10000 with: dt // 16r10000. [lastLength > nextLength] whileTrue:[ rampIndex := rampIndex + 1. rampValue := self makeUnsignedFrom: ((self cCoerce: ramp to:'int *') at: rampIndex). rampValue := (rampValue bitAnd: colorMask) >> colorShift. nextLength := (rampIndex+1) * (rampIndex+1). ]. ]. ]. "Done -- store stuff back" (self cCoerce: deltaST to: 'int *') at: 0 put: ds. (self cCoerce: deltaST to: 'int *') at: 1 put: dt. ^x! ! !BalloonEnginePlugin methodsFor: 'accessing gradients' stamp: 'ar 11/24/1998 22:18'! gradientRampLengthOf: fill ^self obj: fill at: GFRampLength! ! !BalloonEnginePlugin methodsFor: 'accessing gradients' stamp: 'ar 11/24/1998 22:17'! gradientRampLengthOf: fill put: value ^self obj: fill at: GFRampLength put: value! ! !BalloonEnginePlugin methodsFor: 'accessing gradients' stamp: 'ar (auto pragmas dtl 2010-09-27) 11/24/1998 22:25'! gradientRampOf: fill ^objBuffer + fill + GFRampOffset! ! !BalloonEnginePlugin methodsFor: 'testing' stamp: 'ar 11/4/1998 21:46'! isBezier: bezier ^((self objectTypeOf: bezier) bitAnd: GEPrimitiveWideMask) = GEPrimitiveBezier! ! !BalloonEnginePlugin methodsFor: 'testing' stamp: 'ar (auto pragmas 12/08) 11/8/1998 15:14'! isFillOkay: fill ^(fill = 0 or:[(self isFillColor: fill) or:[((self isObject: fill) and:[self isFill: fill])]]) ! ! !BalloonEnginePlugin methodsFor: 'testing' stamp: 'ar 11/4/1998 21:46'! isLine: line ^((self objectTypeOf: line) bitAnd: GEPrimitiveWideMask) = GEPrimitiveLine! ! !BalloonEnginePlugin methodsFor: 'testing' stamp: 'ar 11/6/1998 01:53'! isWideBezier: bezier ^(self isBezier: bezier) and:[self isWide: bezier]! ! !BalloonEnginePlugin methodsFor: 'testing' stamp: 'ar 11/4/1998 22:08'! isWideLine: line ^(self isLine: line) and:[self isWide: line]! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:07'! lineEndXOf: line ^self obj: line at: GLEndX! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:07'! lineEndXOf: line put: value ^self obj: line at: GLEndX put: value! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:07'! lineEndYOf: line ^self obj: line at: GLEndY! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:07'! lineEndYOf: line put: value ^self obj: line at: GLEndY put: value! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:07'! lineErrorAdjDownOf: line ^self obj: line at: GLErrorAdjDown! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:07'! lineErrorAdjDownOf: line put: value ^self obj: line at: GLErrorAdjDown put: value! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:08'! lineErrorAdjUpOf: line ^self obj: line at: GLErrorAdjUp! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:08'! lineErrorAdjUpOf: line put: value ^self obj: line at: GLErrorAdjUp put: value! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:08'! lineErrorOf: line ^self obj: line at: GLError! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:08'! lineErrorOf: line put: value ^self obj: line at: GLError put: value! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:08'! lineXDirectionOf: line ^self obj: line at: GLXDirection! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:09'! lineXDirectionOf: line put: value ^self obj: line at: GLXDirection put: value! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:09'! lineXIncrementOf: line ^self obj: line at: GLXIncrement! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:09'! lineXIncrementOf: line put: value ^self obj: line at: GLXIncrement put: value! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:09'! lineYDirectionOf: line ^self obj: line at: GLYDirection! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:09'! lineYDirectionOf: line put: value ^self obj: line at: GLYDirection put: value! ! !BalloonEnginePlugin methodsFor: 'bezier-loading' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:47'! loadAndSubdivideBezierFrom: point1 via: point2 to: point3 isWide: wideFlag "Load and subdivide the bezier curve from point1/point2/point3. If wideFlag is set then make sure the curve is monoton in X." | bz1 bz2 index2 index1 | bz1 := self allocateBezierStackEntry. engineStopped ifTrue:[^0]. "Load point1/point2/point3 on the top of the stack" self bzStartX: bz1 put: (point1 at: 0). self bzStartY: bz1 put: (point1 at: 1). self bzViaX: bz1 put: (point2 at: 0). self bzViaY: bz1 put: (point2 at: 1). self bzEndX: bz1 put: (point3 at: 0). self bzEndY: bz1 put: (point3 at: 1). "Now check if the bezier curve is monoton. If not, subdivide it." index2 := bz2 := self subdivideToBeMonoton: bz1 inX: wideFlag. bz1 to: bz2 by: 6 do:[:index| index1 := self subdivideBezierFrom: index. index1 > index2 ifTrue:[index2 := index1]. engineStopped ifTrue:[^0]. "Something went wrong" ]. "Return the number of segments" ^index2 // 6! ! !BalloonEnginePlugin methodsFor: 'shapes-polygons' stamp: 'ar 11/24/1998 23:09'! loadArrayPolygon: points nPoints: nPoints fill: fillIndex lineWidth: lineWidth lineFill: lineFill | x0 y0 x1 y1 | self loadPoint: self point1Get from: (interpreterProxy fetchPointer: 0 ofObject: points). interpreterProxy failed ifTrue:[^nil]. x0 := self point1Get at: 0. y0 := self point1Get at: 1. 1 to: nPoints-1 do:[:i| self loadPoint: self point1Get from: (interpreterProxy fetchPointer: i ofObject: points). interpreterProxy failed ifTrue:[^nil]. x1 := self point1Get at: 0. y1 := self point1Get at: 1. self point1Get at: 0 put: x0. self point1Get at: 1 put: y0. self point2Get at: 0 put: x1. self point2Get at: 1 put: y1. self transformPoints: 2. self loadWideLine: lineWidth from: self point1Get to: self point2Get lineFill: lineFill leftFill: fillIndex rightFill: 0. engineStopped ifTrue:[^nil]. x0 := x1. y0 := y1. ].! ! !BalloonEnginePlugin methodsFor: 'shapes-polygons' stamp: 'ar (auto pragmas 12/08) 11/24/1998 23:14'! loadArrayShape: points nSegments: nSegments fill: fillIndex lineWidth: lineWidth lineFill: lineFill | pointOop x0 y0 x1 y1 x2 y2 segs | 0 to: nSegments-1 do:[:i| pointOop := interpreterProxy fetchPointer: (i * 3) ofObject: points. self loadPoint: self point1Get from: pointOop. pointOop := interpreterProxy fetchPointer: (i * 3 + 1) ofObject: points. self loadPoint: self point2Get from: pointOop. pointOop := interpreterProxy fetchPointer: (i * 3 + 2) ofObject: points. self loadPoint: self point3Get from: pointOop. interpreterProxy failed ifTrue:[^nil]. self transformPoints: 3. x0 := self point1Get at: 0. y0 := self point1Get at: 1. x1 := self point2Get at: 0. y1 := self point2Get at: 1. x2 := self point3Get at: 0. y2 := self point3Get at: 1. "Check if we can use a line" ((x0 = y0 and:[x1 = y1]) or:[x1 = x2 and:[y1 = y2]]) ifTrue:[ self loadWideLine: lineWidth from: self point1Get to: self point3Get lineFill: lineFill leftFill: fillIndex rightFill: 0. ] ifFalse:["Need bezier" segs := self loadAndSubdivideBezierFrom: self point1Get via: self point2Get to: self point3Get isWide: (lineWidth ~= 0 and:[lineFill ~= 0]). engineStopped ifTrue:[^nil]. self loadWideBezier: lineWidth lineFill: lineFill leftFill: fillIndex rightFill: 0 n: segs. ]. engineStopped ifTrue:[^nil]. ].! ! !BalloonEnginePlugin methodsFor: 'bezier-loading' stamp: 'ar (auto pragmas 12/08) 11/24/1998 23:15'! loadBezier: bezier segment: index leftFill: leftFillIndex rightFill: rightFillIndex offset: yOffset "Initialize the bezier segment stored on the stack" (self bzEndY: index) >= (self bzStartY: index) ifTrue:[ "Top to bottom" self edgeXValueOf: bezier put: (self bzStartX: index). self edgeYValueOf: bezier put: (self bzStartY: index) - yOffset. self bezierViaXOf: bezier put: (self bzViaX: index). self bezierViaYOf: bezier put: (self bzViaY: index) - yOffset. self bezierEndXOf: bezier put: (self bzEndX: index). self bezierEndYOf: bezier put: (self bzEndY: index) - yOffset. ] ifFalse:[ self edgeXValueOf: bezier put: (self bzEndX: index). self edgeYValueOf: bezier put: (self bzEndY: index) - yOffset. self bezierViaXOf: bezier put: (self bzViaX: index). self bezierViaYOf: bezier put: (self bzViaY: index) - yOffset. self bezierEndXOf: bezier put: (self bzStartX: index). self bezierEndYOf: bezier put: (self bzStartY: index) - yOffset. ]. self edgeZValueOf: bezier put: self currentZGet. self edgeLeftFillOf: bezier put: leftFillIndex. self edgeRightFillOf: bezier put: rightFillIndex. "self debugDrawBezier: bezier."! ! !BalloonEnginePlugin methodsFor: 'fills-bitmaps' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:47'! loadBitmapFill: formOop colormap: cmOop tile: tileFlag from: point1 along: point2 normal: point3 xIndex: xIndex "Load the bitmap fill." | bmFill cmSize cmBits bmBits bmBitsSize bmWidth bmHeight bmDepth ppw bmRaster | cmOop == interpreterProxy nilObject ifTrue:[ cmSize := 0. cmBits := nil. ] ifFalse:[ (interpreterProxy fetchClassOf: cmOop) == interpreterProxy classBitmap ifFalse:[^interpreterProxy primitiveFail]. cmSize := interpreterProxy slotSizeOf: cmOop. cmBits := interpreterProxy firstIndexableField: cmOop. ]. (interpreterProxy isIntegerObject: formOop) ifTrue:[^interpreterProxy primitiveFail]. (interpreterProxy isPointers: formOop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: formOop) < 5 ifTrue:[^interpreterProxy primitiveFail]. bmBits := interpreterProxy fetchPointer: 0 ofObject: formOop. (interpreterProxy fetchClassOf: bmBits) == interpreterProxy classBitmap ifFalse:[^interpreterProxy primitiveFail]. bmBitsSize := interpreterProxy slotSizeOf: bmBits. bmWidth := interpreterProxy fetchInteger: 1 ofObject: formOop. bmHeight := interpreterProxy fetchInteger: 2 ofObject: formOop. bmDepth := interpreterProxy fetchInteger: 3 ofObject: formOop. interpreterProxy failed ifTrue:[^nil]. (bmWidth >= 0 and:[bmHeight >= 0]) ifFalse:[^interpreterProxy primitiveFail]. (bmDepth = 32) | (bmDepth = 8) | (bmDepth = 16) | (bmDepth = 1) | (bmDepth = 2) | (bmDepth = 4) ifFalse:[^interpreterProxy primitiveFail]. (cmSize = 0 or:[cmSize = (1 << bmDepth)]) ifFalse:[^interpreterProxy primitiveFail]. ppw := 32 // bmDepth. bmRaster := bmWidth + (ppw-1) // ppw. bmBitsSize = (bmRaster * bmHeight) ifFalse:[^interpreterProxy primitiveFail]. bmFill := self allocateBitmapFill: cmSize colormap: cmBits. engineStopped ifTrue:[^nil]. self bitmapWidthOf: bmFill put: bmWidth. self bitmapHeightOf: bmFill put: bmHeight. self bitmapDepthOf: bmFill put: bmDepth. self bitmapRasterOf: bmFill put: bmRaster. self bitmapSizeOf: bmFill put: bmBitsSize. self bitmapTileFlagOf: bmFill put: tileFlag. self objectIndexOf: bmFill put: xIndex. self loadFillOrientation: bmFill from: point1 along: point2 normal: point3 width: bmWidth height: bmHeight. ^bmFill! ! !BalloonEnginePlugin methodsFor: 'fills-bitmaps' stamp: 'ar (auto pragmas dtl 2010-09-27) 11/25/1998 17:25'! loadBitsFrom: bmFill "Note: Assumes that the contents of formArray has been checked before" | xIndex formOop bitsOop bitsLen | xIndex := self objectIndexOf: bmFill. xIndex > (interpreterProxy slotSizeOf: formArray) ifTrue:[^nil]. formOop := interpreterProxy fetchPointer: xIndex ofObject: formArray. bitsOop := interpreterProxy fetchPointer: 0 ofObject: formOop. bitsLen := interpreterProxy slotSizeOf: bitsOop. bitsLen = (self bitmapSizeOf: bmFill) ifFalse:[^nil]. ^interpreterProxy firstIndexableField: bitsOop! ! !BalloonEnginePlugin methodsFor: 'shapes-compressed' stamp: 'ar (auto pragmas 12/08) 11/24/1998 21:13'! loadCompressedSegment: segmentIndex from: points short: pointsShort leftFill: leftFill rightFill: rightFill lineWidth: lineWidth lineColor: lineFill "Load the compressed segment identified by segment index" | x0 y0 x1 y1 x2 y2 index segs | "Check if have anything to do at all" (leftFill = rightFill and:[lineWidth = 0 or:[lineFill = 0]]) ifTrue:[^nil]. "Nothing to do" index := segmentIndex * 6. "3 points with x/y each" pointsShort ifTrue:["Load short points" x0 := self loadPointShortAt: (index+0) from: points. y0 := self loadPointShortAt: (index+1) from: points. x1 := self loadPointShortAt: (index+2) from: points. y1 := self loadPointShortAt: (index+3) from: points. x2 := self loadPointShortAt: (index+4) from: points. y2 := self loadPointShortAt: (index+5) from: points. ] ifFalse:[ x0 := self loadPointIntAt: (index+0) from: points. y0 := self loadPointIntAt: (index+1) from: points. x1 := self loadPointIntAt: (index+2) from: points. y1 := self loadPointIntAt: (index+3) from: points. x2 := self loadPointIntAt: (index+4) from: points. y2 := self loadPointIntAt: (index+5) from: points. ]. "Briefly check if can represent the bezier as a line" ((x0 = x1 and:[y0 = y1]) or:[x1 = x2 and:[y1 = y2]]) ifTrue:[ "We can use a line from x0/y0 to x2/y2" (x0 = x2 and:[y0 = y2]) ifTrue:[^nil]. "Nothing to do" "Load and transform points" self point1Get at: 0 put: x0. self point1Get at: 1 put: y0. self point2Get at: 0 put: x2. self point2Get at: 1 put: y2. self transformPoints: 2. ^self loadWideLine: lineWidth from: self point1Get to: self point2Get lineFill: lineFill leftFill: leftFill rightFill: rightFill. ]. "Need bezier curve" "Load and transform points" self point1Get at: 0 put: x0. self point1Get at: 1 put: y0. self point2Get at: 0 put: x1. self point2Get at: 1 put: y1. self point3Get at: 0 put: x2. self point3Get at: 1 put: y2. self transformPoints: 3. segs := self loadAndSubdivideBezierFrom: self point1Get via: self point2Get to: self point3Get isWide: (lineWidth ~= 0 and:[lineFill ~= 0]). engineStopped ifTrue:[^nil]. self loadWideBezier: lineWidth lineFill: lineFill leftFill: leftFill rightFill: rightFill n: segs. ! ! !BalloonEnginePlugin methodsFor: 'shapes-compressed' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:48'! loadCompressedShape: points segments: nSegments leftFills: leftFills rightFills: rightFills lineWidths: lineWidths lineFills: lineFills fillIndexList: fillIndexList pointShort: pointsShort "Load a compressed shape into the engine. WARNING: THIS METHOD NEEDS THE FULL FRAME SIZE!!!!!!!! " | leftRun rightRun widthRun lineFillRun leftLength rightLength widthLength lineFillLength leftValue rightValue widthValue lineFillValue | nSegments = 0 ifTrue:[^0]. "Initialize run length encodings" leftRun := rightRun := widthRun := lineFillRun := -1. leftLength := rightLength := widthLength := lineFillLength := 1. leftValue := rightValue := widthValue := lineFillValue := 0. 1 to: nSegments do:[:i| "Decrement current run length and load new stuff" (leftLength := leftLength - 1) <= 0 ifTrue:[ leftRun := leftRun + 1. leftLength := self shortRunLengthAt: leftRun from: leftFills. leftValue := self shortRunValueAt: leftRun from: leftFills. leftValue = 0 ifFalse:[ leftValue := fillIndexList at: leftValue-1. leftValue := self transformColor: leftValue. engineStopped ifTrue:[^nil]]]. (rightLength := rightLength - 1) <= 0 ifTrue:[ rightRun := rightRun + 1. rightLength := self shortRunLengthAt: rightRun from: rightFills. rightValue := self shortRunValueAt: rightRun from: rightFills. rightValue = 0 ifFalse:[ rightValue := fillIndexList at: rightValue-1. rightValue := self transformColor: rightValue]]. (widthLength := widthLength - 1) <= 0 ifTrue:[ widthRun := widthRun + 1. widthLength := self shortRunLengthAt: widthRun from: lineWidths. widthValue := self shortRunValueAt: widthRun from: lineWidths. widthValue = 0 ifFalse:[widthValue := self transformWidth: widthValue]]. (lineFillLength := lineFillLength - 1) <= 0 ifTrue:[ lineFillRun := lineFillRun + 1. lineFillLength := self shortRunLengthAt: lineFillRun from: lineFills. lineFillValue := self shortRunValueAt: lineFillRun from: lineFills. lineFillValue = 0 ifFalse:[lineFillValue := fillIndexList at: lineFillValue-1]]. self loadCompressedSegment: i - 1 from: points short: pointsShort leftFill: leftValue rightFill: rightValue lineWidth: widthValue lineColor: lineFillValue. engineStopped ifTrue:[^nil]. ].! ! !BalloonEnginePlugin methodsFor: 'fills-gradient' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:48'! loadFillOrientation: fill from: point1 along: point2 normal: point3 width: fillWidth height: fillHeight "Transform the points" | dirX dirY nrmX nrmY dsLength2 dsX dsY dtLength2 dtX dtY | point2 at: 0 put: (point2 at: 0) + (point1 at: 0). point2 at: 1 put: (point2 at: 1) + (point1 at: 1). point3 at: 0 put: (point3 at: 0) + (point1 at: 0). point3 at: 1 put: (point3 at: 1) + (point1 at: 1). self transformPoint: point1. self transformPoint: point2. self transformPoint: point3. dirX := (point2 at: 0) - (point1 at: 0). dirY := (point2 at: 1) - (point1 at: 1). nrmX := (point3 at: 0) - (point1 at: 0). nrmY := (point3 at: 1) - (point1 at: 1). "Compute the scale from direction/normal into ramp size" dsLength2 := (dirX * dirX) + (dirY * dirY). dsLength2 > 0 ifTrue:[ dsX := (dirX asFloat * fillWidth asFloat * 65536.0 / dsLength2 asFloat) asInteger. dsY := (dirY asFloat * fillWidth asFloat * 65536.0 / dsLength2 asFloat) asInteger. ] ifFalse:[ dsX := 0. dsY := 0]. dtLength2 := (nrmX * nrmX) + (nrmY * nrmY). dtLength2 > 0 ifTrue:[ dtX := (nrmX asFloat * fillHeight asFloat * 65536.0 / dtLength2 asFloat) asInteger. dtY := (nrmY asFloat * fillHeight asFloat * 65536.0 / dtLength2 asFloat) asInteger. ] ifFalse:[dtX := 0. dtY := 0]. self fillOriginXOf: fill put: (point1 at: 0). self fillOriginYOf: fill put: (point1 at: 1). self fillDirectionXOf: fill put: dsX. self fillDirectionYOf: fill put: dsY. self fillNormalXOf: fill put: dtX. self fillNormalYOf: fill put: dtY. ! ! !BalloonEnginePlugin methodsFor: 'fills-gradient' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:50'! loadGradientFill: rampOop from: point1 along: point2 normal: point3 isRadial: isRadial "Load the gradient fill as defined by the color ramp." | rampWidth fill | (interpreterProxy fetchClassOf: rampOop) = interpreterProxy classBitmap ifFalse:[^interpreterProxy primitiveFail]. rampWidth := interpreterProxy slotSizeOf: rampOop. fill := self allocateGradientFill: (interpreterProxy firstIndexableField: rampOop) rampWidth: rampWidth isRadial: isRadial. engineStopped ifTrue:[^nil]. self loadFillOrientation: fill from: point1 along: point2 normal: point3 width: rampWidth height: rampWidth. ^fill! ! !BalloonEnginePlugin methodsFor: 'lines-loading' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:50'! loadLine: line from: point1 to: point2 offset: yOffset leftFill: leftFill rightFill: rightFill "Load the line defined by point1 and point2." | p1 p2 yDir | (point1 at: 1) <= (point2 at: 1) ifTrue:[ p1 := point1. p2 := point2. yDir := 1] ifFalse:[ p1 := point2. p2 := point1. yDir := -1]. self edgeXValueOf: line put: (p1 at: 0). self edgeYValueOf: line put: (p1 at: 1) - yOffset. self edgeZValueOf: line put: self currentZGet. self edgeLeftFillOf: line put: leftFill. self edgeRightFillOf: line put: rightFill. self lineEndXOf: line put: (p2 at: 0). self lineEndYOf: line put: (p2 at: 1) - yOffset. self lineYDirectionOf: line put: yDir.! ! !BalloonEnginePlugin methodsFor: 'bezier-loading' stamp: 'ar (auto pragmas 12/08) 11/25/1998 23:21'! loadOval: lineWidth lineFill: lineFill leftFill: leftFill rightFill: rightFill "Load a rectangular oval currently defined by point1/point2" | w h cx cy nSegments | w := ((self point2Get at: 0) - (self point1Get at: 0)) // 2. h := ((self point2Get at: 1) - (self point1Get at: 1)) // 2. cx := ((self point2Get at: 0) + (self point1Get at: 0)) // 2. cy := ((self point2Get at: 1) + (self point1Get at: 1)) // 2. 0 to: 15 do:[:i| self loadOvalSegment: i w: w h: h cx: cx cy: cy. self transformPoints: 3. nSegments := self loadAndSubdivideBezierFrom: self point1Get via: self point2Get to: self point3Get isWide: (lineWidth ~= 0 and:[lineFill ~= 0]). engineStopped ifTrue:[^nil]. self loadWideBezier: lineWidth lineFill: lineFill leftFill: leftFill rightFill: rightFill n: nSegments. engineStopped ifTrue:[^nil]. ].! ! !BalloonEnginePlugin methodsFor: 'bezier-loading' stamp: 'ar (auto pragmas 12/08) 11/8/1998 15:17'! loadOvalSegment: seg w: w h: h cx: cx cy: cy | x0 y0 x2 y2 x1 y1 | "Load start point of segment" x0 := ((self circleCosTable at: seg * 2 + 0) * w asFloat + cx) asInteger. y0 := ((self circleSinTable at: seg * 2 + 0) * h asFloat + cy) asInteger. self point1Get at: 0 put: x0. self point1Get at: 1 put: y0. "Load end point of segment" x2 := ((self circleCosTable at: seg * 2 + 2) * w asFloat + cx) asInteger. y2 := ((self circleSinTable at: seg * 2 + 2) * h asFloat + cy) asInteger. self point3Get at: 0 put: x2. self point3Get at: 1 put: y2. "Load intermediate point of segment" x1 := ((self circleCosTable at: seg * 2 + 1) * w asFloat + cx) asInteger. y1 := ((self circleSinTable at: seg * 2 + 1) * h asFloat + cy) asInteger. "NOTE: The intermediate point is the point ON the curve and not yet the control point (which is OFF the curve)" x1 := (x1 * 2) - (x0 + x2 // 2). y1 := (y1 * 2) - (y0 + y2 // 2). self point2Get at: 0 put: x1. self point2Get at: 1 put: y1.! ! !BalloonEnginePlugin methodsFor: 'private' stamp: 'ar 11/3/1998 23:24'! loadPointIntAt: index from: intArray "Load the int value from the given index in intArray" ^(self cCoerce: intArray to: 'int *') at: index! ! !BalloonEnginePlugin methodsFor: 'private' stamp: 'ar (auto pragmas dtl 2010-09-27) 11/3/1998 23:23'! loadPointShortAt: index from: shortArray "Load the short value from the given index in shortArray" ^(self cCoerce: shortArray to: 'short *') at: index! ! !BalloonEnginePlugin methodsFor: 'shapes-polygons' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:51'! loadPolygon: points nPoints: nPoints fill: fillIndex lineWidth: lineWidth lineFill: lineFill pointsShort: isShort | x0 y0 x1 y1 | isShort ifTrue:[ x0 := self loadPointShortAt: 0 from: points. y0 := self loadPointShortAt: 1 from: points. ] ifFalse:[ x0 := self loadPointIntAt: 0 from: points. y0 := self loadPointIntAt: 1 from: points. ]. 1 to: nPoints-1 do:[:i| isShort ifTrue:[ x1 := self loadPointShortAt: i*2 from: points. y1 := self loadPointShortAt: i*2+1 from: points. ] ifFalse:[ x1 := self loadPointIntAt: i*2 from: points. y1 := self loadPointIntAt: i*2+1 from: points. ]. self point1Get at: 0 put: x0. self point1Get at: 1 put: y0. self point2Get at: 0 put: x1. self point2Get at: 1 put: y1. self transformPoints: 2. self loadWideLine: lineWidth from: self point1Get to: self point2Get lineFill: lineFill leftFill: fillIndex rightFill: 0. engineStopped ifTrue:[^nil]. x0 := x1. y0 := y1. ].! ! !BalloonEnginePlugin methodsFor: 'lines-loading' stamp: 'ar 11/6/1998 17:07'! loadRectangle: lineWidth lineFill: lineFill leftFill: leftFill rightFill: rightFill "Load a rectangle currently defined by point1-point4" self loadWideLine: lineWidth from: self point1Get to: self point2Get lineFill: lineFill leftFill: leftFill rightFill: rightFill. self loadWideLine: lineWidth from: self point2Get to: self point3Get lineFill: lineFill leftFill: leftFill rightFill: rightFill. self loadWideLine: lineWidth from: self point3Get to: self point4Get lineFill: lineFill leftFill: leftFill rightFill: rightFill. self loadWideLine: lineWidth from: self point4Get to: self point1Get lineFill: lineFill leftFill: leftFill rightFill: rightFill. ! ! !BalloonEnginePlugin methodsFor: 'shapes-polygons' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:51'! loadShape: points nSegments: nSegments fill: fillIndex lineWidth: lineWidth lineFill: lineFill pointsShort: pointsShort 1 to: nSegments do:[:i| self loadCompressedSegment: i-1 from: points short: pointsShort leftFill: fillIndex rightFill: 0 lineWidth: lineWidth lineColor: lineFill. engineStopped ifTrue:[^nil]. ].! ! !BalloonEnginePlugin methodsFor: 'bezier-loading' stamp: 'ar (auto pragmas 12/08) 11/8/1998 03:41'! loadWideBezier: lineWidth lineFill: lineFill leftFill: leftFill rightFill: rightFill n: nSegments "Load the (possibly wide) bezier from the segments currently on the bezier stack." | index bezier wide offset | (lineWidth = 0 or:[lineFill = 0]) ifTrue:[wide := false. offset := 0] ifFalse:[wide := true. offset := self offsetFromWidth: lineWidth]. index := nSegments * 6. [index > 0] whileTrue:[ wide ifTrue:[bezier := self allocateWideBezier] ifFalse:[bezier := self allocateBezier]. engineStopped ifTrue:[^0]. self loadBezier: bezier segment: index leftFill: leftFill rightFill: rightFill offset: offset. wide ifTrue:[ self wideBezierFillOf: bezier put: lineFill. self wideBezierWidthOf: bezier put: lineWidth. self wideBezierExtentOf: bezier put: lineWidth. ]. index := index - 6. ]. self wbStackClear.! ! !BalloonEnginePlugin methodsFor: 'lines-loading' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:51'! loadWideLine: lineWidth from: p1 to: p2 lineFill: lineFill leftFill: leftFill rightFill: rightFill "Load a (possibly wide) line defined by the points p1 and p2" | line offset | (lineWidth = 0 or:[lineFill = 0]) ifTrue:[ line := self allocateLine. offset := 0] ifFalse:[ line := self allocateWideLine. offset := self offsetFromWidth: lineWidth]. engineStopped ifTrue:[^0]. self loadLine: line from: p1 to: p2 offset: offset leftFill: leftFill rightFill: rightFill. (self isWide: line) ifTrue:[ self wideLineFillOf: line put: lineFill. self wideLineWidthOf: line put: lineWidth. self wideLineExtentOf: line put: lineWidth].! ! !BalloonEnginePlugin methodsFor: 'private' stamp: 'ar 11/1/1998 03:16'! makeRectFromPoints self point2Get at: 0 put: (self point3Get at: 0). self point2Get at: 1 put: (self point1Get at: 1). self point4Get at: 0 put: (self point1Get at: 0). self point4Get at: 1 put: (self point3Get at: 1).! ! !BalloonEnginePlugin methodsFor: 'private' stamp: 'ar (auto pragmas 12/08) 11/6/1998 17:55'! offsetFromWidth: lineWidth "Common function so that we don't compute that wrong in any place and can easily find all the places where we deal with one-pixel offsets." ^lineWidth // 2! ! !BalloonEnginePlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:07'! primitiveAddBezier | leftFill rightFill viaOop endOop startOop nSegments | "Fail if we have the wrong number of arguments" interpreterProxy methodArgumentCount = 5 ifFalse:[^interpreterProxy primitiveFail]. rightFill := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). leftFill := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 1). viaOop := interpreterProxy stackObjectValue: 2. endOop := interpreterProxy stackObjectValue: 3. startOop := interpreterProxy stackObjectValue: 4. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: (interpreterProxy stackObjectValue: 5) requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. "Make sure the fills are okay" ((self isFillOkay: leftFill) and:[self isFillOkay: rightFill]) ifFalse:[^interpreterProxy primitiveFail]. "Do a quick check if the fillIndices are equal - if so, just ignore it" leftFill = rightFill & false ifTrue:[ ^interpreterProxy pop: 6. "Leave rcvr on stack" ]. self loadPoint: self point1Get from: startOop. self loadPoint: self point2Get from: viaOop. self loadPoint: self point3Get from: endOop. interpreterProxy failed ifTrue:[^0]. self transformPoints: 3. nSegments := self loadAndSubdivideBezierFrom: self point1Get via: self point2Get to: self point3Get isWide: false. self needAvailableSpace: nSegments * GBBaseSize. engineStopped ifFalse:[ leftFill := self transformColor: leftFill. rightFill := self transformColor: rightFill]. engineStopped ifFalse:[ self loadWideBezier: 0 lineFill: 0 leftFill: leftFill rightFill: rightFill n: nSegments. ]. engineStopped ifTrue:[ "Make sure the stack is okay" self wbStackClear. ^interpreterProxy primitiveFail]. interpreterProxy failed ifFalse:[ self storeEngineStateInto: engine. interpreterProxy pop: 5. "Leave rcvr on stack" ].! ! !BalloonEnginePlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas dtl 2010-09-27) 12/5/2003 20:07'! primitiveAddBezierShape | points lineFill lineWidth fillIndex length isArray segSize nSegments | "Fail if we have the wrong number of arguments" interpreterProxy methodArgumentCount = 5 ifFalse:[^interpreterProxy primitiveFail]. lineFill := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). lineWidth := interpreterProxy stackIntegerValue: 1. fillIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 2). nSegments := interpreterProxy stackIntegerValue: 3. points := interpreterProxy stackObjectValue: 4. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: (interpreterProxy stackObjectValue: 5) requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. "First, do a check if the points look okay" length := interpreterProxy slotSizeOf: points. (interpreterProxy isWords: points) ifTrue:[ isArray := false. "Either PointArray or ShortPointArray" (length = (nSegments * 3) or:[length = (nSegments * 6)]) ifFalse:[^interpreterProxy primitiveFail]. ] ifFalse:["Must be Array of points" (interpreterProxy isArray: points) ifFalse:[^interpreterProxy primitiveFail]. length = (nSegments * 3) ifFalse:[^interpreterProxy primitiveFail]. isArray := true. ]. "Now check that we have some hope to have enough free space. Do this by assuming nPoints boundaries of maximum size, hoping that most of the fills will be colors and many boundaries will be line segments" (lineWidth = 0 or:[lineFill = 0]) ifTrue:[segSize := GLBaseSize] ifFalse:[segSize := GLWideSize]. (self needAvailableSpace: segSize * nSegments) ifFalse:[^interpreterProxy primitiveFail]. "Check the fills" ((self isFillOkay: lineFill) and:[self isFillOkay: fillIndex]) ifFalse:[^interpreterProxy primitiveFail]. "Transform colors" lineFill := self transformColor: lineFill. fillIndex := self transformColor: fillIndex. engineStopped ifTrue:[^interpreterProxy primitiveFail]. "Check if have anything at all to do" ((lineFill = 0 or:[lineWidth = 0]) and:[fillIndex = 0]) ifTrue:[^interpreterProxy pop: 5]. "Transform the lineWidth" lineWidth = 0 ifFalse:[ lineWidth := self transformWidth: lineWidth. lineWidth < 1 ifTrue:[lineWidth := 1]]. "And load the actual shape" isArray ifTrue:[ self loadArrayShape: points nSegments: nSegments fill: fillIndex lineWidth: lineWidth lineFill: lineFill. ] ifFalse:[ self loadShape: (interpreterProxy firstIndexableField: points) nSegments: nSegments fill: fillIndex lineWidth: lineWidth lineFill: lineFill pointsShort: (nSegments * 3 = length)]. engineStopped ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy failed ifFalse:[ self needsFlushPut: 1. self storeEngineStateInto: engine. interpreterProxy pop: 5. "Leave rcvr on stack" ].! ! !BalloonEnginePlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:10'! primitiveAddBitmapFill | nrmOop dirOop originOop tileFlag fill xIndex cmOop formOop | "Fail if we have the wrong number of arguments" interpreterProxy methodArgumentCount = 7 ifFalse:[^interpreterProxy primitiveFail]. xIndex := interpreterProxy stackIntegerValue: 0. xIndex <= 0 ifTrue:[^interpreterProxy primitiveFail]. nrmOop := interpreterProxy stackObjectValue: 1. dirOop := interpreterProxy stackObjectValue: 2. originOop := interpreterProxy stackObjectValue: 3. tileFlag := interpreterProxy booleanValueOf: (interpreterProxy stackValue: 4). tileFlag ifTrue:[tileFlag := 1] ifFalse:[tileFlag := 0]. cmOop := interpreterProxy stackObjectValue: 5. formOop := interpreterProxy stackObjectValue: 6. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: (interpreterProxy stackObjectValue: 7) requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. self loadPoint: self point1Get from: originOop. self loadPoint: self point2Get from: dirOop. self loadPoint: self point3Get from: nrmOop. interpreterProxy failed ifTrue:[^0]. fill := self loadBitmapFill: formOop colormap: cmOop tile: tileFlag from: self point1Get along: self point2Get normal: self point3Get xIndex: xIndex-1. engineStopped ifTrue:[ "Make sure the stack is okay" ^interpreterProxy primitiveFail]. interpreterProxy failed ifFalse:[ self storeEngineStateInto: engine. interpreterProxy pop: 8. interpreterProxy push: (interpreterProxy positive32BitIntegerFor: fill). ].! ! !BalloonEnginePlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:06'! primitiveAddCompressedShape | fillIndexList lineFills lineWidths rightFills leftFills nSegments points pointsShort | "Fail if we have the wrong number of arguments" interpreterProxy methodArgumentCount = 7 ifFalse:[^interpreterProxy primitiveFail]. fillIndexList := interpreterProxy stackObjectValue: 0. lineFills := interpreterProxy stackObjectValue: 1. lineWidths := interpreterProxy stackObjectValue: 2. rightFills := interpreterProxy stackObjectValue: 3. leftFills := interpreterProxy stackObjectValue: 4. nSegments := interpreterProxy stackIntegerValue: 5. points := interpreterProxy stackObjectValue: 6. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: (interpreterProxy stackObjectValue: 7) requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. "First, do a check if the compressed shape is okay" (self checkCompressedShape: points segments: nSegments leftFills: leftFills rightFills: rightFills lineWidths: lineWidths lineFills: lineFills fillIndexList: fillIndexList) ifFalse:[^interpreterProxy primitiveFail]. "Now check that we have some hope to have enough free space. Do this by assuming nSegments boundaries of maximum size, hoping that most of the fills will be colors and many boundaries will be line segments" (self needAvailableSpace: (GBBaseSize max: GLBaseSize) * nSegments) ifFalse:[^interpreterProxy primitiveFail]. "Check if the points are short" pointsShort := (interpreterProxy slotSizeOf: points) = (nSegments * 3). "Then actually load the compressed shape" self loadCompressedShape: (interpreterProxy firstIndexableField: points) segments: nSegments leftFills: (interpreterProxy firstIndexableField: leftFills) rightFills: (interpreterProxy firstIndexableField: rightFills) lineWidths: (interpreterProxy firstIndexableField: lineWidths) lineFills: (interpreterProxy firstIndexableField: lineFills) fillIndexList: (interpreterProxy firstIndexableField: fillIndexList) pointShort: pointsShort. engineStopped ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy failed ifFalse:[ self needsFlushPut: 1. self storeEngineStateInto: engine. interpreterProxy pop: 7. "Leave rcvr on stack" ].! ! !BalloonEnginePlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:13'! primitiveAddGradientFill | isRadial nrmOop dirOop originOop rampOop fill | "Fail if we have the wrong number of arguments" interpreterProxy methodArgumentCount = 5 ifFalse:[^interpreterProxy primitiveFail]. isRadial := interpreterProxy booleanValueOf: (interpreterProxy stackValue: 0). nrmOop := interpreterProxy stackValue: 1. dirOop := interpreterProxy stackValue: 2. originOop := interpreterProxy stackValue: 3. rampOop := interpreterProxy stackValue: 4. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: (interpreterProxy stackObjectValue: 5) requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. self loadPoint: self point1Get from: originOop. self loadPoint: self point2Get from: dirOop. self loadPoint: self point3Get from: nrmOop. interpreterProxy failed ifTrue:[^0]. fill := self loadGradientFill: rampOop from: self point1Get along: self point2Get normal: self point3Get isRadial: isRadial. engineStopped ifTrue:[ "Make sure the stack is okay" ^interpreterProxy primitiveFail]. interpreterProxy failed ifFalse:[ self storeEngineStateInto: engine. interpreterProxy pop: 6. interpreterProxy push: (interpreterProxy positive32BitIntegerFor: fill). ].! ! !BalloonEnginePlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:08'! primitiveAddLine | leftFill rightFill endOop startOop | "Fail if we have the wrong number of arguments" interpreterProxy methodArgumentCount = 4 ifFalse:[^interpreterProxy primitiveFail]. rightFill := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). leftFill := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 1). endOop := interpreterProxy stackObjectValue: 2. startOop := interpreterProxy stackObjectValue: 3. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: (interpreterProxy stackObjectValue: 4) requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. "Make sure the fills are okay" ((self isFillOkay: leftFill) and:[self isFillOkay: rightFill]) ifFalse:[^interpreterProxy primitiveFail]. "Load the points" self loadPoint: self point1Get from: startOop. self loadPoint: self point2Get from: endOop. interpreterProxy failed ifTrue:[^0]. "Transform points" self transformPoints: 2. "Transform colors" leftFill := self transformColor: leftFill. rightFill := self transformColor: rightFill. engineStopped ifTrue:[^interpreterProxy primitiveFail]. "Load line" self loadWideLine: 0 from: self point1Get to: self point2Get lineFill: 0 leftFill: leftFill rightFill: rightFill. engineStopped ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy failed ifFalse:[ self storeEngineStateInto: engine. interpreterProxy pop: 4. "Leave rcvr on stack" ].! ! !BalloonEnginePlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:12'! primitiveAddOval | fillIndex borderWidth borderIndex endOop startOop | "Fail if we have the wrong number of arguments" interpreterProxy methodArgumentCount = 5 ifFalse:[^interpreterProxy primitiveFail]. borderIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). borderWidth := interpreterProxy stackIntegerValue: 1. fillIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 2). endOop := interpreterProxy stackObjectValue: 3. startOop := interpreterProxy stackObjectValue: 4. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: (interpreterProxy stackObjectValue: 5) requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. "Make sure the fills are okay" ((self isFillOkay: borderIndex) and:[self isFillOkay: fillIndex]) ifFalse:[^interpreterProxy primitiveFail]. "Transform colors" fillIndex := self transformColor: fillIndex. borderIndex := self transformColor: borderIndex. engineStopped ifTrue:[^interpreterProxy primitiveFail]. "Check if we have anything at all to do" (fillIndex = 0 and:[borderIndex = 0 or:[borderWidth <= 0]]) ifTrue:[ ^interpreterProxy pop: 5. "Leave rcvr on stack" ]. "Make sure we have some space" (self needAvailableSpace: (16 * GBBaseSize)) ifFalse:[^interpreterProxy primitiveFail]. "Check if we need a border" (borderWidth > 0 and:[borderIndex ~= 0]) ifTrue:[borderWidth := self transformWidth: borderWidth] ifFalse:[borderWidth := 0]. "Load the rectangle points" self loadPoint: self point1Get from: startOop. self loadPoint: self point2Get from: endOop. interpreterProxy failed ifTrue:[^0]. self loadOval: borderWidth lineFill: borderIndex leftFill: 0 rightFill: fillIndex. engineStopped ifTrue:[ self wbStackClear. ^interpreterProxy primitiveFail. ]. interpreterProxy failed ifFalse:[ self needsFlushPut: 1. self storeEngineStateInto: engine. interpreterProxy pop: 5. "Leave rcvr on stack" ].! ! !BalloonEnginePlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas dtl 2010-09-27) 12/5/2003 20:08'! primitiveAddPolygon | points lineFill lineWidth fillIndex nPoints length isArray segSize | "Fail if we have the wrong number of arguments" interpreterProxy methodArgumentCount = 5 ifFalse:[^interpreterProxy primitiveFail]. lineFill := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). lineWidth := interpreterProxy stackIntegerValue: 1. fillIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 2). nPoints := interpreterProxy stackIntegerValue: 3. points := interpreterProxy stackObjectValue: 4. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: (interpreterProxy stackObjectValue: 5) requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. "First, do a check if the points look okay" length := interpreterProxy slotSizeOf: points. (interpreterProxy isWords: points) ifTrue:[ isArray := false. "Either PointArray or ShortPointArray" (length = nPoints or:[nPoints * 2 = length]) ifFalse:[^interpreterProxy primitiveFail]. ] ifFalse:["Must be Array of points" (interpreterProxy isArray: points) ifFalse:[^interpreterProxy primitiveFail]. length = nPoints ifFalse:[^interpreterProxy primitiveFail]. isArray := true. ]. "Now check that we have some hope to have enough free space. Do this by assuming nPoints boundaries of maximum size, hoping that most of the fills will be colors and many boundaries will be line segments" (lineWidth = 0 or:[lineFill = 0]) ifTrue:[segSize := GLBaseSize] ifFalse:[segSize := GLWideSize]. (self needAvailableSpace: segSize * nPoints) ifFalse:[^interpreterProxy primitiveFail]. "Check the fills" ((self isFillOkay: lineFill) and:[self isFillOkay: fillIndex]) ifFalse:[^interpreterProxy primitiveFail]. "Transform colors" lineFill := self transformColor: lineFill. fillIndex := self transformColor: fillIndex. engineStopped ifTrue:[^interpreterProxy primitiveFail]. "Check if have anything at all to do" ((lineFill = 0 or:[lineWidth = 0]) and:[fillIndex = 0]) ifTrue:[^interpreterProxy pop: 6]. "Transform the lineWidth" lineWidth = 0 ifFalse:[lineWidth := self transformWidth: lineWidth]. "And load the actual polygon" isArray ifTrue:[ self loadArrayPolygon: points nPoints: nPoints fill: fillIndex lineWidth: lineWidth lineFill: lineFill ] ifFalse:[ self loadPolygon: (interpreterProxy firstIndexableField: points) nPoints: nPoints fill: fillIndex lineWidth: lineWidth lineFill: lineFill pointsShort: (nPoints = length)]. engineStopped ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy failed ifFalse:[ self needsFlushPut: 1. self storeEngineStateInto: engine. interpreterProxy pop: 5. "Leave rcvr on stack" ].! ! !BalloonEnginePlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas dtl 2010-09-27) 5/11/2000 23:09'! primitiveAddRect | fillIndex borderWidth borderIndex endOop startOop | "Fail if we have the wrong number of arguments" interpreterProxy methodArgumentCount = 5 ifFalse:[^interpreterProxy primitiveFail]. borderIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). borderWidth := interpreterProxy stackIntegerValue: 1. fillIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 2). endOop := interpreterProxy stackObjectValue: 3. startOop := interpreterProxy stackObjectValue: 4. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: (interpreterProxy stackObjectValue: 5) requiredState: GEStateUnlocked) ifFalse:[^interpreterProxy primitiveFail]. "Make sure the fills are okay" ((self isFillOkay: borderIndex) and:[self isFillOkay: fillIndex]) ifFalse:[^interpreterProxy primitiveFail]. "Transform colors" borderIndex := self transformColor: borderIndex. fillIndex := self transformColor: fillIndex. engineStopped ifTrue:[^interpreterProxy primitiveFail]. "Check if we have anything at all to do" (fillIndex = 0 and:[borderIndex = 0 or:[borderWidth = 0]]) ifTrue:[ ^interpreterProxy pop: 5. "Leave rcvr on stack" ]. "Make sure we have some space" (self needAvailableSpace: (4 * GLBaseSize)) ifFalse:[^interpreterProxy primitiveFail]. "Check if we need a border" (borderWidth > 0 and:[borderIndex ~= 0]) ifTrue:[borderWidth := self transformWidth: borderWidth] ifFalse:[borderWidth := 0]. "Load the rectangle" self loadPoint: self point1Get from: startOop. self loadPoint: self point3Get from: endOop. interpreterProxy failed ifTrue:[^nil]. self point2Get at: 0 put: (self point3Get at: 0). self point2Get at: 1 put: (self point1Get at: 1). self point4Get at: 0 put: (self point1Get at: 0). self point4Get at: 1 put: (self point3Get at: 1). "Transform the points" self transformPoints: 4. self loadRectangle: borderWidth lineFill: borderIndex leftFill: 0 rightFill: fillIndex. interpreterProxy failed ifFalse:[ self needsFlushPut: 1. self storeEngineStateInto: engine. interpreterProxy pop: 5. "Leave rcvr on stack" ].! ! !BalloonEnginePlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:51'! primitiveGetBezierStats | statOop stats | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. statOop := interpreterProxy stackObjectValue: 0. engine := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (self quickLoadEngineFrom: engine) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isWords: statOop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: statOop) < 4 ifTrue:[^interpreterProxy primitiveFail]. stats := interpreterProxy firstIndexableField: statOop. stats at: 0 put: (stats at: 0) + (workBuffer at: GWBezierMonotonSubdivisions). stats at: 1 put: (stats at: 1) + (workBuffer at: GWBezierHeightSubdivisions). stats at: 2 put: (stats at: 2) + (workBuffer at: GWBezierOverflowSubdivisions). stats at: 3 put: (stats at: 3) + (workBuffer at: GWBezierLineConversions). interpreterProxy pop: 1. "Leave rcvr on stack"! ! !BalloonEnginePlugin methodsFor: 'private' stamp: 'ar (auto pragmas dtl 2010-09-27) 11/25/1998 19:27'! rShiftTable | theTable | ^theTable! ! !BalloonEnginePlugin methodsFor: 'fills-bitmaps' stamp: 'ar (auto pragmas 12/08) 11/27/1998 14:14'! repeatValue: delta max: maxValue | newDelta | newDelta := delta. [newDelta < 0] whileTrue:[newDelta := newDelta + maxValue]. [newDelta >= maxValue] whileTrue:[newDelta := newDelta - maxValue]. ^newDelta! ! !BalloonEnginePlugin methodsFor: 'beziers-wide' stamp: 'ar 11/6/1998 01:54'! returnWideBezierFill ^(dispatchReturnValue := self wideBezierFillOf: dispatchedValue).! ! !BalloonEnginePlugin methodsFor: 'beziers-wide' stamp: 'ar 11/6/1998 01:54'! returnWideBezierWidth ^(dispatchReturnValue := self wideBezierWidthOf: dispatchedValue).! ! !BalloonEnginePlugin methodsFor: 'lines-wide' stamp: 'ar 11/6/1998 17:08'! returnWideLineFill "Return the fill of the (wide) line - this method is called from a case." ^(dispatchReturnValue := self wideLineFillOf: dispatchedValue).! ! !BalloonEnginePlugin methodsFor: 'lines-wide' stamp: 'ar 11/6/1998 17:08'! returnWideLineWidth "Return the width of the (wide) line - this method is called from a case." ^(dispatchReturnValue := self wideLineWidthOf: dispatchedValue).! ! !BalloonEnginePlugin methodsFor: 'private' stamp: 'eem 5/20/2010 15:05'! shortRunLengthAt: i from: runArray "Return the run-length value from the given ShortRunArray." ^((self cCoerce: runArray to:'int *') at: i) bitShift: -16! ! !BalloonEnginePlugin methodsFor: 'private' stamp: 'ar 11/3/1998 22:54'! shortRunValueAt: i from: runArray "Return the run-length value from the given ShortRunArray. Note: We don't need any coercion to short/int here, since we deal basically only with unsigned values." ^(((self cCoerce: runArray to:'int *') at: i) bitAnd: 16rFFFF)! ! !BalloonEnginePlugin methodsFor: 'beziers-simple' stamp: 'ar (auto pragmas 12/08) 11/6/1998 00:07'! stepToFirstBezier "Initialize the current entry in the GET by stepping to the current scan line" ^self stepToFirstBezierIn: (getBuffer at: self getStartGet) at: self currentYGet! ! !BalloonEnginePlugin methodsFor: 'beziers-simple' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 15:52'! stepToFirstBezierIn: bezier at: yValue "Initialize the bezier at yValue. TODO: Check if reducing maxSteps from 2*deltaY to deltaY brings a *significant* performance improvement. In theory this should make for double step performance but will cost in quality. Might be that the AA stuff will compensate for this - but I'm not really sure." | updateData deltaY maxSteps scaledStepSize squaredStepSize startX startY viaX viaY endX endY fwX1 fwX2 fwY1 fwY2 fwDx fwDDx fwDy fwDDy | "Do a quick check if there is anything at all to do" ((self isWide: bezier) not and:[yValue >= (self bezierEndYOf: bezier)]) ifTrue:[^self edgeNumLinesOf: bezier put: 0]. "Now really initialize bezier" startX := self edgeXValueOf: bezier. startY := self edgeYValueOf: bezier. viaX := self bezierViaXOf: bezier. viaY := self bezierViaYOf: bezier. endX := self bezierEndXOf: bezier. endY := self bezierEndYOf: bezier. deltaY := endY - startY. "Initialize integer forward differencing" fwX1 := (viaX - startX) * 2. fwX2 := startX + endX - (viaX * 2). fwY1 := (viaY - startY) * 2. fwY2 := startY + endY - (viaY * 2). maxSteps := deltaY * 2. maxSteps < 2 ifTrue:[maxSteps := 2]. scaledStepSize := 16r1000000 // maxSteps. squaredStepSize := self absoluteSquared8Dot24: scaledStepSize. fwDx := fwX1 * scaledStepSize. fwDDx := fwX2 * squaredStepSize * 2. fwDx := fwDx + (fwDDx // 2). fwDy := fwY1 * scaledStepSize. fwDDy := fwY2 * squaredStepSize * 2. fwDy := fwDy + (fwDDy // 2). "Store the values" self edgeNumLinesOf: bezier put: deltaY. updateData := self bezierUpdateDataOf: bezier. updateData at: GBUpdateX put: (startX * 256). updateData at: GBUpdateY put: (startY * 256). updateData at: GBUpdateDX put: fwDx. updateData at: GBUpdateDY put: fwDy. updateData at: GBUpdateDDX put: fwDDx. updateData at: GBUpdateDDY put: fwDDy. "And step to the first scan line" (startY := self edgeYValueOf: bezier) = yValue ifFalse:[ self stepToNextBezierIn: bezier at: yValue. "Adjust number of lines remaining" self edgeNumLinesOf: bezier put: deltaY - (yValue - startY). ].! ! !BalloonEnginePlugin methodsFor: 'lines-simple' stamp: 'ar (auto pragmas 12/08) 11/4/1998 21:52'! stepToFirstLine "Initialize the current entry in the GET by stepping to the current scan line" ^self stepToFirstLineIn: (getBuffer at: self getStartGet) at: self currentYGet! ! !BalloonEnginePlugin methodsFor: 'lines-simple' stamp: 'ar (auto pragmas 12/08) 11/9/1998 15:38'! stepToFirstLineIn: line at: yValue "Initialize the line at yValue" | deltaX deltaY xDir widthX error xInc errorAdjUp startY | "Do a quick check if there is anything at all to do" ((self isWide: line) not and:[yValue >= (self lineEndYOf: line)]) ifTrue:[^self edgeNumLinesOf: line put: 0]. deltaX := (self lineEndXOf: line) - (self edgeXValueOf: line). deltaY := (self lineEndYOf: line) - (self edgeYValueOf: line). "Check if edge goes left to right" deltaX >= 0 ifTrue:[ xDir := 1. widthX := deltaX. error := 0] ifFalse:[ xDir := -1. widthX := 0 - deltaX. error := 1 - deltaY]. "Check if deltaY is zero. Note: We could actually get out here immediately but wide lines rely on an accurate setup in this case" deltaY = 0 ifTrue:[ error := 0. "No error for horizontal edges" xInc := deltaX. "Encodes width and direction" errorAdjUp := 0] ifFalse:["Check if edge is y-major" deltaY > widthX "Note: The '>' instead of '>=' could be important here..." ifTrue:[ xInc := 0. errorAdjUp := widthX] ifFalse:[ xInc := (widthX // deltaY) * xDir. errorAdjUp := widthX \\ deltaY]]. "Store the values" self edgeNumLinesOf: line put: deltaY. self lineXDirectionOf: line put: xDir. "self lineYDirectionOf: line put: yDir." "<-- Already set" self lineXIncrementOf: line put: xInc. self lineErrorOf: line put: error. self lineErrorAdjUpOf: line put: errorAdjUp. self lineErrorAdjDownOf: line put: deltaY. "And step to the first scan line" (startY := self edgeYValueOf: line) = yValue ifFalse:[ startY to: yValue-1 do:[:i| self stepToNextLineIn: line at: i]. "Adjust number of lines remaining" self edgeNumLinesOf: line put: deltaY - (yValue - startY). ].! ! !BalloonEnginePlugin methodsFor: 'beziers-wide' stamp: 'ar (auto pragmas 12/08) 11/6/1998 02:00'! stepToFirstWideBezier "Initialize the current entry in the GET by stepping to the current scan line" ^self stepToFirstWideBezierIn: (getBuffer at: self getStartGet) at: self currentYGet! ! !BalloonEnginePlugin methodsFor: 'beziers-wide' stamp: 'ar (auto pragmas 12/08) 11/9/1998 15:38'! stepToFirstWideBezierIn: bezier at: yValue "Initialize the bezier at yValue" | lineWidth startY nLines yEntry yExit lineOffset endX xDir | "Get some values" lineWidth := self wideBezierExtentOf: bezier. lineOffset := self offsetFromWidth: lineWidth. "Compute the incremental values of the bezier" endX := self bezierEndXOf: bezier. startY := self edgeYValueOf: bezier. self stepToFirstBezierIn: bezier at: startY. nLines := (self edgeNumLinesOf: bezier). "Copy the incremental update data" 0 to: 5 do:[:i| (self wideBezierUpdateDataOf: bezier) at: i put: ((self bezierUpdateDataOf: bezier) at: i). ]. "Compute primary x direction of curve (e.g., 1: left to right; -1: right to left)." xDir := ((self bezierUpdateDataOf: bezier) at: GBUpdateDX). xDir = 0 ifTrue:[((self bezierUpdateDataOf: bezier) at: GBUpdateDDX)]. xDir >= 0 ifTrue:[xDir := 1] ifFalse:[xDir := -1]. "Adjust the curve to start/end at the right position" xDir < 0 ifTrue:[self adjustWideBezierLeft: bezier width: lineWidth offset: lineOffset endX: endX] ifFalse:[self adjustWideBezierRight: bezier width: lineWidth offset: lineOffset endX: endX]. "Adjust the last value for horizontal lines" nLines = 0 ifTrue:[(self bezierUpdateDataOf: bezier) at: GBUpdateX put: (self bezierFinalXOf: bezier) * 256]. "Adjust the number of lines to include the lineWidth" self edgeNumLinesOf: bezier put: nLines + lineWidth. "Compute the points where we have to turn on/off the fills" yEntry := 0. "turned on at lineOffset" yExit := 0 - nLines - lineOffset. "turned off at zero" self wideBezierEntryOf: bezier put: yEntry. self wideBezierExitOf: bezier put: yExit. "Turn the fills on/off as necessary" (yEntry >= lineOffset and:[yExit < 0]) ifTrue:[self edgeFillsValidate: bezier] ifFalse:[self edgeFillsInvalidate: bezier]. self computeFinalWideBezierValues: bezier width: lineWidth. "And step to the first scan line" startY = yValue ifFalse:[ "Note: Must single step here so that entry/exit works" startY to: yValue-1 do:[:i| self stepToNextWideBezierIn: bezier at: i]. "Adjust number of lines remaining" self edgeNumLinesOf: bezier put: (self edgeNumLinesOf: bezier) - (yValue - startY). ].! ! !BalloonEnginePlugin methodsFor: 'lines-wide' stamp: 'ar (auto pragmas 12/08) 11/4/1998 21:54'! stepToFirstWideLine "Initialize the current entry in the GET by stepping to the current scan line" ^self stepToFirstWideLineIn: (getBuffer at: self getStartGet) at: self currentYGet! ! !BalloonEnginePlugin methodsFor: 'lines-wide' stamp: 'ar (auto pragmas 12/08) 11/9/1998 15:38'! stepToFirstWideLineIn: line at: yValue "Initialize the wide line at yValue." | startY yEntry yExit lineWidth nLines lineOffset startX xDir | "Get some values" lineWidth := self wideLineExtentOf: line. lineOffset := self offsetFromWidth: lineWidth. "Compute the incremental values of the line" startX := self edgeXValueOf: line. startY := self edgeYValueOf: line. self stepToFirstLineIn: line at: startY. nLines := (self edgeNumLinesOf: line). xDir := self lineXDirectionOf: line. "Adjust the line to start at the correct X position" self edgeXValueOf: line put: startX - lineOffset. "Adjust the number of lines to include the lineWidth" self edgeNumLinesOf: line put: nLines + lineWidth. "Adjust the values for x-major lines" xDir > 0 ifTrue:[ self wideLineWidthOf: line put: (self lineXIncrementOf: line) + lineWidth. ] ifFalse:[ self wideLineWidthOf: line put: lineWidth - (self lineXIncrementOf: line). "adding" self edgeXValueOf: line put: (self edgeXValueOf: line) + (self lineXIncrementOf: line). ]. "Compute the points where we have to turn on/off the fills" yEntry := 0. "turned on at lineOffset" yExit := 0 - nLines - lineOffset. "turned off at zero" self wideLineEntryOf: line put: yEntry. self wideLineExitOf: line put: yExit. "Turn the fills on/off as necessary" (yEntry >= lineOffset and:[yExit < 0]) ifTrue:[self edgeFillsValidate: line] ifFalse:[self edgeFillsInvalidate: line]. "And step to the first scan line" startY = yValue ifFalse:[ startY to: yValue-1 do:[:i| self stepToNextWideLineIn: line at: i]. "Adjust number of lines remaining" self edgeNumLinesOf: line put: (self edgeNumLinesOf: line) - (yValue - startY). ]. ! ! !BalloonEnginePlugin methodsFor: 'beziers-simple' stamp: 'ar (auto pragmas 12/08) 11/6/1998 00:08'! stepToNextBezier "Process the current entry in the AET by stepping to the next scan line" ^self stepToNextBezierIn: (aetBuffer at: self aetStartGet) at: self currentYGet! ! !BalloonEnginePlugin methodsFor: 'beziers-simple' stamp: 'ar (auto pragmas 12/08) 11/9/1998 01:49'! stepToNextBezierForward: updateData at: yValue "Incrementally step to the next scan line in the given bezier update data. Note: This method has been written so that inlining works, e.g., not declaring updateData as 'int*' but casting it on every use." | minY lastX lastY fwDx fwDy | lastX := (self cCoerce: updateData to: 'int*') at: GBUpdateX. lastY := (self cCoerce: updateData to: 'int*') at: GBUpdateY. fwDx := (self cCoerce: updateData to: 'int*') at: GBUpdateDX. fwDy := (self cCoerce: updateData to: 'int*') at: GBUpdateDY. minY := yValue * 256. "Step as long as we haven't yet reached minY and also as long as fwDy is greater than zero thus stepping down. Note: The test for fwDy should not be necessary in theory but is a good insurance in practice." [minY > lastY and:[fwDy >= 0]] whileTrue:[ lastX := lastX + ((fwDx + 16r8000) // 16r10000). lastY := lastY + ((fwDy + 16r8000) // 16r10000). fwDx := fwDx + ((self cCoerce: updateData to: 'int*') at: GBUpdateDDX). fwDy := fwDy + ((self cCoerce: updateData to: 'int*') at: GBUpdateDDY). ]. (self cCoerce: updateData to: 'int*') at: GBUpdateX put: lastX. (self cCoerce: updateData to: 'int*') at: GBUpdateY put: lastY. (self cCoerce: updateData to: 'int*') at: GBUpdateDX put: fwDx. (self cCoerce: updateData to: 'int*') at: GBUpdateDY put: fwDy. ^lastX // 256 ! ! !BalloonEnginePlugin methodsFor: 'beziers-simple' stamp: 'ar (auto pragmas 12/08) 11/9/1998 15:39'! stepToNextBezierIn: bezier at: yValue "Incrementally step to the next scan line in the given bezier" | xValue | xValue := self stepToNextBezierForward: (self bezierUpdateDataOf: bezier) at: yValue. self edgeXValueOf: bezier put: xValue.! ! !BalloonEnginePlugin methodsFor: 'lines-simple' stamp: 'ar (auto pragmas 12/08) 11/4/1998 21:53'! stepToNextLine "Process the current entry in the AET by stepping to the next scan line" ^self stepToNextLineIn: (aetBuffer at: self aetStartGet) at: self currentYGet! ! !BalloonEnginePlugin methodsFor: 'lines-simple' stamp: 'ar (auto pragmas 12/08) 11/9/1998 15:39'! stepToNextLineIn: line at: yValue "Incrementally step to the next scan line in the given line" | x err | x := (self edgeXValueOf: line) + (self lineXIncrementOf: line). err := (self lineErrorOf: line) + (self lineErrorAdjUpOf: line). err > 0 ifTrue:[ x := x + (self lineXDirectionOf: line). err := err - (self lineErrorAdjDownOf: line). ]. self lineErrorOf: line put: err. self edgeXValueOf: line put: x.! ! !BalloonEnginePlugin methodsFor: 'beziers-wide' stamp: 'ar (auto pragmas 12/08) 11/6/1998 02:34'! stepToNextWideBezier "Initialize the current entry in the GET by stepping to the current scan line" self stepToNextWideBezierIn: (aetBuffer at: self aetStartGet) at: self currentYGet.! ! !BalloonEnginePlugin methodsFor: 'beziers-wide' stamp: 'ar (auto pragmas 12/08) 11/9/1998 15:39'! stepToNextWideBezierIn: bezier at: yValue "Incrementally step to the next scan line in the given wide bezier" | yEntry yExit lineWidth lineOffset | "Don't inline this" lineWidth := self wideBezierExtentOf: bezier. lineOffset := self offsetFromWidth: lineWidth. yEntry := (self wideBezierEntryOf: bezier) + 1. yExit := (self wideBezierExitOf: bezier) + 1. self wideBezierEntryOf: bezier put: yEntry. self wideBezierExitOf: bezier put: yExit. yEntry >= lineOffset ifTrue:[self edgeFillsValidate: bezier]. yExit >= 0 ifTrue:[self edgeFillsInvalidate: bezier]. "Check if we have to step the upper curve" (yExit + lineOffset < 0) ifTrue:[ self stepToNextBezierForward: (self bezierUpdateDataOf: bezier) at: yValue. ] ifFalse:[ "Adjust the last x value to the final x recorded previously" (self bezierUpdateDataOf: bezier) at: GBUpdateX put: (self bezierFinalXOf: bezier) * 256. ]. "Step the lower curve" self stepToNextBezierForward: (self wideBezierUpdateDataOf: bezier) at: yValue. self computeFinalWideBezierValues: bezier width: lineWidth.! ! !BalloonEnginePlugin methodsFor: 'lines-wide' stamp: 'ar (auto pragmas 12/08) 11/4/1998 21:55'! stepToNextWideLine "Process the current entry in the AET by stepping to the next scan line" ^self stepToNextWideLineIn: (aetBuffer at: self aetStartGet) at: self currentYGet! ! !BalloonEnginePlugin methodsFor: 'lines-wide' stamp: 'ar (auto pragmas 12/08) 11/9/1998 15:39'! stepToNextWideLineIn: line at: yValue "Incrementally step to the next scan line in the given wide line" | yEntry yExit lineWidth lineOffset lastX nextX | "Adjust entry/exit values" yEntry := (self wideLineEntryOf: line) + 1. yExit := (self wideLineExitOf: line) + 1. self wideLineEntryOf: line put: yEntry. self wideLineExitOf: line put: yExit. "Turn fills on/off" lineWidth := self wideLineExtentOf: line. lineOffset := self offsetFromWidth: lineWidth. yEntry >= lineOffset ifTrue:[self edgeFillsValidate: line]. yExit >= 0 ifTrue:[self edgeFillsInvalidate: line]. "Step to the next scan line" lastX := self edgeXValueOf: line. self stepToNextLineIn: line at: yValue. nextX := self edgeXValueOf: line. "Check for special start/end adjustments" (yEntry <= lineWidth or:[yExit+lineOffset >= 0]) ifTrue:[ "Yes, need an update" self adjustWideLine: line afterSteppingFrom: lastX to: nextX. ].! ! !BalloonEnginePlugin methodsFor: 'bezier-loading' stamp: 'ar (auto pragmas 12/08) 11/8/1998 14:36'! subdivideBezier: index "Subdivide the given bezier curve if necessary" | startX startY endX endY deltaX deltaY | startY := self bzStartY: index. endY := self bzEndY: index. "If the receiver is horizontal, don't do anything" (endY = startY) ifTrue:[^index]. "TODO: If the curve can be represented as a line, then do so" "If the height of the curve exceeds 256 pixels, subdivide (forward differencing is numerically not very stable)" deltaY := endY - startY. deltaY < 0 ifTrue:[deltaY := 0 - deltaY]. (deltaY > 255) ifTrue:[ self incrementStat: GWBezierHeightSubdivisions by: 1. ^self computeBezierSplitAtHalf: index]. "Check if the incremental values could possibly overflow the scaled integer range" startX := self bzStartX: index. endX := self bzEndX: index. deltaX := endX - startX. deltaX < 0 ifTrue:[deltaX := 0 - deltaX]. deltaY * 32 < deltaX ifTrue:[ self incrementStat: GWBezierOverflowSubdivisions by: 1. ^self computeBezierSplitAtHalf: index]. ^index ! ! !BalloonEnginePlugin methodsFor: 'bezier-loading' stamp: 'ar (auto pragmas 12/08) 11/8/1998 03:43'! subdivideBezierFrom: index "Recursively subdivide the curve on the bezier stack." | otherIndex index1 index2 | otherIndex := self subdivideBezier: index. otherIndex = index ifFalse:[ index1 := self subdivideBezierFrom: index. engineStopped ifTrue:[^0]. index2 := self subdivideBezierFrom: otherIndex. engineStopped ifTrue:[^0]. index1 >= index2 ifTrue:[^index1] ifFalse:[^index2] ]. ^index! ! !BalloonEnginePlugin methodsFor: 'bezier-loading' stamp: 'ar (auto pragmas 12/08) 11/8/1998 15:17'! subdivideToBeMonoton: base inX: doTestX "Check if the given bezier curve is monoton in Y, and, if desired in X. If not, subdivide it" | index1 index2 base2 | base2 := index1 := index2 := self subdivideToBeMonotonInY: base. doTestX ifTrue:[index1 := self subdivideToBeMonotonInX: base]. index1 > index2 ifTrue:[index2 := index1]. (base ~= base2 and:[doTestX]) ifTrue:[index1 := self subdivideToBeMonotonInX: base2]. index1 > index2 ifTrue:[index2 := index1]. ^index2! ! !BalloonEnginePlugin methodsFor: 'bezier-loading' stamp: 'ar (auto pragmas 12/08) 11/7/1998 19:42'! subdivideToBeMonotonInX: index "Check if the given bezier curve is monoton in X. If not, subdivide it" | denom num startX viaX endX dx1 dx2 | startX := self bzStartX: index. viaX := self bzViaX: index. endX := self bzEndX: index. dx1 := viaX - startX. dx2 := endX - viaX. (dx1 * dx2) >= 0 ifTrue:[^index]. "Bezier is monoton" self incrementStat: GWBezierMonotonSubdivisions by: 1. "Compute split value" denom := dx2 - dx1. num := dx1. num < 0 ifTrue:[num := 0 - num]. denom < 0 ifTrue:[denom := 0 - denom]. ^self computeBezier: index splitAt: (num asFloat / denom asFloat).! ! !BalloonEnginePlugin methodsFor: 'bezier-loading' stamp: 'ar (auto pragmas 12/08) 11/7/1998 19:42'! subdivideToBeMonotonInY: index "Check if the given bezier curve is monoton in Y. If not, subdivide it" | startY viaY endY dy1 dy2 denom num | startY := self bzStartY: index. viaY := self bzViaY: index. endY := self bzEndY: index. dy1 := viaY - startY. dy2 := endY - viaY. (dy1 * dy2) >= 0 ifTrue:[^index]. "Bezier is monoton" self incrementStat: GWBezierMonotonSubdivisions by: 1. "Compute split value" denom := dy2 - dy1. num := dy1. num < 0 ifTrue:[num := 0 - num]. denom < 0 ifTrue:[denom := 0 - denom]. ^self computeBezier: index splitAt: (num asFloat / denom asFloat).! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:18'! wideBezierEntryOf: line ^self obj: line at: GBWideEntry! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:18'! wideBezierEntryOf: line put: value ^self obj: line at: GBWideEntry put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:18'! wideBezierExitOf: line ^self obj: line at: GBWideExit! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:18'! wideBezierExitOf: line put: value ^self obj: line at: GBWideExit put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:20'! wideBezierExtentOf: bezier ^self obj: bezier at: GBWideExtent! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:20'! wideBezierExtentOf: bezier put: value ^self obj: bezier at: GBWideExtent put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:19'! wideBezierFillOf: bezier ^self obj: bezier at: GBWideFill! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:17'! wideBezierFillOf: bezier put: value ^self obj: bezier at: GBWideFill put: value! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar (auto pragmas 12/08) 11/24/1998 22:25'! wideBezierUpdateDataOf: bezier ^objBuffer + bezier + GBWideUpdateData! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:20'! wideBezierWidthOf: line ^self obj: line at: GBWideWidth! ! !BalloonEnginePlugin methodsFor: 'accessing beziers' stamp: 'ar 11/24/1998 22:20'! wideBezierWidthOf: line put: value ^self obj: line at: GBWideWidth put: value! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:09'! wideLineEntryOf: line ^self obj: line at: GLWideEntry! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:10'! wideLineEntryOf: line put: value ^self obj: line at: GLWideEntry put: value! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:10'! wideLineExitOf: line ^self obj: line at: GLWideExit! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:10'! wideLineExitOf: line put: value ^self obj: line at: GLWideExit put: value! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:10'! wideLineExtentOf: line ^self obj: line at: GLWideExtent! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:10'! wideLineExtentOf: line put: value ^self obj: line at: GLWideExtent put: value! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:10'! wideLineFillOf: line ^self obj: line at: GLWideFill! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:11'! wideLineFillOf: line put: value ^self obj: line at: GLWideFill put: value! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:11'! wideLineWidthOf: line ^self obj: line at: GLWideWidth! ! !BalloonEnginePlugin methodsFor: 'accessing lines' stamp: 'ar 11/24/1998 22:11'! wideLineWidthOf: line put: value ^self obj: line at: GLWideWidth put: value! ! BalloonEnginePlugin subclass: #BalloonEngineSimulation instanceVariableNames: 'bbObj workBufferArray' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-InterpreterSimulation'! !BalloonEngineSimulation commentStamp: 'tpr 5/5/2003 11:48' prior: 0! Support for the VM simulator Balloon graphics calls! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 10/28/1998 20:46'! assert: bool bool ifFalse:[^self error:'Assertion failed'].! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 11/9/1998 01:23'! circleCosTable ^CArrayAccessor on: #(1.0 0.98078528040323 0.923879532511287 0.831469612302545 0.7071067811865475 0.555570233019602 0.38268343236509 0.1950903220161286 0.0 -0.1950903220161283 -0.3826834323650896 -0.555570233019602 -0.707106781186547 -0.831469612302545 -0.9238795325112865 -0.98078528040323 -1.0 -0.98078528040323 -0.923879532511287 -0.831469612302545 -0.707106781186548 -0.555570233019602 -0.3826834323650903 -0.1950903220161287 0.0 0.1950903220161282 0.38268343236509 0.555570233019602 0.707106781186547 0.831469612302545 0.9238795325112865 0.98078528040323 1.0 )! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 11/9/1998 01:23'! circleSinTable ^CArrayAccessor on: #(0.0 0.1950903220161282 0.3826834323650897 0.555570233019602 0.707106781186547 0.831469612302545 0.923879532511287 0.98078528040323 1.0 0.98078528040323 0.923879532511287 0.831469612302545 0.7071067811865475 0.555570233019602 0.38268343236509 0.1950903220161286 0.0 -0.1950903220161283 -0.3826834323650896 -0.555570233019602 -0.707106781186547 -0.831469612302545 -0.9238795325112865 -0.98078528040323 -1.0 -0.98078528040323 -0.923879532511287 -0.831469612302545 -0.707106781186548 -0.555570233019602 -0.3826834323650903 -0.1950903220161287 0.0 )! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 11/24/1998 20:50'! colorTransform ^super colorTransform asPluggableAccessor: (Array with:[:obj :index| obj floatAt: index] with:[:obj :index :value| obj floatAt: index put: value])! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'di 7/13/2004 16:42'! copyBitsFrom: x0 to: x1 at: y "Simulate the copyBits primitive" | bb | bbObj isInteger ifTrue: ["Create a proxy object to handle BitBlt calls" bb := BitBltSimulator new. bb initialiseModule. bb setInterpreter: interpreterProxy. (bb loadBitBltFrom: bbObj) ifTrue: [bbObj := bb] ifFalse: [^ self]]. bbObj copyBitsFrom: x0 to: x1 at: y. " interpreterProxy showDisplayBits: bbObj destForm Left: bb affectedLeft Top: bb affectedTop Right: bb affectedRight Bottom: bb affectedBottom. "! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar 5/25/2000 17:58'! debugDrawBezier: line | canvas p1 p2 p3 | self assert:(self isBezier: line). p1 := (self edgeXValueOf: line) @ (self edgeYValueOf: line) // self aaLevelGet. p2 := (self bezierViaXOf: line) @ (self bezierViaYOf: line) // self aaLevelGet. p3 := (self bezierEndXOf: line) @ (self bezierEndYOf: line) // self aaLevelGet. canvas := Display getCanvas. canvas line: p1 to: p2 width: 2 color: Color blue; line: p2 to: p3 width: 2 color: Color blue.! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar 11/1/1998 01:16'! debugDrawEdge: edge self assert: (self isEdge: edge). (self isLine: edge) ifTrue:[^self debugDrawLine: edge]. (self isBezier: edge) ifTrue:[^self debugDrawBezier: edge]. self halt.! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar 5/25/2000 17:58'! debugDrawHLine: yValue | canvas | canvas := Display getCanvas. canvas line: 0 @ (yValue // self aaLevelGet) to: Display extent x @ (yValue // self aaLevelGet) width: 2 color: Color green.! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar 5/25/2000 17:58'! debugDrawLine: line | canvas | self assert: (self isLine: line). canvas := Display getCanvas. canvas line: (self edgeXValueOf: line) @ (self edgeYValueOf: line) // self aaLevelGet to: (self lineEndXOf: line) @ (self lineEndYOf: line) // self aaLevelGet width: 2 color: Color red.! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar 5/25/2000 17:58'! debugDrawLineFrom: pt1 to: pt2 | canvas | canvas := Display getCanvas. canvas line: (pt1 at: 0) @ (pt1 at: 1) // self aaLevelGet to: (pt2 at: 0) @ (pt2 at: 1) // self aaLevelGet width: 1 color: Color red.! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar 5/25/2000 17:58'! debugDrawPt: pt | canvas | canvas := Display getCanvas. canvas fillRectangle:((pt-2) corner: pt+2) color: Color red! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar 5/25/2000 17:58'! debugDrawPtLineFrom: pt1 to: pt2 | canvas | canvas := Display getCanvas. canvas line: pt1 to: pt2 width: 1 color: Color red.! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar (auto pragmas 12/08) 11/25/1998 00:43'! debugPrintObjects | object end | object := 0. end := objUsed. [object < end] whileTrue:[ Transcript cr; nextPut:$#; print: object; space; print: (self objectHeaderOf: object); space. (self isEdge: object) ifTrue:[Transcript nextPutAll:'(edge) ']. (self isFill:object) ifTrue:[Transcript nextPutAll:'(fill) ']. Transcript print: (self objectLengthOf: object); space. Transcript endEntry. object := object + (self objectLengthOf: object). ].! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar 11/1/1998 17:21'! debugPrintPoints: n Transcript cr. n > 0 ifTrue:[ Transcript print: (self point1Get at: 0) @ (self point1Get at: 1); space. ]. n > 1 ifTrue:[ Transcript print: (self point2Get at: 0) @ (self point2Get at: 1); space. ]. n > 2 ifTrue:[ Transcript print: (self point3Get at: 0) @ (self point3Get at: 1); space. ]. n > 3 ifTrue:[ Transcript print: (self point4Get at: 0) @ (self point4Get at: 1); space. ]. Transcript endEntry.! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 10/29/1998 18:44'! dispatchOn: anInteger in: selectorArray "Simulate a case statement via selector table lookup. The given integer must be between 0 and selectorArray size-1, inclusive. For speed, no range test is done, since it is done by the at: operation." self perform: (selectorArray at: (anInteger + 1)).! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 11/24/1998 20:50'! edgeTransform ^super edgeTransform asPluggableAccessor: (Array with:[:obj :index| obj floatAt: index] with:[:obj :index :value| obj floatAt: index put: value])! ! !BalloonEngineSimulation methodsFor: 'initialize' stamp: 'di 7/12/2004 15:54'! initialiseModule super initialiseModule. ^ true! ! !BalloonEngineSimulation methodsFor: 'initialize' stamp: 'tpr 4/2/2004 18:06'! initialize doProfileStats := false. bbPluginName := 'BitBltPlugin'! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 10/29/1998 19:19'! ioMicroMSecs ^Time millisecondClockValue! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 10/28/1998 01:05'! loadBitBltFrom: oop bbObj := oop. ^true! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 11/4/1998 14:05'! loadPointIntAt: index from: intArray "Load the int value from the given index in intArray" ^(index bitAnd: 1) = 0 ifTrue:[(intArray getObject at: (index // 2) + 1) x] ifFalse:[(intArray getObject at: (index // 2) + 1) y]! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'di 7/16/2004 15:07'! loadPointShortAt: index from: intArray "Load the short value from the given index in intArray" | long | long := intArray at: index // 2. ^ ((index bitAnd: 1) = 0 ifTrue:[interpreterProxy halfWordHighInLong32: long] ifFalse:[interpreterProxy halfWordLowInLong32: long]) signedIntFromShort ! ! !BalloonEngineSimulation methodsFor: 'initialize' stamp: 'di 7/15/2004 16:19'! loadWordTransformFrom: transformOop into: destPtr length: n "Load a float array transformation from the given oop" | srcPtr wordDestPtr | true ifTrue: [^ super loadWordTransformFrom: transformOop into: destPtr length: n]. srcPtr := interpreterProxy firstIndexableField: transformOop. wordDestPtr := destPtr as: CArrayAccessor. "Remove float conversion shell" 0 to: n-1 do: [:i | wordDestPtr at: i put: (srcPtr at: i)].! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 10/28/1998 01:05'! makeUnsignedFrom: integer integer < 0 ifTrue:[^(0 - integer - 1) bitInvert32] ifFalse:[^integer]! ! !BalloonEngineSimulation methodsFor: 'initialize' stamp: 'di 7/16/2004 12:06'! primitiveInitializeBuffer "Fix an uninitialized variable (should probably go into the real engine too)" super primitiveInitializeBuffer. self spanEndAAPut: 0.! ! !BalloonEngineSimulation methodsFor: 'initialize' stamp: 'di 7/12/2004 16:15'! primitiveSetBitBltPlugin "Primitive. Set the BitBlt plugin to use." | pluginName | pluginName := interpreterProxy stackValue: 0. "Must be string to work" (interpreterProxy isBytes: pluginName) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy stringOf: pluginName) = bbPluginName ifTrue: [interpreterProxy pop: 1. "Return receiver"] ifFalse: [^interpreterProxy primitiveFail]! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar 11/5/1998 21:15'! printAET | edge | Transcript cr; show:'************* ActiveEdgeTable **************'. 0 to: self aetUsedGet - 1 do:[:i| edge := aetBuffer at: i. Transcript cr; print: i; space; nextPutAll:'edge #';print: edge; space; nextPutAll:'x: '; print: (self edgeXValueOf: edge); space; nextPutAll:'y: '; print: (self edgeYValueOf: edge); space; nextPutAll:'z: '; print: (self edgeZValueOf: edge); space; nextPutAll:'fill0: '; print: (self edgeLeftFillOf: edge); space; nextPutAll:'fill1: '; print: (self edgeRightFillOf: edge); space; nextPutAll:'lines: '; print: (self edgeNumLinesOf: edge); space. (self areEdgeFillsValid: edge) ifFalse:[Transcript nextPutAll:' disabled']. Transcript endEntry. ].! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar 11/5/1998 21:14'! printGET | edge | Transcript cr; show:'************* GlobalEdgeTable **************'. 0 to: self getUsedGet - 1 do:[:i| edge := getBuffer at: i. Transcript cr; print: i; space; nextPutAll:'edge #';print: edge; space; nextPutAll:'x: '; print: (self edgeXValueOf: edge); space; nextPutAll:'y: '; print: (self edgeYValueOf: edge); space; nextPutAll:'z: '; print: (self edgeZValueOf: edge); space; nextPutAll:'fill0: '; print: (self edgeLeftFillOf: edge); space; nextPutAll:'fill1: '; print: (self edgeRightFillOf: edge); space; nextPutAll:'lines: '; print: (self edgeNumLinesOf: edge); space. (self areEdgeFillsValid: edge) ifFalse:[Transcript nextPutAll:' disabled']. Transcript endEntry. ].! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar 10/30/1998 21:57'! quickPrint: curve Transcript nextPut:$(; print: curve start; space; print: curve via; space; print: curve end; nextPut:$).! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar 10/30/1998 22:18'! quickPrintBezier: bezier Transcript cr. Transcript nextPut:$(; print: (self edgeXValueOf: bezier)@(self edgeYValueOf: bezier); space; print: (self bezierViaXOf: bezier)@(self bezierViaYOf: bezier); space; print: (self bezierEndXOf: bezier)@(self bezierEndYOf: bezier); nextPut:$). Transcript endEntry.! ! !BalloonEngineSimulation methodsFor: 'debug support' stamp: 'ar 10/30/1998 22:00'! quickPrintBezier: index first: aBool aBool ifTrue:[Transcript cr]. Transcript nextPut:$(; print: (self bzStartX: index)@(self bzStartY: index); space; print: (self bzViaX: index)@(self bzViaY: index); space; print: (self bzEndX: index)@(self bzEndY: index); nextPut:$). Transcript endEntry.! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 11/25/1998 19:24'! rShiftTable ^CArrayAccessor on: #(0 5 4 0 3 0 0 0 2 0 0 0 0 0 0 0 1).! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'di 7/16/2004 15:11'! shortRunLengthAt: index from: runArray "Load the short value from the given index in intArray" ^ interpreterProxy halfWordHighInLong32: (runArray at: index)! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'di 7/16/2004 15:10'! shortRunValueAt: index from: runArray "Load the short value from the given index in intArray" ^ (interpreterProxy halfWordLowInLong32: (runArray at: index)) signedIntFromShort ! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 10/31/1998 23:07'! showDisplayBits "Do nothing."! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 11/4/1998 19:51'! smallSqrtTable "Return a lookup table for rounded integer square root values from 0 to 31" ^CArrayAccessor on:#(0 1 1 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 )! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'ar 11/25/1998 02:23'! stopBecauseOf: stopReason "Don't stop because of need to flush." stopReason = GErrorNeedFlush ifFalse:[ ^super stopBecauseOf: stopReason. ].! ! !BalloonEngineSimulation methodsFor: 'simulation' stamp: 'di 7/16/2004 12:37'! workBufferPut: wbOop interpreterProxy isInterpreterProxy ifTrue:[^super workBufferPut: wbOop]. workBuffer := ((interpreterProxy firstIndexableField: wbOop) as: BalloonArray) asCArrayAccessor. workBufferArray ifNil: [workBufferArray := Array new: (interpreterProxy slotSizeOf: wbOop)]. workBuffer getObject setSimArray: workBufferArray! ! InterpreterPlugin subclass: #BitBltSimulation instanceVariableNames: 'destForm sourceForm halftoneForm combinationRule destX destY width height sourceX sourceY clipX clipY clipWidth clipHeight sourceWidth sourceHeight sourceDepth sourcePitch sourceBits sourcePPW sourceMSB destWidth destHeight destDepth destPitch destBits destPPW destMSB bitCount skew mask1 mask2 preload nWords destMask hDir vDir sourceIndex sourceDelta destIndex destDelta sx sy dx dy bbW bbH halftoneHeight noSource noHalftone halftoneBase sourceAlpha srcBitShift dstBitShift bitBltOop affectedL affectedR affectedT affectedB opTable maskTable ditherMatrix4x4 ditherThresholds16 ditherValues16 hasSurfaceLock warpSrcShift warpSrcMask warpAlignShift warpAlignMask warpBitShiftTable querySurfaceFn lockSurfaceFn unlockSurfaceFn isWarping cmFlags cmMask cmShiftTable cmMaskTable cmLookupTable cmBitsPerColor dither8Lookup' classVariableNames: 'AllOnes AlphaIndex BBClipHeightIndex BBClipWidthIndex BBClipXIndex BBClipYIndex BBColorMapIndex BBDestFormIndex BBDestXIndex BBDestYIndex BBHalftoneFormIndex BBHeightIndex BBLastIndex BBRuleIndex BBSourceFormIndex BBSourceXIndex BBSourceYIndex BBWarpBase BBWidthIndex BBXTableIndex BinaryPoint BlueIndex ColorMapFixedPart ColorMapIndexedPart ColorMapNewStyle ColorMapPresent CrossedX EndOfRun FixedPt1 FormBitsIndex FormDepthIndex FormHeightIndex FormWidthIndex GreenIndex JitBltHookSize OpTable OpTableSize RedIndex' poolDictionaries: '' category: 'VMMaker-Interpreter'! !BitBltSimulation commentStamp: '' prior: 0! This class implements BitBlt, much as specified in the Blue Book spec. Performance has been enhanced through the use of pointer variables such as sourceIndex and destIndex, and by separating several special cases of the inner loop. Operation has been extended to color, with support for 1, 2, 4, 8, 16, and 32-bit pixel sizes. Conversion between different pixel sizes is facilitated by accepting an optional color map. In addition to the original 16 combination rules, this BitBlt supports 16 fail (for old paint mode) 17 fail (for old mask mode) 18 sourceWord + destinationWord 19 sourceWord - destinationWord 20 rgbAdd: sourceWord with: destinationWord 21 rgbSub: sourceWord with: destinationWord 22 OLDrgbDiff: sourceWord with: destinationWord 23 OLDtallyIntoMap: destinationWord -- old vers doesn't clip to bit boundary 24 alphaBlend: sourceWord with: destinationWord 25 pixPaint: sourceWord with: destinationWord 26 pixMask: sourceWord with: destinationWord 27 rgbMax: sourceWord with: destinationWord 28 rgbMin: sourceWord with: destinationWord 29 rgbMin: sourceWord bitInvert32 with: destinationWord 30 alphaBlendConst: sourceWord with: destinationWord -- alpha passed as an arg 31 alphaPaintConst: sourceWord with: destinationWord -- alpha passed as an arg 32 rgbDiff: sourceWord with: destinationWord 33 tallyIntoMap: destinationWord 34 alphaBlendScaled: sourceWord with: destinationWord This implementation has also been fitted with an experimental "warp drive" that allows abritrary scaling and rotation (and even limited affine deformations) with all BitBlt storage modes supported. To add a new rule to BitBlt... 1. add the new rule method or methods in the category 'combination rules' of BBSim 2. describe it in the class comment of BBSim and in the class comment for BitBlt 3. add refs to initializeRuleTable in proper positions 4. add refs to initBBOpTable, following the pattern ! !BitBltSimulation class methodsFor: 'system simulation' stamp: 'tpr 3/24/2004 13:01'! copyBitsFrom: aBitBlt "Simulate the copyBits primitive" | proxy bb | proxy := InterpreterProxy new. proxy loadStackFrom: thisContext sender home. bb := self simulatorClass new. bb initialiseModule. bb setInterpreter: proxy. proxy success: (bb loadBitBltFrom: aBitBlt). bb copyBits. proxy failed ifFalse:[ proxy showDisplayBits: aBitBlt destForm Left: bb affectedLeft Top: bb affectedTop Right: bb affectedRight Bottom: bb affectedBottom]. ^proxy stackValue: 0! ! !BitBltSimulation class methodsFor: 'translation' stamp: 'tpr 12/29/2005 15:55'! declareCVarsIn: aCCodeGenerator aCCodeGenerator var: 'opTable' declareC: 'void *opTable[' , OpTableSize printString , ']'. aCCodeGenerator var: 'maskTable' declareC:'int maskTable[33] = { 0, 1, 3, 0, 15, 31, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 65535, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1 }'. aCCodeGenerator var: 'ditherMatrix4x4' declareC:'const int ditherMatrix4x4[16] = { 0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5 }'. aCCodeGenerator var: 'ditherThresholds16' declareC:'const int ditherThresholds16[8] = { 0, 2, 4, 6, 8, 12, 14, 16 }'. aCCodeGenerator var: 'ditherValues16' declareC:'const int ditherValues16[32] = { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }'. aCCodeGenerator var: 'warpBitShiftTable' declareC:'int warpBitShiftTable[32]'. aCCodeGenerator var:'cmShiftTable' type:'int *'. aCCodeGenerator var:'cmMaskTable' type:'unsigned int *'. aCCodeGenerator var:'cmLookupTable' type:'unsigned int *'. aCCodeGenerator var: 'dither8Lookup' declareC:' unsigned char dither8Lookup[4096]'. aCCodeGenerator var: 'querySurfaceFn' type: 'void *'. aCCodeGenerator var: 'lockSurfaceFn' type: 'void *'. aCCodeGenerator var: 'unlockSurfaceFn' type: 'void *'! ! !BitBltSimulation class methodsFor: 'initialization' stamp: 'ar 5/4/2001 14:43'! initialize "BitBltSimulation initialize" self initializeRuleTable. "Mask constants" AllOnes := 16rFFFFFFFF. BinaryPoint := 14. FixedPt1 := 1 << BinaryPoint. "Value of 1.0 in Warp's fixed-point representation" "Indices into stopConditions for scanning" EndOfRun := 257. CrossedX := 258. "Form fields" FormBitsIndex := 0. FormWidthIndex := 1. FormHeightIndex := 2. FormDepthIndex := 3. "BitBlt fields" BBDestFormIndex := 0. BBSourceFormIndex := 1. BBHalftoneFormIndex := 2. BBRuleIndex := 3. BBDestXIndex := 4. BBDestYIndex := 5. BBWidthIndex := 6. BBHeightIndex := 7. BBSourceXIndex := 8. BBSourceYIndex := 9. BBClipXIndex := 10. BBClipYIndex := 11. BBClipWidthIndex := 12. BBClipHeightIndex := 13. BBColorMapIndex := 14. BBWarpBase := 15. BBLastIndex := 15. BBXTableIndex := 16. "RGBA indexes" RedIndex := 0. GreenIndex := 1. BlueIndex := 2. AlphaIndex := 3. "Color map flags" ColorMapPresent := 1. "do we have one?" ColorMapFixedPart := 2. "does it have a fixed part?" ColorMapIndexedPart := 4. "does it have an indexed part?" ColorMapNewStyle := 8. "new style color map"! ! !BitBltSimulation class methodsFor: 'initialization' stamp: 'ar 8/21/2002 20:59'! initializeRuleTable "BitBltSimulation initializeRuleTable" "**WARNING** You MUST change initBBOpTable if you change this" OpTable := #( "0" clearWord:with: "1" bitAnd:with: "2" bitAndInvert:with: "3" sourceWord:with: "4" bitInvertAnd:with: "5" destinationWord:with: "6" bitXor:with: "7" bitOr:with: "8" bitInvertAndInvert:with: "9" bitInvertXor:with: "10" bitInvertDestination:with: "11" bitOrInvert:with: "12" bitInvertSource:with: "13" bitInvertOr:with: "14" bitInvertOrInvert:with: "15" destinationWord:with: "16" destinationWord:with: "unused - was old paint" "17" destinationWord:with: "unused - was old mask" "18" addWord:with: "19" subWord:with: "20" rgbAdd:with: "21" rgbSub:with: "22" OLDrgbDiff:with: "23" OLDtallyIntoMap:with: "24" alphaBlend:with: "25" pixPaint:with: "26" pixMask:with: "27" rgbMax:with: "28" rgbMin:with: "29" rgbMinInvert:with: "30" alphaBlendConst:with: "31" alphaPaintConst:with: "32" rgbDiff:with: "33" tallyIntoMap:with: "34" alphaBlendScaled:with: "35" alphaBlendScaled:with: "unused here - only used by FXBlt" "36" alphaBlendScaled:with: "unused here - only used by FXBlt" "37" rgbMul:with: "38" pixSwap:with: "39" pixClear:with: "40" fixAlpha:with: ). OpTableSize := OpTable size + 1. "0-origin indexing" ! ! !BitBltSimulation class methodsFor: 'translation' stamp: 'ar 2/19/2000 20:55'! moduleName ^'BitBltPlugin'! ! !BitBltSimulation class methodsFor: 'translation' stamp: 'jm 5/12/1999 12:02'! opTable ^ OpTable ! ! !BitBltSimulation class methodsFor: 'translation' stamp: 'tpr 2/29/2004 20:05'! requiredMethodNames ^self opTable asSet! ! !BitBltSimulation class methodsFor: 'system simulation' stamp: 'ar 10/27/1999 14:06'! simulatorClass ^BitBltSimulator! ! !BitBltSimulation class methodsFor: 'testing' stamp: 'tpr 3/24/2004 13:03'! test2 "BitBltSimulation test2" | f | Display fillWhite: (0 @ 0 extent: 300 @ 140). 1 to: 12 do: [:i | f := (Form extent: i @ 5) fillBlack. 0 to: 20 do: [:x | f displayOn: Display at: x * 13 @ (i * 10)]]! ! !BitBltSimulation class methodsFor: 'testing' stamp: 'tpr 3/24/2004 13:03'! timingTest: extent "BitBltSimulation timingTest: 640@480" | f f2 map | f := Form extent: extent depth: 8. f2 := Form extent: extent depth: 8. map := Bitmap new: 1 << f2 depth. ^ Array with: (Time millisecondsToRun: [100 timesRepeat: [f fillWithColor: Color white]]) with: (Time millisecondsToRun: [100 timesRepeat: [f copy: f boundingBox from: 0 @ 0 in: f2 rule: Form over]]) with: (Time millisecondsToRun: [100 timesRepeat: [f copyBits: f boundingBox from: f2 at: 0 @ 0 colorMap: map]])! ! !BitBltSimulation class methodsFor: 'system simulation' stamp: 'tpr 3/24/2004 13:02'! warpBitsFrom: aBitBlt "Simulate the warpBits primitive" | proxy bb | proxy := InterpreterProxy new. proxy loadStackFrom: thisContext sender home. bb := self simulatorClass new. bb initialiseModule. bb setInterpreter: proxy. proxy success: (bb loadWarpBltFrom: aBitBlt). bb warpBits. proxy failed ifFalse:[ proxy showDisplayBits: aBitBlt destForm Left: bb affectedLeft Top: bb affectedTop Right: bb affectedRight Bottom: bb affectedBottom]. ^proxy stackValue: 0! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ar (auto pragmas 12/08) 4/18/2001 20:36'! OLDrgbDiff: sourceWord with: destinationWord "Subract the pixels in the source and destination, color by color, and return the sum of the absolute value of all the differences. For non-rgb, XOR the two and return the number of differing pixels. Note that the region is not clipped to bit boundaries, but only to the nearest (enclosing) word. This is because copyLoop does not do pre-merge masking. For accurate results, you must subtract the values obtained from the left and right fringes." | diff pixMask | destDepth < 16 ifTrue: ["Just xor and count differing bits if not RGB" diff := sourceWord bitXor: destinationWord. pixMask := maskTable at: destDepth. [diff = 0] whileFalse: [(diff bitAnd: pixMask) ~= 0 ifTrue: [bitCount := bitCount + 1]. diff := diff >> destDepth]. ^ destinationWord "for no effect"]. destDepth = 16 ifTrue: [diff := (self partitionedSub: sourceWord from: destinationWord nBits: 5 nPartitions: 3). bitCount := bitCount + (diff bitAnd: 16r1F) + (diff>>5 bitAnd: 16r1F) + (diff>>10 bitAnd: 16r1F). diff := (self partitionedSub: sourceWord>>16 from: destinationWord>>16 nBits: 5 nPartitions: 3). bitCount := bitCount + (diff bitAnd: 16r1F) + (diff>>5 bitAnd: 16r1F) + (diff>>10 bitAnd: 16r1F)] ifFalse: [diff := (self partitionedSub: sourceWord from: destinationWord nBits: 8 nPartitions: 3). bitCount := bitCount + (diff bitAnd: 16rFF) + (diff>>8 bitAnd: 16rFF) + (diff>>16 bitAnd: 16rFF)]. ^ destinationWord "For no effect on dest"! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ar 5/17/2001 15:15'! OLDtallyIntoMap: sourceWord with: destinationWord "Tally pixels into the color map. Note that the source should be specified = destination, in order for the proper color map checks to be performed at setup. Note that the region is not clipped to bit boundaries, but only to the nearest (enclosing) word. This is because copyLoop does not do pre-merge masking. For accurate results, you must subtract the values obtained from the left and right fringes." | mapIndex pixMask shiftWord | (cmFlags bitAnd: (ColorMapPresent bitOr: ColorMapIndexedPart)) = (ColorMapPresent bitOr: ColorMapIndexedPart) ifFalse: [^ destinationWord "no op"]. destDepth < 16 ifTrue: ["loop through all packed pixels." pixMask := (maskTable at: destDepth) bitAnd: cmMask. shiftWord := destinationWord. 1 to: destPPW do: [:i | mapIndex := shiftWord bitAnd: pixMask. self tallyMapAt: mapIndex put: (self tallyMapAt: mapIndex) + 1. shiftWord := shiftWord >> destDepth]. ^ destinationWord]. destDepth = 16 ifTrue: ["Two pixels Tally the right half..." mapIndex := self rgbMap: (destinationWord bitAnd: 16rFFFF) from: 5 to: cmBitsPerColor. self tallyMapAt: mapIndex put: (self tallyMapAt: mapIndex) + 1. "... and then left half" mapIndex := self rgbMap: destinationWord>>16 from: 5 to: cmBitsPerColor. self tallyMapAt: mapIndex put: (self tallyMapAt: mapIndex) + 1] ifFalse: ["Just one pixel." mapIndex := self rgbMap: destinationWord from: 8 to: cmBitsPerColor. self tallyMapAt: mapIndex put: (self tallyMapAt: mapIndex) + 1]. ^ destinationWord "For no effect on dest"! ! !BitBltSimulation methodsFor: 'combination rules'! addWord: sourceWord with: destinationWord ^sourceWord + destinationWord! ! !BitBltSimulation methodsFor: 'accessing'! affectedBottom ^affectedB! ! !BitBltSimulation methodsFor: 'accessing'! affectedLeft ^affectedL! ! !BitBltSimulation methodsFor: 'accessing'! affectedRight ^affectedR! ! !BitBltSimulation methodsFor: 'accessing'! affectedTop ^affectedT! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ar (auto pragmas 12/08) 4/6/2003 18:52'! alphaBlend: sourceWord with: destinationWord "Blend sourceWord with destinationWord, assuming both are 32-bit pixels. The source is assumed to have 255*alpha in the high 8 bits of each pixel, while the high 8 bits of the destinationWord will be ignored. The blend produced is alpha*source + (1-alpha)*dest, with the computation being performed independently on each color component. The high byte of the result will be 0." | alpha unAlpha colorMask result blend shift | alpha := sourceWord >> 24. "High 8 bits of source pixel" alpha = 0 ifTrue: [ ^ destinationWord ]. alpha = 255 ifTrue: [ ^ sourceWord ]. unAlpha := 255 - alpha. colorMask := 16rFF. result := 0. "red" shift := 0. blend := ((sourceWord >> shift bitAnd: colorMask) * alpha) + ((destinationWord>>shift bitAnd: colorMask) * unAlpha) + 254 // 255 bitAnd: colorMask. result := result bitOr: blend << shift. "green" shift := 8. blend := ((sourceWord >> shift bitAnd: colorMask) * alpha) + ((destinationWord>>shift bitAnd: colorMask) * unAlpha) + 254 // 255 bitAnd: colorMask. result := result bitOr: blend << shift. "blue" shift := 16. blend := ((sourceWord >> shift bitAnd: colorMask) * alpha) + ((destinationWord>>shift bitAnd: colorMask) * unAlpha) + 254 // 255 bitAnd: colorMask. result := result bitOr: blend << shift. "alpha (pre-multiplied)" shift := 24. blend := (alpha * 255) + ((destinationWord>>shift bitAnd: colorMask) * unAlpha) + 254 // 255 bitAnd: colorMask. result := result bitOr: blend << shift. ^ result ! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'di 6/29/1998 19:55'! alphaBlendConst: sourceWord with: destinationWord ^ self alphaBlendConst: sourceWord with: destinationWord paintMode: false! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ar (auto pragmas 12/08) 1/24/2002 17:31'! alphaBlendConst: sourceWord with: destinationWord paintMode: paintMode "Blend sourceWord with destinationWord using a constant alpha. Alpha is encoded as 0 meaning 0.0, and 255 meaning 1.0. The blend produced is alpha*source + (1.0-alpha)*dest, with the computation being performed independently on each color component. This function could eventually blend into any depth destination, using the same color averaging and mapping as warpBlt. paintMode = true means do nothing if the source pixel value is zero." "This first implementation works with dest depths of 16 and 32 bits only. Normal color mapping will allow sources of lower depths in this case, and results can be mapped directly by truncation, so no extra color maps are needed. To allow storing into any depth will require subsequent addition of two other colormaps, as is the case with WarpBlt." | pixMask destShifted sourceShifted destPixVal rgbMask sourcePixVal unAlpha result pixBlend shift blend maskShifted bitsPerColor | destDepth < 16 ifTrue: [^ destinationWord "no-op"]. unAlpha := 255 - sourceAlpha. pixMask := maskTable at: destDepth. destDepth = 16 ifTrue: [bitsPerColor := 5] ifFalse:[bitsPerColor := 8]. rgbMask := (1<>shift bitAnd: rgbMask) * sourceAlpha) + ((destinationWord>>shift bitAnd: rgbMask) * unAlpha)) + 254 // 255 bitAnd: rgbMask. result := result bitOr: blend<>shift bitAnd: rgbMask) * sourceAlpha) + ((destPixVal>>shift bitAnd: rgbMask) * unAlpha)) + 254 // 255 bitAnd: rgbMask. pixBlend := pixBlend bitOr: blend<> destDepth. sourceShifted := sourceShifted >> destDepth. destShifted := destShifted >> destDepth]. ]. ^ result ! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ar (auto pragmas 12/08) 11/27/1998 23:56'! alphaBlendScaled: sourceWord with: destinationWord "Blend sourceWord with destinationWord using the alpha value from sourceWord. Alpha is encoded as 0 meaning 0.0, and 255 meaning 1.0. In contrast to alphaBlend:with: the color produced is srcColor + (1-srcAlpha) * dstColor e.g., it is assumed that the source color is already scaled." | unAlpha dstMask srcMask b g r a | "Do NOT inline this into optimized loops" unAlpha := 255 - (sourceWord >> 24). "High 8 bits of source pixel" dstMask := destinationWord. srcMask := sourceWord. b := (dstMask bitAnd: 255) * unAlpha >> 8 + (srcMask bitAnd: 255). b > 255 ifTrue:[b := 255]. dstMask := dstMask >> 8. srcMask := srcMask >> 8. g := (dstMask bitAnd: 255) * unAlpha >> 8 + (srcMask bitAnd: 255). g > 255 ifTrue:[g := 255]. dstMask := dstMask >> 8. srcMask := srcMask >> 8. r := (dstMask bitAnd: 255) * unAlpha >> 8 + (srcMask bitAnd: 255). r > 255 ifTrue:[r := 255]. dstMask := dstMask >> 8. srcMask := srcMask >> 8. a := (dstMask bitAnd: 255) * unAlpha >> 8 + (srcMask bitAnd: 255). a > 255 ifTrue:[a := 255]. ^(((((a << 8) + r) << 8) + g) << 8) + b! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'di 6/29/1998 19:56'! alphaPaintConst: sourceWord with: destinationWord sourceWord = 0 ifTrue: [^ destinationWord "opt for all-transparent source"]. ^ self alphaBlendConst: sourceWord with: destinationWord paintMode: true! ! !BitBltSimulation methodsFor: 'inner loop' stamp: 'JMM (auto pragmas 12/08) 7/3/2003 23:55'! alphaSourceBlendBits16 "This version assumes combinationRule = 34 sourcePixSize = 32 destPixSize = 16 sourceForm ~= destForm. " | srcIndex dstIndex sourceWord srcAlpha destWord deltaX deltaY srcY dstY dstMask srcShift ditherBase ditherIndex ditherThreshold | "This particular method should be optimized in itself" deltaY := bbH + 1. "So we can pre-decrement" srcY := sy. dstY := dy. srcShift := (dx bitAnd: 1) * 16. destMSB ifTrue:[srcShift := 16 - srcShift]. mask1 := 16rFFFF << (16 - srcShift). "This is the outer loop" [(deltaY := deltaY - 1) ~= 0] whileTrue:[ srcIndex := sourceBits + (srcY * sourcePitch) + (sx * 4). dstIndex := destBits + (dstY * destPitch) + (dx // 2 * 4). ditherBase := (dstY bitAnd: 3) * 4. ditherIndex := (sx bitAnd: 3) - 1. "For pre-increment" deltaX := bbW + 1. "So we can pre-decrement" dstMask := mask1. dstMask = 16rFFFF ifTrue:[srcShift := 16] ifFalse:[srcShift := 0]. "This is the inner loop" [(deltaX := deltaX - 1) ~= 0] whileTrue:[ ditherThreshold := ditherMatrix4x4 at: ditherBase + (ditherIndex := ditherIndex + 1 bitAnd: 3). sourceWord := self srcLongAt: srcIndex. srcAlpha := sourceWord >> 24. srcAlpha = 255 ifTrue:[ "Dither from 32 to 16 bit" sourceWord := self dither32To16: sourceWord threshold: ditherThreshold. sourceWord = 0 ifTrue:[sourceWord := 1 << srcShift] ifFalse: [sourceWord := sourceWord << srcShift]. "Store masked value" self dstLongAt: dstIndex put: sourceWord mask: dstMask. ] ifFalse:[ "srcAlpha ~= 255" srcAlpha = 0 ifFalse:[ "0 < srcAlpha < 255" "If we have to mix colors then just copy a single word" destWord := self dstLongAt: dstIndex. destWord := destWord bitAnd: dstMask bitInvert32. destWord := destWord >> srcShift. "Expand from 16 to 32 bit by adding zero bits" destWord := (((destWord bitAnd: 16r7C00) bitShift: 9) bitOr: ((destWord bitAnd: 16r3E0) bitShift: 6)) bitOr: (((destWord bitAnd: 16r1F) bitShift: 3) bitOr: 16rFF000000). "Mix colors" sourceWord := self alphaBlendScaled: sourceWord with: destWord. "And dither" sourceWord := self dither32To16: sourceWord threshold: ditherThreshold. sourceWord = 0 ifTrue:[sourceWord := 1 << srcShift] ifFalse:[sourceWord := sourceWord << srcShift]. "Store back" self dstLongAt: dstIndex put: sourceWord mask: dstMask. ]. ]. srcIndex := srcIndex + 4. destMSB ifTrue:[srcShift = 0 ifTrue:[dstIndex := dstIndex + 4]] ifFalse:[srcShift = 0 ifFalse:[dstIndex := dstIndex + 4]]. srcShift := srcShift bitXor: 16. "Toggle between 0 and 16" dstMask := dstMask bitInvert32. "Mask other half word" ]. srcY := srcY + 1. dstY := dstY + 1. ].! ! !BitBltSimulation methodsFor: 'inner loop' stamp: 'ikp (auto pragmas 12/08) 8/4/2004 18:03'! alphaSourceBlendBits32 "This version assumes combinationRule = 34 sourcePixSize = destPixSize = 32 sourceForm ~= destForm. Note: The inner loop has been optimized for dealing with the special cases of srcAlpha = 0.0 and srcAlpha = 1.0 " | srcIndex dstIndex sourceWord srcAlpha destWord deltaX deltaY srcY dstY | "This particular method should be optimized in itself" "Give the compile a couple of hints" "The following should be declared as pointers so the compiler will notice that they're used for accessing memory locations (good to know on an Intel architecture) but then the increments would be different between ST code and C code so must hope the compiler notices what happens (MS Visual C does)" deltaY := bbH + 1. "So we can pre-decrement" srcY := sy. dstY := dy. "This is the outer loop" [(deltaY := deltaY - 1) ~= 0] whileTrue:[ srcIndex := sourceBits + (srcY * sourcePitch) + (sx * 4). dstIndex := destBits + (dstY * destPitch) + (dx * 4). deltaX := bbW + 1. "So we can pre-decrement" "This is the inner loop" [(deltaX := deltaX - 1) ~= 0] whileTrue:[ sourceWord := self srcLongAt: srcIndex. srcAlpha := sourceWord >> 24. srcAlpha = 255 ifTrue:[ self dstLongAt: dstIndex put: sourceWord. srcIndex := srcIndex + 4. dstIndex := dstIndex + 4. "Now copy as many words as possible with alpha = 255" [(deltaX := deltaX - 1) ~= 0 and:[ (sourceWord := self srcLongAt: srcIndex) >> 24 = 255]] whileTrue:[ self dstLongAt: dstIndex put: sourceWord. srcIndex := srcIndex + 4. dstIndex := dstIndex + 4. ]. "Adjust deltaX" deltaX := deltaX + 1. ] ifFalse:[ "srcAlpha ~= 255" srcAlpha = 0 ifTrue:[ srcIndex := srcIndex + 4. dstIndex := dstIndex + 4. "Now skip as many words as possible," [(deltaX := deltaX - 1) ~= 0 and:[ (sourceWord := self srcLongAt: srcIndex) >> 24 = 0]] whileTrue:[ srcIndex := srcIndex + 4. dstIndex := dstIndex + 4. ]. "Adjust deltaX" deltaX := deltaX + 1. ] ifFalse:[ "0 < srcAlpha < 255" "If we have to mix colors then just copy a single word" destWord := self dstLongAt: dstIndex. destWord := self alphaBlendScaled: sourceWord with: destWord. self dstLongAt: dstIndex put: destWord. srcIndex := srcIndex + 4. dstIndex := dstIndex + 4. ]. ]. ]. srcY := srcY + 1. dstY := dstY + 1. ].! ! !BitBltSimulation methodsFor: 'inner loop' stamp: 'tpr (auto pragmas dtl 2010-09-26) 12/29/2005 15:52'! alphaSourceBlendBits8 "This version assumes combinationRule = 34 sourcePixSize = 32 destPixSize = 8 sourceForm ~= destForm. Note: This is not real blending since we don't have the source colors available. " | srcIndex dstIndex sourceWord srcAlpha destWord deltaX deltaY srcY dstY dstMask srcShift adjust mappingTable mapperFlags | mappingTable := self default8To32Table. mapperFlags := cmFlags bitAnd: ColorMapNewStyle bitInvert32. deltaY := bbH + 1. "So we can pre-decrement" srcY := sy. dstY := dy. mask1 := ((dx bitAnd: 3) * 8). destMSB ifTrue:[mask1 := 24 - mask1]. mask2 := AllOnes bitXor:(16rFF << mask1). (dx bitAnd: 1) = 0 ifTrue:[adjust := 0] ifFalse:[adjust := 16r1F1F1F1F]. (dy bitAnd: 1) = 0 ifTrue:[adjust := adjust bitXor: 16r1F1F1F1F]. "This is the outer loop" [(deltaY := deltaY - 1) ~= 0] whileTrue:[ adjust := adjust bitXor: 16r1F1F1F1F. srcIndex := sourceBits + (srcY * sourcePitch) + (sx * 4). dstIndex := destBits + (dstY * destPitch) + (dx // 4 * 4). deltaX := bbW + 1. "So we can pre-decrement" srcShift := mask1. dstMask := mask2. "This is the inner loop" [(deltaX := deltaX - 1) ~= 0] whileTrue:[ sourceWord := ((self srcLongAt: srcIndex) bitAnd: (adjust bitInvert32)) + adjust. srcAlpha := sourceWord >> 24. srcAlpha > 31 ifTrue:["Everything below 31 is transparent" srcAlpha < 224 ifTrue:["Everything above 224 is opaque" destWord := self dstLongAt: dstIndex. destWord := destWord bitAnd: dstMask bitInvert32. destWord := destWord >> srcShift. destWord := mappingTable at: destWord. sourceWord := self alphaBlendScaled: sourceWord with: destWord. ]. sourceWord := self mapPixel: sourceWord flags: mapperFlags. sourceWord := sourceWord << srcShift. "Store back" self dstLongAt: dstIndex put: sourceWord mask: dstMask. ]. srcIndex := srcIndex + 4. destMSB ifTrue:[ srcShift = 0 ifTrue:[dstIndex := dstIndex + 4. srcShift := 24. dstMask := 16r00FFFFFF] ifFalse:[srcShift := srcShift - 8. dstMask := (dstMask >> 8) bitOr: 16rFF000000]. ] ifFalse:[ srcShift = 32 ifTrue:[dstIndex := dstIndex + 4. srcShift := 0. dstMask := 16rFFFFFF00] ifFalse:[srcShift := srcShift + 8. dstMask := dstMask << 8 bitOr: 255]. ]. adjust := adjust bitXor: 16r1F1F1F1F. ]. srcY := srcY + 1. dstY := dstY + 1. ].! ! !BitBltSimulation methodsFor: 'combination rules'! bitAnd: sourceWord with: destinationWord ^sourceWord bitAnd: destinationWord! ! !BitBltSimulation methodsFor: 'combination rules'! bitAndInvert: sourceWord with: destinationWord ^sourceWord bitAnd: destinationWord bitInvert32! ! !BitBltSimulation methodsFor: 'combination rules'! bitInvertAnd: sourceWord with: destinationWord ^sourceWord bitInvert32 bitAnd: destinationWord! ! !BitBltSimulation methodsFor: 'combination rules'! bitInvertAndInvert: sourceWord with: destinationWord ^sourceWord bitInvert32 bitAnd: destinationWord bitInvert32! ! !BitBltSimulation methodsFor: 'combination rules'! bitInvertDestination: sourceWord with: destinationWord ^destinationWord bitInvert32! ! !BitBltSimulation methodsFor: 'combination rules'! bitInvertOr: sourceWord with: destinationWord ^sourceWord bitInvert32 bitOr: destinationWord! ! !BitBltSimulation methodsFor: 'combination rules'! bitInvertOrInvert: sourceWord with: destinationWord ^sourceWord bitInvert32 bitOr: destinationWord bitInvert32! ! !BitBltSimulation methodsFor: 'combination rules'! bitInvertSource: sourceWord with: destinationWord ^sourceWord bitInvert32! ! !BitBltSimulation methodsFor: 'combination rules'! bitInvertXor: sourceWord with: destinationWord ^sourceWord bitInvert32 bitXor: destinationWord! ! !BitBltSimulation methodsFor: 'combination rules'! bitOr: sourceWord with: destinationWord ^sourceWord bitOr: destinationWord! ! !BitBltSimulation methodsFor: 'combination rules'! bitOrInvert: sourceWord with: destinationWord ^sourceWord bitOr: destinationWord bitInvert32! ! !BitBltSimulation methodsFor: 'combination rules'! bitXor: sourceWord with: destinationWord ^sourceWord bitXor: destinationWord! ! !BitBltSimulation methodsFor: 'setup' stamp: 'ar (auto pragmas 12/08) 4/18/2001 20:39'! checkSourceOverlap "check for possible overlap of source and destination" "ar 10/19/1999: This method requires surfaces to be locked." | t | (sourceForm = destForm and: [dy >= sy]) ifTrue: [dy > sy ifTrue: ["have to start at bottom" vDir := -1. sy := sy + bbH - 1. dy := dy + bbH - 1] ifFalse: [(dy = sy) & (dx > sx) ifTrue: ["y's are equal, but x's are backward" hDir := -1. sx := sx + bbW - 1. "start at right" dx := dx + bbW - 1. "and fix up masks" nWords > 1 ifTrue: [t := mask1. mask1 := mask2. mask2 := t]]]. "Dest inits may be affected by this change" destIndex := destBits + (dy * destPitch) + ((dx // destPPW) *4). destDelta := (destPitch * vDir) - (4 * (nWords * hDir))]! ! !BitBltSimulation methodsFor: 'combination rules'! clearWord: source with: destination ^ 0! ! !BitBltSimulation methodsFor: 'setup' stamp: 'ar 4/18/2001 21:15'! clipRange "clip and adjust source origin and extent appropriately" "first in x" destX >= clipX ifTrue: [sx := sourceX. dx := destX. bbW := width] ifFalse: [sx := sourceX + (clipX - destX). bbW := width - (clipX - destX). dx := clipX]. (dx + bbW) > (clipX + clipWidth) ifTrue: [bbW := bbW - ((dx + bbW) - (clipX + clipWidth))]. "then in y" destY >= clipY ifTrue: [sy := sourceY. dy := destY. bbH := height] ifFalse: [sy := sourceY + clipY - destY. bbH := height - (clipY - destY). dy := clipY]. (dy + bbH) > (clipY + clipHeight) ifTrue: [bbH := bbH - ((dy + bbH) - (clipY + clipHeight))]. noSource ifTrue: [^ nil]. sx < 0 ifTrue: [dx := dx - sx. bbW := bbW + sx. sx := 0]. sx + bbW > sourceWidth ifTrue: [bbW := bbW - (sx + bbW - sourceWidth)]. sy < 0 ifTrue: [dy := dy - sy. bbH := bbH + sy. sy := 0]. sy + bbH > sourceHeight ifTrue: [bbH := bbH - (sy + bbH - sourceHeight)]! ! !BitBltSimulation methodsFor: 'setup' stamp: 'ar (auto pragmas 12/08) 4/24/2001 21:19'! copyBits "This function is exported for the Balloon engine" self clipRange. (bbW <= 0 or: [bbH <= 0]) ifTrue: ["zero width or height; noop" affectedL := affectedR := affectedT := affectedB := 0. ^ nil]. "Lock the surfaces" self lockSurfaces ifFalse:[^interpreterProxy primitiveFail]. self copyBitsLockedAndClipped. self unlockSurfaces.! ! !BitBltSimulation methodsFor: 'setup' stamp: 'ar (auto pragmas 12/08) 2/20/2000 19:42'! copyBitsFrom: startX to: stopX at: yValue "Support for the balloon engine." destX := startX. destY := yValue. sourceX := startX. width := (stopX - startX). self copyBits. self showDisplayBits.! ! !BitBltSimulation methodsFor: 'setup' stamp: 'ar (auto pragmas 12/08) 2/20/2001 21:11'! copyBitsLockedAndClipped "Perform the actual copyBits operation. Assume: Surfaces have been locked and clipping was performed." | done | "Try a shortcut for stuff that should be run as quickly as possible" done := self tryCopyingBitsQuickly. done ifTrue:[^nil]. (combinationRule = 30) | (combinationRule = 31) ifTrue: ["Check and fetch source alpha parameter for alpha blend" interpreterProxy methodArgumentCount = 1 ifTrue: [sourceAlpha := interpreterProxy stackIntegerValue: 0. (interpreterProxy failed not and: [(sourceAlpha >= 0) & (sourceAlpha <= 255)]) ifFalse: [^ interpreterProxy primitiveFail]] ifFalse: [^ interpreterProxy primitiveFail]]. bitCount := 0. "Choose and perform the actual copy loop." self performCopyLoop. (combinationRule = 22) | (combinationRule = 32) ifTrue: ["zero width and height; return the count" affectedL := affectedR := affectedT := affectedB := 0]. hDir > 0 ifTrue: [affectedL := dx. affectedR := dx + bbW] ifFalse: [affectedL := dx - bbW + 1. affectedR := dx + 1]. vDir > 0 ifTrue: [affectedT := dy. affectedB := dy + bbH] ifFalse: [affectedT := dy - bbH + 1. affectedB := dy + 1]! ! !BitBltSimulation methodsFor: 'inner loop' stamp: 'ikp (auto pragmas 12/08) 6/11/2004 16:27'! copyLoop | prevWord thisWord skewWord halftoneWord mergeWord hInc y unskew skewMask notSkewMask mergeFnwith destWord | "This version of the inner loop assumes noSource = false." mergeFnwith := self cCoerce: (opTable at: combinationRule+1) to: 'sqInt (*)(sqInt, sqInt)'. mergeFnwith. "null ref for compiler" hInc := hDir*4. "Byte delta" "degenerate skew fixed for Sparc. 10/20/96 ikp" skew == -32 ifTrue: [skew := unskew := skewMask := 0] ifFalse: [skew < 0 ifTrue: [unskew := skew+32. skewMask := AllOnes << (0-skew)] ifFalse: [skew = 0 ifTrue: [unskew := 0. skewMask := AllOnes] ifFalse: [unskew := skew-32. skewMask := AllOnes >> skew]]]. notSkewMask := skewMask bitInvert32. noHalftone ifTrue: [halftoneWord := AllOnes. halftoneHeight := 0] ifFalse: [halftoneWord := self halftoneAt: 0]. y := dy. 1 to: bbH do: "here is the vertical loop" [ :i | halftoneHeight > 1 ifTrue: "Otherwise, its always the same" [halftoneWord := self halftoneAt: y. y := y + vDir]. preload ifTrue: ["load the 64-bit shifter" prevWord := self srcLongAt: sourceIndex. sourceIndex := sourceIndex + hInc] ifFalse: [prevWord := 0]. "Note: the horizontal loop has been expanded into three parts for speed:" "This first section requires masking of the destination store..." destMask := mask1. thisWord := self srcLongAt: sourceIndex. "pick up next word" sourceIndex := sourceIndex + hInc. skewWord := ((prevWord bitAnd: notSkewMask) bitShift: unskew) bitOr: "32-bit rotate" ((thisWord bitAnd: skewMask) bitShift: skew). prevWord := thisWord. destWord := self dstLongAt: destIndex. mergeWord := self mergeFn: (skewWord bitAnd: halftoneWord) with: destWord. destWord := (destMask bitAnd: mergeWord) bitOr: (destWord bitAnd: destMask bitInvert32). self dstLongAt: destIndex put: destWord. destIndex := destIndex + hInc. "This central horizontal loop requires no store masking" destMask := AllOnes. combinationRule = 3 ifTrue: [(skew = 0) & (halftoneWord = AllOnes) ifTrue: ["Very special inner loop for STORE mode with no skew -- just move words" hDir = -1 ifTrue: ["Woeful patch: revert to older code for hDir = -1" 2 to: nWords-1 do: [ :word | thisWord := self srcLongAt: sourceIndex. sourceIndex := sourceIndex + hInc. self dstLongAt: destIndex put: thisWord. destIndex := destIndex + hInc]] ifFalse: [2 to: nWords-1 do: [ :word | "Note loop starts with prevWord loaded (due to preload)" self dstLongAt: destIndex put: prevWord. destIndex := destIndex + hInc. prevWord := self srcLongAt: sourceIndex. sourceIndex := sourceIndex + hInc]]] ifFalse: ["Special inner loop for STORE mode -- no need to call merge" 2 to: nWords-1 do: [ :word | thisWord := self srcLongAt: sourceIndex. sourceIndex := sourceIndex + hInc. skewWord := ((prevWord bitAnd: notSkewMask) bitShift: unskew) bitOr: "32-bit rotate" ((thisWord bitAnd: skewMask) bitShift: skew). prevWord := thisWord. self dstLongAt: destIndex put: (skewWord bitAnd: halftoneWord). destIndex := destIndex + hInc]] ] ifFalse: [2 to: nWords-1 do: "Normal inner loop does merge:" [ :word | thisWord := self srcLongAt: sourceIndex. "pick up next word" sourceIndex := sourceIndex + hInc. skewWord := ((prevWord bitAnd: notSkewMask) bitShift: unskew) bitOr: "32-bit rotate" ((thisWord bitAnd: skewMask) bitShift: skew). prevWord := thisWord. mergeWord := self mergeFn: (skewWord bitAnd: halftoneWord) with: (self dstLongAt: destIndex). self dstLongAt: destIndex put: mergeWord. destIndex := destIndex + hInc] ]. "This last section, if used, requires masking of the destination store..." nWords > 1 ifTrue: [destMask := mask2. thisWord := self srcLongAt: sourceIndex. "pick up next word" sourceIndex := sourceIndex + hInc. skewWord := ((prevWord bitAnd: notSkewMask) bitShift: unskew) bitOr: "32-bit rotate" ((thisWord bitAnd: skewMask) bitShift: skew). destWord := self dstLongAt: destIndex. mergeWord := self mergeFn: (skewWord bitAnd: halftoneWord) with: destWord. destWord := (destMask bitAnd: mergeWord) bitOr: (destWord bitAnd: destMask bitInvert32). self dstLongAt: destIndex put: destWord. destIndex := destIndex + hInc]. sourceIndex := sourceIndex + sourceDelta. destIndex := destIndex + destDelta]! ! !BitBltSimulation methodsFor: 'inner loop' stamp: 'ikp (auto pragmas 12/08) 6/11/2004 16:27'! copyLoopNoSource "Faster copyLoop when source not used. hDir and vDir are both positive, and perload and skew are unused" | halftoneWord mergeWord mergeFnwith destWord | mergeFnwith := self cCoerce: (opTable at: combinationRule+1) to: 'sqInt (*)(sqInt, sqInt)'. mergeFnwith. "null ref for compiler" 1 to: bbH do: "here is the vertical loop" [ :i | noHalftone ifTrue: [halftoneWord := AllOnes] ifFalse: [halftoneWord := self halftoneAt: dy+i-1]. "Note: the horizontal loop has been expanded into three parts for speed:" "This first section requires masking of the destination store..." destMask := mask1. destWord := self dstLongAt: destIndex. mergeWord := self mergeFn: halftoneWord with: destWord. destWord := (destMask bitAnd: mergeWord) bitOr: (destWord bitAnd: destMask bitInvert32). self dstLongAt: destIndex put: destWord. destIndex := destIndex + 4. "This central horizontal loop requires no store masking" destMask := AllOnes. combinationRule = 3 ifTrue: ["Special inner loop for STORE" destWord := halftoneWord. 2 to: nWords-1 do:[ :word | self dstLongAt: destIndex put: destWord. destIndex := destIndex + 4]. ] ifFalse:[ "Normal inner loop does merge" 2 to: nWords-1 do:[ :word | "Normal inner loop does merge" destWord := self dstLongAt: destIndex. mergeWord := self mergeFn: halftoneWord with: destWord. self dstLongAt: destIndex put: mergeWord. destIndex := destIndex + 4]. ]. "This last section, if used, requires masking of the destination store..." nWords > 1 ifTrue: [destMask := mask2. destWord := self dstLongAt: destIndex. mergeWord := self mergeFn: halftoneWord with: destWord. destWord := (destMask bitAnd: mergeWord) bitOr: (destWord bitAnd: destMask bitInvert32). self dstLongAt: destIndex put: destWord. destIndex := destIndex + 4]. destIndex := destIndex + destDelta]! ! !BitBltSimulation methodsFor: 'inner loop' stamp: 'ikp (auto pragmas 12/08) 6/11/2004 16:28'! copyLoopPixMap "This version of the inner loop maps source pixels to a destination form with different depth. Because it is already unweildy, the loop is not unrolled as in the other versions. Preload, skew and skewMask are all overlooked, since pickSourcePixels delivers its destination word already properly aligned. Note that pickSourcePixels could be copied in-line at the top of the horizontal loop, and some of its inits moved out of the loop." "ar 12/7/1999: The loop has been rewritten to use only one pickSourcePixels call. The idea is that the call itself could be inlined. If we decide not to inline pickSourcePixels we could optimize the loop instead." | skewWord halftoneWord mergeWord scrStartBits nSourceIncs startBits endBits sourcePixMask destPixMask mergeFnwith nPix srcShift dstShift destWord words srcShiftInc dstShiftInc dstShiftLeft mapperFlags | mergeFnwith := self cCoerce: (opTable at: combinationRule+1) to: 'sqInt (*)(sqInt, sqInt)'. mergeFnwith. "null ref for compiler" "Additional inits peculiar to unequal source and dest pix size..." sourcePPW := 32//sourceDepth. sourcePixMask := maskTable at: sourceDepth. destPixMask := maskTable at: destDepth. mapperFlags := cmFlags bitAnd: ColorMapNewStyle bitInvert32. sourceIndex := sourceBits + (sy * sourcePitch) + ((sx // sourcePPW) *4). scrStartBits := sourcePPW - (sx bitAnd: sourcePPW-1). bbW < scrStartBits ifTrue: [nSourceIncs := 0] ifFalse: [nSourceIncs := (bbW - scrStartBits)//sourcePPW + 1]. sourceDelta := sourcePitch - (nSourceIncs * 4). "Note following two items were already calculated in destmask setup!!" startBits := destPPW - (dx bitAnd: destPPW-1). endBits := ((dx + bbW - 1) bitAnd: destPPW-1) + 1. bbW < startBits ifTrue:[startBits := bbW]. "Precomputed shifts for pickSourcePixels" srcShift := ((sx bitAnd: sourcePPW - 1) * sourceDepth). dstShift := ((dx bitAnd: destPPW - 1) * destDepth). srcShiftInc := sourceDepth. dstShiftInc := destDepth. dstShiftLeft := 0. sourceMSB ifTrue:[ srcShift := 32 - sourceDepth - srcShift. srcShiftInc := 0 - srcShiftInc]. destMSB ifTrue:[ dstShift := 32 - destDepth - dstShift. dstShiftInc := 0 - dstShiftInc. dstShiftLeft := 32 - destDepth]. 1 to: bbH do: "here is the vertical loop" [ :i | "*** is it possible at all that noHalftone == false? ***" noHalftone ifTrue:[halftoneWord := AllOnes] ifFalse: [halftoneWord := self halftoneAt: dy+i-1]. "setup first load" srcBitShift := srcShift. dstBitShift := dstShift. destMask := mask1. nPix := startBits. "Here is the horizontal loop..." words := nWords. ["pick up the word" skewWord := self pickSourcePixels: nPix flags: mapperFlags srcMask: sourcePixMask destMask: destPixMask srcShiftInc: srcShiftInc dstShiftInc: dstShiftInc. "align next word to leftmost pixel" dstBitShift := dstShiftLeft. destMask = AllOnes ifTrue:["avoid read-modify-write" mergeWord := self mergeFn: (skewWord bitAnd: halftoneWord) with: (self dstLongAt: destIndex). self dstLongAt: destIndex put: (destMask bitAnd: mergeWord). ] ifFalse:[ "General version using dest masking" destWord := self dstLongAt: destIndex. mergeWord := self mergeFn: (skewWord bitAnd: halftoneWord) with: (destWord bitAnd: destMask). destWord := (destMask bitAnd: mergeWord) bitOr: (destWord bitAnd: destMask bitInvert32). self dstLongAt: destIndex put: destWord. ]. destIndex := destIndex + 4. words = 2 "e.g., is the next word the last word?" ifTrue:["set mask for last word in this row" destMask := mask2. nPix := endBits] ifFalse:["use fullword mask for inner loop" destMask := AllOnes. nPix := destPPW]. (words := words - 1) = 0] whileFalse. "--- end of inner loop ---" sourceIndex := sourceIndex + sourceDelta. destIndex := destIndex + destDelta] ! ! !BitBltSimulation methodsFor: 'pixel mapping' stamp: 'ar (auto pragmas dtl 2010-09-26) 11/16/1998 00:23'! default8To32Table "Return the default translation table from 1..8 bit indexed colors to 32bit" "The table has been generated by the following statements" "| pvs hex | String streamContents:[:s| s nextPutAll:'static unsigned int theTable[256] = { '. pvs := (Color colorMapIfNeededFrom: 8 to: 32) asArray. 1 to: pvs size do:[:i| i > 1 ifTrue:[s nextPutAll:', ']. (i-1 \\ 8) = 0 ifTrue:[s cr]. s nextPutAll:'0x'. hex := (pvs at: i) printStringBase: 16. s nextPutAll: (hex copyFrom: 4 to: hex size). ]. s nextPutAll:'};'. ]." | theTable | ^theTable! ! !BitBltSimulation methodsFor: 'pixel mapping' stamp: 'ar (auto pragmas 12/08) 10/27/1999 17:54'! deltaFrom: x1 to: x2 nSteps: n "Utility routine for computing Warp increments." x2 > x1 ifTrue: [^ x2 - x1 + FixedPt1 // (n+1) + 1] ifFalse: [x2 = x1 ifTrue: [^ 0]. ^ 0 - (x1 - x2 + FixedPt1 // (n+1) + 1)]! ! !BitBltSimulation methodsFor: 'setup' stamp: 'ar (auto pragmas 12/08) 4/18/2001 23:02'! destMaskAndPointerInit "Compute masks for left and right destination words" | startBits pixPerM1 endBits | pixPerM1 := destPPW - 1. "A mask, assuming power of two" "how many pixels in first word" startBits := destPPW - (dx bitAnd: pixPerM1). destMSB ifTrue:[ mask1 := AllOnes >> (32 - (startBits*destDepth))] ifFalse:[ mask1 := AllOnes << (32 - (startBits*destDepth))]. "how many pixels in last word" endBits := ((dx + bbW - 1) bitAnd: pixPerM1) + 1. destMSB ifTrue:[mask2 := AllOnes << (32 - (endBits*destDepth))] ifFalse:[mask2 := AllOnes >> (32 - (endBits*destDepth))]. "determine number of words stored per line; merge masks if only 1" bbW < startBits ifTrue: [mask1 := mask1 bitAnd: mask2. mask2 := 0. nWords := 1] ifFalse: [nWords := (bbW - startBits) + pixPerM1 // destPPW + 1]. hDir := vDir := 1. "defaults for no overlap with source" "calculate byte addr and delta, based on first word of data" "Note pitch is bytes and nWords is longs, not bytes" destIndex := destBits + (dy * destPitch) + ((dx // destPPW) *4). destDelta := destPitch * vDir - (4 * (nWords * hDir)). "byte addr delta" ! ! !BitBltSimulation methodsFor: 'combination rules'! destinationWord: sourceWord with: destinationWord ^destinationWord! ! !BitBltSimulation methodsFor: 'pixel mapping' stamp: 'JMM (auto pragmas 12/08) 7/4/2003 11:12'! dither32To16: srcWord threshold: ditherValue "Dither the given 32bit word to 16 bit. Ignore alpha." | addThreshold | "You bet" addThreshold := ditherValue bitShift: 8. ^((dither8Lookup at: (addThreshold+((srcWord bitShift: -16) bitAnd: 255))) bitShift: 10) + ((dither8Lookup at: (addThreshold+((srcWord bitShift: -8) bitAnd: 255))) bitShift: 5) + (dither8Lookup at: (addThreshold+(srcWord bitAnd: 255))). ! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'ar 2/19/2000 21:27'! drawLoopX: xDelta Y: yDelta "This is the primitive implementation of the line-drawing loop. See the comments in BitBlt>>drawLoopX:Y:" | dx1 dy1 px py P affL affR affT affB | xDelta > 0 ifTrue: [dx1 := 1] ifFalse: [xDelta = 0 ifTrue: [dx1 := 0] ifFalse: [dx1 := -1]]. yDelta > 0 ifTrue: [dy1 := 1] ifFalse: [yDelta = 0 ifTrue: [dy1 := 0] ifFalse: [dy1 := -1]]. px := yDelta abs. py := xDelta abs. affL := affT := 9999. "init null rectangle" affR := affB := -9999. py > px ifTrue: ["more horizontal" P := py // 2. 1 to: py do: [:i | destX := destX + dx1. (P := P - px) < 0 ifTrue: [destY := destY + dy1. P := P + py]. i < py ifTrue: [self copyBits. interpreterProxy failed ifTrue: [^ nil "bail out now on failure -- avoid storing x,y"]. (affectedL < affectedR and: [affectedT < affectedB]) ifTrue: ["Affected rectangle grows along the line" affL := affL min: affectedL. affR := affR max: affectedR. affT := affT min: affectedT. affB := affB max: affectedB. (affR - affL) * (affB - affT) > 4000 ifTrue: ["If affected rectangle gets large, update it in chunks" affectedL := affL. affectedR := affR. affectedT := affT. affectedB := affB. self showDisplayBits. affL := affT := 9999. "init null rectangle" affR := affB := -9999]]. ]]] ifFalse: ["more vertical" P := px // 2. 1 to: px do: [:i | destY := destY + dy1. (P := P - py) < 0 ifTrue: [destX := destX + dx1. P := P + px]. i < px ifTrue: [self copyBits. interpreterProxy failed ifTrue: [^ nil "bail out now on failure -- avoid storing x,y"]. (affectedL < affectedR and: [affectedT < affectedB]) ifTrue: ["Affected rectangle grows along the line" affL := affL min: affectedL. affR := affR max: affectedR. affT := affT min: affectedT. affB := affB max: affectedB. (affR - affL) * (affB - affT) > 4000 ifTrue: ["If affected rectangle gets large, update it in chunks" affectedL := affL. affectedR := affR. affectedT := affT. affectedB := affB. self showDisplayBits. affL := affT := 9999. "init null rectangle" affR := affB := -9999]]. ]]]. "Remaining affected rect" affectedL := affL. affectedR := affR. affectedT := affT. affectedB := affB. "store destX, Y back" interpreterProxy storeInteger: BBDestXIndex ofObject: bitBltOop withValue: destX. interpreterProxy storeInteger: BBDestYIndex ofObject: bitBltOop withValue: destY.! ! !BitBltSimulation methodsFor: 'memory access' stamp: 'ikp 8/2/2004 20:25'! dstLongAt: idx ^self long32At: idx! ! !BitBltSimulation methodsFor: 'memory access' stamp: 'ikp 8/2/2004 20:29'! dstLongAt: idx put: value ^self long32At: idx put: value! ! !BitBltSimulation methodsFor: 'memory access' stamp: 'ar (auto pragmas 12/08) 12/7/1999 21:09'! dstLongAt: idx put: srcValue mask: dstMask "Store the given value back into destination form, using dstMask to mask out the bits to be modified. This is an essiantial read-modify-write operation on the destination form." | dstValue | dstValue := self dstLongAt: idx. dstValue := dstValue bitAnd: dstMask. dstValue := dstValue bitOr: srcValue. self dstLongAt: idx put: dstValue.! ! !BitBltSimulation methodsFor: 'pixel mapping' stamp: 'JMM (auto pragmas 12/08) 7/3/2003 23:05'! expensiveDither32To16: srcWord threshold: ditherValue "Dither the given 32bit word to 16 bit. Ignore alpha." | pv threshold value out | "You bet" pv := srcWord bitAnd: 255. threshold := ditherThresholds16 at: (pv bitAnd: 7). value := ditherValues16 at: (pv bitShift: -3). ditherValue < threshold ifTrue:[out := value + 1] ifFalse:[out := value]. pv := (srcWord bitShift: -8) bitAnd: 255. threshold := ditherThresholds16 at: (pv bitAnd: 7). value := ditherValues16 at: (pv bitShift: -3). ditherValue < threshold ifTrue:[out := out bitOr: (value+1 bitShift:5)] ifFalse:[out := out bitOr: (value bitShift: 5)]. pv := (srcWord bitShift: -16) bitAnd: 255. threshold := ditherThresholds16 at: (pv bitAnd: 7). value := ditherValues16 at: (pv bitShift: -3). ditherValue < threshold ifTrue:[out := out bitOr: (value+1 bitShift:10)] ifFalse:[out := out bitOr: (value bitShift: 10)]. ^out! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'tpr (auto pragmas dtl 2010-09-26) 12/29/2005 15:53'! fetchIntOrFloat: fieldIndex ofObject: objectPointer "Return the integer value of the given field of the given object. If the field contains a Float, truncate it and return its integral part. Fail if the given field does not contain a small integer or Float, or if the truncated Float is out of the range of small integers." | fieldOop floatValue | fieldOop := interpreterProxy fetchPointer: fieldIndex ofObject: objectPointer. (interpreterProxy isIntegerObject: fieldOop) ifTrue:[^interpreterProxy integerValueOf: fieldOop]. floatValue := interpreterProxy floatValueOf: fieldOop. (-2147483648.0 <= floatValue and:[floatValue <= 2147483647.0]) ifFalse:[interpreterProxy primitiveFail. ^0]. ^floatValue asInteger! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'tpr (auto pragmas dtl 2010-09-26) 12/29/2005 15:53'! fetchIntOrFloat: fieldIndex ofObject: objectPointer ifNil: defaultValue "Return the integer value of the given field of the given object. If the field contains a Float, truncate it and return its integral part. Fail if the given field does not contain a small integer or Float, or if the truncated Float is out of the range of small integers." | fieldOop floatValue | fieldOop := interpreterProxy fetchPointer: fieldIndex ofObject: objectPointer. (interpreterProxy isIntegerObject: fieldOop) ifTrue:[^interpreterProxy integerValueOf: fieldOop]. (fieldOop = interpreterProxy nilObject) ifTrue:[^defaultValue]. floatValue := interpreterProxy floatValueOf: fieldOop. (-2147483648.0 <= floatValue and:[floatValue <= 2147483647.0]) ifFalse:[interpreterProxy primitiveFail. ^0]. ^floatValue asInteger! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ar 8/21/2002 20:58'! fixAlpha: sourceWord with: destinationWord "For any non-zero pixel value in destinationWord with zero alpha channel take the alpha from sourceWord and fill it in. Intended for fixing alpha channels left at zero during 16->32 bpp conversions." destDepth = 32 ifFalse:[^destinationWord]. "no-op for non 32bpp" destinationWord = 0 ifTrue:[^0]. (destinationWord bitAnd: 16rFF000000) = 0 ifFalse:[^destinationWord]. ^destinationWord bitOr: (sourceWord bitAnd: 16rFF000000) ! ! !BitBltSimulation methodsFor: 'memory access' stamp: 'ikp 8/2/2004 20:25'! halftoneAt: idx "Return a value from the halftone pattern." ^self long32At: halftoneBase + (idx \\ halftoneHeight * 4)! ! !BitBltSimulation methodsFor: 'setup'! ignoreSourceOrHalftone: formPointer formPointer = interpreterProxy nilObject ifTrue: [ ^true ]. combinationRule = 0 ifTrue: [ ^true ]. combinationRule = 5 ifTrue: [ ^true ]. combinationRule = 10 ifTrue: [ ^true ]. combinationRule = 15 ifTrue: [ ^true ]. ^false! ! !BitBltSimulation methodsFor: 'initialize-release' stamp: 'ikp 6/10/2004 15:02'! initBBOpTable self cCode: 'opTable[0+1] = (void *)clearWordwith'. self cCode: 'opTable[1+1] = (void *)bitAndwith'. self cCode: 'opTable[2+1] = (void *)bitAndInvertwith'. self cCode: 'opTable[3+1] = (void *)sourceWordwith'. self cCode: 'opTable[4+1] = (void *)bitInvertAndwith'. self cCode: 'opTable[5+1] = (void *)destinationWordwith'. self cCode: 'opTable[6+1] = (void *)bitXorwith'. self cCode: 'opTable[7+1] = (void *)bitOrwith'. self cCode: 'opTable[8+1] = (void *)bitInvertAndInvertwith'. self cCode: 'opTable[9+1] = (void *)bitInvertXorwith'. self cCode: 'opTable[10+1] = (void *)bitInvertDestinationwith'. self cCode: 'opTable[11+1] = (void *)bitOrInvertwith'. self cCode: 'opTable[12+1] = (void *)bitInvertSourcewith'. self cCode: 'opTable[13+1] = (void *)bitInvertOrwith'. self cCode: 'opTable[14+1] = (void *)bitInvertOrInvertwith'. self cCode: 'opTable[15+1] = (void *)destinationWordwith'. self cCode: 'opTable[16+1] = (void *)destinationWordwith'. self cCode: 'opTable[17+1] = (void *)destinationWordwith'. self cCode: 'opTable[18+1] = (void *)addWordwith'. self cCode: 'opTable[19+1] = (void *)subWordwith'. self cCode: 'opTable[20+1] = (void *)rgbAddwith'. self cCode: 'opTable[21+1] = (void *)rgbSubwith'. self cCode: 'opTable[22+1] = (void *)OLDrgbDiffwith'. self cCode: 'opTable[23+1] = (void *)OLDtallyIntoMapwith'. self cCode: 'opTable[24+1] = (void *)alphaBlendwith'. self cCode: 'opTable[25+1] = (void *)pixPaintwith'. self cCode: 'opTable[26+1] = (void *)pixMaskwith'. self cCode: 'opTable[27+1] = (void *)rgbMaxwith'. self cCode: 'opTable[28+1] = (void *)rgbMinwith'. self cCode: 'opTable[29+1] = (void *)rgbMinInvertwith'. self cCode: 'opTable[30+1] = (void *)alphaBlendConstwith'. self cCode: 'opTable[31+1] = (void *)alphaPaintConstwith'. self cCode: 'opTable[32+1] = (void *)rgbDiffwith'. self cCode: 'opTable[33+1] = (void *)tallyIntoMapwith'. self cCode: 'opTable[34+1] = (void *)alphaBlendScaledwith'. self cCode: 'opTable[35+1] = (void *)alphaBlendScaledwith'. self cCode: 'opTable[36+1] = (void *)alphaBlendScaledwith'. self cCode: 'opTable[37+1] = (void *)rgbMulwith'. self cCode: 'opTable[38+1] = (void *)pixSwapwith'. self cCode: 'opTable[39+1] = (void *)pixClearwith'. self cCode: 'opTable[40+1] = (void *)fixAlphawith'.! ! !BitBltSimulation methodsFor: 'initialize-release' stamp: 'JMM (auto pragmas 12/08) 7/4/2003 11:14'! initDither8Lookup 0 to: 255 do: [:b | 0 to: 15 do: [:t | | value | value := self expensiveDither32To16: b threshold: t. dither8Lookup at: ((t << 8)+b)put: value]]. ! ! !BitBltSimulation methodsFor: 'initialize-release' stamp: 'JMM (auto pragmas 12/08) 7/4/2003 11:16'! initialiseModule self initBBOpTable. self initDither8Lookup. ^true! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'tpr (auto pragmas dtl 2010-09-26) 12/29/2005 15:53'! isIdentityMap: shifts with: masks "Return true if shiftTable/maskTable define an identity mapping." (shifts == nil or:[masks == nil]) ifTrue:[^true]. ((shifts at: RedIndex) = 0 and:[(shifts at: GreenIndex) = 0 and:[(shifts at: BlueIndex) = 0 and:[(shifts at: AlphaIndex) = 0 and:[((masks at: RedIndex) = 16rFF0000) and:[((masks at: GreenIndex) = 16r00FF00) and:[((masks at: BlueIndex) = 16r0000FF) and:[((masks at: AlphaIndex) = 16rFF000000)]]]]]]]) ifTrue:[^true]. ^false! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'ikp (auto pragmas 12/08) 8/2/2004 19:48'! loadBitBltDestForm "Load the dest form for BitBlt. Return false if anything is wrong, true otherwise." | destBitsSize | destBits := interpreterProxy fetchPointer: FormBitsIndex ofObject: destForm. destWidth := interpreterProxy fetchInteger: FormWidthIndex ofObject: destForm. destHeight := interpreterProxy fetchInteger: FormHeightIndex ofObject: destForm. (destWidth >= 0 and: [destHeight >= 0]) ifFalse: [^ false]. destDepth := interpreterProxy fetchInteger: FormDepthIndex ofObject: destForm. destMSB := destDepth > 0. destDepth < 0 ifTrue:[destDepth := 0 - destDepth]. "Ignore an integer bits handle for Display in which case the appropriate values will be obtained by calling ioLockSurfaceBits()." (interpreterProxy isIntegerObject: destBits) ifTrue:[ "Query for actual surface dimensions" (self queryDestSurface: (interpreterProxy integerValueOf: destBits)) ifFalse:[^false]. destPPW := 32 // destDepth. destBits := destPitch := 0. ] ifFalse:[ destPPW := 32 // destDepth. destPitch := destWidth + (destPPW-1) // destPPW * 4. destBitsSize := interpreterProxy byteSizeOf: destBits. ((interpreterProxy isWordsOrBytes: destBits) and: [destBitsSize = (destPitch * destHeight)]) ifFalse: [^ false]. "Skip header since external bits don't have one" destBits := self oopForPointer: (interpreterProxy firstIndexableField: destBits). ]. ^true! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'ar (auto pragmas 12/08) 2/20/2000 19:42'! loadBitBltFrom: bbObj "Load BitBlt from the oop. This function is exported for the Balloon engine." ^self loadBitBltFrom: bbObj warping: false.! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'ar (auto pragmas 12/08) 5/4/2001 14:49'! loadBitBltFrom: bbObj warping: aBool "Load context from BitBlt instance. Return false if anything is amiss" "NOTE this should all be changed to minX/maxX coordinates for simpler clipping -- once it works!!" | ok | bitBltOop := bbObj. isWarping := aBool. combinationRule := interpreterProxy fetchInteger: BBRuleIndex ofObject: bitBltOop. (interpreterProxy failed or: [combinationRule < 0 or: [combinationRule > (OpTableSize - 2)]]) ifTrue: [^ false "operation out of range"]. (combinationRule >= 16 and: [combinationRule <= 17]) ifTrue: [^ false "fail for old simulated paint, erase modes"]. sourceForm := interpreterProxy fetchPointer: BBSourceFormIndex ofObject: bitBltOop. noSource := self ignoreSourceOrHalftone: sourceForm. halftoneForm := interpreterProxy fetchPointer: BBHalftoneFormIndex ofObject: bitBltOop. noHalftone := self ignoreSourceOrHalftone: halftoneForm. destForm := interpreterProxy fetchPointer: BBDestFormIndex ofObject: bbObj. ((interpreterProxy isPointers: destForm) and: [(interpreterProxy slotSizeOf: destForm) >= 4]) ifFalse: [^ false]. ok := self loadBitBltDestForm. ok ifFalse:[^false]. destX := self fetchIntOrFloat: BBDestXIndex ofObject: bitBltOop ifNil: 0. destY := self fetchIntOrFloat: BBDestYIndex ofObject: bitBltOop ifNil: 0. width := self fetchIntOrFloat: BBWidthIndex ofObject: bitBltOop ifNil: destWidth. height := self fetchIntOrFloat: BBHeightIndex ofObject: bitBltOop ifNil: destHeight. interpreterProxy failed ifTrue: [^ false "non-integer value"]. noSource ifTrue: [sourceX := sourceY := 0] ifFalse: [((interpreterProxy isPointers: sourceForm) and: [(interpreterProxy slotSizeOf: sourceForm) >= 4]) ifFalse: [^ false]. ok := self loadBitBltSourceForm. ok ifFalse:[^false]. ok := self loadColorMap. ok ifFalse:[^false]. "Need the implicit setup here in case of 16<->32 bit conversions" (cmFlags bitAnd: ColorMapNewStyle) = 0 ifTrue:[self setupColorMasks]. sourceX := self fetchIntOrFloat: BBSourceXIndex ofObject: bitBltOop ifNil: 0. sourceY := self fetchIntOrFloat: BBSourceYIndex ofObject: bitBltOop ifNil: 0]. ok := self loadHalftoneForm. ok ifFalse:[^false]. clipX := self fetchIntOrFloat: BBClipXIndex ofObject: bitBltOop ifNil: 0. clipY := self fetchIntOrFloat: BBClipYIndex ofObject: bitBltOop ifNil: 0. clipWidth := self fetchIntOrFloat: BBClipWidthIndex ofObject: bitBltOop ifNil: destWidth. clipHeight := self fetchIntOrFloat: BBClipHeightIndex ofObject: bitBltOop ifNil: destHeight. interpreterProxy failed ifTrue: [^ false "non-integer value"]. clipX < 0 ifTrue: [clipWidth := clipWidth + clipX. clipX := 0]. clipY < 0 ifTrue: [clipHeight := clipHeight + clipY. clipY := 0]. clipX+clipWidth > destWidth ifTrue: [clipWidth := destWidth - clipX]. clipY+clipHeight > destHeight ifTrue: [clipHeight := destHeight - clipY]. ^ true! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'ikp (auto pragmas 12/08) 8/2/2004 19:48'! loadBitBltSourceForm "Load the source form for BitBlt. Return false if anything is wrong, true otherwise." | sourceBitsSize | sourceBits := interpreterProxy fetchPointer: FormBitsIndex ofObject: sourceForm. sourceWidth := self fetchIntOrFloat: FormWidthIndex ofObject: sourceForm. sourceHeight := self fetchIntOrFloat: FormHeightIndex ofObject: sourceForm. (sourceWidth >= 0 and: [sourceHeight >= 0]) ifFalse: [^ false]. sourceDepth := interpreterProxy fetchInteger: FormDepthIndex ofObject: sourceForm. sourceMSB := sourceDepth > 0. sourceDepth < 0 ifTrue:[sourceDepth := 0 - sourceDepth]. "Ignore an integer bits handle for Display in which case the appropriate values will be obtained by calling ioLockSurfaceBits()." (interpreterProxy isIntegerObject: sourceBits) ifTrue:[ "Query for actual surface dimensions" (self querySourceSurface: (interpreterProxy integerValueOf: sourceBits)) ifFalse:[^false]. sourcePPW := 32 // sourceDepth. sourceBits := sourcePitch := 0. ] ifFalse:[ sourcePPW := 32 // sourceDepth. sourcePitch := sourceWidth + (sourcePPW-1) // sourcePPW * 4. sourceBitsSize := interpreterProxy byteSizeOf: sourceBits. ((interpreterProxy isWordsOrBytes: sourceBits) and: [sourceBitsSize = (sourcePitch * sourceHeight)]) ifFalse: [^ false]. "Skip header since external bits don't have one" sourceBits := self oopForPointer: (interpreterProxy firstIndexableField: sourceBits). ]. ^true! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'ar (auto pragmas 12/08) 5/4/2001 14:54'! loadColorMap "ColorMap, if not nil, must be longWords, and 2^N long, where N = sourceDepth for 1, 2, 4, 8 bits, or N = 9, 12, or 15 (3, 4, 5 bits per color) for 16 or 32 bits." | cmSize oldStyle oop cmOop | cmFlags := cmMask := cmBitsPerColor := 0. cmShiftTable := nil. cmMaskTable := nil. cmLookupTable := nil. cmOop := interpreterProxy fetchPointer: BBColorMapIndex ofObject: bitBltOop. cmOop = interpreterProxy nilObject ifTrue:[^true]. cmFlags := ColorMapPresent. "even if identity or somesuch - may be cleared later" oldStyle := false. (interpreterProxy isWords: cmOop) ifTrue:[ "This is an old-style color map (indexed only, with implicit RGBA conversion)" cmSize := interpreterProxy slotSizeOf: cmOop. cmLookupTable := interpreterProxy firstIndexableField: cmOop. oldStyle := true. ] ifFalse: [ "A new-style color map (fully qualified)" ((interpreterProxy isPointers: cmOop) and:[(interpreterProxy slotSizeOf: cmOop) >= 3]) ifFalse:[^false]. cmShiftTable := self loadColorMapShiftOrMaskFrom: (interpreterProxy fetchPointer: 0 ofObject: cmOop). cmMaskTable := self loadColorMapShiftOrMaskFrom: (interpreterProxy fetchPointer: 1 ofObject: cmOop). oop := interpreterProxy fetchPointer: 2 ofObject: cmOop. oop = interpreterProxy nilObject ifTrue:[cmSize := 0] ifFalse:[(interpreterProxy isWords: oop) ifFalse:[^false]. cmSize := (interpreterProxy slotSizeOf: oop). cmLookupTable := interpreterProxy firstIndexableField: oop]. cmFlags := cmFlags bitOr: ColorMapNewStyle. ]. (cmSize bitAnd: cmSize - 1) = 0 ifFalse:[^false]. cmMask := cmSize - 1. cmBitsPerColor := 0. cmSize = 512 ifTrue: [cmBitsPerColor := 3]. cmSize = 4096 ifTrue: [cmBitsPerColor := 4]. cmSize = 32768 ifTrue: [cmBitsPerColor := 5]. cmSize = 0 ifTrue:[cmLookupTable := nil. cmMask := 0] ifFalse:[cmFlags := cmFlags bitOr: ColorMapIndexedPart]. oldStyle "needs implicit conversion" ifTrue:[ self setupColorMasks]. "Check if colorMap is just identity mapping for RGBA parts" (self isIdentityMap: cmShiftTable with: cmMaskTable) ifTrue:[ cmMaskTable := nil. cmShiftTable := nil ] ifFalse:[ cmFlags := cmFlags bitOr: ColorMapFixedPart]. ^true! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'ar (auto pragmas dtl 2010-09-26) 5/4/2001 14:52'! loadColorMapShiftOrMaskFrom: mapOop mapOop = interpreterProxy nilObject ifTrue:[^nil]. (interpreterProxy isIntegerObject: mapOop) ifTrue:[interpreterProxy primitiveFail. ^nil]. ((interpreterProxy isWords: mapOop) and:[(interpreterProxy slotSizeOf: mapOop) = 4]) ifFalse:[interpreterProxy primitiveFail. ^nil]. ^interpreterProxy firstIndexableField: mapOop! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'ikp (auto pragmas 12/08) 8/2/2004 19:49'! loadHalftoneForm "Load the halftone form" | halftoneBits | noHalftone ifTrue:[ halftoneBase := nil. ^true]. ((interpreterProxy isPointers: halftoneForm) and: [(interpreterProxy slotSizeOf: halftoneForm) >= 4]) ifTrue: ["Old-style 32xN monochrome halftone Forms" halftoneBits := interpreterProxy fetchPointer: FormBitsIndex ofObject: halftoneForm. halftoneHeight := interpreterProxy fetchInteger: FormHeightIndex ofObject: halftoneForm. (interpreterProxy isWords: halftoneBits) ifFalse: [noHalftone := true]] ifFalse: ["New spec accepts, basically, a word array" ((interpreterProxy isPointers: halftoneForm) not and: [interpreterProxy isWords: halftoneForm]) ifFalse: [^ false]. halftoneBits := halftoneForm. halftoneHeight := interpreterProxy slotSizeOf: halftoneBits]. halftoneBase := self oopForPointer: (interpreterProxy firstIndexableField: halftoneBits). ^true! ! !BitBltSimulation methodsFor: 'surface support' stamp: 'ar 4/18/2001 21:23'! loadSurfacePlugin "Load the surface support plugin" querySurfaceFn := interpreterProxy ioLoadFunction:'ioGetSurfaceFormat' From:'SurfacePlugin'. lockSurfaceFn := interpreterProxy ioLoadFunction:'ioLockSurface' From:'SurfacePlugin'. unlockSurfaceFn := interpreterProxy ioLoadFunction:'ioUnlockSurface' From:'SurfacePlugin'. ^querySurfaceFn ~= 0 and:[lockSurfaceFn ~= 0 and:[unlockSurfaceFn ~= 0]]! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'ar 10/27/1999 16:03'! loadWarpBltFrom: bbObj ^self loadBitBltFrom: bbObj warping: true! ! !BitBltSimulation methodsFor: 'surface support' stamp: 'ikp (auto pragmas dtl 2010-09-26) 6/9/2004 22:51'! lockSurfaces "Get a pointer to the bits of any OS surfaces." "Notes: * For equal source/dest handles only one locking operation is performed. This is to prevent locking of overlapping areas which does not work with certain APIs (as an example, DirectDraw prevents locking of overlapping areas). A special case for non-overlapping but equal source/dest handle would be possible but we would have to transfer this information over to unlockSurfaces somehow (currently, only one unlock operation is performed for equal source and dest handles). Also, this would require a change in the notion of ioLockSurface() which is right now interpreted as a hint and not as a requirement to lock only the specific portion of the surface. * The arguments in ioLockSurface() provide the implementation with an explicit hint what area is affected. It can be very useful to know the max. affected area beforehand if getting the bits requires expensive copy operations (e.g., like a roundtrip to the X server or a glReadPixel op). However, the returned pointer *MUST* point to the virtual origin of the surface and not to the beginning of the rectangle. The promise made by BitBlt is to never access data outside the given rectangle (aligned to 4byte boundaries!!) so it is okay to return a pointer to the virtual origin that is actually outside the valid memory area. * The area provided in ioLockSurface() is already clipped (e.g., it will always be inside the source and dest boundingBox) but it is not aligned to word boundaries yet. It is up to the support code to compute accurate alignment if necessary. * Warping always requires the entire source surface to be locked because there is no beforehand knowledge about what area will actually be traversed. " | sourceHandle destHandle l r t b fn | hasSurfaceLock := false. destBits = 0 ifTrue:["Blitting *to* OS surface" lockSurfaceFn = 0 ifTrue:[self loadSurfacePlugin ifFalse:[^nil]]. fn := self cCoerce: lockSurfaceFn to: 'sqInt (*)(sqInt, sqInt*, sqInt, sqInt, sqInt, sqInt)'. destHandle := interpreterProxy fetchInteger: FormBitsIndex ofObject: destForm. (sourceBits = 0 and:[noSource not]) ifTrue:[ sourceHandle := interpreterProxy fetchInteger: FormBitsIndex ofObject: sourceForm. "Handle the special case of equal source and dest handles" (sourceHandle = destHandle) ifTrue:[ "If we have overlapping source/dest we lock the entire area so that there is only one area transmitted" isWarping ifFalse:[ "When warping we always need the entire surface for the source" sourceBits := self cCode:'fn(sourceHandle, &sourcePitch, 0,0, sourceWidth, sourceHeight)'. ] ifTrue:[ "Otherwise use overlapping area" l := sx min: dx. r := (sx max: dx) + bbW. t := sy min: dy. b := (sy max: sy) + bbH. sourceBits := self cCode:'fn(sourceHandle, &sourcePitch, l, t, r-l, b-t)'. ]. destBits := sourceBits. destPitch := sourcePitch. hasSurfaceLock := true. ^destBits ~~ 0 ]. "Fall through - if not equal it'll be handled below" ]. destBits := self cCode:'fn(destHandle, &destPitch, dx, dy, bbW, bbH)'. hasSurfaceLock := true. ]. (sourceBits == 0 and:[noSource not]) ifTrue:["Blitting *from* OS surface" sourceHandle := interpreterProxy fetchInteger: FormBitsIndex ofObject: sourceForm. lockSurfaceFn = 0 ifTrue:[self loadSurfacePlugin ifFalse:[^nil]]. fn := self cCoerce: lockSurfaceFn to: 'sqInt (*)(sqInt, sqInt*, sqInt, sqInt, sqInt, sqInt)'. "Warping requiring the entire surface" isWarping ifTrue:[ sourceBits := self cCode:'fn(sourceHandle, &sourcePitch, 0, 0, sourceWidth, sourceHeight)'. ] ifFalse:[ sourceBits := self cCode:'fn(sourceHandle, &sourcePitch, sx, sy, bbW, bbH)'. ]. hasSurfaceLock := true. ]. ^destBits ~~ 0 and:[sourceBits ~~ 0 or:[noSource]].! ! !BitBltSimulation methodsFor: 'color mapping' stamp: 'ar (auto pragmas 12/08) 4/26/2001 21:57'! mapPixel: sourcePixel flags: mapperFlags "Color map the given source pixel." | pv | pv := sourcePixel. (mapperFlags bitAnd: ColorMapPresent) ~= 0 ifTrue:[ (mapperFlags bitAnd: ColorMapFixedPart) ~= 0 ifTrue:[ pv := self rgbMapPixel: sourcePixel flags: mapperFlags. "avoid introducing transparency by color reduction" (pv = 0 and:[sourcePixel ~= 0]) ifTrue:[pv := 1]]. (mapperFlags bitAnd: ColorMapIndexedPart) ~= 0 ifTrue:[pv := cmLookupTable at: (pv bitAnd: cmMask)]. ]. ^pv! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ikp (auto pragmas 12/08) 6/11/2004 16:38'! merge: sourceWord with: destinationWord | mergeFnwith | "Sender warpLoop is too big to include this in-line" mergeFnwith := self cCoerce: (opTable at: combinationRule+1) to: 'sqInt (*)(sqInt, sqInt)'. mergeFnwith. "null ref for compiler" ^ self mergeFn: sourceWord with: destinationWord! ! !BitBltSimulation methodsFor: 'initialize-release' stamp: 'ar (auto pragmas 12/08) 5/4/2001 14:46'! moduleUnloaded: aModuleName "The module with the given name was just unloaded. Make sure we have no dangling references." (aModuleName strcmp: 'SurfacePlugin') = 0 ifTrue:[ "The surface plugin just shut down. How nasty." querySurfaceFn := lockSurfaceFn := unlockSurfaceFn := 0. ].! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ar 12/7/1998 21:18'! partitionedAND: word1 to: word2 nBits: nBits nPartitions: nParts "AND word1 to word2 as nParts partitions of nBits each. Any field of word1 not all-ones is treated as all-zeroes. Used for erasing, eg, brush shapes prior to ORing in a color" | mask result | mask := maskTable at: nBits. "partition mask starts at the right" result := 0. 1 to: nParts do: [:i | (word1 bitAnd: mask) = mask ifTrue: [result := result bitOr: (word2 bitAnd: mask)]. mask := mask << nBits "slide left to next partition"]. ^ result ! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'jmv 10/26/2009 08:58'! partitionedAdd: word1 to: word2 nBits: nBits nPartitions: nParts "Add word1 to word2 as nParts partitions of nBits each. This is useful for packed pixels, or packed colors" | mask sum result maskedWord1 | "In C, most arithmetic operations answer the same bit pattern regardless of the operands being signed or unsigned ints (this is due to the way 2's complement numbers work). However, comparisions might fail. Add the proper declaration of words as unsigned int in those cases where comparisions are done (jmv)" mask := maskTable at: nBits. "partition mask starts at the right" result := 0. 1 to: nParts do: [:i | maskedWord1 := word1 bitAnd: mask. sum := maskedWord1 + (word2 bitAnd: mask). (sum <= mask "result must not carry out of partition" and: [ sum >= maskedWord1 ]) "This is needed because in C, integer arithmetic overflows silently!! (jmv)" ifTrue: [result := result bitOr: sum] ifFalse: [result := result bitOr: mask]. mask := mask << nBits "slide left to next partition"]. ^ result ! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'jmv 10/26/2009 08:59'! partitionedMax: word1 with: word2 nBits: nBits nPartitions: nParts "Max word1 to word2 as nParts partitions of nBits each" | mask result | "In C, most arithmetic operations answer the same bit pattern regardless of the operands being signed or unsigned ints (this is due to the way 2's complement numbers work). However, comparisions might fail. Add the proper declaration of words as unsigned int in those cases where comparisions are done (jmv)" mask := maskTable at: nBits. "partition mask starts at the right" result := 0. 1 to: nParts do: [:i | result := result bitOr: ((word2 bitAnd: mask) max: (word1 bitAnd: mask)). mask := mask << nBits "slide left to next partition"]. ^ result ! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'jmv 10/26/2009 08:59'! partitionedMin: word1 with: word2 nBits: nBits nPartitions: nParts "Min word1 to word2 as nParts partitions of nBits each" | mask result | "In C, most arithmetic operations answer the same bit pattern regardless of the operands being signed or unsigned ints (this is due to the way 2's complement numbers work). However, comparisions might fail. Add the proper declaration of words as unsigned int in those cases where comparisions are done (jmv)" mask := maskTable at: nBits. "partition mask starts at the right" result := 0. 1 to: nParts do: [:i | result := result bitOr: ((word2 bitAnd: mask) min: (word1 bitAnd: mask)). mask := mask << nBits "slide left to next partition"]. ^ result ! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'jmv 10/26/2009 09:01'! partitionedMul: word1 with: word2 nBits: nBits nPartitions: nParts "Multiply word1 with word2 as nParts partitions of nBits each. This is useful for packed pixels, or packed colors. Bug in loop version when non-white background" | sMask product result dMask | "In C, integer multiplication might answer a wrong value if the unsigned values are declared as signed. This problem does not affect this method, because the most significant bit (i.e. the sign bit) will always be zero (jmv)" sMask := maskTable at: nBits. "partition mask starts at the right" dMask := sMask << nBits. result := (((word1 bitAnd: sMask)+1) * ((word2 bitAnd: sMask)+1) - 1 bitAnd: dMask) >> nBits. "optimized first step" nParts = 1 ifTrue: [ ^result ]. product := (((word1>>nBits bitAnd: sMask)+1) * ((word2>>nBits bitAnd: sMask)+1) - 1 bitAnd: dMask). result := result bitOr: product. nParts = 2 ifTrue: [ ^result ]. product := (((word1>>(2*nBits) bitAnd: sMask)+1) * ((word2>>(2*nBits) bitAnd: sMask)+1) - 1 bitAnd: dMask). result := result bitOr: product << nBits. nParts = 3 ifTrue: [ ^result ]. product := (((word1>>(3*nBits) bitAnd: sMask)+1) * ((word2>>(3*nBits) bitAnd: sMask)+1) - 1 bitAnd: dMask). result := result bitOr: product << (2*nBits). ^ result " | sMask product result dMask | sMask := maskTable at: nBits. 'partition mask starts at the right' dMask := sMask << nBits. result := (((word1 bitAnd: sMask)+1) * ((word2 bitAnd: sMask)+1) - 1 bitAnd: dMask) >> nBits. 'optimized first step' nBits to: nBits * (nParts-1) by: nBits do: [:ofs | product := (((word1>>ofs bitAnd: sMask)+1) * ((word2>>ofs bitAnd: sMask)+1) - 1 bitAnd: dMask). result := result bitOr: (product bitAnd: dMask) << (ofs-nBits)]. ^ result"! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'jmv 10/26/2009 08:59'! partitionedSub: word1 from: word2 nBits: nBits nPartitions: nParts "Subtract word1 from word2 as nParts partitions of nBits each. This is useful for packed pixels, or packed colors" | mask result p1 p2 | "In C, most arithmetic operations answer the same bit pattern regardless of the operands being signed or unsigned ints (this is due to the way 2's complement numbers work). However, comparisions might fail. Add the proper declaration of words as unsigned int in those cases where comparisions are done (jmv)" mask := maskTable at: nBits. "partition mask starts at the right" result := 0. 1 to: nParts do: [:i | p1 := word1 bitAnd: mask. p2 := word2 bitAnd: mask. p1 < p2 "result is really abs value of thedifference" ifTrue: [result := result bitOr: p2 - p1] ifFalse: [result := result bitOr: p1 - p2]. mask := mask << nBits "slide left to next partition"]. ^ result ! ! !BitBltSimulation methodsFor: 'setup' stamp: 'ar (auto pragmas 12/08) 4/26/2001 19:42'! performCopyLoop "Based on the values provided during setup choose and perform the appropriate inner loop function." "Should be inlined into caller for speed" self destMaskAndPointerInit. noSource ifTrue: ["Simple fill loop" self copyLoopNoSource. ] ifFalse: ["Loop using source and dest" self checkSourceOverlap. (sourceDepth ~= destDepth or: [(cmFlags ~= 0) or:[sourceMSB ~= destMSB]]) ifTrue: [ "If we must convert between pixel depths or use color lookups or swap pixels use the general version" self copyLoopPixMap. ] ifFalse: [ "Otherwise we simple copy pixels and can use a faster version" self sourceSkewAndPointerInit. self copyLoop. ] ].! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'di (auto pragmas 12/08) 9/23/2001 10:26'! pickSourcePixels: nPixels flags: mapperFlags srcMask: srcMask destMask: dstMask srcShiftInc: srcShiftInc dstShiftInc: dstShiftInc "Pick nPix pixels starting at srcBitIndex from the source, map by the color map, and justify them according to dstBitIndex in the resulting destWord." | sourceWord destWord sourcePix destPix srcShift dstShift nPix | "oh please" sourceWord := self srcLongAt: sourceIndex. destWord := 0. srcShift := srcBitShift. "Hint: Keep in register" dstShift := dstBitShift. "Hint: Keep in register" nPix := nPixels. "always > 0 so we can use do { } while(--nPix);" (mapperFlags = (ColorMapPresent bitOr: ColorMapIndexedPart)) ifTrue:[ "a little optimization for (pretty crucial) blits using indexed lookups only" [ "grab, colormap and mix in pixel" sourcePix := sourceWord >> srcShift bitAnd: srcMask. destPix := self tableLookup: cmLookupTable at: (sourcePix bitAnd: cmMask). destWord := destWord bitOr: (destPix bitAnd: dstMask) << dstShift. "adjust dest pix index" dstShift := dstShift + dstShiftInc. "adjust source pix index" ((srcShift := srcShift + srcShiftInc) bitAnd: 16rFFFFFFE0) = 0 ifFalse:[ sourceMSB ifTrue:[srcShift := srcShift + 32] ifFalse:[srcShift := srcShift - 32]. sourceWord := self srcLongAt: (sourceIndex := sourceIndex + 4)]. (nPix := nPix - 1) = 0] whileFalse. ] ifFalse:[ [ "grab, colormap and mix in pixel" sourcePix := sourceWord >> srcShift bitAnd: srcMask. destPix := self mapPixel: sourcePix flags: mapperFlags. destWord := destWord bitOr: (destPix bitAnd: dstMask) << dstShift. "adjust dest pix index" dstShift := dstShift + dstShiftInc. "adjust source pix index" ((srcShift := srcShift + srcShiftInc) bitAnd: 16rFFFFFFE0) = 0 ifFalse:[ sourceMSB ifTrue:[srcShift := srcShift + 32] ifFalse:[srcShift := srcShift - 32]. sourceWord := self srcLongAt: (sourceIndex := sourceIndex + 4)]. (nPix := nPix - 1) = 0] whileFalse. ]. srcBitShift := srcShift. "Store back" ^destWord ! ! !BitBltSimulation methodsFor: 'pixel mapping' stamp: 'ar (auto pragmas 12/08) 4/18/2001 21:15'! pickWarpPixelAtX: xx y: yy "Pick a single pixel from the source for WarpBlt. Note: This method is crucial for WarpBlt speed w/o smoothing and still relatively important when smoothing is used." | x y srcIndex sourceWord sourcePix | "*please*" "note: it would be much faster if we could just avoid these stupid tests for being inside sourceForm." (xx < 0 or:[yy < 0 or:[ (x := xx >> BinaryPoint) >= sourceWidth or:[ (y := yy >> BinaryPoint) >= sourceHeight]]]) ifTrue:[^0]. "out of bounds" "Fetch source word. Note: We should really update srcIndex with sx and sy so that we don't have to do the computation below. We might even be able to simplify the out of bounds test from above." srcIndex := sourceBits + (y * sourcePitch) + (x >> warpAlignShift * 4). sourceWord := self srcLongAt: srcIndex. "Extract pixel from word" srcBitShift := warpBitShiftTable at: (x bitAnd: warpAlignMask). sourcePix := sourceWord >> srcBitShift bitAnd: warpSrcMask. ^sourcePix! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ar (auto pragmas 12/08) 6/16/2002 19:53'! pixClear: sourceWord with: destinationWord "Clear all pixels in destinationWord for which the pixels of sourceWord have the same values. Used to clear areas of some constant color to zero." | mask result nBits pv | destDepth = 32 ifTrue:[ sourceWord = destinationWord ifTrue:[^0] ifFalse:[^destinationWord]. ]. nBits := destDepth. mask := maskTable at: nBits. "partition mask starts at the right" result := 0. 1 to: destPPW do:[:i | pv := destinationWord bitAnd: mask. (sourceWord bitAnd: mask) = pv ifTrue:[pv := 0]. result := result bitOr: pv. mask := mask << nBits "slide left to next partition"]. ^ result! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ar (auto pragmas 12/08) 4/18/2001 20:39'! pixMask: sourceWord with: destinationWord ^ self partitionedAND: sourceWord bitInvert32 to: destinationWord nBits: destDepth nPartitions: destPPW! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ar (auto pragmas 12/08) 4/18/2001 20:39'! pixPaint: sourceWord with: destinationWord sourceWord = 0 ifTrue: [^ destinationWord]. ^ sourceWord bitOr: (self partitionedAND: sourceWord bitInvert32 to: destinationWord nBits: destDepth nPartitions: destPPW)! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ar (auto pragmas 12/08) 4/19/2001 15:38'! pixSwap: sourceWord with: destWord "Swap the pixels in destWord" | result shift lowMask highMask | destPPW = 1 ifTrue:[^destWord]. "a single pixel per word" result := 0. lowMask := (1 << destDepth) - 1. "mask low pixel" highMask := lowMask << (destPPW-1 * destDepth). "mask high pixel" shift := 32 - destDepth. result := result bitOr: ( (destWord bitAnd: lowMask) << shift bitOr: (destWord bitAnd: highMask) >> shift). destPPW <= 2 ifTrue:[^result]. 2 to: destPPW // 2 do:[:i| lowMask := lowMask << destDepth. highMask := highMask >> destDepth. shift := shift - (destDepth * 2). result := result bitOr: ( (destWord bitAnd: lowMask) << shift bitOr: (destWord bitAnd: highMask) >> shift)]. ^result! ! !BitBltSimulation methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 3/24/2004 13:06'! primitiveCopyBits "Invoke the copyBits primitive. If the destination is the display, then copy it to the screen." | rcvr | rcvr := interpreterProxy stackValue: interpreterProxy methodArgumentCount. (self loadBitBltFrom: rcvr) ifFalse:[^interpreterProxy primitiveFail]. self copyBits. interpreterProxy failed ifTrue:[^nil]. self showDisplayBits. interpreterProxy failed ifTrue:[^nil]. interpreterProxy pop: interpreterProxy methodArgumentCount. (combinationRule = 22) | (combinationRule = 32) ifTrue:[ interpreterProxy pop: 1. ^ interpreterProxy pushInteger: bitCount].! ! !BitBltSimulation methodsFor: 'primitives' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/31/2008 18:18'! primitiveDisplayString | kernDelta xTable glyphMap stopIndex startIndex sourceString bbObj maxGlyph ascii glyphIndex sourcePtr left quickBlt | interpreterProxy methodArgumentCount = 6 ifFalse:[^interpreterProxy primitiveFail]. kernDelta := interpreterProxy stackIntegerValue: 0. xTable := interpreterProxy stackObjectValue: 1. glyphMap := interpreterProxy stackObjectValue: 2. ((interpreterProxy fetchClassOf: xTable) = interpreterProxy classArray and:[ (interpreterProxy fetchClassOf: glyphMap) = interpreterProxy classArray]) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: glyphMap) = 256 ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy failed ifTrue:[^nil]. maxGlyph := (interpreterProxy slotSizeOf: xTable) - 2. stopIndex := interpreterProxy stackIntegerValue: 3. startIndex := interpreterProxy stackIntegerValue: 4. sourceString := interpreterProxy stackObjectValue: 5. (interpreterProxy isBytes: sourceString) ifFalse:[^interpreterProxy primitiveFail]. (startIndex > 0 and:[stopIndex > 0 and:[ stopIndex <= (interpreterProxy byteSizeOf: sourceString)]]) ifFalse:[^interpreterProxy primitiveFail]. bbObj := interpreterProxy stackObjectValue: 6. (self loadBitBltFrom: bbObj) ifFalse:[^interpreterProxy primitiveFail]. (combinationRule = 30 or:[combinationRule = 31]) "needs extra source alpha" ifTrue:[^interpreterProxy primitiveFail]. "See if we can go directly into copyLoopPixMap (usually we can)" quickBlt := destBits ~= 0 "no OS surfaces please" and:[sourceBits ~= 0 "and again" and:[noSource = false "needs a source" and:[sourceForm ~= destForm "no blits onto self" and:[(cmFlags ~= 0 or:[sourceMSB ~= destMSB or:[sourceDepth ~= destDepth]]) "no point using slower version" ]]]]. left := destX. sourcePtr := interpreterProxy firstIndexableField: sourceString. startIndex to: stopIndex do:[:charIndex| ascii := self byteAtPointer: sourcePtr + charIndex - 1. glyphIndex := interpreterProxy fetchInteger: ascii ofObject: glyphMap. (glyphIndex < 0 or:[glyphIndex > maxGlyph]) ifTrue:[^interpreterProxy primitiveFail]. sourceX := interpreterProxy fetchInteger: glyphIndex ofObject: xTable. width := (interpreterProxy fetchInteger: glyphIndex+1 ofObject: xTable) - sourceX. interpreterProxy failed ifTrue:[^nil]. self clipRange. "Must clip here" (bbW > 0 and:[bbH > 0]) ifTrue: [ quickBlt ifTrue:[ self destMaskAndPointerInit. self copyLoopPixMap. "both, hDir and vDir are known to be > 0" affectedL := dx. affectedR := dx + bbW. affectedT := dy. affectedB := dy + bbH. ] ifFalse:[self copyBits]]. interpreterProxy failed ifTrue:[^nil]. destX := destX + width + kernDelta. ]. affectedL := left. self showDisplayBits. interpreterProxy pop: 6. "pop args, return rcvr"! ! !BitBltSimulation methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 3/24/2004 13:56'! primitiveDrawLoop "Invoke the line drawing primitive." | rcvr xDelta yDelta | rcvr := interpreterProxy stackValue: 2. xDelta := interpreterProxy stackIntegerValue: 1. yDelta := interpreterProxy stackIntegerValue: 0. (self loadBitBltFrom: rcvr) ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy failed ifFalse:[ self drawLoopX: xDelta Y: yDelta. self showDisplayBits]. interpreterProxy failed ifFalse:[interpreterProxy pop: 2].! ! !BitBltSimulation methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 2/20/2001 21:10'! primitiveWarpBits "Invoke the warpBits primitive. If the destination is the display, then copy it to the screen." | rcvr | rcvr := interpreterProxy stackValue: interpreterProxy methodArgumentCount. (self loadWarpBltFrom: rcvr) ifFalse:[^interpreterProxy primitiveFail]. self warpBits. interpreterProxy failed ifTrue:[^nil]. self showDisplayBits. interpreterProxy failed ifTrue:[^nil]. interpreterProxy pop: interpreterProxy methodArgumentCount.! ! !BitBltSimulation methodsFor: 'surface support' stamp: 'ikp 6/9/2004 22:52'! queryDestSurface: handle "Query the dimension of an OS surface. This method is provided so that in case the inst vars of the source form are broken, *actual* values of the OS surface can be obtained. This might, for instance, happen if the user resizes the main window. Note: Moved to a separate function for better inlining of the caller." querySurfaceFn = 0 ifTrue:[self loadSurfacePlugin ifFalse:[^false]]. ^(self cCode:' ((sqInt (*) (sqInt, sqInt*, sqInt*, sqInt*, sqInt*))querySurfaceFn) (handle, &destWidth, &destHeight, &destDepth, &destMSB)' inSmalltalk:[false])! ! !BitBltSimulation methodsFor: 'surface support' stamp: 'ikp 6/9/2004 22:57'! querySourceSurface: handle "Query the dimension of an OS surface. This method is provided so that in case the inst vars of the source form are broken, *actual* values of the OS surface can be obtained. This might, for instance, happen if the user resizes the main window. Note: Moved to a separate function for better inlining of the caller." querySurfaceFn = 0 ifTrue:[self loadSurfacePlugin ifFalse:[^false]]. ^(self cCode:' ((sqInt (*) (sqInt, sqInt*, sqInt*, sqInt*, sqInt*))querySurfaceFn) (handle, &sourceWidth, &sourceHeight, &sourceDepth, &sourceMSB)' inSmalltalk:[false])! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'jmv 4/1/2009 08:39'! rgbAdd: sourceWord with: destinationWord destDepth < 16 ifTrue: ["Add each pixel separately" ^ self partitionedAdd: sourceWord to: destinationWord nBits: destDepth nPartitions: destPPW]. destDepth = 16 ifTrue: ["Add RGB components of each pixel separately" ^ (self partitionedAdd: sourceWord to: destinationWord nBits: 5 nPartitions: 3) + ((self partitionedAdd: sourceWord>>16 to: destinationWord>>16 nBits: 5 nPartitions: 3) << 16)] ifFalse: ["Add RGBA components of the pixel separately" ^ self partitionedAdd: sourceWord to: destinationWord nBits: 8 nPartitions: 4]! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ar (auto pragmas 12/08) 4/18/2001 20:38'! rgbDiff: sourceWord with: destinationWord "Subract the pixels in the source and destination, color by color, and return the sum of the absolute value of all the differences. For non-rgb, return the number of differing pixels." | pixMask destShifted sourceShifted destPixVal bitsPerColor rgbMask sourcePixVal diff maskShifted | pixMask := maskTable at: destDepth. destDepth = 16 ifTrue: [bitsPerColor := 5. rgbMask := 16r1F] ifFalse: [bitsPerColor := 8. rgbMask := 16rFF]. maskShifted := destMask. destShifted := destinationWord. sourceShifted := sourceWord. 1 to: destPPW do: [:i | (maskShifted bitAnd: pixMask) > 0 ifTrue: ["Only tally pixels within the destination rectangle" destPixVal := destShifted bitAnd: pixMask. sourcePixVal := sourceShifted bitAnd: pixMask. destDepth < 16 ifTrue: [sourcePixVal = destPixVal ifTrue: [diff := 0] ifFalse: [diff := 1]] ifFalse: [diff := (self partitionedSub: sourcePixVal from: destPixVal nBits: bitsPerColor nPartitions: 3). diff := (diff bitAnd: rgbMask) + (diff>>bitsPerColor bitAnd: rgbMask) + ((diff>>bitsPerColor)>>bitsPerColor bitAnd: rgbMask)]. bitCount := bitCount + diff]. maskShifted := maskShifted >> destDepth. sourceShifted := sourceShifted >> destDepth. destShifted := destShifted >> destDepth]. ^ destinationWord "For no effect on dest" ! ! !BitBltSimulation methodsFor: 'color mapping' stamp: 'ar 10/28/1999 16:02'! rgbMap16To32: sourcePixel "Convert the given 16bit pixel value to a 32bit RGBA value. Note: This method is intended to deal with different source formats." ^(((sourcePixel bitAnd: 31) << 3) bitOr: ((sourcePixel bitAnd: 16r3E0) << 6)) bitOr: ((sourcePixel bitAnd: 16r7C00) << 9)! ! !BitBltSimulation methodsFor: 'color mapping' stamp: 'ar 10/27/1999 14:28'! rgbMap32To32: sourcePixel "Convert the given 32bit pixel value to a 32bit RGBA value. Note: This method is intended to deal with different source formats." ^sourcePixel "For now do it simple"! ! !BitBltSimulation methodsFor: 'pixel mapping' stamp: 'di (auto pragmas 12/08) 4/10/1999 17:27'! rgbMap: sourcePixel from: nBitsIn to: nBitsOut "Convert the given pixel value with nBitsIn bits for each color component to a pixel value with nBitsOut bits for each color component. Typical values for nBitsIn/nBitsOut are 3, 5, or 8." | mask d srcPix destPix | (d := nBitsOut - nBitsIn) > 0 ifTrue: ["Expand to more bits by zero-fill" mask := (1 << nBitsIn) - 1. "Transfer mask" srcPix := sourcePixel << d. mask := mask << d. destPix := srcPix bitAnd: mask. mask := mask << nBitsOut. srcPix := srcPix << d. ^ destPix + (srcPix bitAnd: mask) + (srcPix << d bitAnd: mask << nBitsOut)] ifFalse: ["Compress to fewer bits by truncation" d = 0 ifTrue: [nBitsIn = 5 ifTrue: ["Sometimes called with 16 bits, though pixel is 15, but we must never return more than 15." ^ sourcePixel bitAnd: 16r7FFF]. nBitsIn = 8 ifTrue: ["Sometimes called with 32 bits, though pixel is 24, but we must never return more than 24." ^ sourcePixel bitAnd: 16rFFFFFF]. ^ sourcePixel]. "no compression" sourcePixel = 0 ifTrue: [^ sourcePixel]. "always map 0 (transparent) to 0" d := nBitsIn - nBitsOut. mask := (1 << nBitsOut) - 1. "Transfer mask" srcPix := sourcePixel >> d. destPix := srcPix bitAnd: mask. mask := mask << nBitsOut. srcPix := srcPix >> d. destPix := destPix + (srcPix bitAnd: mask) + (srcPix >> d bitAnd: mask << nBitsOut). destPix = 0 ifTrue: [^ 1]. "Dont fall into transparent by truncation" ^ destPix]! ! !BitBltSimulation methodsFor: 'color mapping' stamp: 'ar (auto pragmas 12/08) 4/26/2001 18:37'! rgbMapPixel: sourcePixel flags: mapperFlags "Perform the RGBA conversion for the given source pixel" | val | val := ((sourcePixel bitAnd: (cmMaskTable at: 0)) bitShift: (cmShiftTable at: 0)). val := val bitOr: ((sourcePixel bitAnd: (cmMaskTable at: 1)) bitShift: (cmShiftTable at: 1)). val := val bitOr: ((sourcePixel bitAnd: (cmMaskTable at: 2)) bitShift: (cmShiftTable at: 2)). ^val bitOr: ((sourcePixel bitAnd: (cmMaskTable at: 3)) bitShift: (cmShiftTable at: 3)). ! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'jmv 4/1/2009 08:39'! rgbMax: sourceWord with: destinationWord destDepth < 16 ifTrue: ["Max each pixel separately" ^ self partitionedMax: sourceWord with: destinationWord nBits: destDepth nPartitions: destPPW]. destDepth = 16 ifTrue: ["Max RGB components of each pixel separately" ^ (self partitionedMax: sourceWord with: destinationWord nBits: 5 nPartitions: 3) + ((self partitionedMax: sourceWord>>16 with: destinationWord>>16 nBits: 5 nPartitions: 3) << 16)] ifFalse: ["Max RGBA components of the pixel separately" ^ self partitionedMax: sourceWord with: destinationWord nBits: 8 nPartitions: 4]! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'jmv 4/1/2009 08:39'! rgbMin: sourceWord with: destinationWord destDepth < 16 ifTrue: ["Min each pixel separately" ^ self partitionedMin: sourceWord with: destinationWord nBits: destDepth nPartitions: destPPW]. destDepth = 16 ifTrue: ["Min RGB components of each pixel separately" ^ (self partitionedMin: sourceWord with: destinationWord nBits: 5 nPartitions: 3) + ((self partitionedMin: sourceWord>>16 with: destinationWord>>16 nBits: 5 nPartitions: 3) << 16)] ifFalse: ["Min RGBA components of the pixel separately" ^ self partitionedMin: sourceWord with: destinationWord nBits: 8 nPartitions: 4]! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'jmv 4/1/2009 08:39'! rgbMinInvert: wordToInvert with: destinationWord | sourceWord | sourceWord := wordToInvert bitInvert32. destDepth < 16 ifTrue: ["Min each pixel separately" ^ self partitionedMin: sourceWord with: destinationWord nBits: destDepth nPartitions: destPPW]. destDepth = 16 ifTrue: ["Min RGB components of each pixel separately" ^ (self partitionedMin: sourceWord with: destinationWord nBits: 5 nPartitions: 3) + ((self partitionedMin: sourceWord>>16 with: destinationWord>>16 nBits: 5 nPartitions: 3) << 16)] ifFalse: ["Min RGBA components of the pixel separately" ^ self partitionedMin: sourceWord with: destinationWord nBits: 8 nPartitions: 4]! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'jmv (auto pragmas dtl 2010-09-26) 4/1/2009 08:39'! rgbMul: sourceWord with: destinationWord destDepth < 16 ifTrue: ["Mul each pixel separately" ^ self partitionedMul: sourceWord with: destinationWord nBits: destDepth nPartitions: destPPW]. destDepth = 16 ifTrue: ["Mul RGB components of each pixel separately" ^ (self partitionedMul: sourceWord with: destinationWord nBits: 5 nPartitions: 3) + ((self partitionedMul: sourceWord>>16 with: destinationWord>>16 nBits: 5 nPartitions: 3) << 16)] ifFalse: ["Mul RGBA components of the pixel separately" ^ self partitionedMul: sourceWord with: destinationWord nBits: 8 nPartitions: 4] " | scanner | Display repaintMorphicDisplay. scanner := DisplayScanner quickPrintOn: Display. MessageTally time: [0 to: 760 by: 4 do: [:y |scanner drawString: 'qwrepoiuasfd=)(/&()=#!!lkjzxv.,mn124+09857907QROIYTOAFDJZXNBNB,M-.,Mqwrepoiuasfd=)(/&()=#!!lkjzxv.,mn124+09857907QROIYTOAFDJZXNBNB,M-.,M1234124356785678' at: 0@y]]. "! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'jmv 4/1/2009 08:39'! rgbSub: sourceWord with: destinationWord destDepth < 16 ifTrue: ["Sub each pixel separately" ^ self partitionedSub: sourceWord from: destinationWord nBits: destDepth nPartitions: destPPW]. destDepth = 16 ifTrue: ["Sub RGB components of each pixel separately" ^ (self partitionedSub: sourceWord from: destinationWord nBits: 5 nPartitions: 3) + ((self partitionedSub: sourceWord>>16 from: destinationWord>>16 nBits: 5 nPartitions: 3) << 16)] ifFalse: ["Sub RGBA components of the pixel separately" ^ self partitionedSub: sourceWord from: destinationWord nBits: 8 nPartitions: 4]! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'ar 4/26/2001 19:43'! setupColorMasks "WARNING: For WarpBlt w/ smoothing the source depth is wrong here!!" | bits targetBits | bits := targetBits := 0. sourceDepth <= 8 ifTrue:[^nil]. sourceDepth = 16 ifTrue:[bits := 5]. sourceDepth = 32 ifTrue:[bits := 8]. cmBitsPerColor = 0 ifTrue:["Convert to destDepth" destDepth <= 8 ifTrue:[^nil]. destDepth = 16 ifTrue:[targetBits := 5]. destDepth = 32 ifTrue:[targetBits := 8]] ifFalse:[targetBits := cmBitsPerColor]. self setupColorMasksFrom: bits to: targetBits! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'ar (auto pragmas dtl 2010-09-26) 5/4/2001 14:53'! setupColorMasksFrom: srcBits to: targetBits "Setup color masks for converting an incoming RGB pixel value from srcBits to targetBits." | mask shifts masks deltaBits | self cCode:'' inSmalltalk:[ shifts := CArrayAccessor on: (IntegerArray new: 4). masks := CArrayAccessor on: (WordArray new: 4). ]. deltaBits := targetBits - srcBits. deltaBits = 0 ifTrue:[^0]. deltaBits <= 0 ifTrue:[ mask := 1 << targetBits - 1. "Mask for extracting a color part of the source" masks at: RedIndex put: mask << (srcBits*2 - deltaBits). masks at: GreenIndex put: mask << (srcBits - deltaBits). masks at: BlueIndex put: mask << (0 - deltaBits). masks at: AlphaIndex put: 0] ifFalse:[ mask := 1 << srcBits - 1. "Mask for extracting a color part of the source" masks at: RedIndex put: mask << (srcBits*2). masks at: GreenIndex put: mask << srcBits. masks at: BlueIndex put: mask]. "Shifts for adjusting each value in a cm RGB value" shifts at: RedIndex put: deltaBits * 3. shifts at: GreenIndex put: deltaBits * 2. shifts at: BlueIndex put: deltaBits. shifts at: AlphaIndex put: 0. cmShiftTable := shifts. cmMaskTable := masks. cmFlags := cmFlags bitOr: (ColorMapPresent bitOr: ColorMapFixedPart). ! ! !BitBltSimulation methodsFor: 'interpreter interface' stamp: 'ar 2/19/2000 20:46'! showDisplayBits interpreterProxy showDisplayBits: destForm Left: affectedL Top: affectedT Right: affectedR Bottom: affectedB! ! !BitBltSimulation methodsFor: 'setup' stamp: 'ar (auto pragmas 12/08) 4/18/2001 23:05'! sourceSkewAndPointerInit "This is only used when source and dest are same depth, ie, when the barrel-shift copy loop is used." | dWid sxLowBits dxLowBits pixPerM1 | pixPerM1 := destPPW - 1. "A mask, assuming power of two" sxLowBits := sx bitAnd: pixPerM1. dxLowBits := dx bitAnd: pixPerM1. "check if need to preload buffer (i.e., two words of source needed for first word of destination)" hDir > 0 ifTrue: ["n Bits stored in 1st word of dest" dWid := bbW min: destPPW - dxLowBits. preload := (sxLowBits + dWid) > pixPerM1] ifFalse: [dWid := bbW min: dxLowBits + 1. preload := (sxLowBits - dWid + 1) < 0]. "calculate right-shift skew from source to dest" sourceMSB ifTrue:[skew := (sxLowBits - dxLowBits) * destDepth] ifFalse:[skew := (dxLowBits - sxLowBits) * destDepth]. " -32..32 " preload ifTrue: [skew < 0 ifTrue: [skew := skew+32] ifFalse: [skew := skew-32]]. "Calc byte addr and delta from longWord info" sourceIndex := sourceBits + (sy * sourcePitch) + ((sx // (32//sourceDepth)) *4). "calculate increments from end of 1 line to start of next" sourceDelta := (sourcePitch * vDir) - (4 * (nWords * hDir)). preload ifTrue: ["Compensate for extra source word fetched" sourceDelta := sourceDelta - (4*hDir)].! ! !BitBltSimulation methodsFor: 'combination rules'! sourceWord: sourceWord with: destinationWord ^sourceWord! ! !BitBltSimulation methodsFor: 'memory access' stamp: 'ikp 8/2/2004 20:25'! srcLongAt: idx ^self long32At: idx! ! !BitBltSimulation methodsFor: 'combination rules'! subWord: sourceWord with: destinationWord ^sourceWord - destinationWord! ! !BitBltSimulation methodsFor: 'memory access' stamp: 'tpr (auto pragmas 12/08) 7/28/2003 18:08'! tableLookup: table at: index "Note: Nasty coercion only necessary for the non-inlined version of this method in C. Duh? Oh well, here's the full story. The code below will definitely be inlined so everything that calls this method is fine. But... the translator doesn't quite prune this method so it generates a C function that tries to attempt an array access on an int - and most compilers don't like this. If you don't know what I'm talking about try to remove the C coercion and you'll see what happens when you try to compile a new VM..." ^table at: index ! ! !BitBltSimulation methodsFor: 'combination rules' stamp: 'ar (auto pragmas 12/08) 5/17/2001 15:16'! tallyIntoMap: sourceWord with: destinationWord "Tally pixels into the color map. Those tallied are exactly those in the destination rectangle. Note that the source should be specified == destination, in order for the proper color map checks to be performed at setup." | mapIndex pixMask destShifted maskShifted pixVal | (cmFlags bitAnd: (ColorMapPresent bitOr: ColorMapIndexedPart)) = (ColorMapPresent bitOr: ColorMapIndexedPart) ifFalse: [^ destinationWord "no op"]. pixMask := maskTable at: destDepth. destShifted := destinationWord. maskShifted := destMask. 1 to: destPPW do: [:i | (maskShifted bitAnd: pixMask) = 0 ifFalse: ["Only tally pixels within the destination rectangle" pixVal := destShifted bitAnd: pixMask. destDepth < 16 ifTrue: [mapIndex := pixVal] ifFalse: [destDepth = 16 ifTrue: [mapIndex := self rgbMap: pixVal from: 5 to: cmBitsPerColor] ifFalse: [mapIndex := self rgbMap: pixVal from: 8 to: cmBitsPerColor]]. self tallyMapAt: mapIndex put: (self tallyMapAt: mapIndex) + 1]. maskShifted := maskShifted >> destDepth. destShifted := destShifted >> destDepth]. ^ destinationWord "For no effect on dest"! ! !BitBltSimulation methodsFor: 'memory access' stamp: 'ar 4/26/2001 19:45'! tallyMapAt: idx "Return the word at position idx from the colorMap" ^cmLookupTable at: (idx bitAnd: cmMask)! ! !BitBltSimulation methodsFor: 'memory access' stamp: 'ar 4/26/2001 19:45'! tallyMapAt: idx put: value "Store the word at position idx in the colorMap" ^cmLookupTable at: (idx bitAnd: cmMask) put: value! ! !BitBltSimulation methodsFor: 'setup' stamp: 'ar (auto pragmas 12/08) 4/26/2001 19:44'! tryCopyingBitsQuickly "Shortcut for stuff that's being run from the balloon engine. Since we do this at each scan line we should avoid the expensive setup for source and destination." "We need a source." noSource ifTrue:[^false]. "We handle only combinationRule 34" (combinationRule = 34) ifFalse:[^false]. "We handle only sourceDepth 32" (sourceDepth = 32) ifFalse:[^false]. "We don't handle overlaps" (sourceForm = destForm) ifTrue:[^false]. "We need at least 8bit deep dest forms" (destDepth < 8) ifTrue:[^false]. "If 8bit, then we want a color map" (destDepth = 8 and:[(cmFlags bitAnd: ColorMapPresent) = 0]) ifTrue:[^false]. destDepth = 32 ifTrue:[self alphaSourceBlendBits32]. destDepth = 16 ifTrue:[self alphaSourceBlendBits16]. destDepth = 8 ifTrue:[self alphaSourceBlendBits8]. affectedL := dx. affectedR := dx + bbW. affectedT := dy. affectedB := dy + bbH. ^true! ! !BitBltSimulation methodsFor: 'surface support' stamp: 'ikp (auto pragmas dtl 2010-09-26) 6/11/2004 16:54'! unlockSurfaces "Unlock the bits of any OS surfaces." "See the comment in lockSurfaces. Similar rules apply. That is, the area provided in ioUnlockSurface can be used to determine the dirty region after drawing. If a source is unlocked, then the area will be (0,0,0,0) to indicate that no portion is dirty." | sourceHandle destHandle destLocked fn | hasSurfaceLock ifTrue:[ unlockSurfaceFn = 0 ifTrue:[self loadSurfacePlugin ifFalse:[^nil]]. fn := self cCoerce: unlockSurfaceFn to: 'sqInt (*)(sqInt, sqInt, sqInt, sqInt, sqInt)'. destLocked := false. destHandle := interpreterProxy fetchPointer: FormBitsIndex ofObject: destForm. (interpreterProxy isIntegerObject: destHandle) ifTrue:[ destHandle := interpreterProxy integerValueOf: destHandle. "The destBits are always assumed to be dirty" self cCode:'fn(destHandle, affectedL, affectedT, affectedR-affectedL, affectedB-affectedT)'. destBits := destPitch := 0. destLocked := true. ]. noSource ifFalse:[ sourceHandle := interpreterProxy fetchPointer: FormBitsIndex ofObject: sourceForm. (interpreterProxy isIntegerObject: sourceHandle) ifTrue:[ sourceHandle := interpreterProxy integerValueOf: sourceHandle. "Only unlock sourceHandle if different from destHandle" (destLocked and:[sourceHandle = destHandle]) ifFalse:[self cCode: 'fn(sourceHandle, 0, 0, 0, 0)']. sourceBits := sourcePitch := 0. ]. ]. hasSurfaceLock := false. ].! ! !BitBltSimulation methodsFor: 'setup' stamp: 'jcg 6/14/2010 14:12'! warpBits | ns | ns := noSource. noSource := true. self clipRange. "noSource suppresses sourceRect clipping" noSource := ns. (noSource or: [bbW <= 0 or: [bbH <= 0]]) ifTrue: ["zero width or height; noop" affectedL := affectedR := affectedT := affectedB := 0. ^ nil]. self lockSurfaces ifFalse:[^interpreterProxy primitiveFail]. self destMaskAndPointerInit. self warpLoop. hDir > 0 ifTrue: [affectedL := dx. affectedR := dx + bbW] ifFalse: [affectedL := dx - bbW + 1. affectedR := dx + 1]. vDir > 0 ifTrue: [affectedT := dy. affectedB := dy + bbH] ifFalse: [affectedT := dy - bbH + 1. affectedB := dy + 1]. self unlockSurfaces.! ! !BitBltSimulation methodsFor: 'inner loop' stamp: 'ikp (auto pragmas 12/08) 8/2/2004 19:49'! warpLoop "This version of the inner loop traverses an arbirary quadrilateral source, thus producing a general affine transformation." | skewWord halftoneWord mergeWord startBits deltaP12x deltaP12y deltaP43x deltaP43y pAx pAy pBx pBy xDelta yDelta smoothingCount sourceMapOop nSteps nPix words destWord endBits mergeFnwith dstShiftInc dstShiftLeft mapperFlags | mergeFnwith := self cCoerce: (opTable at: combinationRule+1) to: 'sqInt (*)(sqInt, sqInt)'. mergeFnwith. "null ref for compiler" (interpreterProxy slotSizeOf: bitBltOop) >= (BBWarpBase+12) ifFalse: [^ interpreterProxy primitiveFail]. nSteps := height-1. nSteps <= 0 ifTrue: [nSteps := 1]. pAx := self fetchIntOrFloat: BBWarpBase ofObject: bitBltOop. words := self fetchIntOrFloat: BBWarpBase+3 ofObject: bitBltOop. deltaP12x := self deltaFrom: pAx to: words nSteps: nSteps. deltaP12x < 0 ifTrue: [pAx := words - (nSteps*deltaP12x)]. pAy := self fetchIntOrFloat: BBWarpBase+1 ofObject: bitBltOop. words := self fetchIntOrFloat: BBWarpBase+4 ofObject: bitBltOop. deltaP12y := self deltaFrom: pAy to: words nSteps: nSteps. deltaP12y < 0 ifTrue: [pAy := words - (nSteps*deltaP12y)]. pBx := self fetchIntOrFloat: BBWarpBase+9 ofObject: bitBltOop. words := self fetchIntOrFloat: BBWarpBase+6 ofObject: bitBltOop. deltaP43x := self deltaFrom: pBx to: words nSteps: nSteps. deltaP43x < 0 ifTrue: [pBx := words - (nSteps*deltaP43x)]. pBy := self fetchIntOrFloat: BBWarpBase+10 ofObject: bitBltOop. words := self fetchIntOrFloat: BBWarpBase+7 ofObject: bitBltOop. deltaP43y := self deltaFrom: pBy to: words nSteps: nSteps. deltaP43y < 0 ifTrue: [pBy := words - (nSteps*deltaP43y)]. interpreterProxy failed ifTrue: [^ false]. "ie if non-integers above" interpreterProxy methodArgumentCount = 2 ifTrue: [smoothingCount := interpreterProxy stackIntegerValue: 1. sourceMapOop := interpreterProxy stackValue: 0. sourceMapOop = interpreterProxy nilObject ifTrue: [sourceDepth < 16 ifTrue: ["color map is required to smooth non-RGB dest" ^ interpreterProxy primitiveFail]] ifFalse: [(interpreterProxy slotSizeOf: sourceMapOop) < (1 << sourceDepth) ifTrue: ["sourceMap must be long enough for sourceDepth" ^ interpreterProxy primitiveFail]. sourceMapOop := self oopForPointer: (interpreterProxy firstIndexableField: sourceMapOop)]] ifFalse: [smoothingCount := 1. sourceMapOop := interpreterProxy nilObject]. nSteps := width-1. nSteps <= 0 ifTrue: [nSteps := 1]. startBits := destPPW - (dx bitAnd: destPPW-1). endBits := ((dx + bbW - 1) bitAnd: destPPW-1) + 1. bbW < startBits ifTrue:[startBits := bbW]. destY < clipY ifTrue:[ "Advance increments if there was clipping in y" pAx := pAx + (clipY - destY * deltaP12x). pAy := pAy + (clipY - destY * deltaP12y). pBx := pBx + (clipY - destY * deltaP43x). pBy := pBy + (clipY - destY * deltaP43y)]. "Setup values for faster pixel fetching." self warpLoopSetup. "Setup color mapping if not provided" (smoothingCount > 1 and:[(cmFlags bitAnd: ColorMapNewStyle) = 0]) ifTrue:[ cmLookupTable == nil ifTrue:[ destDepth = 16 ifTrue:[self setupColorMasksFrom: 8 to: 5]. ] ifFalse:[ self setupColorMasksFrom: 8 to: cmBitsPerColor. ]. ]. mapperFlags := cmFlags bitAnd: ColorMapNewStyle bitInvert32. destMSB ifTrue:[ dstShiftInc := 0 - destDepth. dstShiftLeft := 32 - destDepth] ifFalse:[ dstShiftInc := destDepth. dstShiftLeft := 0]. 1 to: bbH do: [ :i | "here is the vertical loop..." xDelta := self deltaFrom: pAx to: pBx nSteps: nSteps. xDelta >= 0 ifTrue: [sx := pAx] ifFalse: [sx := pBx - (nSteps*xDelta)]. yDelta := self deltaFrom: pAy to: pBy nSteps: nSteps. yDelta >= 0 ifTrue: [sy := pAy] ifFalse: [sy := pBy - (nSteps*yDelta)]. destMSB ifTrue:[dstBitShift := 32 - ((dx bitAnd: destPPW - 1) + 1 * destDepth)] ifFalse:[dstBitShift := (dx bitAnd: destPPW - 1) * destDepth]. (destX < clipX) ifTrue:[ "Advance increments if there was clipping in x" sx := sx + (clipX - destX * xDelta). sy := sy + (clipX - destX * yDelta). ]. noHalftone ifTrue: [halftoneWord := AllOnes] ifFalse: [halftoneWord := self halftoneAt: dy+i-1]. destMask := mask1. nPix := startBits. "Here is the inner loop..." words := nWords. ["pick up word" smoothingCount = 1 ifTrue:["Faster if not smoothing" skewWord := self warpPickSourcePixels: nPix xDeltah: xDelta yDeltah: yDelta xDeltav: deltaP12x yDeltav: deltaP12y dstShiftInc: dstShiftInc flags: mapperFlags. ] ifFalse:["more difficult with smoothing" skewWord := self warpPickSmoothPixels: nPix xDeltah: xDelta yDeltah: yDelta xDeltav: deltaP12x yDeltav: deltaP12y sourceMap: sourceMapOop smoothing: smoothingCount dstShiftInc: dstShiftInc. ]. "align next word access to left most pixel" dstBitShift := dstShiftLeft. destMask = AllOnes ifTrue:["avoid read-modify-write" mergeWord := self mergeFn: (skewWord bitAnd: halftoneWord) with: (self dstLongAt: destIndex). self dstLongAt: destIndex put: (destMask bitAnd: mergeWord). ] ifFalse:[ "General version using dest masking" destWord := self dstLongAt: destIndex. mergeWord := self mergeFn: (skewWord bitAnd: halftoneWord) with: (destWord bitAnd: destMask). destWord := (destMask bitAnd: mergeWord) bitOr: (destWord bitAnd: destMask bitInvert32). self dstLongAt: destIndex put: destWord. ]. destIndex := destIndex + 4. words = 2 "e.g., is the next word the last word?" ifTrue:["set mask for last word in this row" destMask := mask2. nPix := endBits] ifFalse:["use fullword mask for inner loop" destMask := AllOnes. nPix := destPPW]. (words := words - 1) = 0] whileFalse. "--- end of inner loop ---" pAx := pAx + deltaP12x. pAy := pAy + deltaP12y. pBx := pBx + deltaP43x. pBy := pBy + deltaP43y. destIndex := destIndex + destDelta]! ! !BitBltSimulation methodsFor: 'pixel mapping' stamp: 'ar (auto pragmas 12/08) 4/19/2001 12:42'! warpLoopSetup "Setup values for faster pixel fetching." | words | "warpSrcShift = log2(sourceDepth)" warpSrcShift := 0. words := sourceDepth. "recycle temp" [words = 1] whileFalse:[ warpSrcShift := warpSrcShift + 1. words := words >> 1]. "warpSrcMask = mask for extracting one pixel from source word" warpSrcMask := maskTable at: sourceDepth. "warpAlignShift: Shift for aligning x position to word boundary" warpAlignShift := 5 - warpSrcShift. "warpAlignMask: Mask for extracting the pixel position from an x position" warpAlignMask := 1 << warpAlignShift - 1. "Setup the lookup table for source bit shifts" "warpBitShiftTable: given an sub-word x value what's the bit shift?" 0 to: warpAlignMask do:[:i| sourceMSB ifTrue:[warpBitShiftTable at: i put: 32 - ( i + 1 << warpSrcShift )] ifFalse:[warpBitShiftTable at: i put: (i << warpSrcShift)]]. ! ! !BitBltSimulation methodsFor: 'pixel mapping' stamp: 'ikp (auto pragmas 12/08) 8/2/2004 20:25'! warpPickSmoothPixels: nPixels xDeltah: xDeltah yDeltah: yDeltah xDeltav: xDeltav yDeltav: yDeltav sourceMap: sourceMap smoothing: n dstShiftInc: dstShiftInc "Pick n (sub-) pixels from the source form, mapped by sourceMap, average the RGB values, map by colorMap and return the new word. This version is only called from WarpBlt with smoothingCount > 1" | rgb x y a r g b xx yy xdh ydh xdv ydv dstMask destWord i j k nPix | "nope - too much stuff in here" dstMask := maskTable at: destDepth. destWord := 0. n = 2 "Try avoiding divides for most common n (divide by 2 is generated as shift)" ifTrue:[xdh := xDeltah // 2. ydh := yDeltah // 2. xdv := xDeltav // 2. ydv := yDeltav // 2] ifFalse:[xdh := xDeltah // n. ydh := yDeltah // n. xdv := xDeltav // n. ydv := yDeltav // n]. i := nPixels. [ x := sx. y := sy. a := r := g := b := 0. "Pick and average n*n subpixels" nPix := 0. "actual number of pixels (not clipped and not transparent)" j := n. [ xx := x. yy := y. k := n. [ "get a single subpixel" rgb := self pickWarpPixelAtX: xx y: yy. (combinationRule=25 "PAINT" and: [rgb = 0]) ifFalse:[ "If not clipped and not transparent, then tally rgb values" nPix := nPix + 1. sourceDepth < 16 ifTrue:[ "Get RGBA values from sourcemap table" rgb := self long32At: sourceMap + (rgb << 2). ] ifFalse:["Already in RGB format" sourceDepth = 16 ifTrue:[rgb := self rgbMap16To32: rgb] ifFalse:[rgb := self rgbMap32To32: rgb]]. b := b + (rgb bitAnd: 255). g := g + (rgb >> 8 bitAnd: 255). r := r + (rgb >> 16 bitAnd: 255). a := a + (rgb >> 24)]. xx := xx + xdh. yy := yy + ydh. (k := k - 1) = 0] whileFalse. x := x + xdv. y := y + ydv. (j := j - 1) = 0] whileFalse. (nPix = 0 or: [combinationRule=25 "PAINT" and: [nPix < (n * n // 2)]]) ifTrue:[ rgb := 0 "All pixels were 0, or most were transparent" ] ifFalse:[ "normalize rgba sums" nPix = 4 "Try to avoid divides for most common n" ifTrue:[r := r >> 2. g := g >> 2. b := b >> 2. a := a >> 2] ifFalse:[ r := r // nPix. g := g // nPix. b := b // nPix. a := a // nPix]. rgb := (a << 24) + (r << 16) + (g << 8) + b. "map the pixel" rgb = 0 ifTrue: [ "only generate zero if pixel is really transparent" (r + g + b + a) > 0 ifTrue: [rgb := 1]]. rgb := self mapPixel: rgb flags: cmFlags. ]. "Mix it in" destWord := destWord bitOr: (rgb bitAnd: dstMask) << dstBitShift. dstBitShift := dstBitShift + dstShiftInc. sx := sx + xDeltah. sy := sy + yDeltah. (i := i - 1) = 0] whileFalse. ^destWord ! ! !BitBltSimulation methodsFor: 'pixel mapping' stamp: 'ar (auto pragmas 12/08) 4/26/2001 00:58'! warpPickSourcePixels: nPixels xDeltah: xDeltah yDeltah: yDeltah xDeltav: xDeltav yDeltav: yDeltav dstShiftInc: dstShiftInc flags: mapperFlags "Pick n pixels from the source form, map by colorMap and return aligned by dstBitShift. This version is only called from WarpBlt with smoothingCount = 1" | dstMask destWord nPix sourcePix destPix | "Yepp - this should go into warpLoop" dstMask := maskTable at: destDepth. destWord := 0. nPix := nPixels. (mapperFlags = (ColorMapPresent bitOr: ColorMapIndexedPart)) ifTrue:[ "a little optimization for (pretty crucial) blits using indexed lookups only" [ "grab, colormap and mix in pixel" sourcePix := self pickWarpPixelAtX: sx y: sy. destPix := cmLookupTable at: (sourcePix bitAnd: cmMask). destWord := destWord bitOr: (destPix bitAnd: dstMask) << dstBitShift. dstBitShift := dstBitShift + dstShiftInc. sx := sx + xDeltah. sy := sy + yDeltah. (nPix := nPix - 1) = 0] whileFalse. ] ifFalse:[ [ "grab, colormap and mix in pixel" sourcePix := self pickWarpPixelAtX: sx y: sy. destPix := self mapPixel: sourcePix flags: mapperFlags. destWord := destWord bitOr: (destPix bitAnd: dstMask) << dstBitShift. dstBitShift := dstBitShift + dstShiftInc. sx := sx + xDeltah. sy := sy + yDeltah. (nPix := nPix - 1) = 0] whileFalse. ]. ^destWord ! ! BitBltSimulation subclass: #BitBltSimulator instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-InterpreterSimulation'! !BitBltSimulator commentStamp: 'tpr 5/5/2003 12:22' prior: 0! Provide bitblt support for the vm simulator! !BitBltSimulator class methodsFor: 'instance creation' stamp: 'ar 5/11/2000 22:06'! new ^super new! ! !BitBltSimulator class methodsFor: 'translation' stamp: 'tpr 5/14/2001 12:19'! shouldBeTranslated "This class should not be translated " ^false! ! !BitBltSimulator methodsFor: 'debug support' stamp: 'ikp 8/2/2004 20:25'! dstLongAt: dstIndex interpreterProxy isInterpreterProxy ifTrue:[^dstIndex long32At: 0]. ((dstIndex anyMask: 3) or:[dstIndex + 4 < destBits or:[ dstIndex > (destBits + (destPitch * destHeight))]]) ifTrue:[self error:'Out of bounds']. ^self long32At: dstIndex! ! !BitBltSimulator methodsFor: 'debug support' stamp: 'ikp 8/2/2004 20:29'! dstLongAt: dstIndex put: value interpreterProxy isInterpreterProxy ifTrue:[^dstIndex long32At: 0 put: value]. ((dstIndex anyMask: 3) or:[dstIndex < destBits or:[ dstIndex >= (destBits + (destPitch * destHeight))]]) ifTrue:[self error:'Out of bounds']. ^self long32At: dstIndex put: value! ! !BitBltSimulator methodsFor: 'simulation' stamp: 'tpr 4/3/2004 23:16'! initBBOpTable opTable := OpTable. maskTable := Array new: 32. #(1 2 4 5 8 16 32) do:[:i| maskTable at: i put: (1 << i)-1]. self initializeDitherTables. warpBitShiftTable := CArrayAccessor on: (Array new: 32).! ! !BitBltSimulator methodsFor: 'simulation' stamp: 'JMM 7/4/2003 11:16'! initializeDitherTables ditherMatrix4x4 := CArrayAccessor on: #( 0 8 2 10 12 4 14 6 3 11 1 9 15 7 13 5). ditherThresholds16 := CArrayAccessor on:#(0 2 4 6 8 10 12 14 16). ditherValues16 := CArrayAccessor on: #(0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30). dither8Lookup := CArrayAccessor on: (Array new: 4096). self initDither8Lookup.! ! !BitBltSimulator methodsFor: 'simulation' stamp: 'di 12/30/97 11:07'! mergeFn: arg1 with: arg2 ^ self perform: (opTable at: combinationRule+1) with: arg1 with: arg2! ! !BitBltSimulator methodsFor: 'simulation' stamp: 'jmv 10/23/2009 09:45'! oopForPointer: pointer "This gets implemented by Macros in C, where its types will also be checked. oop is the width of a machine word, and pointer is a raw address." ^ pointer! ! !BitBltSimulator methodsFor: 'debug support' stamp: 'ikp 8/2/2004 20:25'! srcLongAt: srcIndex interpreterProxy isInterpreterProxy ifTrue:[^srcIndex long32At: 0]. ((srcIndex anyMask: 3) or:[srcIndex + 4 < sourceBits or:[ srcIndex > (sourceBits + (sourcePitch * sourceHeight))]]) ifTrue:[self error:'Out of bounds']. ^self long32At: srcIndex! ! !BitBltSimulator methodsFor: 'simulation' stamp: 'ikp 8/2/2004 20:25'! tableLookup: table at: index ^ self long32At: (table + (index * 4))! ! InterpreterPlugin subclass: #CroquetPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !CroquetPlugin commentStamp: '' prior: 0! An assorted list of useful primitives for Croquet.! !CroquetPlugin class methodsFor: 'as yet unclassified' stamp: 'ar 3/26/2006 19:37'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !CroquetPlugin class methodsFor: 'as yet unclassified' stamp: 'ar 3/26/2006 19:37'! requiresCrossPlatformFiles "default is ok for most, any plugin needing platform specific files must say so" ^true! ! !CroquetPlugin methodsFor: 'cryptography' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/28/2006 12:07'! primitiveARC4Transform "Perform an ARC4 transform of input. Arguments: buffer transformed data startIndex start of transform stopIndex end of transform m key stream data x key state value y key state value Return value: x@y - updated key state value " | y x mOop stopIndex startIndex bufOop bufSize buffer a m b mask ptOop xOop yOop | interpreterProxy methodArgumentCount = 6 ifFalse:[^interpreterProxy primitiveFail]. "pick up arguments" y := interpreterProxy stackIntegerValue: 0. x := interpreterProxy stackIntegerValue: 1. mOop := interpreterProxy stackObjectValue: 2. stopIndex := interpreterProxy stackIntegerValue: 3. startIndex := interpreterProxy stackIntegerValue: 4. bufOop := interpreterProxy stackObjectValue: 5. interpreterProxy failed ifTrue:[^nil]. ((interpreterProxy isBytes: mOop) and:[interpreterProxy isBytes: bufOop]) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy byteSizeOf: mOop) = 256 ifFalse:[^interpreterProxy primitiveFail]. bufSize := interpreterProxy byteSizeOf: bufOop. (startIndex > 0 and:[startIndex <= bufSize]) ifFalse:[^interpreterProxy primitiveFail]. (stopIndex > startIndex and:[stopIndex <= bufSize]) ifFalse:[^interpreterProxy primitiveFail]. m := interpreterProxy firstIndexableField: mOop. buffer := interpreterProxy firstIndexableField: bufOop. startIndex-1 to: stopIndex-1 do:[:i| x := (x + 1) bitAnd: 255. a := m at: x. y := (y + a) bitAnd: 255. b := m at: y. m at: x put: b. m at: y put: a. mask := m at: ((a + b) bitAnd: 255). buffer at: i put: ((buffer at: i) bitXor: mask). ]. ptOop := interpreterProxy instantiateClass: interpreterProxy classPoint indexableSize: 0. interpreterProxy pushRemappableOop: ptOop. xOop := interpreterProxy positive32BitIntegerFor: x. interpreterProxy pushRemappableOop: xOop. yOop := interpreterProxy positive32BitIntegerFor: y. xOop := interpreterProxy popRemappableOop. ptOop := interpreterProxy popRemappableOop. interpreterProxy storePointer: 0 ofObject: ptOop withValue: xOop. interpreterProxy storePointer: 1 ofObject: ptOop withValue: yOop. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy push: ptOop. ! ! !CroquetPlugin methodsFor: 'cryptography' stamp: 'ar (auto pragmas 12/08) 3/29/2006 12:13'! primitiveGatherEntropy "Primitive. Gather good random entropy from a system source." | bufOop bufSize bufPtr okay | (interpreterProxy methodArgumentCount = 1) ifFalse:[^interpreterProxy primitiveFail]. bufOop := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isBytes: bufOop) ifFalse:[^interpreterProxy primitiveFail]. bufSize := interpreterProxy byteSizeOf: bufOop. bufPtr := interpreterProxy firstIndexableField: bufOop. okay := self cCode: 'ioGatherEntropy(bufPtr, bufSize)' inSmalltalk:[bufPtr. bufSize. false]. okay ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushBool: true.! ! !CroquetPlugin methodsFor: 'transforms' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/26/2006 22:32'! primitiveInplaceHouseHolderInvert "Primitive. Perform an inplace house holder matrix inversion" | rcvr d x sigma beta sum s m | self cCode:'' inSmalltalk:[ m := CArrayAccessor on: ((1 to: 4) collect:[:i| CArrayAccessor on: (Array new: 4)]). x := CArrayAccessor on: (Array with: (CArrayAccessor on: #(1.0 0.0 0.0 0.0) copy) with: (CArrayAccessor on: #(0.0 1.0 0.0 0.0) copy) with: (CArrayAccessor on: #(0.0 0.0 1.0 0.0) copy) with: (CArrayAccessor on: #(0.0 0.0 0.0 1.0) copy)). d := CArrayAccessor on: ((1 to: 4) collect:[:i| CArrayAccessor on: (Array new: 4)]). ]. rcvr := self stackMatrix: 0. 0 to: 3 do:[:i| 0 to: 3 do:[:j| (m at: i) at: j put: (rcvr at: i*4+j)]]. 0 to: 3 do:[:j| sigma := 0.0. j to: 3 do:[:i| sigma := sigma + (((m at: i) at: j) * ((m at: i) at: j))]. sigma < 1.0e-10 ifTrue:[^interpreterProxy primitiveFail]. "matrix is singular" (((m at: j) at: j) < 0.0) ifTrue:[ s:= sigma sqrt] ifFalse:[ s:= 0.0 - sigma sqrt]. 0 to: 3 do:[:r| (d at: j) at: r put: s]. beta := 1.0 / ( s * ((m at: j) at: j) - sigma). (m at: j) at: j put: (((m at: j) at: j) - s). "update remaining columns" j+1 to: 3 do:[:k| sum := 0.0. j to: 3 do:[:i| sum := sum + (((m at: i) at: j) * ((m at: i) at: k))]. sum := sum * beta. j to: 3 do:[:i| (m at: i) at: k put: (((m at: i) at: k) + (((m at: i) at: j) * sum))]]. "update vector" 0 to: 3 do:[:r| sum := 0.0. j to: 3 do:[:i| sum := sum + (((x at: i) at: r) * ((m at: i) at: j))]. sum := sum * beta. j to: 3 do:[:i| (x at: i) at: r put:(((x at: i) at: r) + (sum * ((m at: i) at: j)))]. ]. ]. "Now calculate result" 0 to: 3 do:[:r| 3 to: 0 by: -1 do:[:i| i+1 to: 3 do:[:j| (x at: i) at: r put: (((x at: i) at: r) - (((x at: j) at: r) * ((m at: i) at: j))) ]. (x at: i) at: r put: (((x at: i) at: r) / ((d at: i) at: r))]. ]. 0 to: 3 do:[:i| 0 to: 3 do:[:j| rcvr at: i*4+j put: (self cCoerce: ((x at: i) at: j) to:'float')]]. "Return receiver"! ! !CroquetPlugin methodsFor: 'cryptography' stamp: 'ar (auto pragmas 12/08) 3/26/2006 19:45'! primitiveMD5Transform "Perform an MD5 transform of input" | bufOop hashOop hash buffer | interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. hashOop := interpreterProxy stackObjectValue: 0. ((interpreterProxy isWords: hashOop) and:[(interpreterProxy slotSizeOf: hashOop) = 4]) ifFalse:[^interpreterProxy primitiveFail]. hash := interpreterProxy firstIndexableField: hashOop. bufOop := interpreterProxy stackObjectValue: 1. ((interpreterProxy isWords: bufOop) and:[(interpreterProxy slotSizeOf: bufOop) = 16]) ifFalse:[^interpreterProxy primitiveFail]. buffer := interpreterProxy firstIndexableField: bufOop. self cCode:'MD5Transform(hash, buffer)' inSmalltalk:[ hash. buffer. ^interpreterProxy primitiveFail]. "Pop args; return buffer" interpreterProxy pop: interpreterProxy methodArgumentCount+1. interpreterProxy push: bufOop.! ! !CroquetPlugin methodsFor: 'transforms' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/26/2006 22:33'! primitiveOrthoNormInverseMatrix | srcOop dstOop src dst x y z rx ry rz | interpreterProxy methodArgumentCount = 0 ifFalse:[^interpreterProxy primitiveFail]. srcOop := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. ((interpreterProxy isWords: srcOop) and:[(interpreterProxy slotSizeOf: srcOop) = 16]) ifFalse:[^interpreterProxy primitiveFail]. dstOop := interpreterProxy clone: srcOop. "reload srcOop in case of GC" srcOop := interpreterProxy stackObjectValue: 0. src := interpreterProxy firstIndexableField: srcOop. dst := interpreterProxy firstIndexableField: dstOop. "Transpose upper 3x3 matrix" "dst at: 0 put: (src at: 0)." dst at: 1 put: (src at: 4). dst at: 2 put: (src at: 8). dst at: 4 put: (src at: 1). "dst at: 5 put: (src at: 5)." dst at: 6 put: (src at: 9). dst at: 8 put: (src at: 2). dst at: 9 put: (src at: 6). "dst at: 10 put: (src at: 10)." "Compute inverse translation vector" x := src at: 3.. y := src at: 7. z := src at: 11. rx := (x * (dst at: 0)) + (y * (dst at: 1)) + (z * (dst at: 2)). ry := (x * (dst at: 4)) + (y * (dst at: 5)) + (z * (dst at: 6)). rz := (x * (dst at: 8)) + (y * (dst at: 9)) + (z * (dst at: 10)). dst at: 3 put: (self cCoerce: 0.0-rx to: 'float'). dst at: 7 put: (self cCoerce: 0.0-ry to: 'float'). dst at: 11 put: (self cCoerce: 0.0-rz to: 'float'). interpreterProxy pop: 1. interpreterProxy push: dstOop. ! ! !CroquetPlugin methodsFor: 'transforms' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/26/2006 22:33'! primitiveTransformDirection | x y z rx ry rz matrix vertex v3Oop | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. v3Oop := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. ((interpreterProxy isWords: v3Oop) and:[(interpreterProxy slotSizeOf: v3Oop) = 3]) ifFalse:[^interpreterProxy primitiveFail]. vertex := interpreterProxy firstIndexableField: v3Oop. matrix := self stackMatrix: 1. (matrix == nil) ifTrue:[^interpreterProxy primitiveFail]. x := vertex at: 0. y := vertex at: 1. z := vertex at: 2. rx := (x * (matrix at: 0)) + (y * (matrix at: 1)) + (z * (matrix at: 2)). ry := (x * (matrix at: 4)) + (y * (matrix at: 5)) + (z * (matrix at: 6)). rz := (x * (matrix at: 8)) + (y * (matrix at: 9)) + (z * (matrix at: 10)). v3Oop := interpreterProxy clone: v3Oop. vertex := interpreterProxy firstIndexableField: v3Oop. vertex at: 0 put: (self cCoerce: rx to: 'float'). vertex at: 1 put: (self cCoerce: ry to:'float'). vertex at: 2 put: (self cCoerce: rz to: 'float'). interpreterProxy pop: 2. interpreterProxy push: v3Oop. ! ! !CroquetPlugin methodsFor: 'transforms' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/26/2006 22:34'! primitiveTransformMatrixWithInto "Transform two matrices into the third" | m1 m2 m3 | m3 := self stackMatrix: 0. m2 := self stackMatrix: 1. m1 := self stackMatrix: 2. (m1 = nil) | (m2 = nil) | (m3 = nil) ifTrue:[^interpreterProxy primitiveFail]. m2 == m3 ifTrue:[^interpreterProxy primitiveFail]. self transformMatrix: m1 with: m2 into: m3. interpreterProxy pop: 3. "Leave rcvr on stack"! ! !CroquetPlugin methodsFor: 'transforms' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/26/2006 22:43'! primitiveTransformVector3 | x y z rx ry rz rw matrix vertex v3Oop | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. v3Oop := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. ((interpreterProxy isWords: v3Oop) and:[(interpreterProxy slotSizeOf: v3Oop) = 3]) ifFalse:[^interpreterProxy primitiveFail]. vertex := interpreterProxy firstIndexableField: v3Oop. matrix := self stackMatrix: 1. (matrix == nil) ifTrue:[^interpreterProxy primitiveFail]. x := vertex at: 0. y := vertex at: 1. z := vertex at: 2. rx := (x * (matrix at: 0)) + (y * (matrix at: 1)) + (z * (matrix at: 2)) + (matrix at: 3). ry := (x * (matrix at: 4)) + (y * (matrix at: 5)) + (z * (matrix at: 6)) + (matrix at: 7). rz := (x * (matrix at: 8)) + (y * (matrix at: 9)) + (z * (matrix at: 10)) + (matrix at: 11). rw := (x * (matrix at: 12)) + (y * (matrix at: 13)) + (z * (matrix at: 14)) + (matrix at: 15). v3Oop := interpreterProxy clone: v3Oop. vertex := interpreterProxy firstIndexableField: v3Oop. rw = 1.0 ifTrue:[ vertex at: 0 put: (self cCoerce: rx to: 'float'). vertex at: 1 put: (self cCoerce: ry to:'float'). vertex at: 2 put: (self cCoerce: rz to: 'float'). ] ifFalse:[ rw = 0.0 ifTrue:[rw := 0.0] ifFalse:[rw := 1.0 / rw]. vertex at: 0 put: (self cCoerce: rx*rw to:'float'). vertex at: 1 put: (self cCoerce: ry*rw to:'float'). vertex at: 2 put: (self cCoerce: rz*rw to: 'float'). ]. interpreterProxy pop: 2. interpreterProxy push: v3Oop. ! ! !CroquetPlugin methodsFor: 'transforms' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/26/2006 22:34'! primitiveTransposeMatrix | srcOop dstOop src dst | interpreterProxy methodArgumentCount = 0 ifFalse:[^interpreterProxy primitiveFail]. srcOop := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. ((interpreterProxy isWords: srcOop) and:[(interpreterProxy slotSizeOf: srcOop) = 16]) ifFalse:[^interpreterProxy primitiveFail]. dstOop := interpreterProxy clone: srcOop. "reload srcOop in case of GC" srcOop := interpreterProxy stackObjectValue: 0. src := interpreterProxy firstIndexableField: srcOop. dst := interpreterProxy firstIndexableField: dstOop. "dst at: 0 put: (src at: 0)." dst at: 1 put: (src at: 4). dst at: 2 put: (src at: 8). dst at: 3 put: (src at: 12). dst at: 4 put: (src at: 1). "dst at: 5 put: (src at: 5)." dst at: 6 put: (src at: 9). dst at: 7 put: (src at: 13). dst at: 8 put: (src at: 2). dst at: 9 put: (src at: 6). "dst at: 10 put: (src at: 10)." dst at: 11 put: (src at: 14). dst at: 12 put: (src at: 3). dst at: 13 put: (src at: 7). dst at: 14 put: (src at: 11). "dst at: 15 put: (src at: 15)." interpreterProxy pop: 1. interpreterProxy push: dstOop. ! ! !CroquetPlugin methodsFor: 'transforms' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/18/2007 01:25'! primitiveTriBoxIntersects "Primitive. Answer whether an AABB intersects with a given triangle" | minCorner maxCorner v0 v1 v2 result | interpreterProxy methodArgumentCount = 5 ifFalse:[^interpreterProxy primitiveFail]. v2 := self stackVector3: 0. v1 := self stackVector3: 1. v0 := self stackVector3: 2. maxCorner := self stackVector3: 3. minCorner := self stackVector3: 4. result := self cCode:'triBoxOverlap(minCorner, maxCorner, v0, v1, v2)' inSmalltalk:[minCorner. maxCorner. v0. v1. v2. -1]. result < 0 ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: 6. "args+rcvr" interpreterProxy pushBool: result.! ! !CroquetPlugin methodsFor: 'transforms' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/26/2006 22:32'! stackMatrix: index "Load a 4x4 transformation matrix from the interpreter stack. Return a pointer to the matrix data if successful, nil otherwise." | oop | oop := interpreterProxy stackObjectValue: index. oop = nil ifTrue:[^nil]. ((interpreterProxy isWords: oop) and:[(interpreterProxy slotSizeOf: oop) = 16]) ifTrue:[^interpreterProxy firstIndexableField: oop]. ^nil! ! !CroquetPlugin methodsFor: 'transforms' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/18/2007 01:08'! stackVector3: index "Load a Vector3 from the interpreter stack. Return a pointer to the float data if successful, nil otherwise." | oop | oop := interpreterProxy stackObjectValue: index. oop = nil ifTrue:[^nil]. ((interpreterProxy isWords: oop) and:[(interpreterProxy slotSizeOf: oop) = 3]) ifTrue:[^interpreterProxy firstIndexableField: oop]. ^nil! ! !CroquetPlugin methodsFor: 'transforms' stamp: 'ar (auto pragmas dtl 2010-09-27) 3/26/2006 22:34'! transformMatrix: src with: arg into: dst "Transform src with arg into dst. It is allowed that src == dst but not arg == dst" | m1 m2 m3 c1 c2 c3 c4 | m1 := self cCoerce: src to:'float *'. m2 := self cCoerce: arg to: 'float *'. m3 := self cCoerce: dst to: 'float *'. 0 to: 3 do:[:i| "Compute next row" c1 := ((m1 at: 0) * (m2 at: 0)) + ((m1 at: 1) * (m2 at: 4)) + ((m1 at: 2) * (m2 at: 8)) + ((m1 at: 3) * (m2 at: 12)). c2 := ((m1 at: 0) * (m2 at: 1)) + ((m1 at: 1) * (m2 at: 5)) + ((m1 at: 2) * (m2 at: 9)) + ((m1 at: 3) * (m2 at: 13)). c3 := ((m1 at: 0) * (m2 at: 2)) + ((m1 at: 1) * (m2 at: 6)) + ((m1 at: 2) * (m2 at: 10)) + ((m1 at: 3) * (m2 at: 14)). c4 := ((m1 at: 0) * (m2 at: 3)) + ((m1 at: 1) * (m2 at: 7)) + ((m1 at: 2) * (m2 at: 11)) + ((m1 at: 3) * (m2 at: 15)). "Store result" m3 at: 0 put: c1. m3 at: 1 put: c2. m3 at: 2 put: c3. m3 at: 3 put: c4. "Skip src and dst to next row" m1 := m1 + 4. m3 := m3 + 4. ]. ! ! InterpreterPlugin subclass: #DSAPlugin instanceVariableNames: 'dsaRemainder dsaDivisor dsaQuotient remainderDigitCount divisorDigitCount' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !DSAPlugin commentStamp: '' prior: 0! This plugin defines primitives that support the DigitalSignatureAlgorithm class. Three of these primitives support fast multiplication and division of very large integers, three others support the SecureHashAlgorithm. ! !DSAPlugin class methodsFor: 'plugin translation' stamp: 'sma 3/3/2000 12:44'! declareCVarsIn: cg cg var: #dsaRemainder type: #'unsigned char*'. cg var: #dsaDivisor type: #'unsigned char*'. cg var: #dsaQuotient type: #'unsigned char*'! ! !DSAPlugin class methodsFor: 'plugin translation' stamp: 'ar 5/15/2000 22:51'! moduleName "Time millisecondsToRun: [ DSAPlugin translateDoInlining: true]" ^ 'DSAPrims' "Yes - it needs to be named this way or else we'll not find it" ! ! !DSAPlugin methodsFor: 'private' stamp: 'jm 12/21/1999 08:10'! addBackDivisorDigitShift: digitShift "Add back the divisor shifted left by the given number of digits. This is done only when the estimate of quotient digit was one larger than the correct value." | carry rIndex sum | carry := 0. rIndex := digitShift + 1. 1 to: divisorDigitCount do: [:i | sum := (dsaRemainder at: rIndex) + (dsaDivisor at: i) + carry. dsaRemainder at: rIndex put: (sum bitAnd: 16rFF). carry := sum bitShift: -8. rIndex := rIndex + 1]. "do final carry" sum := (dsaRemainder at: rIndex) + carry. dsaRemainder at: rIndex put: (sum bitAnd: 16rFF). "Note: There should be a final carry that cancels out the excess borrow." "Assert: (sum bitShift: -8) ~= 1 ifTrue: [self halt: 'no carry!!']." ! ! !DSAPlugin methodsFor: 'private' stamp: 'jm 12/21/1999 18:48'! bigDivideLoop "This is the core of the divide algorithm. This loop steps through the digit positions of the quotient, each time estimating the right quotient digit, subtracting from the remainder the divisor times the quotient digit shifted left by the appropriate number of digits. When the loop terminates, all digits of the quotient have been filled in and the remainder contains a value less than the divisor. The tricky bit is estimating the next quotient digit. Knuth shows that the digit estimate computed here will never be less than it should be and cannot be more than one over what it should be. Furthermore, the case where the estimate is one too large is extremely rare. For example, in a typical test of 100000 random 60-bit division problems, the rare case only occured five times. See Knuth, volume 2 ('Semi-Numerical Algorithms') 2nd edition, pp. 257-260" | d1 d2 firstDigit firstTwoDigits thirdDigit q digitShift qTooBig | "extract the top two digits of the divisor" d1 := dsaDivisor at: divisorDigitCount. d2 := dsaDivisor at: divisorDigitCount - 1. remainderDigitCount to: divisorDigitCount + 1 by: -1 do: [:j | "extract the top several digits of remainder." firstDigit := dsaRemainder at: j. firstTwoDigits := (firstDigit bitShift: 8) + (dsaRemainder at: j - 1). thirdDigit := dsaRemainder at: j - 2. "estimate q, the next digit of the quotient" firstDigit = d1 ifTrue: [q := 255] ifFalse: [q := firstTwoDigits // d1]. "adjust the estimate of q if necessary" (d2 * q) > (((firstTwoDigits - (q * d1)) bitShift: 8) + thirdDigit) ifTrue: [ q := q - 1. (d2 * q) > (((firstTwoDigits - (q * d1)) bitShift: 8) + thirdDigit) ifTrue: [ q := q - 1]]. digitShift := j - divisorDigitCount - 1. q > 0 ifTrue: [ qTooBig := self subtractDivisorMultipliedByDigit: q digitShift: digitShift. qTooBig ifTrue: [ "this case is extremely rare" self addBackDivisorDigitShift: digitShift. q := q - 1]]. "record this digit of the quotient" dsaQuotient at: digitShift + 1 put: q]. ! ! !DSAPlugin methodsFor: 'private' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:01'! leftRotate: anInteger by: bits "Rotate the given 32-bit integer left by the given number of bits and answer the result." ^ (anInteger << bits) bitOr: (anInteger >> (32 - bits)) ! ! !DSAPlugin methodsFor: 'primitives-integers' stamp: 'jm (auto pragmas 12/08) 12/21/1999 18:48'! primitiveBigDivide "Called with three LargePositiveInteger arguments, rem, div, quo. Divide div into rem and store the quotient into quo, leaving the remainder in rem." "Assume: quo starts out filled with zeros." | rem div quo | quo := interpreterProxy stackObjectValue: 0. div := interpreterProxy stackObjectValue: 1. rem := interpreterProxy stackObjectValue: 2. interpreterProxy success: (interpreterProxy fetchClassOf: rem) = interpreterProxy classLargePositiveInteger. interpreterProxy success: (interpreterProxy fetchClassOf: div) = interpreterProxy classLargePositiveInteger. interpreterProxy success: (interpreterProxy fetchClassOf: quo) = interpreterProxy classLargePositiveInteger. interpreterProxy failed ifTrue:[^ nil]. dsaRemainder := interpreterProxy firstIndexableField: rem. dsaDivisor := interpreterProxy firstIndexableField: div. dsaQuotient := interpreterProxy firstIndexableField: quo. divisorDigitCount := interpreterProxy stSizeOf: div. remainderDigitCount := interpreterProxy stSizeOf: rem. "adjust pointers for base-1 indexing" dsaRemainder := dsaRemainder - 1. dsaDivisor := dsaDivisor - 1. dsaQuotient := dsaQuotient - 1. self bigDivideLoop. interpreterProxy pop: 3. ! ! !DSAPlugin methodsFor: 'primitives-integers' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:02'! primitiveBigMultiply "Multiple f1 by f2, placing the result into prod. f1, f2, and prod must be LargePositiveIntegers, and the length of prod must be the sum of the lengths of f1 and f2." "Assume: prod starts out filled with zeros" | prod f2 f1 prodLen f1Len f2Len prodPtr f2Ptr f1Ptr digit carry k sum | prod := interpreterProxy stackObjectValue: 0. f2 := interpreterProxy stackObjectValue: 1. f1 := interpreterProxy stackObjectValue: 2. interpreterProxy success: (interpreterProxy isBytes: prod). interpreterProxy success: (interpreterProxy isBytes: f2). interpreterProxy success: (interpreterProxy isBytes: f1). interpreterProxy success: (interpreterProxy fetchClassOf: prod) = interpreterProxy classLargePositiveInteger. interpreterProxy success: (interpreterProxy fetchClassOf: f2) = interpreterProxy classLargePositiveInteger. interpreterProxy success: (interpreterProxy fetchClassOf: f1) = interpreterProxy classLargePositiveInteger. interpreterProxy failed ifTrue:[^ nil]. prodLen := interpreterProxy stSizeOf: prod. f1Len := interpreterProxy stSizeOf: f1. f2Len := interpreterProxy stSizeOf: f2. interpreterProxy success: (prodLen = (f1Len + f2Len)). interpreterProxy failed ifTrue:[^ nil]. prodPtr := interpreterProxy firstIndexableField: prod. f2Ptr := interpreterProxy firstIndexableField: f2. f1Ptr := interpreterProxy firstIndexableField: f1. 0 to: f1Len-1 do: [:i | (digit := f1Ptr at: i) ~= 0 ifTrue: [ carry := 0. k := i. "Loop invariants: 0 <= carry <= 16rFF, k = i + j - 1" 0 to: f2Len-1 do: [:j | sum := ((f2Ptr at: j) * digit) + (prodPtr at: k) + carry. carry := sum bitShift: -8. prodPtr at: k put: (sum bitAnd: 255). k := k + 1]. prodPtr at: k put: carry]]. interpreterProxy pop: 3. ! ! !DSAPlugin methodsFor: 'primitives-SHA' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:02'! primitiveExpandBlock "Expand a 64 byte ByteArray (the first argument) into and an Bitmap of 80 32-bit words (the second argument). When reading a 32-bit integer from the ByteArray, consider the first byte to contain the most significant bits of the word (i.e., use big-endian byte ordering)." | expanded buf wordPtr bytePtr src v | expanded := interpreterProxy stackObjectValue: 0. buf := interpreterProxy stackObjectValue: 1. interpreterProxy success: (interpreterProxy isWords: expanded). interpreterProxy success: (interpreterProxy isBytes: buf). interpreterProxy failed ifTrue: [^ nil]. interpreterProxy success: ((interpreterProxy stSizeOf: expanded) = 80). interpreterProxy success: ((interpreterProxy stSizeOf: buf) = 64). interpreterProxy failed ifTrue: [^ nil]. wordPtr := interpreterProxy firstIndexableField: expanded. bytePtr := interpreterProxy firstIndexableField: buf. src := 0. 0 to: 15 do: [:i | v := ((bytePtr at: src) << 24) + ((bytePtr at: src + 1) << 16) + ((bytePtr at: src + 2) << 8) + (bytePtr at: src + 3). wordPtr at: i put: v. src := src + 4]. 16 to: 79 do: [:i | v := (((wordPtr at: i - 3) bitXor: (wordPtr at: i - 8)) bitXor: (wordPtr at: i - 14)) bitXor: (wordPtr at: i - 16). v := self leftRotate: v by: 1. wordPtr at: i put: v]. interpreterProxy pop: 2. ! ! !DSAPlugin methodsFor: 'primitives-SHA' stamp: 'jm (auto pragmas 12/08) 12/21/1999 20:43'! primitiveHasSecureHashPrimitive "Answer true if the secure hash primitive is implemented." interpreterProxy pop: 1. interpreterProxy pushBool: true. ! ! !DSAPlugin methodsFor: 'primitives-SHA' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:02'! primitiveHashBlock "Hash a Bitmap of 80 32-bit words (the first argument), using the given state (the second argument)." | state buf statePtr bufPtr a b c d e tmp | state := interpreterProxy stackObjectValue: 0. buf := interpreterProxy stackObjectValue: 1. interpreterProxy success: (interpreterProxy isWords: state). interpreterProxy success: (interpreterProxy isWords: buf). interpreterProxy failed ifTrue: [^ nil]. interpreterProxy success: ((interpreterProxy stSizeOf: state) = 5). interpreterProxy success: ((interpreterProxy stSizeOf: buf) = 80). interpreterProxy failed ifTrue: [^ nil]. statePtr := interpreterProxy firstIndexableField: state. bufPtr := interpreterProxy firstIndexableField: buf. a := statePtr at: 0. b := statePtr at: 1. c := statePtr at: 2. d := statePtr at: 3. e := statePtr at: 4. 0 to: 19 do: [:i | tmp := 16r5A827999 + ((b bitAnd: c) bitOr: (b bitInvert32 bitAnd: d)) + (self leftRotate: a by: 5) + e + (bufPtr at: i). e := d. d := c. c := self leftRotate: b by: 30. b := a. a := tmp]. 20 to: 39 do: [:i | tmp := 16r6ED9EBA1 + ((b bitXor: c) bitXor: d) + (self leftRotate: a by: 5) + e + (bufPtr at: i). e := d. d := c. c := self leftRotate: b by: 30. b := a. a := tmp]. 40 to: 59 do: [:i | tmp := 16r8F1BBCDC + (((b bitAnd: c) bitOr: (b bitAnd: d)) bitOr: (c bitAnd: d)) + (self leftRotate: a by: 5) + e + (bufPtr at: i). e := d. d := c. c := self leftRotate: b by: 30. b := a. a := tmp]. 60 to: 79 do: [:i | tmp := 16rCA62C1D6 + ((b bitXor: c) bitXor: d) + (self leftRotate: a by: 5) + e + (bufPtr at: i). e := d. d := c. c := self leftRotate: b by: 30. b := a. a := tmp]. statePtr at: 0 put: (statePtr at: 0) + a. statePtr at: 1 put: (statePtr at: 1) + b. statePtr at: 2 put: (statePtr at: 2) + c. statePtr at: 3 put: (statePtr at: 3) + d. statePtr at: 4 put: (statePtr at: 4) + e. interpreterProxy pop: 2. ! ! !DSAPlugin methodsFor: 'primitives-integers' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:02'! primitiveHighestNonZeroDigitIndex "Called with one LargePositiveInteger argument. Answer the index of the top-most non-zero digit." | arg bigIntPtr i | arg := interpreterProxy stackObjectValue: 0. interpreterProxy success: (interpreterProxy fetchClassOf: arg) = interpreterProxy classLargePositiveInteger. interpreterProxy failed ifTrue: [^ nil]. bigIntPtr := interpreterProxy firstIndexableField: arg. i := interpreterProxy stSizeOf: arg. [(i > 0) and: [(bigIntPtr at: (i := i - 1)) = 0]] whileTrue: ["scan down from end to first non-zero digit"]. interpreterProxy pop: 1. interpreterProxy pushInteger: i + 1. ! ! !DSAPlugin methodsFor: 'private' stamp: 'jm 12/21/1999 08:13'! subtractDivisorMultipliedByDigit: digit digitShift: digitShift "Multiply the divisor by the given digit (an integer in the range 0..255), shift it left by the given number of digits, and subtract the result from the current remainder. Answer true if there is an excess borrow, indicating that digit was one too large. (This case is quite rare.)" | borrow rIndex prod resultDigit | borrow := 0. rIndex := digitShift + 1. 1 to: divisorDigitCount do: [:i | prod := ((dsaDivisor at: i) * digit) + borrow. borrow := prod bitShift: -8. resultDigit := (dsaRemainder at: rIndex) - (prod bitAnd: 16rFF). resultDigit < 0 ifTrue: [ "borrow from the next digit" resultDigit := resultDigit + 256. borrow := borrow + 1]. dsaRemainder at: rIndex put: resultDigit. rIndex := rIndex + 1]. "propagate the final borrow if necessary" borrow = 0 ifTrue: [^ false]. resultDigit := (dsaRemainder at: rIndex) - borrow. resultDigit < 0 ifTrue: [ "digit was too large (this case is quite rare)" dsaRemainder at: rIndex put: resultDigit + 256. ^ true] ifFalse: [ dsaRemainder at: rIndex put: resultDigit. ^ false]. ! ! InterpreterPlugin subclass: #DropPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !DropPlugin commentStamp: '' prior: 0! This class defines the necessary primitives for dropping files from the OS onto Squeak. Implementation notes: The drop support is really a two phase process. The first thing the OS code needs to do is to signal an event of type EventTypeDragDropFiles to Squeak. This event needs to include the following information (see sq.h for the definition of sqDragDropFilesEvent): * dragType: DragEnter - dragging mouse entered Squeak window DragMove - dragging mouse moved within Squeak window DragLeave - dragging mouse left Squeak window DragDrop - dropped files onto Squeak window * numFiles: The number of files in the drop operation. * x, y, modifiers: Associated mouse state. When these events are received, the primitives implemented by this plugin come into play. The two primitives can be used to either receive a list of file names or to receive a list of (read-only) file handles. Because drag and drop operations are intended to work in a restricted (plugin) environment, certain security precautions need to be taken: * Access to the contents of the files (e.g., the file streams) must only be granted after a drop occured. Simply dragging the file over the Squeak window is not enough to grant access. * Access to the contents of the files after a drop is allowed to bypass the file sandbox and create a read-only file stream directly. * Access to the names of files can be granted even if the files are only dragged over Squeak (but not dropped). This is so that appropriate user feedback can be given. If somehow possible, the support code should track the location of the drag-and-drop operation and generate appropriate DragMove type events. While not important right now, it will allow us to integrate OS DnD operations with Morphic DnD operation in a seemless manner. ! !DropPlugin class methodsFor: 'translation' stamp: 'tpr 5/23/2001 17:09'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !DropPlugin class methodsFor: 'translation' stamp: 'tpr 3/20/2001 12:15'! requiresPlatformFiles "default is ok for most, any plugin needing platform specific files must say so" ^true! ! !DropPlugin methodsFor: 'initialize' stamp: 'ar (auto pragmas 12/08) 1/10/2001 19:57'! initialiseModule ^self cCode: 'dropInit()' inSmalltalk:[true]! ! !DropPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 1/10/2001 20:46'! primitiveDropRequestFileHandle "Note: File handle creation needs to be handled by specific support code explicitly bypassing the plugin file sand box." | dropIndex handleOop | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. dropIndex := interpreterProxy stackIntegerValue: 0. handleOop := self dropRequestFileHandle: dropIndex. "dropRequestFileHandle needs to return the actual oop returned" interpreterProxy failed ifFalse:[ interpreterProxy pop: 2. interpreterProxy push: handleOop. ].! ! !DropPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 1/10/2001 20:46'! primitiveDropRequestFileName "Note: File handle creation needs to be handled by specific support code explicitly bypassing the plugin file sand box." | dropIndex dropName nameLength nameOop namePtr | interpreterProxy methodArgumentCount = 1 ifFalse:[^interpreterProxy primitiveFail]. dropIndex := interpreterProxy stackIntegerValue: 0. dropName := self dropRequestFileName: dropIndex. "dropRequestFileName returns name or NULL on error" dropName == nil ifTrue:[^interpreterProxy primitiveFail]. nameLength := self strlen: dropName. nameOop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: nameLength. namePtr := interpreterProxy firstIndexableField: nameOop. 0 to: nameLength-1 do:[:i| namePtr at: i put: (dropName at: i)]. interpreterProxy pop: 2. interpreterProxy push: nameOop. ! ! !DropPlugin methodsFor: 'primitives' stamp: 'JMM (auto pragmas 12/08) 9/15/2001 21:14'! setFileAccessCallback: address ^self cCode: 'sqSecFileAccessCallback((void *) address)'.! ! !DropPlugin methodsFor: 'initialize' stamp: 'ar (auto pragmas 12/08) 1/10/2001 19:57'! shutdownModule ^self cCode: 'dropShutdown()' inSmalltalk:[true]! ! InterpreterPlugin subclass: #FFTPlugin instanceVariableNames: 'nu fftSize sinTable sinTableSize permTable permTableSize realData realDataSize imagData imagDataSize' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !FFTPlugin commentStamp: '' prior: 0! FFTPlugin is an example of how plugins are written. It shows the use of FloatArray for heavy numerical stuff as well as the simulation of plugins from Squeak. See also: FFT pluginTransformData: ! !FFTPlugin class methodsFor: 'translation to C' stamp: 'eem 3/5/2009 13:18'! declareCVarsIn: cg cg var: #sinTable type: #'float *'. cg var: #realData type: #'float *'. cg var: #imagData type: #'float *'. cg var: #permTable type: #'unsigned int *'! ! !FFTPlugin methodsFor: 'private' stamp: 'ar (auto pragmas dtl 2010-09-27) 9/16/1998 21:40'! checkedFloatPtrOf: oop "Return the first indexable word of oop which is assumed to be variableWordSubclass" interpreterProxy success: (interpreterProxy isWords: oop). interpreterProxy failed ifTrue:[^0]. ^self cCoerce: (interpreterProxy firstIndexableField: oop) to:'float *'! ! !FFTPlugin methodsFor: 'private' stamp: 'ar (auto pragmas dtl 2010-09-27) 9/16/1998 21:40'! checkedWordPtrOf: oop "Return the first indexable word of oop which is assumed to be variableWordSubclass" interpreterProxy success: (interpreterProxy isWords: oop). ^self cCoerce: (interpreterProxy firstIndexableField: oop) to: 'unsigned int *'! ! !FFTPlugin methodsFor: 'private' stamp: 'ar 10/10/1998 21:43'! loadFFTFrom: fftOop | oop | interpreterProxy success: (interpreterProxy slotSizeOf: fftOop) >= 6. interpreterProxy failed ifTrue:[^false]. nu := interpreterProxy fetchInteger: 0 ofObject: fftOop. fftSize := interpreterProxy fetchInteger: 1 ofObject: fftOop. oop := interpreterProxy fetchPointer: 2 ofObject: fftOop. sinTableSize := interpreterProxy stSizeOf: oop. sinTable := self checkedFloatPtrOf: oop. oop := interpreterProxy fetchPointer: 3 ofObject: fftOop. permTableSize := interpreterProxy stSizeOf: oop. permTable := self checkedWordPtrOf: oop. oop := interpreterProxy fetchPointer: 4 ofObject: fftOop. realDataSize := interpreterProxy stSizeOf: oop. realData := self checkedFloatPtrOf: oop. oop := interpreterProxy fetchPointer: 5 ofObject: fftOop. imagDataSize := interpreterProxy stSizeOf: oop. imagData := self checkedFloatPtrOf: oop. "Check assumptions about sizes" interpreterProxy success: (1 << nu = fftSize) & (fftSize // 4 + 1 = sinTableSize) & (fftSize = realDataSize) & (fftSize = imagDataSize) & (realDataSize = imagDataSize). ^interpreterProxy failed == false! ! !FFTPlugin methodsFor: 'transforming' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:05'! permuteData | i end a b tmp | i := 0. end := permTableSize. [i < end] whileTrue: [a := (permTable at: i) - 1. b := (permTable at: i+1) - 1. (a < realDataSize and:[b < realDataSize]) ifFalse:[^interpreterProxy success: false]. tmp := realData at: a. realData at: a put: (realData at: b). realData at: b put: tmp. tmp := imagData at: a. imagData at: a put: (imagData at: b). imagData at: b put: tmp. i := i + 2]! ! !FFTPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 10/11/1998 01:59'! primitiveFFTPermuteData | rcvr | rcvr := interpreterProxy stackObjectValue: 0. (self loadFFTFrom: rcvr) ifFalse:[^nil]. self permuteData. interpreterProxy failed ifTrue:[ "permuteData went wrong. Do the permutation again -- this will restore the original order" self permuteData].! ! !FFTPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 10/11/1998 01:59'! primitiveFFTScaleData | rcvr | rcvr := interpreterProxy stackObjectValue: 0. (self loadFFTFrom: rcvr) ifFalse:[^nil]. self scaleData.! ! !FFTPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 10/11/1998 01:59'! primitiveFFTTransformData | rcvr forward | forward := interpreterProxy booleanValueOf: (interpreterProxy stackValue: 0). rcvr := interpreterProxy stackObjectValue: 1. (self loadFFTFrom: rcvr) ifFalse:[^nil]. self transformData: forward. interpreterProxy failed ifFalse:[ interpreterProxy pop: 1. "Leave rcvr on stack" ].! ! !FFTPlugin methodsFor: 'transforming' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:05'! scaleData "Scale all elements by 1/n when doing inverse" | realN | fftSize <= 1 ifTrue:[^nil]. realN := self cCoerce: (1.0 / (self cCoerce: fftSize to: 'double')) to: 'float'. 0 to: fftSize-1 do: [:i | realData at: i put: (realData at: i) * realN. imagData at: i put: (imagData at: i) * realN]! ! !FFTPlugin methodsFor: 'transforming' stamp: 'ar 9/16/1998 20:21'! transformData: forward self permuteData. interpreterProxy failed ifTrue:[ "permuteData went wrong. Do the permutation again -- this will restore the original order" self permuteData. ^nil]. self transformForward: forward. forward ifFalse: [self scaleData] "Reverse transform must scale to be an inverse"! ! !FFTPlugin methodsFor: 'transforming' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:06'! transformForward: forward | lev lev1 ip theta realU imagU realT imagT i fftSize2 fftSize4 fftScale ii | fftSize2 := fftSize // 2. fftSize4 := fftSize // 4. 1 to: nu do: [:level | lev := 1 bitShift: level. lev1 := lev // 2. fftScale := fftSize // lev. 1 to: lev1 do: [:j | theta := j-1 * fftScale. "pi * (j-1) / lev1 mapped onto 0..n/2" theta < fftSize4 "Compute U, the complex multiplier for each level" ifTrue: [realU := sinTable at: sinTableSize - theta - 1. imagU := sinTable at: theta] ifFalse: [realU := 0.0 - (sinTable at: theta - fftSize4). imagU := sinTable at: fftSize2 - theta]. forward ifFalse: [imagU := 0.0 - imagU]. " Here is the inner loop... j to: n by: lev do: [:i | hand-transformed to whileTrue... " i := j. [i <= fftSize] whileTrue: [ip := i + lev1 - 1. ii := i-1. realT := ((realData at: ip) * realU) - ((imagData at: ip) * imagU). imagT := ((realData at: ip) * imagU) + ((imagData at: ip) * realU). realData at: ip put: (realData at: ii) - realT. imagData at: ip put: (imagData at: ii) - imagT. realData at: ii put: (realData at: ii) + realT. imagData at: ii put: (imagData at: ii) + imagT. i := i + lev]]].! ! InterpreterPlugin subclass: #FilePlugin instanceVariableNames: 'sCCPfn sCDPfn sCGFTfn sCLPfn sCSFTfn sDFAfn sCDFfn sCOFfn sCRFfn sHFAfn' classVariableNames: 'DirBadPath DirEntryFound DirNoMoreEntries' poolDictionaries: '' category: 'VMMaker-Plugins'! !FilePlugin commentStamp: 'tpr 5/5/2003 12:01' prior: 0! Provide access to the host machine file system. Requires both the Cross platform support files from platforms - Cross - plugins - FilePlugin (or some suitable replacement) and the platform specific fils from platforms - {your platform} - plugins - FilePlugin.! !FilePlugin class methodsFor: 'translation' stamp: 'ikp 6/14/2004 13:52'! declareCVarsIn: aCCodeGenerator aCCodeGenerator var: 'sCCPfn' type: 'void *'. aCCodeGenerator var: 'sCDPfn' type: 'void *'. aCCodeGenerator var: 'sCGFTfn' type: 'void *'. aCCodeGenerator var: 'sCLPfn' type: 'void *'. aCCodeGenerator var: 'sCSFTfn' type: 'void *'. aCCodeGenerator var: 'sDFAfn' type: 'void *'. aCCodeGenerator var: 'sCDFfn' type: 'void *'. aCCodeGenerator var: 'sCOFfn' type: 'void *'. aCCodeGenerator var: 'sCRFfn' type: 'void *'. aCCodeGenerator var: 'sHFAfn' type: 'void *'. aCCodeGenerator addHeaderFile: '"FilePlugin.h"'! ! !FilePlugin class methodsFor: 'translation' stamp: 'tpr 5/23/2001 17:09'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !FilePlugin class methodsFor: 'class initialization' stamp: 'ar 5/12/2000 16:04'! initialize "FilePlugin initialize" DirEntryFound := 0. DirNoMoreEntries := 1. DirBadPath := 2.! ! !FilePlugin class methodsFor: 'translation' stamp: 'tpr 7/4/2001 15:12'! requiresCrossPlatformFiles "this plugin requires cross platform files in order to work" ^true! ! !FilePlugin class methodsFor: 'translation' stamp: 'tpr 11/29/2000 22:37'! requiresPlatformFiles "this plugin requires platform specific files in order to work" ^true! ! !FilePlugin class methodsFor: 'instance creation' stamp: 'ar 5/11/2000 22:13'! simulatorClass ^FilePluginSimulator! ! !FilePlugin methodsFor: 'directory primitives' stamp: 'ar 5/11/2000 21:31'! asciiDirectoryDelimiter ^ self cCode: 'dir_Delimitor()' inSmalltalk: [FileDirectory pathNameDelimiter asciiValue]! ! !FilePlugin methodsFor: 'file primitives' stamp: 'tpr (auto pragmas 12/08) 12/30/2005 15:23'! fileOpenName: nameIndex size: nameSize write: writeFlag secure: secureFlag "Open the named file, possibly checking security. Answer the file oop." | file fileOop okToOpen | fileOop := interpreterProxy instantiateClass: interpreterProxy classByteArray indexableSize: self fileRecordSize. file := self fileValueOf: fileOop. interpreterProxy failed ifFalse: [ secureFlag ifTrue: [ "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCOFfn ~= 0 ifTrue: [okToOpen := self cCode: '((sqInt (*) (char *, sqInt, sqInt)) sCOFfn)(nameIndex, nameSize, writeFlag)' inSmalltalk:[true]. okToOpen ifFalse: [interpreterProxy primitiveFail]]]]. interpreterProxy failed ifFalse: [self cCode: 'sqFileOpen(file, nameIndex, nameSize, writeFlag)' inSmalltalk: [file]]. ^ fileOop! ! !FilePlugin methodsFor: 'file primitives' stamp: 'eem 2/10/2009 13:42'! fileRecordSize "Return the size of a Smalltalk file record in bytes." ^ self cCode: 'sizeof(SQFile)'.! ! !FilePlugin methodsFor: 'file primitives' stamp: 'eem 2/10/2009 13:42'! fileValueOf: objectPointer "Return a pointer to the first byte of of the file record within the given Smalltalk object, or nil if objectPointer is not a file record." (((interpreterProxy isBytes: objectPointer) and: [(interpreterProxy byteSizeOf: objectPointer) = self fileRecordSize])) ifFalse:[interpreterProxy primitiveFail. ^nil]. ^interpreterProxy firstIndexableField: objectPointer! ! !FilePlugin methodsFor: 'file primitives' stamp: 'tpr (auto pragmas 12/08) 12/21/2005 19:06'! getThisSession "Exported entry point for the VM. Only used by AsynchFilePlugin and needs to be reowrked now we have a VM global session Id capability" ^self cCode: 'sqFileThisSession()'.! ! !FilePlugin methodsFor: 'initialize-release' stamp: 'JMM (auto pragmas 12/08) 1/21/2002 11:02'! initialiseModule sCCPfn := interpreterProxy ioLoadFunction: 'secCanCreatePathOfSize' From: 'SecurityPlugin'. sCDPfn := interpreterProxy ioLoadFunction: 'secCanDeletePathOfSize' From: 'SecurityPlugin'. sCGFTfn := interpreterProxy ioLoadFunction: 'secCanGetFileTypeOfSize' From: 'SecurityPlugin'. sCLPfn := interpreterProxy ioLoadFunction: 'secCanListPathOfSize' From: 'SecurityPlugin'. sCSFTfn := interpreterProxy ioLoadFunction: 'secCanSetFileTypeOfSize' From: 'SecurityPlugin'. sDFAfn := interpreterProxy ioLoadFunction: 'secDisableFileAccess' From: 'SecurityPlugin'. sCDFfn := interpreterProxy ioLoadFunction: 'secCanDeleteFileOfSize' From: 'SecurityPlugin'. sCOFfn := interpreterProxy ioLoadFunction: 'secCanOpenFileOfSizeWritable' From: 'SecurityPlugin'. sCRFfn := interpreterProxy ioLoadFunction: 'secCanRenameFileOfSize' From: 'SecurityPlugin'. sHFAfn := interpreterProxy ioLoadFunction: 'secHasFileAccess' From: 'SecurityPlugin'. ^self cCode: 'sqFileInit()' inSmalltalk:[true]! ! !FilePlugin methodsFor: 'directory primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:06'! makeDirEntryName: entryName size: entryNameSize createDate: createDate modDate: modifiedDate isDir: dirFlag fileSize: fileSize | modDateOop createDateOop nameString results stringPtr fileSizeOop | "allocate storage for results, remapping newly allocated oops in case GC happens during allocation" interpreterProxy pushRemappableOop: (interpreterProxy instantiateClass: (interpreterProxy classArray) indexableSize: 5). interpreterProxy pushRemappableOop: (interpreterProxy instantiateClass: (interpreterProxy classString) indexableSize: entryNameSize).. interpreterProxy pushRemappableOop: (interpreterProxy positive32BitIntegerFor: createDate). interpreterProxy pushRemappableOop: (interpreterProxy positive32BitIntegerFor: modifiedDate). interpreterProxy pushRemappableOop: (interpreterProxy positive64BitIntegerFor: fileSize). fileSizeOop := interpreterProxy popRemappableOop. modDateOop := interpreterProxy popRemappableOop. createDateOop := interpreterProxy popRemappableOop. nameString := interpreterProxy popRemappableOop. results := interpreterProxy popRemappableOop. "copy name into Smalltalk string" stringPtr := interpreterProxy firstIndexableField: nameString. 0 to: entryNameSize - 1 do: [ :i | stringPtr at: i put: (entryName at: i). ]. interpreterProxy storePointer: 0 ofObject: results withValue: nameString. interpreterProxy storePointer: 1 ofObject: results withValue: createDateOop. interpreterProxy storePointer: 2 ofObject: results withValue: modDateOop. dirFlag ifTrue: [ interpreterProxy storePointer: 3 ofObject: results withValue: interpreterProxy trueObject ] ifFalse: [ interpreterProxy storePointer: 3 ofObject: results withValue: interpreterProxy falseObject ]. interpreterProxy storePointer: 4 ofObject: results withValue: fileSizeOop. ^ results! ! !FilePlugin methodsFor: 'initialize-release' stamp: 'JMM (auto pragmas 12/08) 1/21/2002 11:03'! moduleUnloaded: aModuleName "The module with the given name was just unloaded. Make sure we have no dangling references." (aModuleName strcmp: 'SecurityPlugin') = 0 ifTrue:[ "The security plugin just shut down. How odd." sCCPfn := sCDPfn := sCGFTfn := sCLPfn := sCSFTfn := sDFAfn := sCDFfn := sCOFfn := sCRFfn := sHFAfn := 0. ].! ! !FilePlugin methodsFor: 'directory primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:50'! primitiveDirectoryCreate | dirName dirNameIndex dirNameSize okToCreate | dirName := interpreterProxy stackValue: 0. (interpreterProxy isBytes: dirName) ifFalse: [^interpreterProxy primitiveFail]. dirNameIndex := interpreterProxy firstIndexableField: dirName. dirNameSize := interpreterProxy byteSizeOf: dirName. "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCCPfn ~= 0 ifTrue: [okToCreate := self cCode: ' ((sqInt (*)(char *, sqInt))sCCPfn)(dirNameIndex, dirNameSize)'. okToCreate ifFalse: [^interpreterProxy primitiveFail]]. (self cCode: 'dir_Create(dirNameIndex, dirNameSize)' inSmalltalk: [false]) ifFalse: [^interpreterProxy primitiveFail]. interpreterProxy pop: 1! ! !FilePlugin methodsFor: 'directory primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:49'! primitiveDirectoryDelete | dirName dirNameIndex dirNameSize okToDelete | dirName := interpreterProxy stackValue: 0. (interpreterProxy isBytes: dirName) ifFalse: [^interpreterProxy primitiveFail]. dirNameIndex := interpreterProxy firstIndexableField: dirName. dirNameSize := interpreterProxy byteSizeOf: dirName. "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCDPfn ~= 0 ifTrue: [okToDelete := self cCode: ' ((sqInt (*)(char *, sqInt))sCDPfn)(dirNameIndex, dirNameSize)'. okToDelete ifFalse: [^interpreterProxy primitiveFail]]. (self cCode: 'dir_Delete(dirNameIndex, dirNameSize)' inSmalltalk: [false]) ifFalse: [^interpreterProxy primitiveFail]. interpreterProxy pop: 1! ! !FilePlugin methodsFor: 'directory primitives' stamp: 'eem 6/22/2010 11:11'! primitiveDirectoryDelimitor | ascii | ascii := self asciiDirectoryDelimiter. ((ascii >= 0) and: [ascii <= 255]) ifFalse: [^interpreterProxy primitiveFail]. interpreterProxy pop: 1 thenPush: (interpreterProxy fetchPointer: ascii ofObject: (interpreterProxy characterTable))! ! !FilePlugin methodsFor: 'directory primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:50'! primitiveDirectoryGetMacTypeAndCreator | creatorString typeString fileName creatorStringIndex typeStringIndex fileNameIndex fileNameSize okToGet | creatorString := interpreterProxy stackValue: 0. typeString := interpreterProxy stackValue: 1. fileName := interpreterProxy stackValue: 2. ((interpreterProxy isBytes: creatorString) and: [(interpreterProxy byteSizeOf: creatorString) = 4]) ifFalse: [^interpreterProxy primitiveFail]. ((interpreterProxy isBytes: typeString) and: [(interpreterProxy byteSizeOf: typeString) = 4]) ifFalse: [^interpreterProxy primitiveFail]. (interpreterProxy isBytes: fileName) ifFalse: [^interpreterProxy primitiveFail]. creatorStringIndex := interpreterProxy firstIndexableField: creatorString. typeStringIndex := interpreterProxy firstIndexableField: typeString. fileNameIndex := interpreterProxy firstIndexableField: fileName. fileNameSize := interpreterProxy byteSizeOf: fileName. "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCGFTfn ~= 0 ifTrue: [okToGet := self cCode: ' ((sqInt (*)(char *, sqInt))sCGFTfn)(fileNameIndex, fileNameSize)'. okToGet ifFalse: [^interpreterProxy primitiveFail]]. (self cCode: 'dir_GetMacFileTypeAndCreator(fileNameIndex, fileNameSize, typeStringIndex, creatorStringIndex)' inSmalltalk: [true]) ifFalse: [^interpreterProxy primitiveFail]. interpreterProxy pop: 3! ! !FilePlugin methodsFor: 'directory primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:50'! primitiveDirectoryLookup | index pathName pathNameIndex pathNameSize status entryName entryNameSize createDate modifiedDate dirFlag fileSize okToList | index := interpreterProxy stackIntegerValue: 0. pathName := interpreterProxy stackValue: 1. (interpreterProxy isBytes: pathName) ifFalse: [^interpreterProxy primitiveFail]. pathNameIndex := interpreterProxy firstIndexableField: pathName. pathNameSize := interpreterProxy byteSizeOf: pathName. "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCLPfn ~= 0 ifTrue: [okToList := self cCode: '((sqInt (*)(char *, sqInt))sCLPfn)(pathNameIndex, pathNameSize)'] ifFalse: [okToList := true]. okToList ifTrue: [status := self cCode: 'dir_Lookup(pathNameIndex, pathNameSize, index, entryName, &entryNameSize, &createDate, &modifiedDate, &dirFlag, &fileSize)'] ifFalse: [status := DirNoMoreEntries]. interpreterProxy failed ifTrue: [^nil]. status = DirNoMoreEntries ifTrue: ["no more entries; return nil" interpreterProxy pop: 3 "pop pathName, index, rcvr" thenPush: interpreterProxy nilObject. ^nil]. status = DirBadPath ifTrue: [^interpreterProxy primitiveFail]."bad path" interpreterProxy pop: 3 "pop pathName, index, rcvr" thenPush: (self makeDirEntryName: entryName size: entryNameSize createDate: createDate modDate: modifiedDate isDir: dirFlag fileSize: fileSize)! ! !FilePlugin methodsFor: 'directory primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:51'! primitiveDirectorySetMacTypeAndCreator | creatorString typeString fileName creatorStringIndex typeStringIndex fileNameIndex fileNameSize okToSet | creatorString := interpreterProxy stackValue: 0. typeString := interpreterProxy stackValue: 1. fileName := interpreterProxy stackValue: 2. ((interpreterProxy isBytes: creatorString) and: [(interpreterProxy byteSizeOf: creatorString) = 4]) ifFalse: [^interpreterProxy primitiveFail]. ((interpreterProxy isBytes: typeString) and: [(interpreterProxy byteSizeOf: typeString) = 4]) ifFalse: [^interpreterProxy primitiveFail]. (interpreterProxy isBytes: fileName) ifFalse: [^interpreterProxy primitiveFail]. creatorStringIndex := interpreterProxy firstIndexableField: creatorString. typeStringIndex := interpreterProxy firstIndexableField: typeString. fileNameIndex := interpreterProxy firstIndexableField: fileName. fileNameSize := interpreterProxy byteSizeOf: fileName. "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCSFTfn ~= 0 ifTrue: [okToSet := self cCode: ' ((sqInt (*)(char *, sqInt))sCSFTfn)(fileNameIndex, fileNameSize)'. okToSet ifFalse: [^interpreterProxy primitiveFail]]. (self cCode: 'dir_SetMacFileTypeAndCreator(fileNameIndex, fileNameSize,typeStringIndex, creatorStringIndex)' inSmalltalk: [true]) ifFalse: [^interpreterProxy primitiveFail]. interpreterProxy pop: 3! ! !FilePlugin methodsFor: 'security primitives' stamp: 'John M McIntosh (auto pragmas dtl 2010-09-27) 5/5/2009 10:56'! primitiveDisableFileAccess "If the security plugin can be loaded, use it to turn off file access If not, assume it's ok" sDFAfn ~= 0 ifTrue: [self cCode: ' ((sqInt (*)(void))sDFAfn)()']. ! ! !FilePlugin methodsFor: 'file primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:07'! primitiveFileAtEnd | file atEnd | file := self fileValueOf: (interpreterProxy stackValue: 0). interpreterProxy failed ifFalse: [atEnd := self sqFileAtEnd: file]. interpreterProxy failed ifFalse: [interpreterProxy pop: 2. "rcvr, file" interpreterProxy pushBool: atEnd]! ! !FilePlugin methodsFor: 'file primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:08'! primitiveFileClose | file | file := self fileValueOf: (interpreterProxy stackValue: 0). interpreterProxy failed ifFalse: [ self sqFileClose: file ]. interpreterProxy failed ifFalse: [ interpreterProxy pop: 1 "pop file; leave rcvr on stack" ].! ! !FilePlugin methodsFor: 'file primitives' stamp: 'tpr (auto pragmas 12/08) 12/30/2005 16:42'! primitiveFileDelete | namePointer nameIndex nameSize okToDelete | namePointer := interpreterProxy stackValue: 0. (interpreterProxy isBytes: namePointer) ifFalse: [^ interpreterProxy primitiveFail]. nameIndex := interpreterProxy firstIndexableField: namePointer. nameSize := interpreterProxy byteSizeOf: namePointer. "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCDFfn ~= 0 ifTrue: [okToDelete := self cCode: ' ((sqInt (*)(char *, sqInt))sCDFfn)(nameIndex, nameSize)'. okToDelete ifFalse: [^ interpreterProxy primitiveFail]]. self sqFileDeleteName: nameIndex Size: nameSize. interpreterProxy failed ifFalse: [interpreterProxy pop: 1]! ! !FilePlugin methodsFor: 'file primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:08'! primitiveFileFlush | file | file := self fileValueOf: (interpreterProxy stackValue: 0). interpreterProxy failed ifFalse:[self sqFileFlush: file]. interpreterProxy failed ifFalse: [interpreterProxy pop: 1].! ! !FilePlugin methodsFor: 'file primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:14'! primitiveFileGetPosition | file position | file := self fileValueOf: (interpreterProxy stackValue: 0). interpreterProxy failed ifFalse: [position := self sqFileGetPosition: file]. interpreterProxy failed ifFalse: [ interpreterProxy pop: 2 thenPush: (interpreterProxy positive64BitIntegerFor: position)].! ! !FilePlugin methodsFor: 'file primitives' stamp: 'tpr (auto pragmas 12/08) 12/30/2005 15:22'! primitiveFileOpen | writeFlag namePointer filePointer nameIndex nameSize | writeFlag := interpreterProxy booleanValueOf: (interpreterProxy stackValue: 0). namePointer := interpreterProxy stackValue: 1. (interpreterProxy isBytes: namePointer) ifFalse: [^ interpreterProxy primitiveFail]. nameIndex := interpreterProxy firstIndexableField: namePointer. nameSize := interpreterProxy byteSizeOf: namePointer. filePointer := self fileOpenName: nameIndex size: nameSize write: writeFlag secure: true. interpreterProxy failed ifFalse: [interpreterProxy pop: 3 "rcvr, name, writeFlag" thenPush: filePointer] ! ! !FilePlugin methodsFor: 'file primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:49'! primitiveFileRead | count startIndex array file byteSize arrayIndex bytesRead | count := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). startIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 1). array := interpreterProxy stackValue: 2. file := self fileValueOf: (interpreterProxy stackValue: 3). "buffer can be any indexable words or bytes object except CompiledMethod" (interpreterProxy isWordsOrBytes: array) ifFalse: [^interpreterProxy primitiveFail]. (interpreterProxy isWords: array) ifTrue: [byteSize := 4] ifFalse: [byteSize := 1]. ((startIndex >= 1) and: [(startIndex + count - 1) <= (interpreterProxy slotSizeOf: array)]) ifFalse: [^interpreterProxy primitiveFail]. arrayIndex := interpreterProxy firstIndexableField: array. "Note: adjust startIndex for zero-origin indexing" bytesRead := self sqFile: file Read: (count * byteSize) Into: arrayIndex At: ((startIndex - 1) * byteSize). interpreterProxy failed ifFalse: [ interpreterProxy pop: 5 "pop rcvr, file, array, startIndex, count" thenPush:(interpreterProxy integerObjectOf: bytesRead // byteSize). "push # of elements read"].! ! !FilePlugin methodsFor: 'file primitives' stamp: 'tpr (auto pragmas 12/08) 12/30/2005 15:31'! primitiveFileRename | oldNamePointer newNamePointer oldNameIndex oldNameSize newNameIndex newNameSize okToRename | newNamePointer := interpreterProxy stackValue: 0. oldNamePointer := interpreterProxy stackValue: 1. ((interpreterProxy isBytes: newNamePointer) and: [interpreterProxy isBytes: oldNamePointer]) ifFalse: [^interpreterProxy primitiveFail]. newNameIndex := interpreterProxy firstIndexableField: newNamePointer. newNameSize := interpreterProxy byteSizeOf: newNamePointer. oldNameIndex := interpreterProxy firstIndexableField: oldNamePointer. oldNameSize := interpreterProxy byteSizeOf: oldNamePointer. "If the security plugin can be loaded, use it to check for rename permission. If not, assume it's ok" sCRFfn ~= 0 ifTrue: [okToRename := self cCode: ' ((sqInt (*)(char *, sqInt))sCRFfn)(oldNameIndex, oldNameSize)'. okToRename ifFalse: [^interpreterProxy primitiveFail]]. self sqFileRenameOld: oldNameIndex Size: oldNameSize New: newNameIndex Size: newNameSize. interpreterProxy failed ifFalse: [interpreterProxy pop: 2]! ! !FilePlugin methodsFor: 'file primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:09'! primitiveFileSetPosition | newPosition file sz | (interpreterProxy isIntegerObject: (interpreterProxy stackValue: 0)) ifFalse: [sz := self cCode: 'sizeof(squeakFileOffsetType)'. (interpreterProxy byteSizeOf: (interpreterProxy stackValue: 0)) > sz ifTrue: [^interpreterProxy primitiveFail]]. newPosition := interpreterProxy positive64BitValueOf: (interpreterProxy stackValue: 0). file := self fileValueOf: (interpreterProxy stackValue: 1). interpreterProxy failed ifFalse:[ self sqFile: file SetPosition: newPosition ]. interpreterProxy failed ifFalse:[ interpreterProxy pop: 2 "pop position, file; leave rcvr on stack" ].! ! !FilePlugin methodsFor: 'file primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:15'! primitiveFileSize | file size | file := self fileValueOf: (interpreterProxy stackValue: 0). interpreterProxy failed ifFalse:[size := self sqFileSize: file]. interpreterProxy failed ifFalse: [ interpreterProxy pop: 2 thenPush: (interpreterProxy positive64BitIntegerFor: size)].! ! !FilePlugin methodsFor: 'file primitives' stamp: 'dtl 12/26/2010 17:31'! primitiveFileStdioHandles "Answer an Array of file handles for standard in, standard out and standard error, with nil in entries that are unvailable, e.g. because the platform does not provide standard error, etc. Fail if there are no standard i/o facilities on the platform or if the security plugin denies access or if memory runs out." | fileRecords result validMask | sHFAfn ~= 0 ifTrue: [(self cCode: ' ((sqInt (*)(void))sHFAfn)()' inSmalltalk: [true]) ifFalse: [^interpreterProxy primitiveFail]]. validMask := self sqFileStdioHandlesInto: (self addressOf: fileRecords). validMask = 0 ifTrue: [^interpreterProxy primitiveFail]. result := interpreterProxy instantiateClass: interpreterProxy classArray indexableSize: 3. result = nil ifTrue: [^interpreterProxy primitiveFail]. interpreterProxy pushRemappableOop: result. 0 to: 2 do: [:index| | r | (validMask bitAnd: (1 << index)) ~= 0 ifTrue: [result := interpreterProxy instantiateClass: interpreterProxy classByteArray indexableSize: self fileRecordSize. result = nil ifTrue: [interpreterProxy popRemappableOop. ^interpreterProxy primitiveFail]. r := interpreterProxy popRemappableOop. interpreterProxy storePointer: index ofObject: r withValue: result. interpreterProxy pushRemappableOop: r. self mem: (interpreterProxy firstIndexableField: result) cp: (self addressOf: (fileRecords at: index)) y: self fileRecordSize]]. result := interpreterProxy popRemappableOop. interpreterProxy pop: 1 thenPush: result! ! !FilePlugin methodsFor: 'file primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:16'! primitiveFileTruncate "ftruncate is not an ansi function so we have a macro to point to a suitable platform implementation" | truncatePosition file sz | (interpreterProxy isIntegerObject: (interpreterProxy stackValue: 0)) ifFalse: [sz := self cCode: 'sizeof(squeakFileOffsetType)'. (interpreterProxy byteSizeOf: (interpreterProxy stackValue: 0)) > sz ifTrue: [^ interpreterProxy primitiveFail]]. truncatePosition := interpreterProxy positive64BitValueOf: (interpreterProxy stackValue: 0). file := self fileValueOf: (interpreterProxy stackValue: 1). interpreterProxy failed ifFalse: [self sqFile: file Truncate: truncatePosition]. interpreterProxy failed ifFalse: [interpreterProxy pop: 2 "pop position, file; leave rcvr on stack"]! ! !FilePlugin methodsFor: 'file primitives' stamp: 'tpr (auto pragmas 12/08) 12/30/2005 15:34'! primitiveFileWrite | count startIndex array file byteSize arrayIndex bytesWritten | count := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). startIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 1). array := interpreterProxy stackValue: 2. file := self fileValueOf: (interpreterProxy stackValue: 3). "buffer can be any indexable words or bytes object except CompiledMethod " (interpreterProxy isWordsOrBytes: array) ifFalse: [^ interpreterProxy primitiveFail]. (interpreterProxy isWords: array) ifTrue: [byteSize := 4] ifFalse: [byteSize := 1]. (startIndex >= 1 and: [startIndex + count - 1 <= (interpreterProxy slotSizeOf: array)]) ifFalse: [^ interpreterProxy primitiveFail]. interpreterProxy failed ifFalse: [arrayIndex := interpreterProxy firstIndexableField: array. "Note: adjust startIndex for zero-origin indexing" bytesWritten := self sqFile: file Write: count * byteSize From: arrayIndex At: startIndex - 1 * byteSize]. interpreterProxy failed ifFalse: [interpreterProxy pop: 5 thenPush:( interpreterProxy integerObjectOf: bytesWritten // byteSize)]! ! !FilePlugin methodsFor: 'security primitives' stamp: 'tpr (auto pragmas 12/08) 12/30/2005 15:41'! primitiveHasFileAccess | hasAccess | "If the security plugin can be loaded, use it to check . If not, assume it's ok" sHFAfn ~= 0 ifTrue: [hasAccess := self cCode: ' ((sqInt (*)(void))sHFAfn)()' inSmalltalk: [true]] ifFalse: [hasAccess := true]. interpreterProxy pop: 1. interpreterProxy pushBool: hasAccess! ! !FilePlugin methodsFor: 'file primitives' stamp: 'ar (auto pragmas 12/08) 5/13/2000 14:51'! setMacFile: fileName Type: typeString AndCreator: creatorString "Exported entry point for the VM. Needed for image saving only and no-op on anything but Macs." ^self cCode: 'dir_SetMacFileTypeAndCreator(fileName, strlen(fileName), typeString, creatorString)'.! ! !FilePlugin methodsFor: 'initialize-release' stamp: 'ar (auto pragmas 12/08) 5/12/2000 16:54'! shutdownModule ^self cCode: 'sqFileShutdown()' inSmalltalk:[true]! ! FilePlugin subclass: #FilePluginSimulator instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-InterpreterSimulation'! !FilePluginSimulator commentStamp: 'tpr 5/5/2003 12:02' prior: 0! File plugin simulation for the VM simulator! !FilePluginSimulator class methodsFor: 'translation' stamp: 'tpr 5/14/2001 12:34'! shouldBeTranslated "This class should not be translated" ^false! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 5/11/2000 22:10'! fileValueOf: objectPointer ^interpreterProxy fileValueOf: objectPointer! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 19:23'! ioCanCreatePath: dirNameIndex OfSize: dirNameSize "Return true if we're allowed to create a directory with the given name" ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:16'! ioCanDeleteFile: nameIndex OfSize: nameSize "Return true if we're allowed to delete the file with the given name" ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:16'! ioCanDeletePath: dirNameIndex OfSize: dirNameSize "Return true if we're allowed to delete the directory with the given name" ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:16'! ioCanGetFileType: fileNameIndex OfSize: fileNameSize "Return true if we're allowed to retrieve the (mac) file type of the given file." ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:17'! ioCanListPath: pathNameIndex OfSize: pathNameSize "Return true if we're allowed to list the contents of the given directory" ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:17'! ioCanOpenFile: nameIndex OfSize: nameSize Writable: writeFlag "Return true if we're allowed to open the given file (possibly in write mode)" ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:17'! ioCanRenameFile: oldNameIndex OfSize: oldNameSize "Return true if we're allowed to rename the given file" ^true! ! !FilePluginSimulator methodsFor: 'file security' stamp: 'ar 2/5/2001 18:18'! ioCanSetFileType: fileNameIndex OfSize: fileNameSize "Return true if we're allowed to set the (mac) file type and creator on the given file" ^true! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 5/11/2000 22:11'! makeDirEntryName: entryName size: entryNameSize createDate: createDate modDate: modifiedDate isDir: dirFlag fileSize: fileSize ^interpreterProxy makeDirEntryName: entryName size: entryNameSize createDate: createDate modDate: modifiedDate isDir: dirFlag fileSize: fileSize ! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'di 6/23/2004 14:18'! oopForPointer: pointer "This gets implemented by Macros in C, where its types will also be checked. oop is the width of a machine word, and pointer is a raw address." ^ pointer! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 5/11/2000 22:11'! primitiveDirectoryLookup ^interpreterProxy primitiveDirectoryLookup! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 5/11/2000 22:12'! primitiveFileDelete ^interpreterProxy primitiveFileDelete ! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 5/11/2000 22:12'! primitiveFileOpen ^interpreterProxy primitiveFileOpen! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 5/11/2000 22:12'! primitiveFileRename ^interpreterProxy primitiveFileRename! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 5/11/2000 22:09'! sqFile: file Read: count Into: byteArrayIndex At: startIndex ^interpreterProxy sqFile: file Read: count Into: byteArrayIndex At: startIndex! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 5/11/2000 22:09'! sqFile: file SetPosition: newPosition ^interpreterProxy sqFile: file SetPosition: newPosition! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'JMM 5/24/2001 21:58'! sqFile: file Truncate: truncatePosition ^interpreterProxy sqFile: file Truncate: truncatePosition! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 5/11/2000 22:09'! sqFile: file Write: count From: byteArrayIndex At: startIndex ^interpreterProxy sqFile: file Write: count From: byteArrayIndex At: startIndex! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 5/11/2000 22:09'! sqFileAtEnd: file ^interpreterProxy sqFileAtEnd: file! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 5/11/2000 22:09'! sqFileClose: file ^interpreterProxy sqFileClose: file! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 2/6/2001 17:54'! sqFileFlush: file ^interpreterProxy sqFileFlush: file! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 5/11/2000 22:10'! sqFileGetPosition: file ^interpreterProxy sqFileGetPosition: file! ! !FilePluginSimulator methodsFor: 'simulation' stamp: 'ar 5/11/2000 22:10'! sqFileSize: file ^interpreterProxy sqFileSize: file! ! InterpreterPlugin subclass: #FloatArrayPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !FloatArrayPlugin commentStamp: 'tpr 5/2/2003 15:42' prior: 0! FloatArrayPlugin provides fast access to FloatArrays for batch processing of float numbers! !FloatArrayPlugin class methodsFor: 'translation to C' stamp: 'ar 9/15/1998 00:30'! declareCVarsIn: cg "Nothing to declare..."! ! !FloatArrayPlugin methodsFor: 'arithmetic primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:18'! primitiveAddFloatArray "Primitive. Add the receiver and the argument, both FloatArrays and store the result into the receiver." | rcvr arg rcvrPtr argPtr length | arg := interpreterProxy stackObjectValue: 0. rcvr := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. interpreterProxy success: (interpreterProxy isWords: arg). interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy failed ifTrue:[^nil]. length := interpreterProxy stSizeOf: arg. interpreterProxy success: (length = (interpreterProxy stSizeOf: rcvr)). interpreterProxy failed ifTrue:[^nil]. rcvrPtr := self cCoerce: (interpreterProxy firstIndexableField: rcvr) to: 'float *'. argPtr := self cCoerce: (interpreterProxy firstIndexableField: arg) to: 'float *'. 0 to: length-1 do:[:i| rcvrPtr at: i put: (rcvrPtr at: i) + (argPtr at: i)]. interpreterProxy pop: 1. "Leave rcvr on stack"! ! !FloatArrayPlugin methodsFor: 'arithmetic primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:18'! primitiveAddScalar "Primitive. Add the argument, a scalar value to the receiver, a FloatArray" | rcvr rcvrPtr value length | value := interpreterProxy stackFloatValue: 0. rcvr := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy failed ifTrue:[^nil]. length := interpreterProxy stSizeOf: rcvr. rcvrPtr := self cCoerce: (interpreterProxy firstIndexableField: rcvr) to: 'float *'. 0 to: length-1 do:[:i| rcvrPtr at: i put: (rcvrPtr at: i) + value]. interpreterProxy pop: 1. "Leave rcvr on stack"! ! !FloatArrayPlugin methodsFor: 'access primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:19'! primitiveAt | index rcvr floatValue floatPtr | index := interpreterProxy stackIntegerValue: 0. rcvr := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy success: (index > 0 and:[index <= (interpreterProxy slotSizeOf: rcvr)]). interpreterProxy failed ifTrue:[^nil]. floatPtr := interpreterProxy firstIndexableField: rcvr. floatValue := (floatPtr at: index-1) asFloat. interpreterProxy pop: 2. interpreterProxy pushFloat: floatValue.! ! !FloatArrayPlugin methodsFor: 'access primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:19'! primitiveAtPut | value floatValue index rcvr floatPtr | value := interpreterProxy stackValue: 0. (interpreterProxy isIntegerObject: value) ifTrue:[floatValue := (interpreterProxy integerValueOf: value) asFloat] ifFalse:[floatValue := interpreterProxy floatValueOf: value]. index := interpreterProxy stackIntegerValue: 1. rcvr := interpreterProxy stackObjectValue: 2. interpreterProxy failed ifTrue:[^nil]. interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy success: (index > 0 and:[index <= (interpreterProxy slotSizeOf: rcvr)]). interpreterProxy failed ifTrue:[^nil]. floatPtr := interpreterProxy firstIndexableField: rcvr. floatPtr at: index-1 put: (self cCoerce: floatValue to:'float'). interpreterProxy failed ifFalse: [interpreterProxy pop: 3 thenPush: value].! ! !FloatArrayPlugin methodsFor: 'arithmetic primitives' stamp: 'dtl (auto pragmas dtl 2010-09-27) 5/31/2008 18:20'! primitiveDivFloatArray "Primitive. Add the receiver and the argument, both FloatArrays and store the result into the receiver." | rcvr arg rcvrPtr argPtr length | arg := interpreterProxy stackObjectValue: 0. rcvr := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. interpreterProxy success: (interpreterProxy isWords: arg). interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy failed ifTrue:[^nil]. length := interpreterProxy stSizeOf: arg. interpreterProxy success: (length = (interpreterProxy stSizeOf: rcvr)). interpreterProxy failed ifTrue:[^nil]. rcvrPtr := self cCoerce: (interpreterProxy firstIndexableField: rcvr) to: 'float *'. argPtr := self cCoerce: (interpreterProxy firstIndexableField: arg) to: 'float *'. "Check if any of the argument's values is zero" 0 to: length-1 do:[:i| ( self intAtPointer:(self cCoerce: (argPtr + i) to: 'char*')) = 0 ifTrue:[^interpreterProxy primitiveFail]]. 0 to: length-1 do:[:i| rcvrPtr at: i put: (rcvrPtr at: i) / (argPtr at: i). ]. interpreterProxy pop: 1. "Leave rcvr on stack"! ! !FloatArrayPlugin methodsFor: 'arithmetic primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:19'! primitiveDivScalar "Primitive. Add the argument, a scalar value to the receiver, a FloatArray" | rcvr rcvrPtr value inverse length | value := interpreterProxy stackFloatValue: 0. rcvr := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. value = 0.0 ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy failed ifTrue:[^nil]. length := interpreterProxy stSizeOf: rcvr. rcvrPtr := self cCoerce: (interpreterProxy firstIndexableField: rcvr) to: 'float *'. inverse := 1.0 / value. 0 to: length-1 do:[:i| rcvrPtr at: i put: (rcvrPtr at: i) * inverse. ]. interpreterProxy pop: 1. "Leave rcvr on stack"! ! !FloatArrayPlugin methodsFor: 'arithmetic primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:20'! primitiveDotProduct "Primitive. Compute the dot product of the receiver and the argument. The dot product is defined as the sum of the products of the individual elements." | rcvr arg rcvrPtr argPtr length result | arg := interpreterProxy stackObjectValue: 0. rcvr := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. interpreterProxy success: (interpreterProxy isWords: arg). interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy failed ifTrue:[^nil]. length := interpreterProxy stSizeOf: arg. interpreterProxy success: (length = (interpreterProxy stSizeOf: rcvr)). interpreterProxy failed ifTrue:[^nil]. rcvrPtr := self cCoerce: (interpreterProxy firstIndexableField: rcvr) to: 'float *'. argPtr := self cCoerce: (interpreterProxy firstIndexableField: arg) to: 'float *'. result := 0.0. 0 to: length-1 do:[:i| result := result + ((rcvrPtr at: i) * (argPtr at: i)). ]. interpreterProxy pop: 2. "Pop args + rcvr" interpreterProxy pushFloat: result. "Return result"! ! !FloatArrayPlugin methodsFor: 'access primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:20'! primitiveEqual | rcvr arg rcvrPtr argPtr length | arg := interpreterProxy stackObjectValue: 0. rcvr := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. interpreterProxy success: (interpreterProxy isWords: arg). interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy failed ifTrue:[^nil]. interpreterProxy pop: 2. length := interpreterProxy stSizeOf: arg. length = (interpreterProxy stSizeOf: rcvr) ifFalse:[^interpreterProxy pushBool: false]. rcvrPtr := self cCoerce: (interpreterProxy firstIndexableField: rcvr) to: 'float *'. argPtr := self cCoerce: (interpreterProxy firstIndexableField: arg) to: 'float *'. 0 to: length-1 do:[:i| (rcvrPtr at: i) = (argPtr at: i) ifFalse:[^interpreterProxy pushBool: false]. ]. ^interpreterProxy pushBool: true! ! !FloatArrayPlugin methodsFor: 'access primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:20'! primitiveHashArray | rcvr rcvrPtr length result | rcvr := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy failed ifTrue:[^nil]. length := interpreterProxy stSizeOf: rcvr. rcvrPtr := self cCoerce: (interpreterProxy firstIndexableField: rcvr) to: 'int *'. result := 0. 0 to: length-1 do:[:i| result := result + (rcvrPtr at: i). ]. interpreterProxy pop: 1. ^interpreterProxy pushInteger: (result bitAnd: 16r1FFFFFFF)! ! !FloatArrayPlugin methodsFor: 'arithmetic primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:20'! primitiveMulFloatArray "Primitive. Add the receiver and the argument, both FloatArrays and store the result into the receiver." | rcvr arg rcvrPtr argPtr length | arg := interpreterProxy stackObjectValue: 0. rcvr := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. interpreterProxy success: (interpreterProxy isWords: arg). interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy failed ifTrue:[^nil]. length := interpreterProxy stSizeOf: arg. interpreterProxy success: (length = (interpreterProxy stSizeOf: rcvr)). interpreterProxy failed ifTrue:[^nil]. rcvrPtr := self cCoerce: (interpreterProxy firstIndexableField: rcvr) to: 'float *'. argPtr := self cCoerce: (interpreterProxy firstIndexableField: arg) to: 'float *'. 0 to: length-1 do:[:i| rcvrPtr at: i put: (rcvrPtr at: i) * (argPtr at: i). ]. interpreterProxy pop: 1. "Leave rcvr on stack"! ! !FloatArrayPlugin methodsFor: 'arithmetic primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:20'! primitiveMulScalar "Primitive. Add the argument, a scalar value to the receiver, a FloatArray" | rcvr rcvrPtr value length | value := interpreterProxy stackFloatValue: 0. rcvr := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy failed ifTrue:[^nil]. length := interpreterProxy stSizeOf: rcvr. rcvrPtr := self cCoerce: (interpreterProxy firstIndexableField: rcvr) to: 'float *'. 0 to: length-1 do:[:i| rcvrPtr at: i put: (rcvrPtr at: i) * value. ]. interpreterProxy pop: 1. "Leave rcvr on stack"! ! !FloatArrayPlugin methodsFor: 'arithmetic primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:21'! primitiveSubFloatArray "Primitive. Add the receiver and the argument, both FloatArrays and store the result into the receiver." | rcvr arg rcvrPtr argPtr length | arg := interpreterProxy stackObjectValue: 0. rcvr := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. interpreterProxy success: (interpreterProxy isWords: arg). interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy failed ifTrue:[^nil]. length := interpreterProxy stSizeOf: arg. interpreterProxy success: (length = (interpreterProxy stSizeOf: rcvr)). interpreterProxy failed ifTrue:[^nil]. rcvrPtr := self cCoerce: (interpreterProxy firstIndexableField: rcvr) to: 'float *'. argPtr := self cCoerce: (interpreterProxy firstIndexableField: arg) to: 'float *'. 0 to: length-1 do:[:i| rcvrPtr at: i put: (rcvrPtr at: i) - (argPtr at: i). ]. interpreterProxy pop: 1. "Leave rcvr on stack"! ! !FloatArrayPlugin methodsFor: 'arithmetic primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:21'! primitiveSubScalar "Primitive. Add the argument, a scalar value to the receiver, a FloatArray" | rcvr rcvrPtr value length | value := interpreterProxy stackFloatValue: 0. rcvr := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy failed ifTrue:[^nil]. length := interpreterProxy stSizeOf: rcvr. rcvrPtr := self cCoerce: (interpreterProxy firstIndexableField: rcvr) to: 'float *'. 0 to: length-1 do:[:i| rcvrPtr at: i put: (rcvrPtr at: i) - value. ]. interpreterProxy pop: 1. "Leave rcvr on stack"! ! !FloatArrayPlugin methodsFor: 'arithmetic primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:21'! primitiveSum "Primitive. Find the sum of each float in the receiver, a FloatArray, and stash the result into the argument Float." | rcvr rcvrPtr length sum | rcvr := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. interpreterProxy success: (interpreterProxy isWords: rcvr). interpreterProxy failed ifTrue:[^nil]. length := interpreterProxy stSizeOf: rcvr. rcvrPtr := self cCoerce: (interpreterProxy firstIndexableField: rcvr) to: 'float *'. sum := 0.0. 0 to: length-1 do:[:i| sum := sum + (rcvrPtr at: i). ]. interpreterProxy pop: 1 thenPush: (interpreterProxy floatObjectOf: sum)! ! InterpreterPlugin subclass: #FloatMathPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !FloatMathPlugin class methodsFor: 'translation' stamp: 'ar 11/6/2005 02:48'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !FloatMathPlugin class methodsFor: 'translation' stamp: 'ar 11/6/2005 16:20'! requiresCrossPlatformFiles "default is ok for most, any plugin needing platform specific files must say so" ^true! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:33'! primitiveArcCos "Computes acos(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_acos(rcvr)' inSmalltalk: [rcvr arcCos]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:33'! primitiveArcCosH "Computes acosh(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_acosh(rcvr)' inSmalltalk: [rcvr arcCosH]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:33'! primitiveArcSin "Computes asin(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_asin(rcvr)' inSmalltalk: [rcvr arcSin]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:31'! primitiveArcSinH "Computes asinh(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_asinh(rcvr)' inSmalltalk: [rcvr arcSinH]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:31'! primitiveArcTan "Computes atan(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_atan(rcvr)' inSmalltalk: [rcvr arcTan]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:31'! primitiveArcTan2 "Computes atan2(receiver, arg)" | rcvr arg result | arg := interpreterProxy stackFloatValue: 0. rcvr := interpreterProxy stackFloatValue: 1. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_atan2(rcvr, arg)' inSmalltalk: [rcvr arcTan: arg]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:31'! primitiveArcTanH "Computes atanh(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_atanh(rcvr)' inSmalltalk: [rcvr arcTanH]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:32'! primitiveCos "Computes cos(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_cos(rcvr)' inSmalltalk: [rcvr cos]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:32'! primitiveCosH "Computes cosh(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_cosh(rcvr)' inSmalltalk: [rcvr cosH]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:32'! primitiveExp "Computes E raised to the receiver power." | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := (self cCode: '__ieee754_exp(rcvr)' inSmalltalk: [rcvr exp]). (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:32'! primitiveFMod "Computes receiver \\ arg" | rcvr arg result | arg := interpreterProxy stackFloatValue: 0. rcvr := interpreterProxy stackFloatValue: 1. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_fmod(rcvr, arg)' inSmalltalk: [rcvr \\ arg]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 22:51'! primitiveFractionalPart "Computes receiver \\ 1.0" | rcvr result trunc | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_modf(rcvr, &trunc)' inSmalltalk: [rcvr fractionPart]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:32'! primitiveHypot "hypot(x,y) returns sqrt(x^2+y^2) with error less than 1 ulps" | rcvr arg result | arg := interpreterProxy stackFloatValue: 0. rcvr := interpreterProxy stackFloatValue: 1. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_hypot(rcvr, arg)' inSmalltalk: [rcvr hypot: arg]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:32'! primitiveLog10 "Computes log10(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. rcvr < 0.0 ifTrue:[^interpreterProxy primitiveFail]. result := self cCode: '__ieee754_log10(rcvr)' inSmalltalk: [rcvr log: 10]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:32'! primitiveLogN "Computes log(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. rcvr < 0.0 ifTrue:[^interpreterProxy primitiveFail]. result := self cCode: '__ieee754_log(rcvr)' inSmalltalk: [rcvr ln]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:32'! primitiveRaisedToPower "Computes receiver**arg" | rcvr arg result | arg := interpreterProxy stackFloatValue: 0. rcvr := interpreterProxy stackFloatValue: 1. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_pow(rcvr, arg)' inSmalltalk: [rcvr raisedTo: arg]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:32'! primitiveSin "Computes sin(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_sin(rcvr)' inSmalltalk: [rcvr sin]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:32'! primitiveSinH "Computes sinh(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_sinh(rcvr)' inSmalltalk: [rcvr sinH]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:33'! primitiveSqrt "Computes sqrt(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. rcvr < 0.0 ifTrue:[^interpreterProxy primitiveFail]. result := self cCode: '__ieee754_sqrt(rcvr)' inSmalltalk: [rcvr sqrt]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:33'! primitiveTan "Computes tan(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_tan(rcvr)' inSmalltalk: [rcvr tan]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:33'! primitiveTanH "Computes tanh(receiver)" | rcvr result | rcvr := interpreterProxy stackFloatValue: 0. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_tanh(rcvr)' inSmalltalk: [rcvr tanH]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! !FloatMathPlugin methodsFor: 'float primitives' stamp: 'ar (auto pragmas 12/08) 4/17/2006 21:33'! primitiveTimesTwoPower "Computes E raised to the receiver power." | rcvr arg result | arg := interpreterProxy stackIntegerValue: 0. rcvr := interpreterProxy stackFloatValue: 1. (interpreterProxy failed) ifTrue:[^nil]. result := self cCode: '__ieee754_ldexp(rcvr, arg)' inSmalltalk: [rcvr timesTwoPower: arg]. (self isnan: result) ifTrue:[^interpreterProxy primitiveFail]. interpreterProxy pop: interpreterProxy methodArgumentCount + 1. interpreterProxy pushFloat: result.! ! InterpreterPlugin subclass: #InflatePlugin instanceVariableNames: 'zipCollection zipReadLimit zipPosition zipState zipBitBuf zipBitPos zipSource zipSourcePos zipSourceLimit zipLitTable zipDistTable zipCollectionSize zipLitTableSize zipDistTableSize' classVariableNames: 'MaxBits StateNoMoreData' poolDictionaries: '' category: 'VMMaker-Plugins'! !InflatePlugin commentStamp: '' prior: 0! This plugin implements the one crucial function for efficiently decompressing streams.! InflatePlugin subclass: #DeflatePlugin instanceVariableNames: 'zipHashHead zipHashTail zipHashValue zipBlockPos zipBlockStart zipLiterals zipDistances zipLiteralFreq zipDistanceFreq zipLiteralCount zipLiteralSize zipMatchCount zipMatchLengthCodes zipDistanceCodes zipCrcTable zipExtraLengthBits zipExtraDistanceBits zipBaseLength zipBaseDistance' classVariableNames: 'DeflateHashBits DeflateHashMask DeflateHashShift DeflateHashTableSize DeflateMaxDistance DeflateMaxDistanceCodes DeflateMaxLiteralCodes DeflateMaxMatch DeflateMinMatch DeflateWindowMask DeflateWindowSize' poolDictionaries: '' category: 'VMMaker-Plugins'! !DeflatePlugin commentStamp: 'tpr 5/5/2003 11:52' prior: 0! This adds Zip deflating support. InflatePlugin should not be translated but this subclass should since it is incorporated within that class's translation process! !DeflatePlugin class methodsFor: 'translation' stamp: 'sma 3/3/2000 12:33'! declareCVarsIn: cg super declareCVarsIn: cg. "Required since we share some instVars" cg var: #zipHashHead type: #'unsigned int*'. cg var: #zipHashTail type: #'unsigned int*'. cg var: #zipLiterals type: #'unsigned char*'. cg var: #zipDistances type: #'unsigned int*'. cg var: #zipLiteralFreq type: #'unsigned int*'. cg var: #zipDistanceFreq type: #'unsigned int*'. cg var: #zipMatchLengthCodes type: #'unsigned int' array: ZipWriteStream matchLengthCodes. cg var: #zipDistanceCodes type: #'unsigned int' array: ZipWriteStream distanceCodes. cg var: #zipCrcTable type: #'unsigned int' array: GZipWriteStream crcTable. cg var: #zipExtraLengthBits type: #'unsigned int' array: ZipWriteStream extraLengthBits. cg var: #zipExtraDistanceBits type: #'unsigned int' array: ZipWriteStream extraDistanceBits. cg var: #zipBaseLength type: #'unsigned int' array: ZipWriteStream baseLength. cg var: #zipBaseDistance type: #'unsigned int' array: ZipWriteStream baseDistance! ! !DeflatePlugin class methodsFor: 'class initialization' stamp: 'ar 12/29/1999 20:54'! initialize "DeflatePlugin initialize" DeflateWindowSize := 16r8000. DeflateWindowMask := DeflateWindowSize - 1. DeflateMinMatch := 3. DeflateMaxMatch := 258. DeflateMaxDistance := DeflateWindowSize. DeflateHashBits := 15. DeflateHashTableSize := 1 << DeflateHashBits. DeflateHashMask := DeflateHashTableSize - 1. DeflateHashShift := (DeflateHashBits + DeflateMinMatch - 1) // DeflateMinMatch. DeflateMaxLiteralCodes := ZipWriteStream maxLiteralCodes. DeflateMaxDistanceCodes := ZipWriteStream maxDistanceCodes.! ! !DeflatePlugin methodsFor: 'deflating' stamp: 'ar (auto pragmas 12/08) 12/29/1999 21:59'! compare: here with: matchPos min: minLength "Compare the two strings and return the length of matching characters. minLength is a lower bound for match lengths that will be accepted. Note: here and matchPos are zero based." | length | "First test if we can actually get longer than minLength" (zipCollection at: here+minLength) = (zipCollection at: matchPos+minLength) ifFalse:[^0]. (zipCollection at: here+minLength-1) = (zipCollection at: matchPos+minLength-1) ifFalse:[^0]. "Then test if we have an initial match at all" (zipCollection at: here) = (zipCollection at: matchPos) ifFalse:[^0]. (zipCollection at: here+1) = (zipCollection at: matchPos+1) ifFalse:[^1]. "Finally do the real comparison" length := 2. [length < DeflateMaxMatch and:[ (zipCollection at: here+length) = (zipCollection at: matchPos+length)]] whileTrue:[length := length + 1]. ^length! ! !DeflatePlugin methodsFor: 'deflating' stamp: 'ar (auto pragmas 12/08) 12/29/1999 22:00'! deflateBlock: lastIndex chainLength: chainLength goodMatch: goodMatch "Continue deflating the receiver's collection from blockPosition to lastIndex. Note that lastIndex must be at least MaxMatch away from the end of collection" | here matchResult flushNeeded hereMatch hereLength newMatch newLength hasMatch | zipBlockPos > lastIndex ifTrue:[^false]. "Nothing to deflate" zipLiteralCount >= zipLiteralSize ifTrue:[^true]. hasMatch := false. here := zipBlockPos. [here <= lastIndex] whileTrue:[ hasMatch ifFalse:[ "Find the first match" matchResult := self findMatch: here lastLength: DeflateMinMatch-1 lastMatch: here chainLength: chainLength goodMatch: goodMatch. self insertStringAt: here. "update hash table" hereMatch := matchResult bitAnd: 16rFFFF. hereLength := matchResult bitShift: -16]. "Look ahead if there is a better match at the next position" matchResult := self findMatch: here+1 lastLength: hereLength lastMatch: hereMatch chainLength: chainLength goodMatch: goodMatch. newMatch := matchResult bitAnd: 16rFFFF. newLength := matchResult bitShift: -16. "Now check if the next match is better than the current one. If not, output the current match (provided that the current match is at least MinMatch long)" (hereLength >= newLength and:[hereLength >= DeflateMinMatch]) ifTrue:[ "Encode the current match" flushNeeded := self encodeMatch: hereLength distance: here - hereMatch. "Insert all strings up to the end of the current match. Note: The first string has already been inserted." 1 to: hereLength-1 do:[:i| self insertStringAt: (here := here + 1)]. hasMatch := false. here := here + 1. ] ifFalse:[ "Either the next match is better than the current one or we didn't have a good match after all (e.g., current match length < MinMatch). Output a single literal." flushNeeded := self encodeLiteral: (zipCollection at: here). here := here + 1. (here <= lastIndex and:[flushNeeded not]) ifTrue:[ "Cache the results for the next round" self insertStringAt: here. hasMatch := true. hereMatch := newMatch. hereLength := newLength]. ]. flushNeeded ifTrue:[zipBlockPos := here. ^true]. ]. zipBlockPos := here. ^false! ! !DeflatePlugin methodsFor: 'encoding' stamp: 'ar (auto pragmas 12/08) 12/29/1999 20:37'! encodeLiteral: lit "Encode the given literal" zipLiterals at: zipLiteralCount put: lit. zipDistances at: zipLiteralCount put: 0. zipLiteralFreq at: lit put: (zipLiteralFreq at: lit) + 1. zipLiteralCount := zipLiteralCount + 1. ^zipLiteralCount = zipLiteralSize "We *must* flush" or:[(zipLiteralCount bitAnd: 16rFFF) = 0 "Only check every N kbytes" and:[self shouldFlush]]! ! !DeflatePlugin methodsFor: 'encoding' stamp: 'ar (auto pragmas 12/08) 12/29/1999 20:37'! encodeMatch: length distance: dist "Encode the given match of length length starting at dist bytes ahead" | literal distance | zipLiterals at: zipLiteralCount put: length - DeflateMinMatch. zipDistances at: zipLiteralCount put: dist. literal := (zipMatchLengthCodes at: length - DeflateMinMatch). zipLiteralFreq at: literal put: (zipLiteralFreq at: literal) + 1. dist < 257 ifTrue:[distance := zipDistanceCodes at: dist - 1] ifFalse:[distance := zipDistanceCodes at: 256 + (dist - 1 bitShift: -7)]. zipDistanceFreq at: distance put: (zipDistanceFreq at: distance) + 1. zipLiteralCount := zipLiteralCount + 1. zipMatchCount := zipMatchCount + 1. ^zipLiteralCount = zipLiteralSize "We *must* flush" or:[(zipLiteralCount bitAnd: 16rFFF) = 0 "Only check every N kbytes" and:[self shouldFlush]]! ! !DeflatePlugin methodsFor: 'deflating' stamp: 'ar (auto pragmas 12/08) 12/29/1999 22:00'! findMatch: here lastLength: lastLength lastMatch: lastMatch chainLength: maxChainLength goodMatch: goodMatch "Find the longest match for the string starting at here. If there is no match longer than lastLength return lastMatch/lastLength. Traverse at most maxChainLength entries in the hash table. Stop if a match of at least goodMatch size has been found." | matchResult matchPos distance chainLength limit bestLength length | "Compute the default match result" matchResult := (lastLength bitShift: 16) bitOr: lastMatch. "There is no way to find a better match than MaxMatch" lastLength >= DeflateMaxMatch ifTrue:[^matchResult]. "Start position for searches" matchPos := zipHashHead at: (self updateHashAt: here + DeflateMinMatch - 1). "Compute the distance to the (possible) match" distance := here - matchPos. "Note: It is required that 0 < distance < MaxDistance" (distance > 0 and:[distance < DeflateMaxDistance]) ifFalse:[^matchResult]. chainLength := maxChainLength. "Max. nr of match chain to search" here > DeflateMaxDistance "Limit for matches that are too old" ifTrue:[limit := here - DeflateMaxDistance] ifFalse:[limit := 0]. "Best match length so far (current match must be larger to take effect)" bestLength := lastLength. [true] whileTrue:[ "Compare the current string with the string at match position" length := self compare: here with: matchPos min: bestLength. "Truncate accidental matches beyound stream position" (here + length > zipPosition) ifTrue:[length := zipPosition - here]. "Ignore very small matches if they are too far away" (length = DeflateMinMatch and:[(here - matchPos) > (DeflateMaxDistance // 4)]) ifTrue:[length := DeflateMinMatch - 1]. length > bestLength ifTrue:["We have a new (better) match than before" "Compute the new match result" matchResult := (length bitShift: 16) bitOr: matchPos. bestLength := length. "There is no way to find a better match than MaxMatch" bestLength >= DeflateMaxMatch ifTrue:[^matchResult]. "But we may have a good, fast match" bestLength > goodMatch ifTrue:[^matchResult]. ]. (chainLength := chainLength - 1) > 0 ifFalse:[^matchResult]. "Compare with previous entry in hash chain" matchPos := zipHashTail at: (matchPos bitAnd: DeflateWindowMask). matchPos <= limit ifTrue:[^matchResult]. "Match position is too old" ].! ! !DeflatePlugin methodsFor: 'deflating' stamp: 'ar (auto pragmas 12/08) 12/29/1999 21:59'! insertStringAt: here "Insert the string at the given start position into the hash table. Note: The hash value is updated starting at MinMatch-1 since all strings before have already been inserted into the hash table (and the hash value is updated as well)." | prevEntry | zipHashValue := self updateHashAt: (here + DeflateMinMatch - 1). prevEntry := zipHashHead at: zipHashValue. zipHashHead at: zipHashValue put: here. zipHashTail at: (here bitAnd: DeflateWindowMask) put: prevEntry.! ! !DeflatePlugin methodsFor: 'primitive support' stamp: 'ar (auto pragmas dtl 2010-09-27) 12/30/1999 15:28'! loadDeflateStreamFrom: rcvr | oop | ((interpreterProxy isPointers: rcvr) and:[ (interpreterProxy slotSizeOf: rcvr) >= 15]) ifFalse:[^false]. oop := interpreterProxy fetchPointer: 0 ofObject: rcvr. (interpreterProxy isIntegerObject: oop) ifTrue:[^interpreterProxy primitiveFail]. (interpreterProxy isBytes: oop) ifFalse:[^interpreterProxy primitiveFail]. zipCollection := interpreterProxy firstIndexableField: oop. zipCollectionSize := interpreterProxy byteSizeOf: oop. zipPosition := interpreterProxy fetchInteger: 1 ofObject: rcvr. zipReadLimit := interpreterProxy fetchInteger: 2 ofObject: rcvr. "zipWriteLimit := interpreterProxy fetchInteger: 3 ofObject: rcvr." oop := interpreterProxy fetchPointer: 4 ofObject: rcvr. ((interpreterProxy isIntegerObject: oop) or:[ (interpreterProxy isWords: oop) not]) ifTrue:[^false]. (interpreterProxy slotSizeOf: oop) = DeflateHashTableSize ifFalse:[^false]. zipHashHead := interpreterProxy firstIndexableField: oop. oop := interpreterProxy fetchPointer: 5 ofObject: rcvr. ((interpreterProxy isIntegerObject: oop) or:[ (interpreterProxy isWords: oop) not]) ifTrue:[^false]. (interpreterProxy slotSizeOf: oop) = DeflateWindowSize ifFalse:[^false]. zipHashTail := interpreterProxy firstIndexableField: oop. zipHashValue := interpreterProxy fetchInteger: 6 ofObject: rcvr. zipBlockPos := interpreterProxy fetchInteger: 7 ofObject: rcvr. "zipBlockStart := interpreterProxy fetchInteger: 8 ofObject: rcvr." oop := interpreterProxy fetchPointer: 9 ofObject: rcvr. ((interpreterProxy isIntegerObject: oop) or:[ (interpreterProxy isBytes: oop) not]) ifTrue:[^false]. zipLiteralSize := interpreterProxy slotSizeOf: oop. zipLiterals := interpreterProxy firstIndexableField: oop. oop := interpreterProxy fetchPointer: 10 ofObject: rcvr. ((interpreterProxy isIntegerObject: oop) or:[ (interpreterProxy isWords: oop) not]) ifTrue:[^false]. (interpreterProxy slotSizeOf: oop) < zipLiteralSize ifTrue:[^false]. zipDistances := interpreterProxy firstIndexableField: oop. oop := interpreterProxy fetchPointer: 11 ofObject: rcvr. ((interpreterProxy isIntegerObject: oop) or:[ (interpreterProxy isWords: oop) not]) ifTrue:[^false]. (interpreterProxy slotSizeOf: oop) = DeflateMaxLiteralCodes ifFalse:[^false]. zipLiteralFreq := interpreterProxy firstIndexableField: oop. oop := interpreterProxy fetchPointer: 12 ofObject: rcvr. ((interpreterProxy isIntegerObject: oop) or:[ (interpreterProxy isWords: oop) not]) ifTrue:[^false]. (interpreterProxy slotSizeOf: oop) = DeflateMaxDistanceCodes ifFalse:[^false]. zipDistanceFreq := interpreterProxy firstIndexableField: oop. zipLiteralCount := interpreterProxy fetchInteger: 13 ofObject: rcvr. zipMatchCount := interpreterProxy fetchInteger: 14 ofObject: rcvr. ^interpreterProxy failed not! ! !DeflatePlugin methodsFor: 'primitive support' stamp: 'ar (auto pragmas 12/08) 12/30/1999 15:28'! loadZipEncoderFrom: rcvr | oop | ((interpreterProxy isPointers: rcvr) and:[ (interpreterProxy slotSizeOf: rcvr) >= 6]) ifFalse:[^false]. oop := interpreterProxy fetchPointer: 0 ofObject: rcvr. (interpreterProxy isIntegerObject: oop) ifTrue:[^interpreterProxy primitiveFail]. (interpreterProxy isBytes: oop) ifFalse:[^interpreterProxy primitiveFail]. zipCollection := interpreterProxy firstIndexableField: oop. zipCollectionSize := interpreterProxy byteSizeOf: oop. zipPosition := interpreterProxy fetchInteger: 1 ofObject: rcvr. zipReadLimit := interpreterProxy fetchInteger: 2 ofObject: rcvr. "zipWriteLimit := interpreterProxy fetchInteger: 3 ofObject: rcvr." zipBitBuf := interpreterProxy fetchInteger: 4 ofObject: rcvr. zipBitPos := interpreterProxy fetchInteger: 5 ofObject: rcvr. ^interpreterProxy failed not! ! !DeflatePlugin methodsFor: 'encoding' stamp: 'ar (auto pragmas 12/08) 12/30/1999 15:26'! nextZipBits: nBits put: value "Require: zipCollection, zipCollectionSize, zipPosition, zipBitBuf, zipBitPos. " (value >= 0 and:[(1 << nBits) > value]) ifFalse:[^interpreterProxy primitiveFail]. zipBitBuf := zipBitBuf bitOr: (value bitShift: zipBitPos). zipBitPos := zipBitPos + nBits. [zipBitPos >= 8 and:[zipPosition < zipCollectionSize]] whileTrue:[ zipCollection at: zipPosition put: (zipBitBuf bitAnd: 255). zipPosition := zipPosition + 1. zipBitBuf := zipBitBuf >> 8. zipBitPos := zipBitPos - 8]. ! ! !DeflatePlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 12/29/1999 22:21'! primitiveDeflateBlock "Primitive. Deflate the current contents of the receiver." | goodMatch chainLength lastIndex rcvr result | interpreterProxy methodArgumentCount = 3 ifFalse:[^interpreterProxy primitiveFail]. goodMatch := interpreterProxy stackIntegerValue: 0. chainLength := interpreterProxy stackIntegerValue: 1. lastIndex := interpreterProxy stackIntegerValue: 2. rcvr := interpreterProxy stackObjectValue: 3. interpreterProxy failed ifTrue:[^nil]. self cCode:'' inSmalltalk:[ zipMatchLengthCodes := CArrayAccessor on: ZipWriteStream matchLengthCodes. zipDistanceCodes := CArrayAccessor on: ZipWriteStream distanceCodes]. (self loadDeflateStreamFrom: rcvr) ifFalse:[^interpreterProxy primitiveFail]. result := self deflateBlock: lastIndex chainLength: chainLength goodMatch: goodMatch. interpreterProxy failed ifFalse:[ "Store back modified values" interpreterProxy storeInteger: 6 ofObject: rcvr withValue: zipHashValue. interpreterProxy storeInteger: 7 ofObject: rcvr withValue: zipBlockPos. interpreterProxy storeInteger: 13 ofObject: rcvr withValue: zipLiteralCount. interpreterProxy storeInteger: 14 ofObject: rcvr withValue: zipMatchCount]. interpreterProxy failed ifFalse:[ interpreterProxy pop: 4. interpreterProxy pushBool: result. ].! ! !DeflatePlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:00'! primitiveDeflateUpdateHashTable "Primitive. Update the hash tables after data has been moved by delta." | delta table tableSize tablePtr entry | interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. delta := interpreterProxy stackIntegerValue: 0. table := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isWords: table) ifFalse:[^interpreterProxy primitiveFail]. tableSize := interpreterProxy slotSizeOf: table. tablePtr := interpreterProxy firstIndexableField: table. 0 to: tableSize-1 do:[:i| entry := tablePtr at: i. entry >= delta ifTrue:[tablePtr at: i put: entry - delta] ifFalse:[tablePtr at: i put: 0]]. interpreterProxy pop: 2. "Leave rcvr on stack"! ! !DeflatePlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:01'! primitiveUpdateAdler32 "Primitive. Update a 32bit CRC value." | collection stopIndex startIndex length bytePtr s1 adler32 s2 b | interpreterProxy methodArgumentCount = 4 ifFalse:[^interpreterProxy primitiveFail]. collection := interpreterProxy stackObjectValue: 0. stopIndex := interpreterProxy stackIntegerValue: 1. startIndex := interpreterProxy stackIntegerValue: 2. adler32 := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 3). interpreterProxy failed ifTrue:[^0]. ((interpreterProxy isBytes: collection) and:[stopIndex >= startIndex and:[startIndex > 0]]) ifFalse:[^interpreterProxy primitiveFail]. length := interpreterProxy byteSizeOf: collection. (stopIndex <= length) ifFalse:[^interpreterProxy primitiveFail]. bytePtr := interpreterProxy firstIndexableField: collection. startIndex := startIndex - 1. stopIndex := stopIndex - 1. s1 := adler32 bitAnd: 16rFFFF. s2 := (adler32 >> 16) bitAnd: 16rFFFF. startIndex to: stopIndex do:[:i| b := bytePtr at: i. s1 := (s1 + b) \\ 65521. s2 := (s2 + s1) \\ 65521. ]. adler32 := (s2 bitShift: 16) + s1. interpreterProxy pop: 5. "args + rcvr" interpreterProxy push: (interpreterProxy positive32BitIntegerFor: adler32).! ! !DeflatePlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:01'! primitiveUpdateGZipCrc32 "Primitive. Update a 32bit CRC value." | collection stopIndex startIndex crc length bytePtr | interpreterProxy methodArgumentCount = 4 ifFalse:[^interpreterProxy primitiveFail]. collection := interpreterProxy stackObjectValue: 0. stopIndex := interpreterProxy stackIntegerValue: 1. startIndex := interpreterProxy stackIntegerValue: 2. crc := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 3). interpreterProxy failed ifTrue:[^0]. ((interpreterProxy isBytes: collection) and:[stopIndex >= startIndex and:[startIndex > 0]]) ifFalse:[^interpreterProxy primitiveFail]. length := interpreterProxy byteSizeOf: collection. (stopIndex <= length) ifFalse:[^interpreterProxy primitiveFail]. bytePtr := interpreterProxy firstIndexableField: collection. self cCode:'' inSmalltalk:[zipCrcTable := CArrayAccessor on: GZipWriteStream crcTable]. startIndex := startIndex - 1. stopIndex := stopIndex - 1. startIndex to: stopIndex do:[:i| crc := (zipCrcTable at: ((crc bitXor: (bytePtr at: i)) bitAnd: 255)) bitXor: (crc >> 8). ]. interpreterProxy pop: 5. "args + rcvr" interpreterProxy push: (interpreterProxy positive32BitIntegerFor: crc).! ! !DeflatePlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 12/30/1999 15:54'! primitiveZipSendBlock | distTree litTree distStream litStream rcvr result | interpreterProxy methodArgumentCount = 4 ifFalse:[^interpreterProxy primitiveFail]. distTree := interpreterProxy stackObjectValue: 0. litTree := interpreterProxy stackObjectValue: 1. distStream := interpreterProxy stackObjectValue: 2. litStream := interpreterProxy stackObjectValue: 3. rcvr := interpreterProxy stackObjectValue: 4. interpreterProxy failed ifTrue:[^nil]. (self loadZipEncoderFrom: rcvr) ifFalse:[^interpreterProxy primitiveFail]. ((interpreterProxy isPointers: distTree) and:[ (interpreterProxy slotSizeOf: distTree) >= 2]) ifFalse:[^interpreterProxy primitiveFail]. ((interpreterProxy isPointers: litTree) and:[ (interpreterProxy slotSizeOf: litTree) >= 2]) ifFalse:[^interpreterProxy primitiveFail]. ((interpreterProxy isPointers: litStream) and:[ (interpreterProxy slotSizeOf: litStream) >= 3]) ifFalse:[^interpreterProxy primitiveFail]. ((interpreterProxy isPointers: distStream) and:[ (interpreterProxy slotSizeOf: distStream) >= 3]) ifFalse:[^interpreterProxy primitiveFail]. self cCode:'' inSmalltalk:[ zipMatchLengthCodes := CArrayAccessor on: ZipWriteStream matchLengthCodes. zipDistanceCodes := CArrayAccessor on: ZipWriteStream distanceCodes. zipExtraLengthBits := CArrayAccessor on: ZipWriteStream extraLengthBits. zipExtraDistanceBits := CArrayAccessor on: ZipWriteStream extraDistanceBits. zipBaseLength := CArrayAccessor on: ZipWriteStream baseLength. zipBaseDistance := CArrayAccessor on: ZipWriteStream baseDistance]. result := self sendBlock: litStream with: distStream with: litTree with: distTree. interpreterProxy failed ifFalse:[ interpreterProxy storeInteger: 1 ofObject: rcvr withValue: zipPosition. interpreterProxy storeInteger: 4 ofObject: rcvr withValue: zipBitBuf. interpreterProxy storeInteger: 5 ofObject: rcvr withValue: zipBitPos. ]. interpreterProxy failed ifFalse:[ interpreterProxy pop: 5. "rcvr + args" interpreterProxy pushInteger: result. ].! ! !DeflatePlugin methodsFor: 'encoding' stamp: 'tpr (auto pragmas dtl 2010-09-27) 12/29/2005 16:01'! sendBlock: literalStream with: distanceStream with: litTree with: distTree "Require: zipCollection, zipCollectionSize, zipPosition, zipBitBuf, zipBitPos. " | oop litPos litLimit litArray distArray lit dist sum llBitLengths llCodes distBitLengths distCodes code extra litBlCount distBlCount | oop := interpreterProxy fetchPointer: 0 ofObject: literalStream. litPos := interpreterProxy fetchInteger: 1 ofObject: literalStream. litLimit := interpreterProxy fetchInteger: 2 ofObject: literalStream. ((interpreterProxy isIntegerObject: oop) not and:[litPos <= litLimit and:[ litLimit <= (interpreterProxy byteSizeOf: oop) and:[interpreterProxy isBytes: oop]]]) ifFalse:[^interpreterProxy primitiveFail]. litArray := interpreterProxy firstIndexableField: oop. oop := interpreterProxy fetchPointer: 0 ofObject: distanceStream. ((interpreterProxy isIntegerObject: oop) not and:[ (interpreterProxy fetchInteger: 1 ofObject: distanceStream) = litPos and:[ (interpreterProxy fetchInteger: 2 ofObject: distanceStream) = litLimit]]) ifFalse:[^interpreterProxy primitiveFail]. ((interpreterProxy isWords: oop) and:[ litLimit <= (interpreterProxy slotSizeOf: oop)]) ifFalse:[^interpreterProxy primitiveFail]. distArray := interpreterProxy firstIndexableField: oop. oop := interpreterProxy fetchPointer: 0 ofObject: litTree. ((interpreterProxy isIntegerObject: oop) not and:[interpreterProxy isWords: oop]) ifFalse:[^interpreterProxy primitiveFail]. litBlCount := interpreterProxy slotSizeOf: oop. llBitLengths := interpreterProxy firstIndexableField: oop. oop := interpreterProxy fetchPointer: 1 ofObject: litTree. ((interpreterProxy isIntegerObject: oop) not and:[interpreterProxy isWords: oop]) ifFalse:[^interpreterProxy primitiveFail]. (litBlCount = (interpreterProxy slotSizeOf: oop)) ifFalse:[^interpreterProxy primitiveFail]. llCodes := interpreterProxy firstIndexableField: oop. oop := interpreterProxy fetchPointer: 0 ofObject: distTree. ((interpreterProxy isIntegerObject: oop) not and:[interpreterProxy isWords: oop]) ifFalse:[^interpreterProxy primitiveFail]. distBlCount := interpreterProxy slotSizeOf: oop. distBitLengths := interpreterProxy firstIndexableField: oop. oop := interpreterProxy fetchPointer: 1 ofObject: distTree. ((interpreterProxy isIntegerObject: oop) not and:[interpreterProxy isWords: oop]) ifFalse:[^interpreterProxy primitiveFail]. (distBlCount = (interpreterProxy slotSizeOf: oop)) ifFalse:[^interpreterProxy primitiveFail]. distCodes := interpreterProxy firstIndexableField: oop. interpreterProxy failed ifTrue:[^nil]. self nextZipBits: 0 put: 0. "Flush pending bits if necessary" sum := 0. [litPos < litLimit and:[zipPosition + 4 < zipCollectionSize]] whileTrue:[ lit := litArray at: litPos. dist := distArray at: litPos. litPos := litPos + 1. dist = 0 ifTrue:["literal" sum := sum + 1. lit < litBlCount ifFalse:[^interpreterProxy primitiveFail]. self nextZipBits: (llBitLengths at: lit) put: (llCodes at: lit). ] ifFalse:["match" sum := sum + lit + DeflateMinMatch. lit < 256 ifFalse:[^interpreterProxy primitiveFail]. code := zipMatchLengthCodes at: lit. code < litBlCount ifFalse:[^interpreterProxy primitiveFail]. self nextZipBits: (llBitLengths at: code) put: (llCodes at: code). extra := zipExtraLengthBits at: code - 257. extra = 0 ifFalse:[ lit := lit - (zipBaseLength at: code - 257). self nextZipBits: extra put: lit]. dist := dist - 1. dist < 16r8000 ifFalse:[^interpreterProxy primitiveFail]. dist < 256 ifTrue:[code := zipDistanceCodes at: dist] ifFalse:[code := zipDistanceCodes at: 256 + (dist >> 7)]. code < distBlCount ifFalse:[^interpreterProxy primitiveFail]. self nextZipBits: (distBitLengths at: code) put: (distCodes at: code). extra := zipExtraDistanceBits at: code. extra = 0 ifFalse:[ dist := dist - (zipBaseDistance at: code). self nextZipBits: extra put: dist]. ]. ]. interpreterProxy failed ifTrue:[^nil]. interpreterProxy storeInteger: 1 ofObject: literalStream withValue: litPos. interpreterProxy storeInteger: 1 ofObject: distanceStream withValue: litPos. ^sum! ! !DeflatePlugin methodsFor: 'encoding' stamp: 'ar (auto pragmas 12/08) 12/29/1999 22:00'! shouldFlush "Check if we should flush the current block. Flushing can be useful if the input characteristics change." | nLits | zipLiteralCount = zipLiteralSize ifTrue:[^true]. "We *must* flush" (zipLiteralCount bitAnd: 16rFFF) = 0 ifFalse:[^false]. "Only check every N kbytes" zipMatchCount * 10 <= zipLiteralCount ifTrue:[ "This is basically random data. There is no need to flush early since the overhead for encoding the trees will add to the overall size" ^false]. "Try to adapt to the input data. We flush if the ratio between matches and literals changes beyound a certain threshold" nLits := zipLiteralCount - zipMatchCount. nLits <= zipMatchCount ifTrue:[^false]. "whow!! so many matches" ^nLits * 4 <= zipMatchCount! ! !DeflatePlugin methodsFor: 'deflating' stamp: 'ar 12/29/1999 20:28'! updateHash: nextValue "Update the running hash value based on the next input byte. Return the new updated hash value." ^((zipHashValue bitShift: DeflateHashShift) bitXor: nextValue) bitAnd: DeflateHashMask.! ! !DeflatePlugin methodsFor: 'deflating' stamp: 'ar 12/29/1999 20:29'! updateHashAt: here "Update the hash value at position here (one based)" ^self updateHash: (zipCollection at: here)! ! !InflatePlugin class methodsFor: 'translation' stamp: 'sma 3/3/2000 12:31'! declareCVarsIn: cg cg var: #zipCollection type: #'unsigned char*'. cg var: #zipSource type: #'unsigned char*'. cg var: #zipLitTable type: #'unsigned int*'. cg var: #zipDistTable type: #'unsigned int*'! ! !InflatePlugin class methodsFor: 'class initialization' stamp: 'ar 12/21/1999 23:02'! initialize "InflatePlugin initialize" MaxBits := 16. StateNoMoreData := 1.! ! !InflatePlugin class methodsFor: 'translation' stamp: 'ar 5/11/2000 23:58'! moduleName ^'ZipPlugin'! ! !InflatePlugin class methodsFor: 'translation' stamp: 'tpr 5/14/2001 12:27'! shouldBeTranslated "InflatePlugin should not be translated but its subclass should since it is incorporated within that class's translation process" ^self ~= InflatePlugin! ! !InflatePlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 12/22/1999 00:04'! primitiveInflateDecompressBlock "Primitive. Inflate a single block." | oop rcvr | interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. "distance table" oop := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isWords: oop) ifFalse:[^interpreterProxy primitiveFail]. zipDistTable := interpreterProxy firstIndexableField: oop. zipDistTableSize := interpreterProxy slotSizeOf: oop. "literal table" oop := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isWords: oop) ifFalse:[^interpreterProxy primitiveFail]. zipLitTable := interpreterProxy firstIndexableField: oop. zipLitTableSize := interpreterProxy slotSizeOf: oop. "Receiver (InflateStream)" rcvr := interpreterProxy stackObjectValue: 2. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isPointers: rcvr) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: rcvr) < 9 ifTrue:[^interpreterProxy primitiveFail]. "All the integer instvars" zipReadLimit := interpreterProxy fetchInteger: 2 ofObject: rcvr. zipState := interpreterProxy fetchInteger: 3 ofObject: rcvr. zipBitBuf := interpreterProxy fetchInteger: 4 ofObject: rcvr. zipBitPos := interpreterProxy fetchInteger: 5 ofObject: rcvr. zipSourcePos := interpreterProxy fetchInteger: 7 ofObject: rcvr. zipSourceLimit := interpreterProxy fetchInteger: 8 ofObject: rcvr. interpreterProxy failed ifTrue:[^nil]. zipReadLimit := zipReadLimit - 1. zipSourcePos := zipSourcePos - 1. zipSourceLimit := zipSourceLimit - 1. "collection" oop := interpreterProxy fetchPointer: 0 ofObject: rcvr. (interpreterProxy isIntegerObject: oop) ifTrue:[^interpreterProxy primitiveFail]. (interpreterProxy isBytes: oop) ifFalse:[^interpreterProxy primitiveFail]. zipCollection := interpreterProxy firstIndexableField: oop. zipCollectionSize := interpreterProxy byteSizeOf: oop. "source" oop := interpreterProxy fetchPointer: 6 ofObject: rcvr. (interpreterProxy isIntegerObject: oop) ifTrue:[^interpreterProxy primitiveFail]. (interpreterProxy isBytes: oop) ifFalse:[^interpreterProxy primitiveFail]. zipSource := interpreterProxy firstIndexableField: oop. "do the primitive" self zipDecompressBlock. interpreterProxy failed ifFalse:[ "store modified values back" interpreterProxy storeInteger: 2 ofObject: rcvr withValue: zipReadLimit + 1. interpreterProxy storeInteger: 3 ofObject: rcvr withValue: zipState. interpreterProxy storeInteger: 4 ofObject: rcvr withValue: zipBitBuf. interpreterProxy storeInteger: 5 ofObject: rcvr withValue: zipBitPos. interpreterProxy storeInteger: 7 ofObject: rcvr withValue: zipSourcePos + 1. interpreterProxy pop: 2. ].! ! !InflatePlugin methodsFor: 'inflating' stamp: 'tpr (auto pragmas dtl 2010-09-28) 12/29/2005 16:22'! zipDecodeValueFrom: table size: tableSize "Decode the next value in the receiver using the given huffman table." | bits bitsNeeded tableIndex value index | bitsNeeded := (table at: 0) bitShift: -24. "Initial bits needed" bitsNeeded > MaxBits ifTrue:[interpreterProxy primitiveFail. ^0]. tableIndex := 2. "First real table" [true] whileTrue:[ bits := self zipNextBits: bitsNeeded. "Get bits" index := tableIndex + bits - 1. index >= tableSize ifTrue:[interpreterProxy primitiveFail. ^0]. value := table at: index. "Lookup entry in table" (value bitAnd: 16r3F000000) = 0 ifTrue:[^value]. "Check if it is a leaf node" "Fetch sub table" tableIndex := value bitAnd: 16rFFFF. "Table offset in low 16 bit" bitsNeeded := (value bitShift: -24) bitAnd: 255. "Additional bits in high 8 bit" bitsNeeded > MaxBits ifTrue:[interpreterProxy primitiveFail. ^0]]. ^0! ! !InflatePlugin methodsFor: 'inflating' stamp: 'ar (auto pragmas 12/08) 12/22/1999 00:04'! zipDecompressBlock | value extra length distance oldPos oldBits oldBitPos dstPos srcPos max | max := zipCollectionSize - 1. [zipReadLimit < max and:[zipSourcePos <= zipSourceLimit]] whileTrue:[ "Back up stuff if we're running out of space" oldBits := zipBitBuf. oldBitPos := zipBitPos. oldPos := zipSourcePos. value := self zipDecodeValueFrom: zipLitTable size: zipLitTableSize. value < 256 ifTrue:[ "A literal" zipCollection at: (zipReadLimit := zipReadLimit + 1) put: value. ] ifFalse:["length/distance or end of block" value = 256 ifTrue:["End of block" zipState := zipState bitAnd: StateNoMoreData. ^0]. "Compute the actual length value (including possible extra bits)" extra := (value bitShift: -16) - 1. length := value bitAnd: 16rFFFF. extra > 0 ifTrue:[length := length + (self zipNextBits: extra)]. "Compute the distance value" value := self zipDecodeValueFrom: zipDistTable size: zipDistTableSize. extra := (value bitShift: -16). distance := value bitAnd: 16rFFFF. extra > 0 ifTrue:[distance := distance + (self zipNextBits: extra)]. (zipReadLimit + length >= max) ifTrue:[ zipBitBuf := oldBits. zipBitPos := oldBitPos. zipSourcePos := oldPos. ^0]. dstPos := zipReadLimit. srcPos := zipReadLimit - distance. 1 to: length do:[:i| zipCollection at: dstPos+i put: (zipCollection at: srcPos+i)]. zipReadLimit := zipReadLimit + length. ]. ].! ! !InflatePlugin methodsFor: 'inflating' stamp: 'ar (auto pragmas 12/08) 12/21/1999 23:06'! zipNextBits: n | bits byte | [zipBitPos < n] whileTrue:[ byte := zipSource at: (zipSourcePos := zipSourcePos + 1). zipBitBuf := zipBitBuf + (byte << zipBitPos). zipBitPos := zipBitPos + 8]. bits := zipBitBuf bitAnd: (1 << n)-1. zipBitBuf := zipBitBuf >> n. zipBitPos := zipBitPos - n. ^bits! ! !InterpreterPlugin class methodsFor: 'accessing' stamp: 'tpr 12/17/2003 16:52'! allCallsOn "Answer a SortedCollection of all the methods that refer to me. Most classes simply defer to SystemDictionary>allCallsOn: but some have special requirements - plugins may have a module name that does not match the class name" self theNonMetaClass name ~= self moduleName asSymbol ifTrue:[^super allCallsOn, (self systemNavigation allCallsOn: self moduleName asSymbol)] ifFalse:[^super allCallsOn]! ! !InterpreterPlugin class methodsFor: 'translation' stamp: 'ar 5/12/2000 00:24'! baseDirectoryName "Return the directory into which plugins should be generated by default." ^FileDirectory default pathName! ! !InterpreterPlugin class methodsFor: 'translation' stamp: 'ikp 8/3/2004 18:55'! buildCodeGeneratorUpTo: aPluginClass "Build a CCodeGenerator for the plugin" | cg theClass | cg := self codeGeneratorClass new initialize. cg pluginName: self moduleName. "Add an extra declaration for module name" cg declareModuleName: self moduleNameAndVersion. theClass := aPluginClass. [theClass == Object | (theClass == InterpreterSimulationObject)] whileFalse:[ cg addClass: theClass. theClass := theClass superclass]. ^cg! ! !InterpreterPlugin class methodsFor: 'private' stamp: 'tpr 6/9/2003 16:41'! codeGeneratorClass "return the appropriate class of code generator for this kind ofplugin" ^VMPluginCodeGenerator! ! !InterpreterPlugin class methodsFor: 'translation' stamp: 'ar 5/12/2000 00:34'! declareCVarsIn: aCCodeGenerator "Note: This method must be implemented by all subclasses to declare variables." aCCodeGenerator var: #interpreterProxy type: #'struct VirtualMachine*'. self declareHeaderFilesIn: aCCodeGenerator.! ! !InterpreterPlugin class methodsFor: 'translation' stamp: 'tpr 5/23/2001 17:14'! declareHeaderFilesIn: aCCodeGenerator self hasHeaderFile ifTrue:[ aCCodeGenerator addHeaderFile: '"', self moduleName,'.h"'].! ! !InterpreterPlugin class methodsFor: 'instance creation' stamp: 'ar 12/31/2001 01:36'! doPrimitive: primitiveName | proxy plugin | proxy := InterpreterProxy new. proxy loadStackFrom: thisContext sender. plugin := self simulatorClass new. plugin setInterpreter: proxy. (plugin respondsTo: #initialiseModule) ifTrue:[plugin initialiseModule]. plugin perform: primitiveName asSymbol. ^ proxy stackValue: 0! ! !InterpreterPlugin class methodsFor: 'translation' stamp: 'tpr 5/23/2001 17:03'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^false! ! !InterpreterPlugin class methodsFor: 'class initialization' stamp: 'ar 9/16/1998 20:26'! initialize "Nothing to do ..."! ! !InterpreterPlugin class methodsFor: 'accessing' stamp: 'RMF 3/27/2000 09:39'! isCPP ^ false! ! !InterpreterPlugin class methodsFor: 'translation' stamp: 'tpr 5/28/2008 19:03'! isSuitablePluginForPlatform: platName "Is this plugin one that should be built for platName? We do NOT test for the existence of any external files here" "generic answer is true" ^true! ! !InterpreterPlugin class methodsFor: 'accessing' stamp: 'sma 4/22/2000 12:32'! moduleExtension ^ self isCPP ifTrue: ['.cpp'] ifFalse: ['.c']! ! !InterpreterPlugin class methodsFor: 'accessing' stamp: 'sma 3/3/2000 12:24'! moduleName "Answer the receiver's module name that is used for the plugin's C code." ^ self name asString! ! !InterpreterPlugin class methodsFor: 'accessing' stamp: 'TPR 5/23/2000 15:33'! moduleNameAndVersion "Answer the receiver's module name and version info that is used for the plugin's C code. The default is to append the code generation date, but any useful text is ok (keep it short)" ^ self moduleName, Character space asString, Date today asString! ! !InterpreterPlugin class methodsFor: 'compiling' stamp: 'tpr 2/17/2005 13:19'! noteCompilationOf: aSelector meta: isMeta "note the recompiliation by resetting the timeStamp " timeStamp := Time totalSeconds. ^super noteCompilationOf: aSelector meta: isMeta! ! !InterpreterPlugin class methodsFor: 'translation' stamp: 'tpr 2/27/2004 19:05'! requiredMethodNames "return the list of method names that should be retained for export or other support reasons" "just which methods?" ^#()! ! !InterpreterPlugin class methodsFor: 'translation' stamp: 'tpr 7/2/2001 16:33'! requiresCrossPlatformFiles "default is ok for most, any plugin needing cross platform files aside from a normal header must say so. See SoundCodecPlugin for example" ^self hasHeaderFile! ! !InterpreterPlugin class methodsFor: 'translation' stamp: 'tpr 11/21/2000 11:53'! requiresPlatformFiles "default is ok for most, any plugin needing platform specific files must say so" ^false! ! !InterpreterPlugin class methodsFor: 'translation' stamp: 'tpr 5/14/2001 12:05'! shouldBeTranslated "is this class intended to be translated as a plugin? Most subclasses should answer true, but some such as:- TestInterpreterPlugin FlippArrayPlugin2 InflatePlugin should answer false for various reasons." ^true! ! !InterpreterPlugin class methodsFor: 'accessing' stamp: 'ajh 8/21/2002 21:43'! simulatorClass "For running from Smalltalk - answer a class that can be used to simulate the receiver, or nil if you want the primitives in this module to always fail, causing simulation to fall through to the Smalltalk code. By default every non-TestInterpreterPlugin can simulate itself." ^ self! ! !InterpreterPlugin class methodsFor: 'translation' stamp: 'tpr 9/26/2001 07:27'! storeString: s onFileNamed: fileName "Store the given string in a file of the given name." | f | f := CrLfFileStream forceNewFileNamed: fileName. f nextPutAll: s. f close.! ! !InterpreterPlugin class methodsFor: 'accessing' stamp: 'tpr 3/26/2002 15:25'! timeStamp ^timeStamp ifNil:[0]! ! !InterpreterPlugin class methodsFor: 'translation' stamp: 'tpr 4/9/2002 16:14'! translateInDirectory: directory doInlining: inlineFlag "This is the default method for writing out sources for a plugin. Several classes need special handling, so look at all implementors of this message" | cg fname fstat | fname := self moduleName, '.c'. "don't translate if the file is newer than my timeStamp" fstat := directory entryAt: fname ifAbsent:[nil]. fstat ifNotNil:[self timeStamp < fstat modificationTime ifTrue:[^nil]]. self initialize. cg := self buildCodeGeneratorUpTo: self. cg storeCodeOnFile: (directory fullNameFor: fname) doInlining: inlineFlag. ^cg exportedPrimitiveNames asArray! ! !InterpreterPlugin methodsFor: 'initialize' stamp: 'ikp (auto pragmas 12/08) 8/3/2004 19:18'! getInterpreter "Note: This is coded so that plugins can be run from Squeak." ^interpreterProxy! ! !InterpreterPlugin methodsFor: 'initialize' stamp: 'ar (auto pragmas dtl 2010-09-28) 5/13/2000 02:00'! getModuleName "Note: This is hardcoded so it can be run from Squeak. The module name is used for validating a module *after* it is loaded to check if it does really contain the module we're thinking it contains. This is important!!" ^moduleName! ! !InterpreterPlugin methodsFor: 'debugging' stamp: 'yo 1/1/2004 11:09'! halt self cCode: '' inSmalltalk: [nil halt].! ! !InterpreterPlugin methodsFor: 'debugging' stamp: 'tpr (auto pragmas dtl 2010-09-28) 12/29/2005 16:34'! msg: s self cCode: 'fprintf(stderr, "\n%s: %s", moduleName, s)' inSmalltalk: [Transcript cr; show: self class moduleName , ': ' , s; endEntry]! ! !InterpreterPlugin methodsFor: 'initialize' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:53'! setInterpreter: anInterpreter "Note: This is coded so that is can be run from Squeak." | ok | interpreterProxy := anInterpreter. ok := self cCode: 'interpreterProxy->majorVersion() == VM_PROXY_MAJOR'. ok == false ifTrue: [^ false]. ok := self cCode: 'interpreterProxy->minorVersion() >= VM_PROXY_MINOR'. ^ ok! ! InterpreterPlugin subclass: #JPEGReaderPlugin instanceVariableNames: 'yComponent crComponent cbComponent ySampleStream crSampleStream cbSampleStream yBlocks crBlocks cbBlocks residuals ditherMask jpegBits jpegBitsSize jpegNaturalOrder jsCollection jsPosition jsReadLimit jsBitBuffer jsBitCount acTable dcTable acTableSize dcTableSize' classVariableNames: 'BlockWidthIndex BlueIndex ConstBits CurrentXIndex CurrentYIndex DCTSize DCTSize2 FIXn0n298631336 FIXn0n34414 FIXn0n390180644 FIXn0n541196100 FIXn0n71414 FIXn0n765366865 FIXn0n899976223 FIXn1n175875602 FIXn1n40200 FIXn1n501321110 FIXn1n77200 FIXn1n847759065 FIXn1n961570560 FIXn2n053119869 FIXn2n562915447 FIXn3n072711026 GreenIndex HScaleIndex LookaheadBitsIndex LookaheadSymbolIndex MCUBlockIndex MCUWidthIndex MaxBits MaxMCUBlocks MaxSample MaxcodeIndex MinComponentSize Pass1Bits Pass1Div Pass2Div PriorDCValueIndex RedIndex SampleOffset VScaleIndex' poolDictionaries: '' category: 'VMMaker-Plugins'! !JPEGReaderPlugin commentStamp: 'tpr 5/5/2003 12:10' prior: 0! This is another JPEG reader plugin, this time not requiring jpeglib support. ! !JPEGReaderPlugin class methodsFor: 'translation' stamp: 'ar 3/4/2001 21:13'! declareCVarsIn: cg cg var: 'yComponent' declareC: 'int yComponent[' , MinComponentSize printString , ']'. cg var: 'crComponent' declareC: 'int crComponent[' , MinComponentSize printString , ']'. cg var: 'cbComponent' declareC: 'int cbComponent[' , MinComponentSize printString , ']'. cg var: 'yBlocks' declareC: 'int *yBlocks[' , MaxMCUBlocks printString , ']'. cg var: 'crBlocks' declareC: 'int *crBlocks[' , MaxMCUBlocks printString , ']'. cg var: 'cbBlocks' declareC: 'int *cbBlocks[' , MaxMCUBlocks printString , ']'. cg var: 'residuals' declareC: 'int *residuals'. cg var: 'jpegBits' declareC: 'int *jpegBits'. cg var: 'jpegNaturalOrder' declareC: 'int jpegNaturalOrder[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }'. cg var: 'jsCollection' declareC:'unsigned char *jsCollection'. cg var: 'acTable' declareC:'int *acTable'. cg var: 'dcTable' declareC:'int *dcTable'. ! ! !JPEGReaderPlugin class methodsFor: 'class initialization' stamp: 'ar 3/4/2001 19:13'! initialize "JPEGReaderPlugin initialize" DCTSize := 8. MaxSample := (2 raisedToInteger: DCTSize) - 1. SampleOffset := MaxSample // 2. DCTSize2 := DCTSize squared. ConstBits := 13. Pass1Bits := 2. Pass1Div := 1 bitShift: ConstBits - Pass1Bits. Pass2Div := 1 bitShift: ConstBits + Pass1Bits + 3. "fixed-point Inverse Discrete Cosine Transform (IDCT) constants" FIXn0n298631336 := 2446. FIXn0n390180644 := 3196. FIXn0n541196100 := 4433. FIXn0n765366865 := 6270. FIXn0n899976223 := 7373. FIXn1n175875602 := 9633. FIXn1n501321110 := 12299. FIXn1n847759065 := 15137. FIXn1n961570560 := 16069. FIXn2n053119869 := 16819. FIXn2n562915447 := 20995. FIXn3n072711026 := 25172. "fixed-point color conversion constants" FIXn0n34414 := 22554. FIXn0n71414 := 46802. FIXn1n40200 := 91881. FIXn1n77200 := 116130. CurrentXIndex := 0. CurrentYIndex := 1. HScaleIndex := 2. VScaleIndex := 3. MCUBlockIndex := 4. BlockWidthIndex := 5. MCUWidthIndex := 8. PriorDCValueIndex := 10. MinComponentSize := 11. RedIndex := 0. GreenIndex := 1. BlueIndex := 2. MaxMCUBlocks := 128. MaxBits := 16.! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar 3/4/2001 21:11'! cbColorComponentFrom: oop ^(self colorComponent: cbComponent from: oop) and:[self colorComponentBlocks: cbBlocks from: oop]! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar (auto pragmas 12/08) 3/4/2001 20:08'! colorComponent: aColorComponent from: oop (interpreterProxy isIntegerObject: oop) ifTrue:[^false]. (interpreterProxy isPointers: oop) ifFalse:[^false]. (interpreterProxy slotSizeOf: oop) < MinComponentSize ifTrue:[^false]. aColorComponent at: CurrentXIndex put: (interpreterProxy fetchInteger: CurrentXIndex ofObject: oop). aColorComponent at: CurrentYIndex put: (interpreterProxy fetchInteger: CurrentYIndex ofObject: oop). aColorComponent at: HScaleIndex put: (interpreterProxy fetchInteger: HScaleIndex ofObject: oop). aColorComponent at: VScaleIndex put: (interpreterProxy fetchInteger: VScaleIndex ofObject: oop). aColorComponent at: BlockWidthIndex put: (interpreterProxy fetchInteger: BlockWidthIndex ofObject: oop). aColorComponent at: MCUWidthIndex put: (interpreterProxy fetchInteger: MCUWidthIndex ofObject: oop). aColorComponent at: PriorDCValueIndex put: (interpreterProxy fetchInteger: PriorDCValueIndex ofObject: oop). ^interpreterProxy failed not! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar (auto pragmas 12/08) 3/4/2001 20:08'! colorComponentBlocks: blocks from: oop | arrayOop max blockOop | (interpreterProxy isIntegerObject: oop) ifTrue:[^false]. (interpreterProxy isPointers: oop) ifFalse:[^false]. (interpreterProxy slotSizeOf: oop) < MinComponentSize ifTrue:[^false]. arrayOop := interpreterProxy fetchPointer: MCUBlockIndex ofObject: oop. (interpreterProxy isIntegerObject: arrayOop) ifTrue:[^false]. (interpreterProxy isPointers: arrayOop) ifFalse:[^false]. max := interpreterProxy slotSizeOf: arrayOop. max > MaxMCUBlocks ifTrue:[^false]. 0 to: max-1 do:[:i| blockOop := interpreterProxy fetchPointer: i ofObject: arrayOop. (interpreterProxy isIntegerObject: blockOop) ifTrue:[^false]. (interpreterProxy isWords: blockOop) ifFalse:[^false]. (interpreterProxy slotSizeOf: blockOop) = DCTSize2 ifFalse:[^false]. blocks at: i put: (interpreterProxy firstIndexableField: blockOop). ]. ^interpreterProxy failed not! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar 3/4/2001 22:24'! colorConvertGrayscaleMCU | y | yComponent at: CurrentXIndex put: 0. yComponent at: CurrentYIndex put: 0. 0 to: jpegBitsSize-1 do:[:i| y := self nextSampleY. y := y + (residuals at: GreenIndex). y := y min: MaxSample. residuals at: GreenIndex put: (y bitAnd: ditherMask). y := y bitAnd: MaxSample - ditherMask. y := y max: 1. jpegBits at: i put: 16rFF000000 + (y<<16) + (y<<8) + y. ].! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar 3/4/2001 21:11'! colorConvertMCU | y cb cr red green blue | yComponent at: CurrentXIndex put: 0. yComponent at: CurrentYIndex put: 0. cbComponent at: CurrentXIndex put: 0. cbComponent at: CurrentYIndex put: 0. crComponent at: CurrentXIndex put: 0. crComponent at: CurrentYIndex put: 0. 0 to: jpegBitsSize-1 do:[:i| y := self nextSampleY. cb := self nextSampleCb. cb := cb - SampleOffset. cr := self nextSampleCr. cr := cr - SampleOffset. red := y + ((FIXn1n40200 * cr) // 65536) + (residuals at: RedIndex). red := red min: MaxSample. red := red max: 0. residuals at: RedIndex put: (red bitAnd: ditherMask). red := red bitAnd: MaxSample - ditherMask. red := red max: 1. green := y - ((FIXn0n34414 * cb) // 65536) - ((FIXn0n71414 * cr) // 65536) + (residuals at: GreenIndex). green := green min: MaxSample. green := green max: 0. residuals at: GreenIndex put: (green bitAnd: ditherMask). green := green bitAnd: MaxSample - ditherMask. green := green max: 1. blue := y + ((FIXn1n77200 * cb) // 65536) + (residuals at: BlueIndex). blue := blue min: MaxSample. blue := blue max: 0. residuals at: BlueIndex put: (blue bitAnd: ditherMask). blue := blue bitAnd: MaxSample - ditherMask. blue := blue max: 1. jpegBits at: i put: 16rFF000000 + (red bitShift: 16) + (green bitShift: 8) + blue. ].! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar 3/4/2001 21:11'! crColorComponentFrom: oop ^(self colorComponent: crComponent from: oop) and:[self colorComponentBlocks: crBlocks from: oop]! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar (auto pragmas 12/08) 3/4/2001 21:17'! decodeBlockInto: anArray component: aColorComponent | byte zeroCount bits index | byte := self jpegDecodeValueFrom: dcTable size: dcTableSize. byte < 0 ifTrue:[^interpreterProxy primitiveFail]. byte ~= 0 ifTrue: [ bits := self getBits: byte. byte := self scaleAndSignExtend: bits inFieldWidth: byte]. byte := aColorComponent at: PriorDCValueIndex put: (aColorComponent at: PriorDCValueIndex) + byte. anArray at: 0 put: byte. 1 to: DCTSize2 - 1 do:[:i| anArray at: i put: 0]. index := 1. [index < DCTSize2] whileTrue:[ byte := self jpegDecodeValueFrom: acTable size: acTableSize. byte < 0 ifTrue:[^interpreterProxy primitiveFail]. zeroCount := byte >> 4. byte := byte bitAnd: 16r0F. byte ~= 0 ifTrue:[ index := index + zeroCount. bits := self getBits: byte. byte := self scaleAndSignExtend: bits inFieldWidth: byte. (index < 0 or:[index >= DCTSize2]) ifTrue:[^interpreterProxy primitiveFail]. anArray at: (jpegNaturalOrder at: index) put: byte. ] ifFalse:[ zeroCount = 15 ifTrue: [index := index + zeroCount] ifFalse: [^ nil]. ]. index := index + 1 ].! ! !JPEGReaderPlugin methodsFor: 'stream support' stamp: 'ar 3/4/2001 20:44'! fillBuffer | byte | [jsBitCount <= 16] whileTrue:[ jsPosition < jsReadLimit ifFalse:[^jsBitCount]. byte := jsCollection at: jsPosition. jsPosition := jsPosition + 1. byte = 16rFF ifTrue:["peek for 00" ((jsPosition < jsReadLimit) and:[(jsCollection at: jsPosition) = 16r00]) ifFalse:[ jsPosition := jsPosition - 1. ^jsBitCount]. jsPosition := jsPosition + 1]. jsBitBuffer := (jsBitBuffer bitShift: 8) bitOr: byte. jsBitCount := jsBitCount + 8]. ^jsBitCount! ! !JPEGReaderPlugin methodsFor: 'stream support' stamp: 'ar 3/4/2001 21:22'! getBits: requestedBits | value | requestedBits > jsBitCount ifTrue:[ self fillBuffer. requestedBits > jsBitCount ifTrue:[^-1]]. value := jsBitBuffer bitShift: (requestedBits - jsBitCount). jsBitBuffer := jsBitBuffer bitAnd: (1 bitShift: (jsBitCount - requestedBits)) -1. jsBitCount := jsBitCount - requestedBits. ^ value! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar (auto pragmas dtl 2010-09-28) 3/4/2001 21:16'! idctBlockInt: anArray qt: qt | ws anACTerm dcval z2 z3 z1 t2 t3 t0 t1 t10 t13 t11 t12 z4 z5 v | self cCode:'' inSmalltalk:[ws := CArrayAccessor on: (IntegerArray new: 64)]. "Pass 1: process columns from anArray, store into work array" 0 to: DCTSize-1 do:[:i | anACTerm := -1. 1 to: DCTSize-1 do:[:row| anACTerm = -1 ifTrue:[ (anArray at: row * DCTSize + i) = 0 ifFalse:[anACTerm := row]]]. anACTerm = -1 ifTrue:[ dcval := (anArray at: i) * (qt at: 0) bitShift: Pass1Bits. 0 to: DCTSize-1 do: [:j | ws at: (j * DCTSize + i) put: dcval] ] ifFalse:[ z2 := (anArray at: (DCTSize * 2 + i)) * (qt at: (DCTSize * 2 + i)). z3 := (anArray at: (DCTSize * 6 + i)) * (qt at: (DCTSize * 6 + i)). z1 := (z2 + z3) * FIXn0n541196100. t2 := z1 + (z3 * (0 - FIXn1n847759065)). t3 := z1 + (z2 * FIXn0n765366865). z2 := (anArray at: i) * (qt at: i). z3 := (anArray at: (DCTSize * 4 + i)) * (qt at: (DCTSize * 4 + i)). t0 := (z2 + z3) bitShift: ConstBits. t1 := (z2 - z3) bitShift: ConstBits. t10 := t0 + t3. t13 := t0 - t3. t11 := t1 + t2. t12 := t1 - t2. t0 := (anArray at: (DCTSize * 7 + i)) * (qt at: (DCTSize * 7 + i)). t1 := (anArray at: (DCTSize * 5 + i)) * (qt at: (DCTSize * 5 + i)). t2 := (anArray at: (DCTSize * 3 + i)) * (qt at: (DCTSize * 3 + i)). t3 := (anArray at: (DCTSize + i)) * (qt at: (DCTSize + i)). z1 := t0 + t3. z2 := t1 + t2. z3 := t0 + t2. z4 := t1 + t3. z5 := (z3 + z4) * FIXn1n175875602. t0 := t0 * FIXn0n298631336. t1 := t1 * FIXn2n053119869. t2 := t2 * FIXn3n072711026. t3 := t3 * FIXn1n501321110. z1 := z1 * (0 - FIXn0n899976223). z2 := z2 * (0 - FIXn2n562915447). z3 := z3 * (0 - FIXn1n961570560). z4 := z4 * (0 - FIXn0n390180644). z3 := z3 + z5. z4 := z4 + z5. t0 := t0 + z1 + z3. t1 := t1 +z2 +z4. t2 := t2 + z2 + z3. t3 := t3 + z1 + z4. ws at: i put: (t10 + t3) // Pass1Div. ws at: (DCTSize * 7 + i) put: (t10 - t3) // Pass1Div. ws at: (DCTSize * 1 + i) put: (t11 + t2) // Pass1Div. ws at: (DCTSize * 6 + i) put: (t11 - t2) // Pass1Div. ws at: (DCTSize * 2 + i) put: (t12 + t1) // Pass1Div. ws at: (DCTSize * 5 + i) put: (t12 - t1) // Pass1Div. ws at: (DCTSize * 3 + i) put: (t13 + t0) // Pass1Div. ws at: (DCTSize * 4 + i) put: (t13 - t0) // Pass1Div]]. "Pass 2: process rows from work array, store back into anArray" 0 to: DCTSize2-DCTSize by: DCTSize do:[:i | z2 := ws at: i + 2. z3 := ws at: i + 6. z1 := (z2 + z3) * FIXn0n541196100. t2 := z1 + (z3 * (0-FIXn1n847759065)). t3 := z1 + (z2 * FIXn0n765366865). t0 := (ws at: i) + (ws at: (i + 4)) bitShift: ConstBits. t1 := (ws at: i) - (ws at: (i + 4)) bitShift: ConstBits. t10 := t0 + t3. t13 := t0 - t3. t11 := t1 + t2. t12 := t1 -t2. t0 := ws at: (i + 7). t1 := ws at: (i + 5). t2 := ws at: (i + 3). t3 := ws at: (i + 1). z1 := t0 + t3. z2 := t1 + t2. z3 := t0 + t2. z4 := t1 + t3. z5 := (z3 + z4) * FIXn1n175875602. t0 := t0 * FIXn0n298631336. t1 := t1 * FIXn2n053119869. t2 := t2 * FIXn3n072711026. t3 := t3 * FIXn1n501321110. z1 := z1 * (0-FIXn0n899976223). z2 := z2 * (0-FIXn2n562915447). z3 := z3 * (0-FIXn1n961570560). z4 := z4 * (0-FIXn0n390180644). z3 := z3 + z5. z4 := z4 + z5. t0 := t0 + z1 + z3. t1 := t1 + z2 + z4. t2 := t2 + z2 + z3. t3 := t3 + z1 + z4. v := (t10 + t3) // Pass2Div + SampleOffset. v := v min: MaxSample. v := v max: 0. anArray at: i put: v. v := (t10 - t3) // Pass2Div + SampleOffset. v := v min: MaxSample. v := v max: 0. anArray at: (i + 7) put: v. v := (t11 + t2) // Pass2Div + SampleOffset. v := v min: MaxSample. v := v max: 0. anArray at: (i + 1) put: v. v := (t11 - t2) // Pass2Div + SampleOffset. v := v min: MaxSample. v := v max: 0. anArray at: (i + 6) put: v. v := (t12 + t1) // Pass2Div + SampleOffset. v := v min: MaxSample. v := v max: 0. anArray at: (i + 2) put: v. v := (t12 - t1) // Pass2Div + SampleOffset. v := v min: MaxSample. v := v max: 0. anArray at: (i + 5) put: v. v := (t13 + t0) // Pass2Div + SampleOffset. v := v min: MaxSample. v := v max: 0. anArray at: (i + 3) put: v. v := (t13 - t0) // Pass2Div + SampleOffset. v := v min: MaxSample. v := v max: 0. anArray at: (i + 4) put: v].! ! !JPEGReaderPlugin methodsFor: 'stream support' stamp: 'tpr (auto pragmas dtl 2010-09-28) 12/29/2005 16:36'! jpegDecodeValueFrom: table size: tableSize "Decode the next value in the receiver using the given huffman table." | bits bitsNeeded tableIndex value index | bitsNeeded := (table at: 0) >> 24. "Initial bits needed" bitsNeeded > MaxBits ifTrue:[^-1]. tableIndex := 2. "First real table" [true] whileTrue:[ bits := self getBits: bitsNeeded. "Get bits" bits < 0 ifTrue:[^-1]. index := tableIndex + bits - 1. index >= tableSize ifTrue:[^-1]. value := table at: index. "Lookup entry in table" (value bitAnd: 16r3F000000) = 0 ifTrue:[^value]. "Check if it is a leaf node" "Fetch sub table" tableIndex := value bitAnd: 16rFFFF. "Table offset in low 16 bit" bitsNeeded := (value >> 24) bitAnd: 255. "Additional bits in high 8 bit" bitsNeeded > MaxBits ifTrue:[^-1]]. ^-1! ! !JPEGReaderPlugin methodsFor: 'stream support' stamp: 'ar 3/4/2001 19:12'! loadJPEGStreamFrom: streamOop | oop sz | (interpreterProxy slotSizeOf: streamOop) < 5 ifTrue:[^false]. (interpreterProxy isPointers: streamOop) ifFalse:[^false]. oop := interpreterProxy fetchPointer: 0 ofObject: streamOop. (interpreterProxy isIntegerObject: oop) ifTrue:[^false]. (interpreterProxy isBytes: oop) ifFalse:[^false]. jsCollection := interpreterProxy firstIndexableField: oop. sz := interpreterProxy byteSizeOf: oop. jsPosition := interpreterProxy fetchInteger: 1 ofObject: streamOop. jsReadLimit := interpreterProxy fetchInteger: 2 ofObject: streamOop. jsBitBuffer := interpreterProxy fetchInteger: 3 ofObject: streamOop. jsBitCount := interpreterProxy fetchInteger: 4 ofObject: streamOop. interpreterProxy failed ifTrue:[^false]. sz < jsReadLimit ifTrue:[^false]. (jsPosition < 0 or:[jsPosition >= jsReadLimit]) ifTrue:[^false]. ^true! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar (auto pragmas 12/08) 3/4/2001 21:11'! nextSampleCb | dx dy blockIndex sampleIndex sample curX sx sy | dx := curX := cbComponent at: CurrentXIndex. dy := cbComponent at: CurrentYIndex. sx := cbComponent at: HScaleIndex. sy := cbComponent at: VScaleIndex. (sx = 0 and:[sy = 0]) ifFalse:[ dx := dx // sx. dy := dy // sy. ]. blockIndex := (dy bitShift: -3) * (cbComponent at: BlockWidthIndex) + (dx bitShift: -3). sampleIndex := ((dy bitAnd: 7) bitShift: 3) + (dx bitAnd: 7). sample := (cbBlocks at: blockIndex) at: sampleIndex. curX := curX + 1. curX < ((cbComponent at: MCUWidthIndex) * 8) ifTrue:[ cbComponent at: CurrentXIndex put: curX. ] ifFalse:[ cbComponent at: CurrentXIndex put: 0. cbComponent at: CurrentYIndex put: (cbComponent at: CurrentYIndex) + 1. ]. ^ sample! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar (auto pragmas 12/08) 3/4/2001 21:11'! nextSampleCr | dx dy blockIndex sampleIndex sample curX sx sy | dx := curX := crComponent at: CurrentXIndex. dy := crComponent at: CurrentYIndex. sx := crComponent at: HScaleIndex. sy := crComponent at: VScaleIndex. (sx = 0 and:[sy = 0]) ifFalse:[ dx := dx // sx. dy := dy // sy. ]. blockIndex := (dy bitShift: -3) * (crComponent at: BlockWidthIndex) + (dx bitShift: -3). sampleIndex := ((dy bitAnd: 7) bitShift: 3) + (dx bitAnd: 7). sample := (crBlocks at: blockIndex) at: sampleIndex. curX := curX + 1. curX < ((crComponent at: MCUWidthIndex) * 8) ifTrue:[ crComponent at: CurrentXIndex put: curX. ] ifFalse:[ crComponent at: CurrentXIndex put: 0. crComponent at: CurrentYIndex put: (crComponent at: CurrentYIndex) + 1. ]. ^ sample! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar (auto pragmas 12/08) 3/4/2001 21:16'! nextSampleFrom: aComponent blocks: aBlockArray | dx dy blockIndex sampleIndex sample curX sx sy | dx := curX := aComponent at: CurrentXIndex. dy := aComponent at: CurrentYIndex. sx := aComponent at: HScaleIndex. sy := aComponent at: VScaleIndex. (sx = 0 and:[sy = 0]) ifFalse:[ dx := dx // sx. dy := dy // sy. ]. blockIndex := (dy bitShift: -3) * (aComponent at: BlockWidthIndex) + (dx bitShift: -3). sampleIndex := ((dy bitAnd: 7) bitShift: 3) + (dx bitAnd: 7). sample := (aBlockArray at: blockIndex) at: sampleIndex. curX := curX + 1. curX < ((aComponent at: MCUWidthIndex) * 8) ifTrue:[ aComponent at: CurrentXIndex put: curX. ] ifFalse:[ aComponent at: CurrentXIndex put: 0. aComponent at: CurrentYIndex put: (aComponent at: CurrentYIndex) + 1. ]. ^ sample! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar (auto pragmas 12/08) 3/4/2001 21:10'! nextSampleY | dx dy blockIndex sampleIndex sample curX sx sy | dx := curX := yComponent at: CurrentXIndex. dy := yComponent at: CurrentYIndex. sx := yComponent at: HScaleIndex. sy := yComponent at: VScaleIndex. (sx = 0 and:[sy = 0]) ifFalse:[ dx := dx // sx. dy := dy // sy. ]. blockIndex := (dy bitShift: -3) * (yComponent at: BlockWidthIndex) + (dx bitShift: -3). sampleIndex := ((dy bitAnd: 7) bitShift: 3) + (dx bitAnd: 7). sample := (yBlocks at: blockIndex) at: sampleIndex. curX := curX + 1. curX < ((yComponent at: MCUWidthIndex) * 8) ifTrue:[ yComponent at: CurrentXIndex put: curX. ] ifFalse:[ yComponent at: CurrentXIndex put: 0. yComponent at: CurrentYIndex put: (yComponent at: CurrentYIndex) + 1. ]. ^ sample! ! !JPEGReaderPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 3/4/2001 22:21'! primitiveColorConvertGrayscaleMCU "Requires: JPEGColorComponent bits WordArray with: 3*Integer (residuals) ditherMask " | arrayOop | self stInit. interpreterProxy methodArgumentCount = 4 ifFalse:[^interpreterProxy primitiveFail]. ditherMask := interpreterProxy stackIntegerValue: 0. arrayOop := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. ((interpreterProxy isWords: arrayOop) and:[(interpreterProxy slotSizeOf: arrayOop) = 3]) ifFalse:[^interpreterProxy primitiveFail]. residuals := interpreterProxy firstIndexableField: arrayOop. arrayOop := interpreterProxy stackObjectValue: 2. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isWords: arrayOop) ifFalse:[^interpreterProxy primitiveFail]. jpegBitsSize := interpreterProxy slotSizeOf: arrayOop. jpegBits := interpreterProxy firstIndexableField: arrayOop. arrayOop := interpreterProxy stackObjectValue: 3. interpreterProxy failed ifTrue:[^nil]. (self yColorComponentFrom: arrayOop) ifFalse:[^interpreterProxy primitiveFail]. self colorConvertGrayscaleMCU. interpreterProxy pop: 4.! ! !JPEGReaderPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 3/4/2001 21:13'! primitiveColorConvertMCU "Requires: Array with: 3*JPEGColorComponent bits WordArray with: 3*Integer (residuals) ditherMask " | arrayOop | self stInit. interpreterProxy methodArgumentCount = 4 ifFalse:[^interpreterProxy primitiveFail]. ditherMask := interpreterProxy stackIntegerValue: 0. arrayOop := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. ((interpreterProxy isWords: arrayOop) and:[(interpreterProxy slotSizeOf: arrayOop) = 3]) ifFalse:[^interpreterProxy primitiveFail]. residuals := interpreterProxy firstIndexableField: arrayOop. arrayOop := interpreterProxy stackObjectValue: 2. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isWords: arrayOop) ifFalse:[^interpreterProxy primitiveFail]. jpegBitsSize := interpreterProxy slotSizeOf: arrayOop. jpegBits := interpreterProxy firstIndexableField: arrayOop. arrayOop := interpreterProxy stackObjectValue: 3. interpreterProxy failed ifTrue:[^nil]. ((interpreterProxy isPointers: arrayOop) and:[(interpreterProxy slotSizeOf: arrayOop) = 3]) ifFalse:[^interpreterProxy primitiveFail]. (self yColorComponentFrom: (interpreterProxy fetchPointer: 0 ofObject: arrayOop)) ifFalse:[^interpreterProxy primitiveFail]. (self cbColorComponentFrom: (interpreterProxy fetchPointer: 1 ofObject: arrayOop)) ifFalse:[^interpreterProxy primitiveFail]. (self crColorComponentFrom: (interpreterProxy fetchPointer: 2 ofObject: arrayOop)) ifFalse:[^interpreterProxy primitiveFail]. self colorConvertMCU. interpreterProxy pop: 4.! ! !JPEGReaderPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 3/4/2001 21:21'! primitiveDecodeMCU "In: anArray WordArray of: DCTSize2 aColorComponent JPEGColorComponent dcTable WordArray acTable WordArray stream JPEGStream " | arrayOop oop anArray | self cCode:'' inSmalltalk:[self stInit]. interpreterProxy methodArgumentCount = 5 ifFalse:[^interpreterProxy primitiveFail]. oop := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. (self loadJPEGStreamFrom: oop) ifFalse:[^interpreterProxy primitiveFail]. arrayOop := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isWords: arrayOop) ifFalse:[^interpreterProxy primitiveFail]. acTableSize := interpreterProxy slotSizeOf: arrayOop. acTable := interpreterProxy firstIndexableField: arrayOop. arrayOop := interpreterProxy stackObjectValue: 2. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isWords: arrayOop) ifFalse:[^interpreterProxy primitiveFail]. dcTableSize := interpreterProxy slotSizeOf: arrayOop. dcTable := interpreterProxy firstIndexableField: arrayOop. oop := interpreterProxy stackObjectValue: 3. interpreterProxy failed ifTrue:[^nil]. (self colorComponent: yComponent from: oop) ifFalse:[^interpreterProxy primitiveFail]. arrayOop := interpreterProxy stackObjectValue: 4. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isWords: arrayOop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: arrayOop) = DCTSize2 ifFalse:[^interpreterProxy primitiveFail]. anArray := interpreterProxy firstIndexableField: arrayOop. interpreterProxy failed ifTrue:[^nil]. self decodeBlockInto: anArray component: yComponent. interpreterProxy failed ifTrue:[^nil]. self storeJPEGStreamOn: (interpreterProxy stackValue: 0). interpreterProxy storeInteger: PriorDCValueIndex ofObject: (interpreterProxy stackValue: 3) withValue: (yComponent at: PriorDCValueIndex). interpreterProxy pop: 5.! ! !JPEGReaderPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 3/4/2001 21:14'! primitiveIdctInt "In: anArray: IntegerArray new: DCTSize2 qt: IntegerArray new: DCTSize2. " | arrayOop anArray qt | self cCode:'' inSmalltalk:[self stInit]. interpreterProxy methodArgumentCount = 2 ifFalse:[^interpreterProxy primitiveFail]. arrayOop := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. ((interpreterProxy isWords: arrayOop) and:[(interpreterProxy slotSizeOf: arrayOop) = DCTSize2]) ifFalse:[^interpreterProxy primitiveFail]. qt := interpreterProxy firstIndexableField: arrayOop. arrayOop := interpreterProxy stackObjectValue: 1. interpreterProxy failed ifTrue:[^nil]. ((interpreterProxy isWords: arrayOop) and:[(interpreterProxy slotSizeOf: arrayOop) = DCTSize2]) ifFalse:[^interpreterProxy primitiveFail]. anArray := interpreterProxy firstIndexableField: arrayOop. self idctBlockInt: anArray qt: qt. interpreterProxy pop: 2.! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar (auto pragmas 12/08) 3/4/2001 17:16'! scaleAndSignExtend: aNumber inFieldWidth: w aNumber < (1 bitShift: (w - 1)) ifTrue: [^aNumber - (1 bitShift: w) + 1] ifFalse: [^aNumber]! ! !JPEGReaderPlugin methodsFor: 'initialize' stamp: 'ar 3/4/2001 21:10'! stInit self cCode:'' inSmalltalk:[ yComponent := CArrayAccessor on: (IntegerArray new: MinComponentSize). cbComponent := CArrayAccessor on: (IntegerArray new: MinComponentSize). crComponent := CArrayAccessor on: (IntegerArray new: MinComponentSize). yBlocks := CArrayAccessor on: (Array new: MaxMCUBlocks). crBlocks := CArrayAccessor on: (Array new: MaxMCUBlocks). cbBlocks := CArrayAccessor on: (Array new: MaxMCUBlocks). jpegNaturalOrder := CArrayAccessor on: #( 0 1 8 16 9 2 3 10 17 24 32 25 18 11 4 5 12 19 26 33 40 48 41 34 27 20 13 6 7 14 21 28 35 42 49 56 57 50 43 36 29 22 15 23 30 37 44 51 58 59 52 45 38 31 39 46 53 60 61 54 47 55 62 63). ].! ! !JPEGReaderPlugin methodsFor: 'stream support' stamp: 'ar 3/4/2001 19:04'! storeJPEGStreamOn: streamOop interpreterProxy storeInteger: 1 ofObject: streamOop withValue: jsPosition. interpreterProxy storeInteger: 3 ofObject: streamOop withValue: jsBitBuffer. interpreterProxy storeInteger: 4 ofObject: streamOop withValue: jsBitCount.! ! !JPEGReaderPlugin methodsFor: 'decoding' stamp: 'ar 3/4/2001 21:10'! yColorComponentFrom: oop ^(self colorComponent: yComponent from: oop) and:[self colorComponentBlocks: yBlocks from: oop]! ! InterpreterPlugin subclass: #Matrix2x3Plugin instanceVariableNames: 'm23ResultX m23ResultY m23ArgX m23ArgY' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !Matrix2x3Plugin class methodsFor: 'class initialization' stamp: 'sma 3/3/2000 12:39'! declareCVarsIn: cg cg var: #m23ResultX type: #double. cg var: #m23ResultY type: #double. cg var: #m23ArgX type: #double. cg var: #m23ArgY type: #double! ! !Matrix2x3Plugin methodsFor: 'private' stamp: 'ar (auto pragmas dtl 2010-09-28) 11/9/1998 15:17'! loadArgumentMatrix: matrix "Load the argument matrix" interpreterProxy failed ifTrue:[^nil]. ((interpreterProxy isWords: matrix) and:[(interpreterProxy slotSizeOf: matrix) = 6]) ifFalse:[interpreterProxy primitiveFail. ^nil]. ^self cCoerce: (interpreterProxy firstIndexableField: matrix) to:'float *'.! ! !Matrix2x3Plugin methodsFor: 'private' stamp: 'ar 11/9/1998 16:17'! loadArgumentPoint: point "Load the argument point into m23ArgX and m23ArgY" | oop isInt | interpreterProxy failed ifTrue:[^nil]. "Check class of point" (interpreterProxy fetchClassOf: point) = (interpreterProxy classPoint) ifFalse:[^interpreterProxy primitiveFail]. "Load X value" oop := interpreterProxy fetchPointer: 0 ofObject: point. isInt := interpreterProxy isIntegerObject: oop. (isInt or:[interpreterProxy isFloatObject: oop]) ifFalse:[^interpreterProxy primitiveFail]. isInt ifTrue:[m23ArgX := interpreterProxy integerValueOf: oop] ifFalse:[m23ArgX := interpreterProxy floatValueOf: oop]. "Load Y value" oop := interpreterProxy fetchPointer: 1 ofObject: point. isInt := interpreterProxy isIntegerObject: oop. (isInt or:[interpreterProxy isFloatObject: oop]) ifFalse:[^interpreterProxy primitiveFail]. isInt ifTrue:[m23ArgY := interpreterProxy integerValueOf: oop] ifFalse:[m23ArgY := interpreterProxy floatValueOf: oop]. ! ! !Matrix2x3Plugin methodsFor: 'transforming' stamp: 'tpr (auto pragmas dtl 2010-09-28) 12/29/2005 17:02'! matrix2x3ComposeMatrix: m1 with: m2 into: m3 "Multiply matrix m1 with m2 and store the result into m3." | a11 a12 a13 a21 a22 a23 | a11 := ((m1 at: 0) * (m2 at: 0)) + ((m1 at: 1) * (m2 at: 3)). a12 := ((m1 at: 0) * (m2 at: 1)) + ((m1 at: 1) * (m2 at: 4)). a13 := ((m1 at: 0) * (m2 at: 2)) + ((m1 at: 1) * (m2 at: 5)) + (m1 at: 2). a21 := ((m1 at: 3) * (m2 at: 0)) + ((m1 at: 4) * (m2 at: 3)). a22 := ((m1 at: 3) * (m2 at: 1)) + ((m1 at: 4) * (m2 at: 4)). a23 := ((m1 at: 3) * (m2 at: 2)) + ((m1 at: 4) * (m2 at: 5)) + (m1 at: 5). m3 at: 0 put: (self cCoerce: a11 to: 'float'). m3 at: 1 put: (self cCoerce: a12 to: 'float'). m3 at: 2 put: (self cCoerce: a13 to: 'float'). m3 at: 3 put: (self cCoerce: a21 to: 'float'). m3 at: 4 put: (self cCoerce: a22 to: 'float'). m3 at: 5 put: (self cCoerce: a23 to: 'float'). ! ! !Matrix2x3Plugin methodsFor: 'transforming' stamp: 'tpr (auto pragmas dtl 2010-09-28) 12/29/2005 17:02'! matrix2x3InvertPoint: m "Invert the pre-loaded argument point by the given matrix" | x y det detX detY | x := m23ArgX - (m at: 2). y := m23ArgY - (m at: 5). det := ((m at: 0) * (m at: 4)) - ((m at: 1) * (m at: 3)). det = 0.0 ifTrue:[^interpreterProxy primitiveFail]."Matrix is singular." det := 1.0 / det. detX := (x * (m at: 4)) - ((m at: 1) * y). detY := ((m at: 0) * y) - (x * (m at: 3)). m23ResultX := detX * det. m23ResultY := detY * det.! ! !Matrix2x3Plugin methodsFor: 'transforming' stamp: 'tpr (auto pragmas dtl 2010-09-28) 12/29/2005 17:03'! matrix2x3TransformPoint: m "Transform the pre-loaded argument point by the given matrix" m23ResultX := (m23ArgX * (m at: 0)) + (m23ArgY * (m at: 1)) + (m at: 2). m23ResultY := (m23ArgX * (m at: 3)) + (m23ArgY * (m at: 4)) + (m at: 5).! ! !Matrix2x3Plugin methodsFor: 'private' stamp: 'ar 11/14/1998 02:37'! okayIntValue: value ^(value >= -1073741824 asFloat and:[m23ResultX <= 1073741823 asFloat]) ! ! !Matrix2x3Plugin methodsFor: 'primitives' stamp: 'dtl 10/14/2010 23:23'! primitiveComposeMatrix | m1 m2 m3 result | self cCode: '' "Make this fail in simulation" inSmalltalk: [interpreterProxy success: false. ^ nil]. m3 := self loadArgumentMatrix: (result := interpreterProxy stackObjectValue: 0). m2 := self loadArgumentMatrix: (interpreterProxy stackObjectValue: 1). m1 := self loadArgumentMatrix: (interpreterProxy stackObjectValue: 2). interpreterProxy failed ifTrue:[^nil]. self matrix2x3ComposeMatrix: m1 with: m2 into: m3. interpreterProxy pop: 3 thenPush: result! ! !Matrix2x3Plugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas dtl 2010-09-28) 12/29/2005 17:03'! primitiveInvertPoint | matrix | self loadArgumentPoint: (interpreterProxy stackObjectValue: 0). matrix := self loadArgumentMatrix: (interpreterProxy stackObjectValue: 1). interpreterProxy failed ifTrue:[^nil]. self matrix2x3InvertPoint: matrix. interpreterProxy failed ifFalse:[self roundAndStoreResultPoint: 2].! ! !Matrix2x3Plugin methodsFor: 'primitives' stamp: 'dtl 10/14/2010 23:25'! primitiveInvertRectInto | matrix srcOop dstOop originX originY cornerX cornerY minX maxX minY maxY | dstOop := interpreterProxy stackObjectValue: 0. srcOop := interpreterProxy stackObjectValue: 1. matrix := self loadArgumentMatrix: (interpreterProxy stackObjectValue: 2). interpreterProxy failed ifTrue:[^nil]. (interpreterProxy fetchClassOf: srcOop) = (interpreterProxy fetchClassOf: dstOop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isPointers: srcOop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: srcOop) = 2 ifFalse:[^interpreterProxy primitiveFail]. "Load top-left point" self loadArgumentPoint: (interpreterProxy fetchPointer: 0 ofObject: srcOop). interpreterProxy failed ifTrue:[^nil]. originX := m23ArgX. originY := m23ArgY. self matrix2x3InvertPoint: matrix. minX := maxX := m23ResultX. minY := maxY := m23ResultY. "Load bottom-right point" self loadArgumentPoint:(interpreterProxy fetchPointer: 1 ofObject: srcOop). interpreterProxy failed ifTrue:[^nil]. cornerX := m23ArgX. cornerY := m23ArgY. self matrix2x3InvertPoint: matrix. minX := minX min: m23ResultX. maxX := maxX max: m23ResultX. minY := minY min: m23ResultY. maxY := maxY max: m23ResultY. "Load top-right point" m23ArgX := cornerX. m23ArgY := originY. self matrix2x3InvertPoint: matrix. minX := minX min: m23ResultX. maxX := maxX max: m23ResultX. minY := minY min: m23ResultY. maxY := maxY max: m23ResultY. "Load bottom-left point" m23ArgX := originX. m23ArgY := cornerY. self matrix2x3InvertPoint: matrix. minX := minX min: m23ResultX. maxX := maxX max: m23ResultX. minY := minY min: m23ResultY. maxY := maxY max: m23ResultY. interpreterProxy failed ifFalse:[ dstOop := self roundAndStoreResultRect: dstOop x0: minX y0: minY x1: maxX y1: maxY]. interpreterProxy failed ifFalse:[ interpreterProxy pop: 3 thenPush: dstOop ] ! ! !Matrix2x3Plugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas dtl 2010-09-28) 12/29/2005 17:03'! primitiveIsIdentity | matrix | matrix := self loadArgumentMatrix: (interpreterProxy stackObjectValue: 0). interpreterProxy failed ifTrue:[^nil]. interpreterProxy pop: 1. interpreterProxy pushBool:( ((matrix at: 0) = (self cCoerce: 1.0 to: 'float')) & ((matrix at: 1) = (self cCoerce: 0.0 to: 'float')) & ((matrix at: 2) = (self cCoerce: 0.0 to: 'float')) & ((matrix at: 3) = (self cCoerce: 0.0 to: 'float')) & ((matrix at: 4) = (self cCoerce: 1.0 to: 'float')) & ((matrix at: 5) = (self cCoerce: 0.0 to: 'float'))).! ! !Matrix2x3Plugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas dtl 2010-09-28) 12/29/2005 17:04'! primitiveIsPureTranslation | matrix | matrix := self loadArgumentMatrix: (interpreterProxy stackObjectValue: 0). interpreterProxy failed ifTrue:[^nil]. interpreterProxy pop: 1. interpreterProxy pushBool:( ((matrix at: 0) = (self cCoerce: 1.0 to: 'float')) & ((matrix at: 1) = (self cCoerce: 0.0 to: 'float')) & ((matrix at: 3) = (self cCoerce: 0.0 to: 'float')) & ((matrix at: 4) = (self cCoerce: 1.0 to: 'float'))).! ! !Matrix2x3Plugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas dtl 2010-09-28) 12/29/2005 17:04'! primitiveTransformPoint | matrix | self loadArgumentPoint: (interpreterProxy stackObjectValue: 0). matrix := self loadArgumentMatrix: (interpreterProxy stackObjectValue: 1). interpreterProxy failed ifTrue:[^nil]. self matrix2x3TransformPoint: matrix. self roundAndStoreResultPoint: 2.! ! !Matrix2x3Plugin methodsFor: 'primitives' stamp: 'dtl 10/14/2010 23:27'! primitiveTransformRectInto | matrix srcOop dstOop originX originY cornerX cornerY minX maxX minY maxY | dstOop := interpreterProxy stackObjectValue: 0. srcOop := interpreterProxy stackObjectValue: 1. matrix := self loadArgumentMatrix: (interpreterProxy stackObjectValue: 2). interpreterProxy failed ifTrue:[^nil]. (interpreterProxy fetchClassOf: srcOop) = (interpreterProxy fetchClassOf: dstOop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy isPointers: srcOop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy slotSizeOf: srcOop) = 2 ifFalse:[^interpreterProxy primitiveFail]. "Load top-left point" self loadArgumentPoint: (interpreterProxy fetchPointer: 0 ofObject: srcOop). interpreterProxy failed ifTrue:[^nil]. originX := m23ArgX. originY := m23ArgY. self matrix2x3TransformPoint: matrix. minX := maxX := m23ResultX. minY := maxY := m23ResultY. "Load bottom-right point" self loadArgumentPoint:(interpreterProxy fetchPointer: 1 ofObject: srcOop). interpreterProxy failed ifTrue:[^nil]. cornerX := m23ArgX. cornerY := m23ArgY. self matrix2x3TransformPoint: matrix. minX := minX min: m23ResultX. maxX := maxX max: m23ResultX. minY := minY min: m23ResultY. maxY := maxY max: m23ResultY. "Load top-right point" m23ArgX := cornerX. m23ArgY := originY. self matrix2x3TransformPoint: matrix. minX := minX min: m23ResultX. maxX := maxX max: m23ResultX. minY := minY min: m23ResultY. maxY := maxY max: m23ResultY. "Load bottom-left point" m23ArgX := originX. m23ArgY := cornerY. self matrix2x3TransformPoint: matrix. minX := minX min: m23ResultX. maxX := maxX max: m23ResultX. minY := minY min: m23ResultY. maxY := maxY max: m23ResultY. dstOop := self roundAndStoreResultRect: dstOop x0: minX y0: minY x1: maxX y1: maxY. interpreterProxy failed ifFalse:[ interpreterProxy pop: 3 thenPush: dstOop ] ! ! !Matrix2x3Plugin methodsFor: 'private' stamp: 'eem 7/10/2010 21:38'! roundAndStoreResultPoint: nItemsToPop "Store the result of a previous operation. Fail if we cannot represent the result as SmallInteger" m23ResultX := m23ResultX + 0.5. m23ResultY := m23ResultY + 0.5. (self okayIntValue: m23ResultX) ifFalse:[^interpreterProxy primitiveFail]. (self okayIntValue: m23ResultY) ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy pop: nItemsToPop thenPush: (interpreterProxy makePointwithxValue: m23ResultX asInteger yValue: m23ResultY asInteger)! ! !Matrix2x3Plugin methodsFor: 'private' stamp: 'tpr (auto pragmas dtl 2010-09-28) 12/29/2005 17:04'! roundAndStoreResultRect: dstOop x0: x0 y0: y0 x1: x1 y1: y1 "Check, round and store the result of a rectangle operation" | minX maxX minY maxY originOop cornerOop rectOop | minX := x0 + 0.5. (self okayIntValue: minX) ifFalse:[^interpreterProxy primitiveFail]. maxX := x1 + 0.5. (self okayIntValue: maxX) ifFalse:[^interpreterProxy primitiveFail]. minY := y0 + 0.5. (self okayIntValue: minY) ifFalse:[^interpreterProxy primitiveFail]. maxY := y1 + 0.5. (self okayIntValue: maxY) ifFalse:[^interpreterProxy primitiveFail]. interpreterProxy pushRemappableOop: dstOop. originOop := interpreterProxy makePointwithxValue: minX asInteger yValue: minY asInteger. interpreterProxy pushRemappableOop: originOop. cornerOop := interpreterProxy makePointwithxValue: maxX asInteger yValue: maxY asInteger. originOop := interpreterProxy popRemappableOop. rectOop := interpreterProxy popRemappableOop. interpreterProxy storePointer: 0 ofObject: rectOop withValue: originOop. interpreterProxy storePointer: 1 ofObject: rectOop withValue: cornerOop. ^rectOop! ! InterpreterPlugin subclass: #MiscPrimitivePlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !MiscPrimitivePlugin commentStamp: 'dtl 12/2/2009 11:28' prior: 0! This plugin pulls together a number of translatable methods with no particularly meaningful home. See class>translatedPrimitives for the list. The primitives in this plugin consist of various methods in the image that can benefit greatly from translation to C, but that do not inherently require translation. These may be thought of not as traditional primitives, but as methods that have been annotated for translation to C by this plugin. This approach allows performance critical methods to be written entirely in Smalltalk, then marked for translation as needed to achieve improved performance.! !MiscPrimitivePlugin class methodsFor: 'translation' stamp: 'tpr 4/9/2002 16:15'! translateInDirectory: directory doInlining: inlineFlag "handle a special case code string rather than normal generated code." | cg fname fstat | fname := self moduleName, '.c'. "don't translate if the file is newer than my timeStamp" fstat := directory entryAt: fname ifAbsent:[nil]. fstat ifNotNil:[self timeStamp < fstat modificationTime ifTrue:[^nil]]. self initialize. cg := self buildCodeGeneratorUpTo: InterpreterPlugin. cg addMethodsForPrimitives: self translatedPrimitives. self storeString: cg generateCodeStringForPrimitives onFileNamed: (directory fullNameFor: fname). ^cg exportedPrimitiveNames asArray ! ! !MiscPrimitivePlugin class methodsFor: 'translation' stamp: 'eem 5/24/2010 09:15'! translatedPrimitives "an assorted list of various primitives" ^#( (Bitmap compress:toByteArray:) (Bitmap decompress:fromByteArray:at:) (Bitmap encodeBytesOf:in:at:) (Bitmap encodeInt:in:at:) (ByteString compare:with:collated:) (ByteString translate:from:to:table:) (ByteString findFirstInString:inSet:startingAt:) (ByteString indexOfAscii:inString:startingAt:) (ByteString findSubstring:in:startingAt:matchTable:) (ByteArray hashBytes:startingWith:) (SampledSound convert8bitSignedFrom:to16Bit:) ) "| tps | 'This opens a list browser on all translated primitives in the image'. tps := (SystemNavigation default allImplementorsOf: #translatedPrimitives) inject: Set new into: [:tp :mr| tp addAll: (mr actualClass theNonMetaClass translatedPrimitives collect: [:pair| MethodReference class: (((Smalltalk at: pair first) canUnderstand: pair last) ifTrue: [Smalltalk at: pair first] ifFalse: [(Smalltalk at: pair first) class]) selector: pair last]); yourself]. SystemNavigation default browseMessageList: tps asArray sort name: 'Translated Primitives' "! ! InterpreterPlugin subclass: #SecurityPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !SecurityPlugin commentStamp: 'tpr 5/5/2003 12:19' prior: 0! IMPLEMENTATION NOTES: The support should assume a trusted directory based on which access to files is granted when running in restricted mode. If necessary, links need to be resolved before granting access (currently, this applies only to platforms on which links can be created by simply creating the right kind of file). The untrusted user directory returned MUST be different from the image and VM location. Otherwise a Badlet could attempt to overwrite these by using simple file primitives. The secure directory location returned by the primitive is a place to store per-user security information. Again, this place needs to be outside the untrusted space. Examples: [Windows] * VM+image location: "C:\Program Files\Squeak\" * secure directory location: "C:\Program Files\Squeak\username\" * untrusted user directory: "C:\My Squeak\username\" [Unix] * VM+image location: "/user/local/squeak" * secure directory location: "~username/.squeak/ * untrusted user directory: "~username/squeak/" [Mac] * plugin VM location: "MacHD:Netscape:Plugins:" * standalone VM and image location: "MacHD:Squeak:" * secure directory location: "MacHD:Squeak:username:" * untrusted user directory: "MacHD:My Squeak:username:" Restoring the rights revoked by an image might be possible by some interaction with the VM directly. Any such action should be preceeded by a BIG FAT WARNING - the average user will never need that ability (if she does, we did something wrong) so this is a last resort in cases where something fundamtally tricky happened. ! !SecurityPlugin class methodsFor: 'translation' stamp: 'tpr 5/23/2001 17:10'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !SecurityPlugin class methodsFor: 'translation' stamp: 'tpr 3/20/2001 12:33'! requiresPlatformFiles "default is ok for most, any plugin needing platform specific files must say so" ^true! ! !SecurityPlugin methodsFor: 'initialize' stamp: 'JMM (auto pragmas 12/08) 8/15/2001 11:59'! initialiseModule ^self cCode: 'ioInitSecurity()' inSmalltalk:[true]! ! !SecurityPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 7/24/2003 12:54'! primitiveCanWriteImage interpreterProxy pop: 1. interpreterProxy pushBool: (self cCode:'ioCanWriteImage()' inSmalltalk:[true])! ! !SecurityPlugin methodsFor: 'primitives' stamp: 'John M McIntosh (auto pragmas dtl 2010-09-28) 5/5/2009 10:59'! primitiveDisableImageWrite self cCode:'ioDisableImageWrite()'. ! ! !SecurityPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/30/2005 15:51'! primitiveGetSecureUserDirectory "Primitive. Return the secure directory for the current user." | dirName dirLen dirOop dirPtr | dirName := self cCode: 'ioGetSecureUserDirectory()' inSmalltalk: [nil]. (dirName == nil or:[interpreterProxy failed]) ifTrue:[^interpreterProxy primitiveFail]. dirLen := self strlen: dirName. dirOop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: dirLen. interpreterProxy failed ifTrue:[^nil]. dirPtr := interpreterProxy firstIndexableField: dirOop. 0 to: dirLen-1 do:[:i| dirPtr at: i put: (dirName at: i)]. interpreterProxy pop: 1 thenPush: dirOop.! ! !SecurityPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/30/2005 15:52'! primitiveGetUntrustedUserDirectory "Primitive. Return the untrusted user directory name." | dirName dirLen dirOop dirPtr | dirName := self cCode:'ioGetUntrustedUserDirectory()' inSmalltalk:[nil]. (dirName == nil or:[interpreterProxy failed]) ifTrue:[^interpreterProxy primitiveFail]. dirLen := self strlen: dirName. dirOop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: dirLen. interpreterProxy failed ifTrue:[^nil]. dirPtr := interpreterProxy firstIndexableField: dirOop. 0 to: dirLen-1 do:[:i| dirPtr at: i put: (dirName at: i)]. interpreterProxy pop: 1 thenPush: dirOop.! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCan: socket ListenOnPort: port ^self cCode: 'ioCanListenOnPort(socket, port)'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCanConnect: addr ToPort: port ^self cCode: 'ioCanConnectToPort(addr, port)'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCanCreate: netType SocketOfType: socketType ^self cCode: 'ioCanCreateSocketOfType(netType, socketType)'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCanCreatePath: dirName OfSize: dirNameSize ^self cCode: 'ioCanCreatePathOfSize(dirName, dirNameSize)'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCanDeleteFile: fileName OfSize: fileNameSize ^self cCode: 'ioCanDeleteFileOfSize(fileName, fileNameSize)'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCanDeletePath: dirName OfSize: dirNameSize ^self cCode: 'ioCanDeletePathOfSize(dirName, dirNameSize)'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCanGetFileType: fileName OfSize: fileNameSize ^self cCode: 'ioCanGetFileTypeOfSize(fileName, fileNameSize)'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCanListPath: pathName OfSize: pathNameSize ^self cCode: 'ioCanListPathOfSize(pathName, pathNameSize)'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCanOpenAsyncFile: fileName OfSize: fileNameSize Writable: writeFlag ^self cCode: 'ioCanOpenAsyncFileOfSizeWritable(fileName, fileNameSize, writeFlag)'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCanOpenFile: fileName OfSize: fileNameSize Writable: writeFlag ^self cCode: 'ioCanOpenFileOfSizeWritable(fileName, fileNameSize, writeFlag)'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCanRenameFile: fileName OfSize: fileNameSize ^self cCode: 'ioCanRenameFileOfSize(fileName, fileNameSize)'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCanRenameImage ^self cCode: 'ioCanRenameImage()'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCanSetFileType: fileName OfSize: fileNameSize ^self cCode: 'ioCanSetFileTypeOfSize(fileName, fileNameSize)'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secCanWriteImage ^self cCode: 'ioCanWriteImage()'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secDisableFileAccess ^self cCode: 'ioDisableFileAccess()'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secDisableSocketAccess ^self cCode: 'ioDisableSocketAccess()'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secHasFileAccess ^self cCode: 'ioHasFileAccess()'! ! !SecurityPlugin methodsFor: 'exported functions' stamp: '(auto pragmas 12/08) '! secHasSocketAccess ^self cCode: 'ioHasSocketAccess()'! ! InterpreterPlugin subclass: #SlangTestSupportPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Tests'! !SlangTestSupportPlugin commentStamp: 'dtl 9/19/2010 21:36' prior: 0! SlangTestSupport implements translatable methods for use in SlangTest unit tests. This is a subclass of InterpreterPlugin, which provides coverage of slang translation for base plugins. "VMMaker clearCacheEntriesFor: SlangTestSupportPlugin. SlangTestSupportPlugin asCString"! !SlangTestSupportPlugin methodsFor: 'export declaration' stamp: 'dtl 9/19/2010 12:29'! declareExportFalseByMethod "SlangTestSupport asCString: #declareExportFalseByMethod" self export: false ! ! !SlangTestSupportPlugin methodsFor: 'export declaration' stamp: 'dtl 9/19/2010 12:29'! declareExportFalseByPragma "SlangTestSupport asCString: #declareExportFalseByPragma" ! ! !SlangTestSupportPlugin methodsFor: 'export declaration' stamp: 'dtl 9/19/2010 12:21'! declareExportTrueByMethod "SlangTestSupport asCString: #declareExportTrueByMethod" self export: true ! ! !SlangTestSupportPlugin methodsFor: 'export declaration' stamp: 'dtl 9/19/2010 12:21'! declareExportTrueByPragma "SlangTestSupport asCString: #declareExportTrueByPragma" ! ! !SlangTestSupportPlugin methodsFor: 'static declaration' stamp: 'dtl 9/19/2010 12:29'! declareStaticFalseByMethod "SlangTestSupport asCString: #declareStaticFalseByMethod" self static: false ! ! !SlangTestSupportPlugin methodsFor: 'static declaration' stamp: 'dtl 9/19/2010 12:30'! declareStaticFalseByPragma "SlangTestSupport asCString: #declareStaticFalseByPragma" ! ! !SlangTestSupportPlugin methodsFor: 'static declaration' stamp: 'dtl 9/19/2010 12:29'! declareStaticTrueByMethod "SlangTestSupport asCString: #declareStaticTrueByMethod" self static: true ! ! !SlangTestSupportPlugin methodsFor: 'static declaration' stamp: 'dtl 9/19/2010 12:30'! declareStaticTrueByPragma "SlangTestSupport asCString: #declareStaticTrueByPragma" ! ! !SlangTestSupportPlugin methodsFor: 'inlining' stamp: 'dtl 9/19/2010 11:50'! inlineByMethod "SlangTestSupport asCString: #inlineByMethod" "SlangTestSupport asInlinedCString: #inlineByMethod" | bar foo | foo := self methodThatShouldBeInlinedByMethod. bar := self methodThatShouldNotBeInlinedByMethod! ! !SlangTestSupportPlugin methodsFor: 'inlining' stamp: 'dtl 9/19/2010 11:50'! inlineByPragma "SlangTestSupport asCString: #inlineByPragma" "SlangTestSupport asInlinedCString: #inlineByPragma" | bar foo | foo := self methodThatShouldBeInlinedByPragma. bar := self methodThatShouldNotBeInlinedByPragma! ! !SlangTestSupportPlugin methodsFor: 'inlining' stamp: 'dtl 9/18/2010 17:59'! methodThatShouldBeInlinedByMethod self inline: true. ^ #foo! ! !SlangTestSupportPlugin methodsFor: 'inlining' stamp: 'dtl 9/18/2010 18:01'! methodThatShouldBeInlinedByPragma ^ #foo! ! !SlangTestSupportPlugin methodsFor: 'inlining' stamp: 'dtl 9/18/2010 18:01'! methodThatShouldNotBeInlinedByMethod self inline: false. ^ #bar! ! !SlangTestSupportPlugin methodsFor: 'inlining' stamp: 'dtl 9/18/2010 18:01'! methodThatShouldNotBeInlinedByPragma ^ #bar! ! !SlangTestSupportPlugin methodsFor: 'type declaration' stamp: 'dtl 9/19/2010 11:50'! returnTypeByMethod "SlangTestSupport asCString: #returnTypeByMethod" self returnTypeC: 'char *'. ! ! !SlangTestSupportPlugin methodsFor: 'type declaration' stamp: 'dtl 9/19/2010 11:51'! returnTypeByPragma "SlangTestSupport asCString: #returnTypeByPragma" ! ! !SlangTestSupportPlugin methodsFor: 'type declaration' stamp: 'dtl 9/19/2010 11:51'! varDefByMethod "SlangTestSupport asCString: #varDefByMethod" | foo bar | self var: #foo type: 'char *'. self var: #bar declareC: 'unsigned int * bar' ! ! !SlangTestSupportPlugin methodsFor: 'type declaration' stamp: 'dtl 9/19/2010 22:25'! varDefByMethodAndPragma "SlangTestSupportPlugin asCString: #varDefByMethodAndPragma" | foo bar baz fum | self var: #foo type: 'char *'. self var: #bar declareC: 'unsigned int * bar' ! ! !SlangTestSupportPlugin methodsFor: 'type declaration' stamp: 'dtl 9/19/2010 12:05'! varDefByPragma "SlangTestSupport asCString: #varDefByPragma" | foo bar | ! ! InterpreterPlugin subclass: #SmartSyntaxInterpreterPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-SmartSyntaxPlugins'! !SmartSyntaxInterpreterPlugin commentStamp: '' prior: 0! Subclass of InterpreterPlugin, used in connection with TestCodeGenerator for named primitives with type coercion specifications! SmartSyntaxInterpreterPlugin subclass: #AsynchFilePlugin instanceVariableNames: 'sCOAFfn' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !AsynchFilePlugin commentStamp: 'tpr 5/2/2003 15:22' prior: 0! Implements the asynchronous file primitives available on a few platforms. See the platform specific files in platforms- {your platform} - plugins - Asynchplugin! !AsynchFilePlugin class methodsFor: 'translation' stamp: 'JMM 5/23/2005 18:59'! declareCVarsIn: cg super declareCVarsIn: cg. cg var: #sCOAFfn type: #'void *'. ! ! !AsynchFilePlugin class methodsFor: 'translation' stamp: 'tpr 5/23/2001 17:04'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !AsynchFilePlugin class methodsFor: 'translation' stamp: 'tpr 11/29/2000 22:37'! requiresPlatformFiles "this plugin requires platform specific files in order to work" ^true! ! !AsynchFilePlugin methodsFor: 'primitives' stamp: 'TPR (auto pragmas 12/08) 2/7/2000 13:01'! asyncFileValueOf: oop "Return a pointer to the first byte of the async file record within the given Smalltalk bytes object, or nil if oop is not an async file record." interpreterProxy success: ((interpreterProxy isIntegerObject: oop) not and: [(interpreterProxy isBytes: oop) and: [(interpreterProxy slotSizeOf: oop) = (self cCode: 'sizeof(AsyncFile)')]]). interpreterProxy failed ifTrue: [^ nil]. ^ self cCode: '(AsyncFile *) (oop + 4)' ! ! !AsynchFilePlugin methodsFor: 'primitives' stamp: 'dtl (auto pragmas dtl 2010-09-27) 6/30/2008 08:16'! bufferPointer: buffer startIndex: startIndex "Adjust for zero-origin indexing. This is implemented as a separate method in order to encourage inlining." ^ (self pointerForOop: buffer) + self baseHeaderSize + startIndex - 1. ! ! !AsynchFilePlugin methodsFor: 'initialize-release' stamp: 'JMM (auto pragmas 12/08) 1/20/2002 22:00'! initialiseModule "Initialise the module" sCOAFfn := interpreterProxy ioLoadFunction: 'secCanOpenAsyncFileOfSizeWritable' From: 'SecurityPlugin'. ^self cCode: 'asyncFileInit()' inSmalltalk:[true]! ! !AsynchFilePlugin methodsFor: 'initialize-release' stamp: 'tpr (auto pragmas 12/08) 3/24/2004 14:51'! moduleUnloaded: aModuleName "The module with the given name was just unloaded. Make sure we have no dangling references." (aModuleName strcmp: 'SecurityPlugin') = 0 ifTrue: ["The security plugin just shut down. How odd. Zero the function pointer we have into it" sCOAFfn := 0]! ! !AsynchFilePlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 14:15'! primitiveAsyncFileClose: fh | f | self primitive: 'primitiveAsyncFileClose' parameters: #(Oop ). f := self asyncFileValueOf: fh. self asyncFileClose: f! ! !AsynchFilePlugin methodsFor: 'primitives' stamp: 'John M McIntosh (auto pragmas dtl 2010-09-27) 12/1/2009 21:42'! primitiveAsyncFileOpen: fileName forWrite: writeFlag semaIndex: semaIndex | fileNameSize fOop f okToOpen | self primitive: 'primitiveAsyncFileOpen' parameters: #(#String #Boolean #SmallInteger ). fileNameSize := interpreterProxy slotSizeOf: (fileName asOop: String). "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCOAFfn ~= 0 ifTrue: [okToOpen := self cCode: ' ((sqInt (*) (char *, sqInt, sqInt)) sCOAFfn)(fileName, fileNameSize, writeFlag)'. okToOpen ifFalse: [^ interpreterProxy primitiveFail]]. fOop := interpreterProxy instantiateClass: interpreterProxy classByteArray indexableSize: (self cCode: 'sizeof(AsyncFile)'). f := self asyncFileValueOf: fOop. interpreterProxy failed ifFalse: [self cCode: 'asyncFileOpen(f, fileName, fileNameSize, writeFlag, semaIndex)']. ^ fOop! ! !AsynchFilePlugin methodsFor: 'primitives' stamp: 'dtl (auto pragmas dtl 2010-09-27) 5/31/2008 18:38'! primitiveAsyncFileReadResult: fhandle intoBuffer: buffer at: start count: num | bufferSize bufferPtr r f count startIndex | self primitive: 'primitiveAsyncFileReadResult' parameters: #(Oop Oop SmallInteger SmallInteger ). f := self asyncFileValueOf: fhandle. count := num. startIndex := start. bufferSize := interpreterProxy slotSizeOf: buffer. "in bytes or words" (interpreterProxy isWords: buffer) ifTrue: ["covert word counts to byte counts" count := count * 4. startIndex := startIndex - 1 * 4 + 1. bufferSize := bufferSize * 4]. interpreterProxy success: (startIndex >= 1 and: [startIndex + count - 1 <= bufferSize]). bufferPtr := self bufferPointer: buffer startIndex: startIndex. interpreterProxy failed ifFalse: [r := self cCode: 'asyncFileReadResult(f, bufferPtr, count)']. ^ r asOop: SmallInteger! ! !AsynchFilePlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 14:16'! primitiveAsyncFileReadStart: fHandle fPosition: fPosition count: count | f | self primitive: 'primitiveAsyncFileReadStart' parameters: #(Oop SmallInteger SmallInteger). f := self asyncFileValueOf: fHandle. self cCode: 'asyncFileReadStart(f, fPosition, count)' ! ! !AsynchFilePlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 14:16'! primitiveAsyncFileWriteResult: fHandle | f r | self primitive: 'primitiveAsyncFileWriteResult' parameters:#(Oop). f := self asyncFileValueOf: fHandle. r := self cCode:' asyncFileWriteResult(f)'. ^r asOop: SmallInteger! ! !AsynchFilePlugin methodsFor: 'primitives' stamp: 'dtl (auto pragmas dtl 2010-09-27) 5/31/2008 18:38'! primitiveAsyncFileWriteStart: fHandle fPosition: fPosition fromBuffer: buffer at: start count: num | f bufferSize bufferPtr count startIndex | self primitive: 'primitiveAsyncFileWriteStart' parameters: #(Oop SmallInteger Oop SmallInteger SmallInteger ). f := self asyncFileValueOf: fHandle. interpreterProxy failed ifTrue: [^ nil]. count := num. startIndex := start. bufferSize := interpreterProxy slotSizeOf: buffer. "in bytes or words" (interpreterProxy isWords: buffer) ifTrue: ["convert word counts to byte counts" count := count * self bytesPerWord. startIndex := startIndex - 1 * self bytesPerWord + 1. bufferSize := bufferSize * self bytesPerWord]. interpreterProxy success: (startIndex >= 1 and: [startIndex + count - 1 <= bufferSize]). bufferPtr := self bufferPointer: buffer startIndex: startIndex. interpreterProxy failed ifFalse: [self cCode: 'asyncFileWriteStart(f, fPosition, bufferPtr, count)']! ! !AsynchFilePlugin methodsFor: 'initialize-release' stamp: 'ar (auto pragmas 12/08) 5/12/2000 16:54'! shutdownModule "Initialise the module" ^self cCode: 'asyncFileShutdown()' inSmalltalk:[true]! ! SmartSyntaxInterpreterPlugin subclass: #ClipboardExtendedPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !ClipboardExtendedPlugin methodsFor: 'io' stamp: 'JSM 5/8/2006 23:39'! ioAddClipboardData: clipboard data: data dataFormat: aFormat | clipboardAddress formatLength dataLength | self primitive: 'ioAddClipboardData' parameters: #(Oop ByteArray String). clipboardAddress := interpreterProxy positive32BitValueOf: clipboard. dataLength := interpreterProxy slotSizeOf: data cPtrAsOop. formatLength := interpreterProxy slotSizeOf: aFormat cPtrAsOop. self sqPasteboardPutItemFlavor: clipboardAddress data: data length: dataLength formatType: aFormat formatLength: formatLength. ! ! !ClipboardExtendedPlugin methodsFor: 'io' stamp: 'JSM 5/6/2006 18:59'! ioClearClipboard: clipboard | clipboardAddress | self primitive: 'ioClearClipboard' parameters: #(Oop). clipboardAddress := interpreterProxy positive32BitValueOf: clipboard. self sqPasteboardClear: clipboardAddress.! ! !ClipboardExtendedPlugin methodsFor: 'io' stamp: 'JSM 5/6/2006 19:23'! ioCreateClipboard | clipboardAddress | self primitive: 'ioCreateClipboard' parameters: #(). clipboardAddress := interpreterProxy positive32BitIntegerFor: self sqCreateClipboard. ^ clipboardAddress.! ! !ClipboardExtendedPlugin methodsFor: 'io' stamp: 'JSM 5/9/2006 01:39'! ioGetClipboardFormat: clipboard formatNumber: formatNumber | clipboardAddress itemCount | self primitive: 'ioGetClipboardFormat' parameters: #(#Oop #SmallInteger ). clipboardAddress := interpreterProxy positive32BitValueOf: clipboard. itemCount := self sqPasteboardGetItemCount: clipboardAddress. itemCount > 0 ifTrue: [^ self sqPasteboardCopyItemFlavors: clipboardAddress itemNumber: formatNumber]. ^ interpreterProxy nilObject! ! !ClipboardExtendedPlugin methodsFor: 'io' stamp: 'JSM 5/7/2006 13:07'! ioReadClipboardData: clipboard format: format | clipboardAddress formatLength | self primitive: 'ioReadClipboardData' parameters: #(Oop String). clipboardAddress := interpreterProxy positive32BitValueOf: clipboard. formatLength := interpreterProxy slotSizeOf: format cPtrAsOop. ^ self sqPasteboardCopyItemFlavorData: clipboardAddress format: format formatLength: formatLength. ! ! SmartSyntaxInterpreterPlugin subclass: #FileCopyPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !FileCopyPlugin commentStamp: 'tpr 5/2/2003 15:48' prior: 0! This plugin is a simple workaround for the lamentable state of the Squeak file handling system; it provides a primitive to copy a file or tree via the OS facility and thus preserve all the OS attributes in the most trivial possible manner. Not intended for a long life and should be replaced by better code as soon as possible. The key benefit it offers is maintenance of any OS flags, tags, bits and bobs belonging to the file. Since it requires platform support it will only be built when supported on your platform! !FileCopyPlugin class methodsFor: 'translation' stamp: 'tpr 4/27/2001 11:02'! requiresPlatformFiles "this plugin requires platform specific files in order to work" ^true! ! !FileCopyPlugin methodsFor: 'system primitives' stamp: 'tpr 4/10/2002 19:34'! primitiveFile: srcName copyTo: dstName |srcSz dstSz ok | self primitive: 'primitiveFileCopyNamedTo' parameters: #(String String). srcSz := interpreterProxy slotSizeOf: srcName cPtrAsOop. dstSz := interpreterProxy slotSizeOf: dstName cPtrAsOop. ok := self sqCopyFile: srcName size: srcSz to: dstName size: dstSz. ok ifFalse:[interpreterProxy primitiveFail]. ! ! SmartSyntaxInterpreterPlugin subclass: #GeniePlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !GeniePlugin commentStamp: '' prior: 0! This plugin implements the functionality of CRStrokeFeature>>sameClassAbsoluteStrokeDistance: aCRFeature forReference: aBoolean . This means that changes there should be mirrored here!! GeniePlugin>>majorNO should be in sync with version number of Genie. ! !GeniePlugin class methodsFor: 'check installed plugin' stamp: 'sr 6/25/2001 20:49'! majorNO | no | ^ (no := self versionNO) ifNotNil: [no // 1000] ! ! !GeniePlugin class methodsFor: 'check installed plugin' stamp: 'sr 6/25/2001 20:50'! minorNO | no | ^ (no := self versionNO) ifNotNil: [no \\ 1000] ! ! !GeniePlugin class methodsFor: 'translation' stamp: 'sr 4/15/2001 17:44'! moduleNameAndVersion "Answer the receiver's module name and version info that is used for the plugin's C code. The default is to append the code generation date, but any useful text is ok (keep it short)" ^ self moduleName, Character space asString, self version, Character space asString, Date today asString! ! !GeniePlugin class methodsFor: 'translation' stamp: 'sr 6/25/2001 20:42'! version "Answer the receiver's version info as String." "Somewhat a hack, but calling class methods from inst methods doesn't result in usable C-code..." | inst | inst := self new. ^ 'v', inst majorNO asString, '.', inst minorNO asString! ! !GeniePlugin class methodsFor: 'check installed plugin' stamp: 'sr 6/25/2001 20:46'! versionNO ^ nil ! ! !GeniePlugin class methodsFor: 'check installed plugin' stamp: 'NS 8/8/2001 15:31'! versionString ^ 'v', (self versionNO / 1000 asFloat) asString! ! !GeniePlugin methodsFor: 'computation' stamp: 'tpr 12/29/2005 16:21'! cSquaredDistanceFrom: aPoint to: bPoint "arguments are pointer to ints paired as x,y coordinates of points" | aPointX aPointY bPointX bPointY xDiff yDiff | self var: #aPoint type: 'int * '. self var: #bPoint type: 'int * '. aPointX := aPoint at: 0. aPointY := aPoint at: 1. bPointX := bPoint at: 0. bPointY := bPoint at: 1. xDiff := bPointX - aPointX. yDiff := bPointY - aPointY. ^ xDiff * xDiff + (yDiff * yDiff)! ! !GeniePlugin methodsFor: 'computation' stamp: 'sr 6/5/2001 06:53'! cSubstAngleFactorFrom: startDegreeNumber to: endDegreeNumber | absDiff | absDiff := (endDegreeNumber - startDegreeNumber) abs. absDiff > 180 ifTrue: [absDiff := 360 - absDiff]. ^ absDiff * absDiff bitShift: -6! ! !GeniePlugin methodsFor: 'version' stamp: 'NS 7/12/2001 11:54'! majorNO ^ 2! ! !GeniePlugin methodsFor: 'version' stamp: 'NS 7/12/2001 11:54'! minorNO ^ 0! ! !GeniePlugin methodsFor: 'computation' stamp: 'dtl 8/18/2009 07:24'! primSameClassAbsoluteStrokeDistanceMyPoints: myPointsOop otherPoints: otherPointsOop myVectors: myVectorsOop otherVectors: otherVectorsOop mySquaredLengths: mySquaredLengthsOop otherSquaredLengths: otherSquaredLengthsOop myAngles: myAnglesOop otherAngles: otherAnglesOop maxSizeAndReferenceFlag: maxSizeAndRefFlag rowBase: rowBaseOop rowInsertRemove: rowInsertRemoveOop rowInsertRemoveCount: rowInsertRemoveCountOop | base insertRemove jLimiT substBase insert remove subst removeBase insertBase insertRemoveCount additionalMultiInsertRemoveCost myPoints otherPoints myVectors otherVectors rowInsertRemoveCount mySquaredLengths otherSquaredLengths myAngles otherAngles rowBase rowInsertRemove otherPointsSize myVectorsSize otherVectorsSize otherSquaredLengthsSize rowBaseSize maxDist maxSize forReference jM1 iM1 iM1T2 jM1T2 | self var: #myPoints type: 'int * '. self var: #otherPoints type: 'int * '. self var: #myVectors type: 'int * '. self var: #otherVectors type: 'int * '. self var: #mySquaredLengths type: 'int * '. self var: #otherSquaredLengths type: 'int * '. self var: #myAngles type: 'int * '. self var: #otherAngles type: 'int * '. self var: #rowBase type: 'int * '. self var: #rowInsertRemove type: 'int * '. self var: #rowInsertRemoveCount type: 'int * '. self primitive: 'primSameClassAbsoluteStrokeDistanceMyPoints_otherPoints_myVectors_otherVectors_mySquaredLengths_otherSquaredLengths_myAngles_otherAngles_maxSizeAndReferenceFlag_rowBase_rowInsertRemove_rowInsertRemoveCount' parameters: #(#Oop #Oop #Oop #Oop #Oop #Oop #Oop #Oop #SmallInteger #Oop #Oop #Oop) receiver: #Oop. interpreterProxy failed ifTrue: [self msg: 'failed 1'. ^ nil]. interpreterProxy success: (interpreterProxy isWords: myPointsOop) & (interpreterProxy isWords: otherPointsOop) & (interpreterProxy isWords: myVectorsOop) & (interpreterProxy isWords: otherVectorsOop) & (interpreterProxy isWords: mySquaredLengthsOop) & (interpreterProxy isWords: otherSquaredLengthsOop) & (interpreterProxy isWords: myAnglesOop) & (interpreterProxy isWords: otherAnglesOop) & (interpreterProxy isWords: rowBaseOop) & (interpreterProxy isWords: rowInsertRemoveOop) & (interpreterProxy isWords: rowInsertRemoveCountOop). interpreterProxy failed ifTrue: [self msg: 'failed 2'. ^ nil]. interpreterProxy success: (interpreterProxy is: myPointsOop MemberOf: 'PointArray') & (interpreterProxy is: otherPointsOop MemberOf: 'PointArray'). interpreterProxy failed ifTrue: [self msg: 'failed 3'. ^ nil]. myPoints := interpreterProxy firstIndexableField: myPointsOop. otherPoints := interpreterProxy firstIndexableField: otherPointsOop. myVectors := interpreterProxy firstIndexableField: myVectorsOop. otherVectors := interpreterProxy firstIndexableField: otherVectorsOop. mySquaredLengths := interpreterProxy firstIndexableField: mySquaredLengthsOop. otherSquaredLengths := interpreterProxy firstIndexableField: otherSquaredLengthsOop. myAngles := interpreterProxy firstIndexableField: myAnglesOop. otherAngles := interpreterProxy firstIndexableField: otherAnglesOop. rowBase := interpreterProxy firstIndexableField: rowBaseOop. rowInsertRemove := interpreterProxy firstIndexableField: rowInsertRemoveOop. rowInsertRemoveCount := interpreterProxy firstIndexableField: rowInsertRemoveCountOop. "Note: myPointsSize and mySquaredLengthsSize variables eliminated to reduce method temporary variable count for closure-enabled images" "PointArrays" "myPointsSize := (interpreterProxy stSizeOf: myPointsOop) bitShift: -1." otherPointsSize := (interpreterProxy stSizeOf: otherPointsOop) bitShift: -1. myVectorsSize := (interpreterProxy stSizeOf: myVectorsOop) bitShift: -1. otherVectorsSize := (interpreterProxy stSizeOf: otherVectorsOop) bitShift: -1. "IntegerArrays" "mySquaredLengthsSize := interpreterProxy stSizeOf: mySquaredLengthsOop." otherSquaredLengthsSize := interpreterProxy stSizeOf: otherSquaredLengthsOop. rowBaseSize := interpreterProxy stSizeOf: rowBaseOop. interpreterProxy success: rowBaseSize = (interpreterProxy stSizeOf: rowInsertRemoveOop) & (rowBaseSize = (interpreterProxy stSizeOf: rowInsertRemoveCountOop)) & (rowBaseSize > otherVectorsSize). interpreterProxy failed ifTrue: [self msg: 'failed 4'. ^ nil]. interpreterProxy success: (interpreterProxy stSizeOf: mySquaredLengthsOop) >= (myVectorsSize - 1) & (((interpreterProxy stSizeOf: myPointsOop) bitShift: -1) >= myVectorsSize) & (otherSquaredLengthsSize >= (otherVectorsSize - 1)) & (otherPointsSize >= otherVectorsSize) & ((interpreterProxy stSizeOf: myAnglesOop) >= (myVectorsSize - 1)) & ((interpreterProxy stSizeOf: otherAnglesOop) >= (otherVectorsSize - 1)). interpreterProxy failed ifTrue: [self msg: 'failed 5'. ^ nil]. "maxSizeAndRefFlag contains the maxium feature size (pixel) and also indicates whether the reference flag (boolean) is set. Therefore the maximum size is moved to the left and the reference flag is stored in the LSB. Note: This is necessary to avoid more than 12 primitive parameters" forReference := maxSizeAndRefFlag bitAnd: 1. maxSize := maxSizeAndRefFlag bitShift: -1. maxDist := 1 bitShift: 29. forReference ifTrue: [additionalMultiInsertRemoveCost := 0] ifFalse: [additionalMultiInsertRemoveCost := maxSize * maxSize bitShift: -10]. "C indices!!!!" rowBase at: 0 put: 0. rowInsertRemove at: 0 put: 0. rowInsertRemoveCount at: 0 put: 2. insertRemove := 0 - additionalMultiInsertRemoveCost. jLimiT := otherVectorsSize. otherPointsSize >= (jLimiT - 1) & (otherSquaredLengthsSize >= (jLimiT - 1)) ifFalse: [^ interpreterProxy primitiveFail]. 1 to: jLimiT do: [:j | jM1 := j - 1. insertRemove := insertRemove + ((otherSquaredLengths at: jM1) + (self cSquaredDistanceFrom: (otherPoints + (jM1 bitShift: 1)) to: myPoints) bitShift: -7) + additionalMultiInsertRemoveCost. rowInsertRemove at: j put: insertRemove. rowBase at: j put: insertRemove * j. rowInsertRemoveCount at: j put: j + 1]. insertRemove := (rowInsertRemove at: 0) - additionalMultiInsertRemoveCost. 1 to: myVectorsSize do: [:i | iM1 := i - 1. iM1T2 := iM1 bitShift: 1. substBase := rowBase at: 0. insertRemove := insertRemove + ((mySquaredLengths at: iM1) + (self cSquaredDistanceFrom: (myPoints + iM1T2) to: otherPoints) bitShift: -7) + additionalMultiInsertRemoveCost. rowInsertRemove at: 0 put: insertRemove. rowBase at: 0 put: insertRemove * i. rowInsertRemoveCount at: 0 put: i + 1. jLimiT := otherVectorsSize. 1 to: jLimiT do: [:j | jM1 := j - 1. jM1T2 := jM1 bitShift: 1. removeBase := rowBase at: j. insertBase := rowBase at: jM1. remove := (mySquaredLengths at: iM1) + (self cSquaredDistanceFrom: (myPoints + iM1T2) to: (otherPoints + (j bitShift: 1))) bitShift: -7. (insertRemove := rowInsertRemove at: j) = 0 ifTrue: [removeBase := removeBase + remove] ifFalse: [removeBase := removeBase + insertRemove + (remove * (rowInsertRemoveCount at: j)). remove := remove + insertRemove]. insert := (otherSquaredLengths at: jM1) + (self cSquaredDistanceFrom: (otherPoints + jM1T2) to: (myPoints + (i bitShift: 1))) bitShift: -7. (insertRemove := rowInsertRemove at: jM1) = 0 ifTrue: [insertBase := insertBase + insert] ifFalse: [insertBase := insertBase + insertRemove + (insert * (rowInsertRemoveCount at: jM1)). insert := insert + insertRemove]. forReference ifTrue: [substBase := maxDist] ifFalse: [subst := (self cSquaredDistanceFrom: (otherVectors + jM1T2) to: (myVectors + iM1T2)) + (self cSquaredDistanceFrom: (otherPoints + jM1T2) to: (myPoints + iM1T2)) * (16 + (self cSubstAngleFactorFrom: (otherAngles at: jM1) to: (myAngles at: iM1))) bitShift: -11. substBase := substBase + subst]. (substBase <= removeBase and: [substBase <= insertBase]) ifTrue: [base := substBase. insertRemove := 0. insertRemoveCount := 1] ifFalse: [removeBase <= insertBase ifTrue: [base := removeBase. insertRemove := remove + additionalMultiInsertRemoveCost. insertRemoveCount := (rowInsertRemoveCount at: j) + 1] ifFalse: [base := insertBase. insertRemove := insert + additionalMultiInsertRemoveCost. insertRemoveCount := (rowInsertRemoveCount at: jM1) + 1]]. substBase := rowBase at: j. rowBase at: j put: (base min: maxDist). rowInsertRemove at: j put: (insertRemove min: maxDist). rowInsertRemoveCount at: j put: insertRemoveCount]. insertRemove := rowInsertRemove at: 0]. ^ base asOop: SmallInteger ! ! !GeniePlugin methodsFor: 'version' stamp: 'sr 6/25/2001 20:39'! primVersionNO "majorNO * 1000 + minorNO" self primitive: 'primVersionNO' parameters: #() receiver: #Oop. ^ (self majorNO * 1000 + self minorNO) asOop: SmallInteger! ! SmartSyntaxInterpreterPlugin subclass: #HostWindowPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !HostWindowPlugin commentStamp: 'tpr 10/14/2004 15:57' prior: 0! This plugin provides access to creating, destroying and manipulating host OS windows. See the Cross/plugins/HostWindowPlugin/HostWindowPlugin.h file for documented declarations for the C functions you need to provide.! !HostWindowPlugin class methodsFor: 'translation' stamp: 'JMM 8/17/2004 20:24'! hasHeaderFile ^true! ! !HostWindowPlugin class methodsFor: 'translation' stamp: 'tpr 7/20/2004 13:09'! requiresPlatformFiles ^true! ! !HostWindowPlugin methodsFor: 'system primitives' stamp: 'tpr 9/20/2004 12:32'! primitiveCloseHostWindow: windowIndex "Close a host window. windowIndex is the SmallInt handle returned previously by primitiveCreateHostWindow. Fail if the index is invalid or the platform code fails" | ok | self primitive: 'primitiveCloseHostWindow' parameters: #(SmallInteger). ok := self closeWindow: windowIndex. ok ifFalse:[interpreterProxy primitiveFail]. ! ! !HostWindowPlugin methodsFor: 'system primitives' stamp: 'tpr 10/3/2004 10:34'! primitiveCreateHostWindowWidth: w height: h originX: x y: y attributes: list "Create a host window of width 'w' pixels, height 'h' with the origin of the user area at 'x@y' from the topleft corner of the screen. Return the SmallInt value of the internal index to the window description block - which is whatever the host platform code needs it to be." | windowIndex listLength | self primitive: 'primitiveCreateHostWindow' parameters: #(SmallInteger SmallInteger SmallInteger SmallInteger ByteArray). "createWindowWidthheightoriginXyattr(int w, int h, int x, int y, int* attributeList) must create a hostwindow and return an integer index. Return 0 if failed" listLength := interpreterProxy slotSizeOf: list cPtrAsOop. windowIndex := self createWindowWidth: w height: h originX: x y: y attr: list length: listLength. windowIndex > 0 ifTrue:[^windowIndex asSmallIntegerObj] ifFalse:[^interpreterProxy primitiveFail]. ! ! !HostWindowPlugin methodsFor: 'system primitives' stamp: 'tpr 10/14/2004 15:58'! primitiveHostWindowPosition: windowIndex "Return the origin position of the user area of the window in pixels from the topleft corner of the screen. Fail if the windowIndex is invalid or the platform routine returns -1 to indicate failure" | pos | self primitive: 'primitiveHostWindowPosition' parameters: #(SmallInteger ). pos := self ioPositionOfWindow: windowIndex. pos = -1 ifTrue: [^ interpreterProxy primitiveFail] ifFalse: [^ interpreterProxy makePointwithxValue: pos >> 16 yValue: (pos bitAnd: 16rFFFF)]! ! !HostWindowPlugin methodsFor: 'system primitives' stamp: 'tpr 10/14/2004 15:58'! primitiveHostWindowPositionSet: windowIndex x: x y: y "Set the origin position of the user area of the window in pixels from the topleft corner of the screen- return the position actually set by the OS/GUI/window manager. Fail if the windowIndex is invalid or the platform routine returns -1 to indicate failure" | pos | self primitive: 'primitiveHostWindowPositionSet' parameters: #(SmallInteger SmallInteger SmallInteger). pos := self ioPositionOfWindowSet: windowIndex x: x y: y. pos = -1 ifTrue: [^ interpreterProxy primitiveFail] ifFalse: [^ interpreterProxy makePointwithxValue: pos >> 16 yValue: (pos bitAnd: 16rFFFF)]! ! !HostWindowPlugin methodsFor: 'system primitives' stamp: 'tpr 10/14/2004 15:59'! primitiveHostWindowSize: windowIndex "Return the size of the user area of the window in pixels. Fail if the windowIndex is invalid or the platform routine returns -1 to indicate failure" | size | self primitive: 'primitiveHostWindowSize' parameters: #(SmallInteger ). size := self ioSizeOfWindow: windowIndex. size = -1 ifTrue: [^ interpreterProxy primitiveFail] ifFalse: [^ interpreterProxy makePointwithxValue: size >> 16 yValue: (size bitAnd: 16rFFFF)]! ! !HostWindowPlugin methodsFor: 'system primitives' stamp: 'tpr 10/14/2004 15:59'! primitiveHostWindowSizeSet: windowIndex x: x y: y "Set the size of the user area of the window in pixels - return what is actually set by the OS/GUI/window manager. Fail if the windowIndex is invalid or the platform routine returns -1 to indicate failure" | size | self primitive: 'primitiveHostWindowSizeSet' parameters: #(SmallInteger SmallInteger SmallInteger). size := self ioSizeOfWindowSet: windowIndex x: x y: y. size = -1 ifTrue: [^ interpreterProxy primitiveFail] ifFalse: [^ interpreterProxy makePointwithxValue: size >> 16 yValue: (size bitAnd: 16rFFFF)]! ! !HostWindowPlugin methodsFor: 'system primitives' stamp: 'tpr 9/20/2004 12:38'! primitiveHostWindowTitle: id string: titleString "Set the title bar label of the window. Fail if the windowIndex is invalid or the platform routine returns -1 to indicate failure" | res titleLength | self primitive: 'primitiveHostWindowTitle' parameters: #(SmallInteger String). titleLength := interpreterProxy slotSizeOf: titleString cPtrAsOop. res := self cCode: 'ioSetTitleOfWindow(id, titleString, titleLength)'. res = -1 ifTrue: [interpreterProxy primitiveFail]! ! !HostWindowPlugin methodsFor: 'system primitives' stamp: 'John M McIntosh 12/1/2009 21:44'! primitiveShowHostWindow: windowIndex bits: dispBits width: w height: h depth: d left: left right: right top: top bottom: bottom "Host window analogue of DisplayScreen> primShowRectLeft:right:top:bottom: (Interpreter>primitiveShowDisplayRect) which takes the window index, bitmap details and the rectangle bounds. Fail if the windowIndex is invalid or the platform routine returns false to indicate failure" |ok| self var: #dispBits type: 'unsigned char * '. self primitive: 'primitiveShowHostWindowRect' parameters: #(SmallInteger WordArray SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger). "Tell the vm to copy pixel's from dispBits to the screen - this is just ioShowDisplay with the extra parameter of the windowIndex integer" ok := self cCode: 'ioShowDisplayOnWindow(dispBits, w, h, d, left, right, top, bottom, windowIndex)'. ok ifFalse:[interpreterProxy primitiveFail]! ! !HostWindowPlugin methodsFor: 'initialize-release' stamp: 'tpr 9/17/2004 18:16'! shutdownModule "do any window related VM closing down work your platform requires." self export: true. ^self cCode: 'ioCloseAllWindows()' inSmalltalk:[true]! ! SmartSyntaxInterpreterPlugin subclass: #InternetConfigPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !InternetConfigPlugin commentStamp: 'tpr 5/5/2003 12:05' prior: 0! This plugin provides access to the Mac's internet configuration toolkit - so long as you are running on a Mac.! !InternetConfigPlugin class methodsFor: 'translation' stamp: 'JMM 9/26/2001 12:21'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !InternetConfigPlugin class methodsFor: 'translation' stamp: 'JMM 9/26/2001 12:21'! requiresPlatformFiles "this plugin requires platform specific files in order to work" ^true! ! !InternetConfigPlugin methodsFor: 'initialize' stamp: 'JMM (auto pragmas 12/08) 9/26/2001 12:22'! initialiseModule ^self cCode: 'sqInternetConfigurationInit()' inSmalltalk:[true]! ! !InternetConfigPlugin methodsFor: 'system primitives' stamp: 'JMM 9/28/2001 13:06'! primitiveGetMacintoshFileTypeAndCreatorFrom: aFileName | oop ptr keyLength creator | self primitive: 'primitiveGetMacintoshFileTypeAndCreatorFrom' parameters: #(String). self var: #aFile declareC: 'char aFile[256]'. self var: #creator declareC: 'char creator[8]'. self var: #ptr type: 'char *'. keyLength := interpreterProxy byteSizeOf: aFileName cPtrAsOop. self sqInternetGetMacintoshFileTypeAndCreatorFrom: aFileName keySize: keyLength into: creator. oop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: 8. ptr := interpreterProxy firstIndexableField: oop. 0 to: 7 do:[:i| ptr at: i put: (creator at: i)]. ^oop. ! ! !InternetConfigPlugin methodsFor: 'system primitives' stamp: 'JMM 10/5/2001 09:56'! primitiveGetStringKeyedBy: aKey | oop ptr size aString keyLength | self primitive: 'primitiveGetStringKeyedBy' parameters: #(String). self var: #aString declareC: 'char aString[1025]'. self var: #ptr type: 'char *'. keyLength := interpreterProxy byteSizeOf: aKey cPtrAsOop. size := self sqInternetConfigurationGetStringKeyedBy: aKey keySize: keyLength into: aString. oop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: size. ptr := interpreterProxy firstIndexableField: oop. 0 to: size-1 do:[:i| ptr at: i put: (aString at: i)]. ^oop. ! ! !InternetConfigPlugin methodsFor: 'initialize' stamp: 'JMM (auto pragmas 12/08) 9/26/2001 12:22'! shutdownModule ^self cCode: 'sqInternetConfigurationShutdown()' inSmalltalk:[true]! ! SmartSyntaxInterpreterPlugin subclass: #JPEGReadWriter2Plugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !JPEGReadWriter2Plugin commentStamp: '' prior: 0! This work is a Squeak VM Plugin version of LibJPEG. The following sentence applies to this class: "This software is based in part on the work of the Independent JPEG Group". You can read more about it at www.ijg.org In addition to the code generated from this class, the plugin uses the following files (from LibJPEG ver. 6b): jerror.c jcmarker.c jdmarker.c jctrans.c jcparam.c jdapimin.c jcapimin.c jidctred.c jidctflt.c jidctfst.c jidctint.c jccoefct.c jdinput.c jdmaster.c jdcoefct.c jdhuff.c jdphuff.c jcphuff.c jchuff.c jcomapi.c jcinit.c jcmaster.c jdcolor.c jdtrans.c jmemmgr.c jutils.c jddctmgr.c jcdctmgr.c jquant2.c jquant1.c jmemnobs.c jfdctint.c jfdctfst.c jfdctflt.c jdsample.c jdpostct.c jdmerge.c jdmainct.c jdapistd.c jcsample.c jcprepct.c jcmainct.c jccolor.c jcapistd.c jversion.h jpeglib.h jdhuff.h jchuff.h jerror.h jmorecfg.h jmemsys.h jpegint.h jdct.h jinclude.h ! !JPEGReadWriter2Plugin class methodsFor: 'translation' stamp: 'JMM 10/3/2001 11:44'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !JPEGReadWriter2Plugin class methodsFor: 'translation' stamp: 'tpr 3/1/2002 17:03'! requiresCrossPlatformFiles "default is ok for most, any plugin needing cross platform files must say so" ^true! ! !JPEGReadWriter2Plugin class methodsFor: 'translation' stamp: 'JMM 10/3/2001 11:48'! requiresPlatformFiles "default is ok for most, any plugin needing platform specific files must say so" ^true! ! !JPEGReadWriter2Plugin methodsFor: 'initialize-release' stamp: 'JMM (auto pragmas 12/08) 12/25/2003 23:09'! initialiseModule ^true! ! !JPEGReadWriter2Plugin methodsFor: 'primitives' stamp: 'jmv (auto pragmas 12/08) 11/30/2001 00:17'! primImageHeight: aJPEGDecompressStruct self primitive: 'primImageHeight' parameters: #(ByteArray). "Various parameter checks" self cCode: ' interpreterProxy->success ((interpreterProxy->stSizeOf(interpreterProxy->stackValue(0))) >= (sizeof(struct jpeg_decompress_struct))); if (interpreterProxy->failed()) return null; ' inSmalltalk: []. ^(self cCode: '((j_decompress_ptr)aJPEGDecompressStruct)->image_height' inSmalltalk: [0]) asOop: SmallInteger! ! !JPEGReadWriter2Plugin methodsFor: 'primitives' stamp: 'jmv (auto pragmas 12/08) 11/30/2001 00:17'! primImageWidth: aJPEGDecompressStruct self primitive: 'primImageWidth' parameters: #(ByteArray). "Various parameter checks" self cCode: ' interpreterProxy->success ((interpreterProxy->stSizeOf(interpreterProxy->stackValue(0))) >= (sizeof(struct jpeg_decompress_struct))); if (interpreterProxy->failed()) return null; ' inSmalltalk: []. ^(self cCode: '((j_decompress_ptr)aJPEGDecompressStruct)->image_width' inSmalltalk: [0]) asOop: SmallInteger! ! !JPEGReadWriter2Plugin methodsFor: 'primitives' stamp: 'jmv (auto pragmas 12/08) 11/30/2001 00:17'! primJPEGCompressStructSize self primitive: 'primJPEGCompressStructSize' parameters: #(). ^(self cCode: 'sizeof(struct jpeg_compress_struct)' inSmalltalk: [0]) asOop: SmallInteger! ! !JPEGReadWriter2Plugin methodsFor: 'primitives' stamp: 'jmv (auto pragmas 12/08) 11/30/2001 00:17'! primJPEGDecompressStructSize self primitive: 'primJPEGDecompressStructSize' parameters: #(). ^(self cCode: 'sizeof(struct jpeg_decompress_struct)' inSmalltalk: [0]) asOop: SmallInteger! ! !JPEGReadWriter2Plugin methodsFor: 'primitives' stamp: 'jmv (auto pragmas 12/08) 11/30/2001 00:17'! primJPEGErrorMgr2StructSize self primitive: 'primJPEGErrorMgr2StructSize' parameters: #(). ^(self cCode: 'sizeof(struct error_mgr2)' inSmalltalk: [0]) asOop: SmallInteger! ! !JPEGReadWriter2Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 11/27/2001 00:45'! primJPEGPluginIsPresent self primitive: 'primJPEGPluginIsPresent' parameters: #(). ^true asOop: Boolean! ! !JPEGReadWriter2Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:54'! primJPEGReadHeader: aJPEGDecompressStruct fromByteArray: source errorMgr: aJPEGErrorMgr2Struct | pcinfo pjerr sourceSize | self primitive: 'primJPEGReadHeaderfromByteArrayerrorMgr' parameters: #(ByteArray ByteArray ByteArray). pcinfo := nil. pjerr := nil. sourceSize := nil. pcinfo. pjerr. sourceSize. "Various parameter checks" self cCode: ' interpreterProxy->success ((interpreterProxy->stSizeOf(interpreterProxy->stackValue(2))) >= (sizeof(struct jpeg_decompress_struct))); interpreterProxy->success ((interpreterProxy->stSizeOf(interpreterProxy->stackValue(0))) >= (sizeof(struct error_mgr2))); if (interpreterProxy->failed()) return null; ' inSmalltalk: []. self cCode: ' sourceSize = interpreterProxy->stSizeOf(interpreterProxy->stackValue(1)); pcinfo = (j_decompress_ptr)aJPEGDecompressStruct; pjerr = (error_ptr2)aJPEGErrorMgr2Struct; if (sourceSize) { pcinfo->err = jpeg_std_error(&pjerr->pub); pjerr->pub.error_exit = error_exit; if (setjmp(pjerr->setjmp_buffer)) { jpeg_destroy_decompress(pcinfo); sourceSize = 0; } if (sourceSize) { jpeg_create_decompress(pcinfo); jpeg_mem_src(pcinfo, source, sourceSize); jpeg_read_header(pcinfo, TRUE); } } ' inSmalltalk: [].! ! !JPEGReadWriter2Plugin methodsFor: 'primitives' stamp: 'dtl 10/9/2010 09:13'! primJPEGReadImage: aJPEGDecompressStruct fromByteArray: source onForm: form doDithering: ditherFlag errorMgr: aJPEGErrorMgr2Struct | pcinfo pjerr buffer rowStride formBits formDepth i j formPix ok rOff gOff bOff rOff2 gOff2 bOff2 formWidth formHeight pixPerWord formPitch formBitsSize sourceSize r1 r2 g1 g2 b1 b2 formBitsOops dmv1 dmv2 di dmi dmo | self primitive: 'primJPEGReadImagefromByteArrayonFormdoDitheringerrorMgr' parameters: #(ByteArray ByteArray Form Boolean ByteArray). "Avoid warnings when saving method" pcinfo := nil. pjerr := nil. buffer := nil. rowStride := nil. formDepth := nil. formBits := nil. i := nil. j := nil. formPix := nil. ok := nil. rOff := nil. gOff := nil. bOff := nil. rOff2 := nil. gOff2 := nil. bOff2 := nil. sourceSize := nil. r1 := nil. r2 := nil. g1 := nil. g2 := nil. b1 := nil. b2 := nil. dmv1 := nil. dmv2 := nil. di := nil. dmi := nil. dmo := nil. pcinfo. pjerr. buffer. rowStride. formBits. formDepth. i. j. formPix. ok. rOff. gOff. bOff. rOff2. gOff2. bOff2. sourceSize. r1. r2. g1.g2. b1. b2. dmv1. dmv2. di. dmi. dmo. formBitsOops := interpreterProxy fetchPointer: 0 ofObject: form. formDepth := interpreterProxy fetchInteger: 3 ofObject: form. "Various parameter checks" self cCode: ' interpreterProxy->success ((interpreterProxy->stSizeOf(interpreterProxy->stackValue(4))) >= (sizeof(struct jpeg_decompress_struct))); interpreterProxy->success ((interpreterProxy->stSizeOf(interpreterProxy->stackValue(0))) >= (sizeof(struct error_mgr2))); if (interpreterProxy->failed()) return null; ' inSmalltalk: []. formWidth := (self cCode: '((j_decompress_ptr)aJPEGDecompressStruct)->image_width' inSmalltalk: [0]). formHeight := (self cCode: '((j_decompress_ptr)aJPEGDecompressStruct)->image_height' inSmalltalk: [0]). pixPerWord := 32 // formDepth. formPitch := formWidth + (pixPerWord-1) // pixPerWord * 4. formBitsSize := interpreterProxy byteSizeOf: formBitsOops. interpreterProxy success: ((interpreterProxy isWordsOrBytes: formBitsOops) and: [formBitsSize = (formPitch * formHeight)]). interpreterProxy failed ifTrue: [^ nil]. formBits := interpreterProxy firstIndexableField: formBitsOops. self cCode: ' sourceSize = interpreterProxy->stSizeOf(interpreterProxy->stackValue(3)); if (sourceSize == 0) { interpreterProxy->success(false); return null; } pcinfo = (j_decompress_ptr)aJPEGDecompressStruct; pjerr = (error_ptr2)aJPEGErrorMgr2Struct; pcinfo->err = jpeg_std_error(&pjerr->pub); pjerr->pub.error_exit = error_exit; ok = 1; if (setjmp(pjerr->setjmp_buffer)) { jpeg_destroy_decompress(pcinfo); ok = 0; } if (ok) { ok = jpeg_mem_src_newLocationOfData(pcinfo, source, sourceSize); if (ok) { /* Dither Matrix taken from Form>>orderedDither32To16, but rewritten for this method. */ int ditherMatrix1[] = { 2, 0, 14, 12, 1, 3, 13, 15 }; int ditherMatrix2[] = { 10, 8, 6, 4, 9, 11, 5, 7 }; jpeg_start_decompress(pcinfo); rowStride = pcinfo->output_width * pcinfo->output_components; if (pcinfo->out_color_components == 3) { rOff = 0; gOff = 1; bOff = 2; rOff2 = 3; gOff2 = 4; bOff2 = 5; } else { rOff = 0; gOff = 0; bOff = 0; rOff2 = 1; gOff2 = 1; bOff2 = 1; } /* Make a one-row-high sample array that will go away when done with image */ buffer = (*(pcinfo->mem)->alloc_sarray) ((j_common_ptr) pcinfo, JPOOL_IMAGE, rowStride, 1); /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library state variable cinfo.output_scanline as the * loop counter, so that we dont have to keep track ourselves. */ while (pcinfo->output_scanline < pcinfo->output_height) { /* jpeg_read_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could ask for * more than one scanline at a time if thats more convenient. */ (void) jpeg_read_scanlines(pcinfo, buffer, 1); switch (formDepth) { case 32: for(i = 0, j = 0; i < rowStride; i +=(pcinfo->out_color_components), j++) { formPix = (255 << 24) | (buffer[0][i+rOff] << 16) | (buffer[0][i+gOff] << 8) | buffer[0][i+bOff]; if (formPix == 0) formPix = 1; formBits [ ((pcinfo->output_scanline - 1) * (pcinfo->image_width)) + j ] = formPix; } break; case 16: for(i = 0, j = 0; i < rowStride; i +=(pcinfo->out_color_components*2), j++) { r1 = buffer[0][i+rOff]; r2 = buffer[0][i+rOff2]; g1 = buffer[0][i+gOff]; g2 = buffer[0][i+gOff2]; b1 = buffer[0][i+bOff]; b2 = buffer[0][i+bOff2]; if (!!ditherFlag) { r1 = r1 >> 3; r2 = r2 >> 3; g1 = g1 >> 3; g2 = g2 >> 3; b1 = b1 >> 3; b2 = b2 >> 3; } else { /* Do 4x4 ordered dithering. Taken from Form>>orderedDither32To16 */ dmv1 = ditherMatrix1[ ((pcinfo->output_scanline & 3 )<< 1) | (j&1) ]; dmv2 = ditherMatrix2[ ((pcinfo->output_scanline & 3 )<< 1) | (j&1) ]; di = (r1 * 496) >> 8; dmi = di & 15; dmo = di >> 4; if(dmv1 < dmi) { r1 = dmo+1; } else { r1 = dmo; }; di = (g1 * 496) >> 8; dmi = di & 15; dmo = di >> 4; if(dmv1 < dmi) { g1 = dmo+1; } else { g1 = dmo; }; di = (b1 * 496) >> 8; dmi = di & 15; dmo = di >> 4; if(dmv1 < dmi) { b1 = dmo+1; } else { b1 = dmo; }; di = (r2 * 496) >> 8; dmi = di & 15; dmo = di >> 4; if(dmv2 < dmi) { r2 = dmo+1; } else { r2 = dmo; }; di = (g2 * 496) >> 8; dmi = di & 15; dmo = di >> 4; if(dmv2 < dmi) { g2 = dmo+1; } else { g2 = dmo; }; di = (b2 * 496) >> 8; dmi = di & 15; dmo = di >> 4; if(dmv2 < dmi) { b2 = dmo+1; } else { b2 = dmo; }; } formPix = (r1 << 10) | (g1 << 5) | b1; if (!!formPix) formPix = 1; formPix = (formPix << 16) | (r2 << 10) | (g2 << 5) | b2; if (!!(formPix & 65535)) formPix = formPix | 1; formBits [ ((pcinfo->output_scanline - 1) * (pcinfo->image_width)) / 2 + j ] = formPix; } break; } } jpeg_finish_decompress(pcinfo); } jpeg_destroy_decompress(pcinfo); } ' inSmalltalk: [].! ! !JPEGReadWriter2Plugin methodsFor: 'primitives' stamp: 'dtl 10/9/2010 13:28'! primJPEGWriteImage: aJPEGCompressStruct onByteArray: destination form: form quality: quality progressiveJPEG: progressiveFlag errorMgr: aJPEGErrorMgr2Struct | pcinfo pjerr buffer rowStride formBits formWidth formHeight formDepth i j formPix destinationSize pixPerWord formPitch formBitsSize formBitsOops | self primitive: 'primJPEGWriteImageonByteArrayformqualityprogressiveJPEGerrorMgr' parameters: #(ByteArray ByteArray Form SmallInteger Boolean ByteArray). pcinfo := nil. pjerr := nil. buffer :=nil. rowStride := nil. formBits := nil. formWidth := nil. formHeight := nil. formDepth := nil. i := nil. j := nil. formPix := nil. destinationSize := nil. pcinfo. pjerr. buffer. rowStride. formBits. formWidth. formHeight. formDepth. i. j. formPix. destinationSize. formBitsOops := interpreterProxy fetchPointer: 0 ofObject: form. formWidth := interpreterProxy fetchInteger: 1 ofObject: form. formHeight := interpreterProxy fetchInteger: 2 ofObject: form. formDepth := interpreterProxy fetchInteger: 3 ofObject: form. "Various parameter checks" self cCode: ' interpreterProxy->success ((interpreterProxy->stSizeOf(interpreterProxy->stackValue(5))) >= (sizeof(struct jpeg_compress_struct))); interpreterProxy->success ((interpreterProxy->stSizeOf(interpreterProxy->stackValue(0))) >= (sizeof(struct error_mgr2))); if (interpreterProxy->failed()) return null; ' inSmalltalk: []. pixPerWord := 32 // formDepth. formPitch := formWidth + (pixPerWord-1) // pixPerWord * 4. formBitsSize := interpreterProxy byteSizeOf: formBitsOops. interpreterProxy success: ((interpreterProxy isWordsOrBytes: formBitsOops) and: [formBitsSize = (formPitch * formHeight)]). interpreterProxy failed ifTrue: [^ nil]. formBits := interpreterProxy firstIndexableField: formBitsOops. self cCode: ' destinationSize = interpreterProxy->stSizeOf(interpreterProxy->stackValue(4)); pcinfo = (j_compress_ptr)aJPEGCompressStruct; pjerr = (error_ptr2)aJPEGErrorMgr2Struct; if (destinationSize) { pcinfo->err = jpeg_std_error(&pjerr->pub); pjerr->pub.error_exit = error_exit; if (setjmp(pjerr->setjmp_buffer)) { jpeg_destroy_compress(pcinfo); destinationSize = 0; } if (destinationSize) { jpeg_create_compress(pcinfo); jpeg_mem_dest(pcinfo, destination, &destinationSize); pcinfo->image_width = formWidth; pcinfo->image_height = formHeight; pcinfo->input_components = 3; pcinfo->in_color_space = JCS_RGB; jpeg_set_defaults(pcinfo); if (quality > 0) jpeg_set_quality (pcinfo, quality, 1); if (progressiveFlag) jpeg_simple_progression(pcinfo); jpeg_start_compress(pcinfo, TRUE); rowStride = formWidth * 3; /* Make a one-row-high sample array that will go away when done with image */ buffer = (*(pcinfo->mem)->alloc_sarray) ((j_common_ptr) pcinfo, JPOOL_IMAGE, rowStride, 1); while (pcinfo->next_scanline < pcinfo->image_height) { switch (formDepth) { case 32: for(i = 0, j = 0; i < rowStride; i +=3, j++) { formPix = formBits [ ((pcinfo->next_scanline) * formWidth) + j ]; buffer[0][i] = (formPix >> 16) & 255; buffer[0][i+1] = (formPix >> 8) & 255; buffer[0][i+2] = formPix & 255; } break; case 16: for(i = 0, j = 0; i < rowStride; i +=6, j++) { formPix = formBits [ ((pcinfo->next_scanline) * formWidth) / 2 + j ]; buffer[0][i] = (formPix >> 23) & 248; buffer[0][i+1] = (formPix >> 18) & 248; buffer[0][i+2] = (formPix >> 13) & 248; buffer[0][i+3] = (formPix >> 7) & 248; buffer[0][i+4] = (formPix >> 2) & 248; buffer[0][i+5] = (formPix << 3) & 248; } break; } (void) jpeg_write_scanlines(pcinfo, buffer, 1); } jpeg_finish_compress(pcinfo); jpeg_destroy_compress(pcinfo); } } ' inSmalltalk: []. ^(self cCode: 'destinationSize' inSmalltalk: [0]) asOop: SmallInteger! ! !JPEGReadWriter2Plugin methodsFor: 'initialize-release' stamp: 'JMM (auto pragmas 12/08) 12/25/2003 23:11'! shutdownModule ^true! ! SmartSyntaxInterpreterPlugin subclass: #JoystickTabletPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !JoystickTabletPlugin commentStamp: 'tpr 5/2/2003 15:48' prior: 0! This plugin implements the interface to the joystick and tablet input devices, if you have one. Since it requires platform support it will only be built when supported on your platform! !JoystickTabletPlugin class methodsFor: 'translation' stamp: 'tpr 5/23/2001 17:08'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !JoystickTabletPlugin class methodsFor: 'translation' stamp: 'tpr 3/26/2002 15:22'! requiresPlatformFiles " this plugin requires platform specific files in order to work" ^true! ! !JoystickTabletPlugin methodsFor: 'initialize-release' stamp: 'ar (auto pragmas 12/08) 5/12/2000 16:53'! initialiseModule ^self cCode: 'joystickInit()' inSmalltalk:[true]! ! !JoystickTabletPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:35'! primitiveGetTabletParameters: cursorIndex "Get information on the pen tablet attached to this machine. Fail if there is no tablet. If successful, the result is an array of integers; see the Smalltalk call on this primitive for its interpretation." | resultSize result resultPtr | self primitive: 'primitiveGetTabletParameters' parameters: #(SmallInteger). resultSize := self tabletResultSize. result := interpreterProxy instantiateClass: interpreterProxy classBitmap indexableSize: resultSize. resultPtr := result asIntPtr. interpreterProxy success: (self cCode: 'tabletGetParameters(cursorIndex, resultPtr)'). ^result! ! !JoystickTabletPlugin methodsFor: 'primitives' stamp: 'TPR 3/24/2000 18:33'! primitiveReadJoystick: index "Read an input word from the joystick with the given index." self primitive: 'primitiveReadJoystick' parameters: #(SmallInteger). ^(self joystickRead: index) asPositiveIntegerObj! ! !JoystickTabletPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:36'! primitiveReadTablet: cursorIndex "Get the current state of the cursor of the pen tablet specified by my argument. Fail if there is no tablet. If successful, the result is an array of integers; see the Smalltalk call on this primitive for its interpretation." | resultSize result resultPtr| self primitive: 'primitiveReadTablet' parameters: #(SmallInteger). resultSize := self tabletResultSize. result := interpreterProxy instantiateClass: interpreterProxy classBitmap indexableSize: resultSize. resultPtr := result asIntPtr. interpreterProxy success: (self cCode: 'tabletRead(cursorIndex, resultPtr)'). ^result! ! !JoystickTabletPlugin methodsFor: 'initialize-release' stamp: 'tpr (auto pragmas 12/08) 3/26/2002 15:22'! shutdownModule ^self cCode: 'joystickShutdown()' inSmalltalk:[true]! ! SmartSyntaxInterpreterPlugin subclass: #LargeIntegersPlugin instanceVariableNames: 'andOpIndex orOpIndex xorOpIndex' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !LargeIntegersPlugin commentStamp: 'sr 6/14/2004 14:04' prior: 0! LargeIntegersPlugin provides functions for speeding up LargeInteger arithmetics. Usually it is part of your installation as 'LargeIntegers' plugin (a C-compiled binary). Correctly installed? ---------------------- Probably you are just working with it. To be really sure try 100 factorial. "to force plugin loading" SmalltalkImage current listLoadedModules. Then you should see 'LargeIntegers' somewhere in the output strings. If this should not be the case, you probably have a problem. Variables ----------- Inst vars: andOpIndex C constant orOpIndex C constant xorOpIndex C constant Used like an enum, in ST one would use symbols instead. Class vars: none History -------- v1.5 - no code change at all compared to v1.4 - made to outsource testing code (LargeIntegersPluginTest) introduced in earlier versions - updated class comment: reference to LargeIntegersPluginTest removed v1.4 - no semantic change compared to v1.3 - >>cHighBit: improved (could be faster now) - fix: class comment - improved class comment - >>flag: introduced to allow #flag: messages (does nothing) - new: class>>buildCodeGeneratorUpTo: as hook for switching debugMode (default is not to change anything) - removed: class>>new (obsolete) - minor cleanup of source code layout v1.3 - fix: >>primDigitDiv:negative: now checks if its Integer args are normalized; without this change the plugin crashes, if a division by zero through a non normalized - filled with zero bytes - arg occurs. This can happen through printing by the inspector windows after changing the bytes of a LargeInteger manually. v1.2 - fix: >>anyBitOfBytes: aBytesOop from: start to: stopArg v1.1 - >>primGetModuleName for checking the version of the plugin; - >>primDigitBitShiftMagnitude and >>primAnyBitFrom:to: for supporting - not installing!! - unification of shift semantics of negative Integers; v1.0 - speeds up digitDiv:neg: at about 20%. In >>cCoreDigitDivDiv:len:rem:len:quo:len: the 'nibble' arithmetic is removed. ! !LargeIntegersPlugin class methodsFor: 'translation' stamp: 'sr 6/8/2004 18:48'! buildCodeGeneratorUpTo: someClass "A hook to control generation of the plugin. Don't know how to set the debug mode otherwise if using the VMMaker gui. Possibly there is a better way." | cg | cg := super buildCodeGeneratorUpTo: someClass. "example: cg generateDebugCode: true." ^ cg! ! !LargeIntegersPlugin class methodsFor: 'translation' stamp: 'sr 4/8/2000 05:40'! declareCVarsIn: cg cg var: 'andOpIndex' declareC: 'const int andOpIndex = 0'. cg var: 'orOpIndex' declareC: 'const int orOpIndex = 1'. cg var: 'xorOpIndex' declareC: 'const int xorOpIndex = 2'! ! !LargeIntegersPlugin class methodsFor: 'translation' stamp: 'ar 5/17/2000 16:08'! moduleName ^'LargeIntegers'! ! !LargeIntegersPlugin class methodsFor: 'translation' stamp: 'eem 2/10/2009 14:48'! moduleNameAndVersion "Answer the receiver's module name and version info that is used for the plugin's C code. The default is to append the code generation date, but any useful text is ok (keep it short)" ^ self moduleName, ' ', self version! ! !LargeIntegersPlugin class methodsFor: 'translation' stamp: 'sr 6/14/2004 13:52'! version "Answer the receiver's version info as String." ^ 'v1.5'! ! !LargeIntegersPlugin methodsFor: 'util' stamp: 'sr 11/29/2000 13:41'! anyBitOfBytes: aBytesOop from: start to: stopArg "Argument has to be aBytesOop!!" "Tests for any magnitude bits in the interval from start to stopArg." | magnitude rightShift leftShift stop firstByteIx lastByteIx | self debugCode: [self msg: 'anyBitOfBytes: aBytesOop from: start to: stopArg']. start < 1 | (stopArg < 1) ifTrue: [^ interpreterProxy primitiveFail]. magnitude := aBytesOop. stop := stopArg min: (self highBitOfBytes: magnitude). start > stop ifTrue: [^ false]. firstByteIx := start - 1 // 8 + 1. lastByteIx := stop - 1 // 8 + 1. rightShift := 0 - (start - 1 \\ 8). leftShift := 7 - (stop - 1 \\ 8). firstByteIx = lastByteIx ifTrue: [| digit mask | mask := (255 bitShift: 0 - rightShift) bitAnd: (255 bitShift: 0 - leftShift). digit := self digitOfBytes: magnitude at: firstByteIx. ^ (digit bitAnd: mask) ~= 0]. ((self digitOfBytes: magnitude at: firstByteIx) bitShift: rightShift) ~= 0 ifTrue: [^ true]. firstByteIx + 1 to: lastByteIx - 1 do: [:ix | (self digitOfBytes: magnitude at: ix) ~= 0 ifTrue: [^ true]]. (((self digitOfBytes: magnitude at: lastByteIx) bitShift: leftShift) bitAnd: 255) ~= 0 ifTrue: [^ true]. ^ false! ! !LargeIntegersPlugin methodsFor: 'util' stamp: 'sr 6/8/2004 05:10'! byteSizeOfBytes: bytesOop "Precondition: bytesOop is not anInteger and a bytes object." "Function #byteSizeOf: is used by the interpreter, be careful with name clashes..." ^ interpreterProxy slotSizeOf: bytesOop! ! !LargeIntegersPlugin methodsFor: 'oop functions' stamp: 'sr 6/8/2004 05:07'! bytes: aBytesOop Lshift: shiftCount "Attention: this method invalidates all oop's!! Only newBytes is valid at return." "Does not normalize." | newBytes highBit newLen oldLen | oldLen := self byteSizeOfBytes: aBytesOop. (highBit := self cBytesHighBit: (interpreterProxy firstIndexableField: aBytesOop) len: oldLen) = 0 ifTrue: [^ 0 asOop: SmallInteger]. newLen := highBit + shiftCount + 7 // 8. self remapOop: aBytesOop in: [newBytes := interpreterProxy instantiateClass: (interpreterProxy fetchClassOf: aBytesOop) indexableSize: newLen]. self cBytesLshift: shiftCount from: (interpreterProxy firstIndexableField: aBytesOop) len: oldLen to: (interpreterProxy firstIndexableField: newBytes) len: newLen. ^ newBytes! ! !LargeIntegersPlugin methodsFor: 'oop functions' stamp: 'sr 6/8/2004 05:06'! bytes: aBytesOop Rshift: anInteger bytes: b lookfirst: a "Attention: this method invalidates all oop's!! Only newBytes is valid at return." "Shift right 8*b+anInteger bits, 0<=n<8. Discard all digits beyond a, and all zeroes at or below a." "Does not normalize." | n x f m digit i oldLen newLen newBytes | n := 0 - anInteger. x := 0. f := n + 8. i := a. m := 255 bitShift: 0 - f. digit := self digitOfBytes: aBytesOop at: i. [((digit bitShift: n) bitOr: x) = 0 and: [i ~= 1]] whileTrue: [x := digit bitShift: f. "Can't exceed 8 bits" i := i - 1. digit := self digitOfBytes: aBytesOop at: i]. i <= b ifTrue: [^ interpreterProxy instantiateClass: (interpreterProxy fetchClassOf: aBytesOop) indexableSize: 0"Integer new: 0 neg: self negative"]. "All bits lost" oldLen := self byteSizeOfBytes: aBytesOop. newLen := i - b. self remapOop: aBytesOop in: [newBytes := interpreterProxy instantiateClass: (interpreterProxy fetchClassOf: aBytesOop) indexableSize: newLen]. "r := Integer new: i - b neg: self negative." " count := i. " self cCoreBytesRshiftCount: i n: n m: m f: f bytes: b from: (interpreterProxy firstIndexableField: aBytesOop) len: oldLen to: (interpreterProxy firstIndexableField: newBytes) len: newLen. ^ newBytes! ! !LargeIntegersPlugin methodsFor: 'oop util' stamp: 'sr 6/8/2004 05:06'! bytes: aBytesObject growTo: newLen "Attention: this method invalidates all oop's!! Only newBytes is valid at return." "Does not normalize." | newBytes oldLen copyLen | self remapOop: aBytesObject in: [newBytes := interpreterProxy instantiateClass: (interpreterProxy fetchClassOf: aBytesObject) indexableSize: newLen]. oldLen := self byteSizeOfBytes: aBytesObject. oldLen < newLen ifTrue: [copyLen := oldLen] ifFalse: [copyLen := newLen]. self cBytesCopyFrom: (interpreterProxy firstIndexableField: aBytesObject) to: (interpreterProxy firstIndexableField: newBytes) len: copyLen. ^ newBytes! ! !LargeIntegersPlugin methodsFor: 'oop util' stamp: 'sr 6/8/2004 05:05'! bytesOrInt: oop growTo: len "Attention: this method invalidates all oop's!! Only newBytes is valid at return." | newBytes val class | (interpreterProxy isIntegerObject: oop) ifTrue: [val := interpreterProxy integerValueOf: oop. val < 0 ifTrue: [class := interpreterProxy classLargeNegativeInteger] ifFalse: [class := interpreterProxy classLargePositiveInteger]. newBytes := interpreterProxy instantiateClass: class indexableSize: len. self cCopyIntVal: val toBytes: newBytes] ifFalse: [newBytes := self bytes: oop growTo: len]. ^ newBytes! ! !LargeIntegersPlugin methodsFor: 'C core' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:58'! cByteOp: opIndex short: pByteShort len: shortLen long: pByteLong len: longLen into: pByteRes "pByteRes len = longLen." | limit | limit := shortLen - 1. opIndex = andOpIndex ifTrue: [0 to: limit do: [:i | pByteRes at: i put: ((pByteShort at: i) bitAnd: (pByteLong at: i))]. limit := longLen - 1. shortLen to: limit do: [:i | pByteRes at: i put: 0]. ^ 0]. opIndex = orOpIndex ifTrue: [0 to: limit do: [:i | pByteRes at: i put: ((pByteShort at: i) bitOr: (pByteLong at: i))]. limit := longLen - 1. shortLen to: limit do: [:i | pByteRes at: i put: (pByteLong at: i)]. ^ 0]. opIndex = xorOpIndex ifTrue: [0 to: limit do: [:i | pByteRes at: i put: ((pByteShort at: i) bitXor: (pByteLong at: i))]. limit := longLen - 1. shortLen to: limit do: [:i | pByteRes at: i put: (pByteLong at: i)]. ^ 0]. ^ interpreterProxy primitiveFail! ! !LargeIntegersPlugin methodsFor: 'C core util' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:58'! cBytesCopyFrom: pFrom to: pTo len: len | limit | self cCode: '' inSmalltalk: [ (interpreterProxy isKindOf: InterpreterSimulator) ifTrue: [ "called from InterpreterSimulator" limit := len - 1. 0 to: limit do: [:i | interpreterProxy byteAt: pTo + i put: (interpreterProxy byteAt: pFrom + i) ]. ^ 0 ]. ]. limit := len - 1. 0 to: limit do: [:i | pTo at: i put: (pFrom at: i)]. ^ 0! ! !LargeIntegersPlugin methodsFor: 'C core util' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:55'! cBytesHighBit: pByte len: len "Answer the index (in bits) of the high order bit of the receiver, or zero if the receiver is zero. This method is allowed (and needed) for LargeNegativeIntegers as well, since Squeak's LargeIntegers are sign/magnitude." | realLength lastDigit | realLength := len. [(lastDigit := pByte at: realLength - 1) = 0] whileTrue: [(realLength := realLength - 1) = 0 ifTrue: [^ 0]]. ^ (self cHighBit: lastDigit) + (8 * (realLength - 1))! ! !LargeIntegersPlugin methodsFor: 'C core' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:59'! cBytesLshift: shiftCount from: pFrom len: lenFrom to: pTo len: lenTo "C indexed!!" | byteShift bitShift carry rShift mask limit digit lastIx | byteShift := shiftCount // 8. bitShift := shiftCount \\ 8. bitShift = 0 ifTrue: ["Fast version for byte-aligned shifts" "C indexed!!" ^ self cBytesReplace: pTo from: byteShift to: lenTo - 1 with: pFrom startingAt: 0]. carry := 0. rShift := bitShift - 8. mask := 255 bitShift: 0 - bitShift. limit := byteShift - 1. 0 to: limit do: [:i | pTo at: i put: 0]. limit := lenTo - byteShift - 2. self sqAssert: limit < lenFrom. 0 to: limit do: [:i | digit := pFrom at: i. pTo at: i + byteShift put: (((digit bitAnd: mask) bitShift: bitShift) bitOr: carry). carry := digit bitShift: rShift]. lastIx := limit + 1. lastIx > (lenFrom - 1) ifTrue: [digit := 0] ifFalse: [digit := pFrom at: lastIx]. pTo at: lastIx + byteShift put: (((digit bitAnd: mask) bitShift: bitShift) bitOr: carry). carry := digit bitShift: rShift. self sqAssert: carry = 0! ! !LargeIntegersPlugin methodsFor: 'C core util' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:59'! cBytesReplace: pTo from: start to: stop with: pFrom startingAt: repStart "C indexed!!" ^ self cBytesCopyFrom: pFrom + repStart to: pTo + start len: stop - start + 1! ! !LargeIntegersPlugin methodsFor: 'C core util' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:56'! cCopyIntVal: val toBytes: bytes | pByte | pByte := interpreterProxy firstIndexableField: bytes. 1 to: (self cDigitLengthOfCSI: val) do: [:ix | pByte at: ix - 1 put: (self cDigitOfCSI: val at: ix)]! ! !LargeIntegersPlugin methodsFor: 'C core' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:56'! cCoreBytesRshiftCount: count n: n m: m f: f bytes: b from: pFrom len: fromLen to: pTo len: toLen | x digit | self sqAssert: b < fromLen. x := (pFrom at: b) bitShift: n. self sqAssert: count - 1 < fromLen. b + 1 to: count - 1 do: [:j | digit := pFrom at: j. pTo at: j - b - 1 put: (((digit bitAnd: m) bitShift: f) bitOr: x). "Avoid values > 8 bits" x := digit bitShift: n]. count = fromLen ifTrue: [digit := 0] ifFalse: [digit := pFrom at: count]. pTo at: count - b - 1 put: (((digit bitAnd: m) bitShift: f) bitOr: x)! ! !LargeIntegersPlugin methodsFor: 'C core' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:56'! cCoreDigitDivDiv: pDiv len: divLen rem: pRem len: remLen quo: pQuo len: quoLen | dl ql dh dnh j t hi lo r3 l a cond q r1r2 mul | dl := divLen - 1. "Last actual byte of data (ST ix)" ql := quoLen. dh := pDiv at: dl - 1. dl = 1 ifTrue: [dnh := 0] ifFalse: [dnh := pDiv at: dl - 2]. 1 to: ql do: [:k | "maintain quo*arg+rem=self" "Estimate rem/div by dividing the leading two bytes of rem by dh." "The estimate is q = qhi*16+qlo, where qhi and qlo are nibbles." "Nibbles are kicked off!! We use full 16 bits now, because we are in the year 2000 ;-) [sr]" j := remLen + 1 - k. "r1 := rem digitAt: j." (pRem at: j - 1) = dh ifTrue: [q := 255] ifFalse: ["Compute q = (r1,r2)//dh, t = (r1,r2)\\dh. Note that r1,r2 are bytes, not nibbles. Be careful not to generate intermediate results exceeding 13 bits." "r2 := (rem digitAt: j - 2)." r1r2 := ((pRem at: j - 1) bitShift: 8) + (pRem at: j - 2). t := r1r2 \\ dh. q := r1r2 // dh. "Next compute (hi,lo) := q*dnh" mul := q * dnh. hi := mul bitShift: -8. lo := mul bitAnd: 255. "Correct overestimate of q. Max of 2 iterations through loop -- see Knuth vol. 2" j < 3 ifTrue: [r3 := 0] ifFalse: [r3 := pRem at: j - 3]. [(t < hi or: [t = hi and: [r3 < lo]]) ifTrue: ["i.e. (t,r3) < (hi,lo)" q := q - 1. lo := lo - dnh. lo < 0 ifTrue: [hi := hi - 1. lo := lo + 256]. cond := hi >= dh] ifFalse: [cond := false]. cond] whileTrue: [hi := hi - dh]]. "Subtract q*div from rem" l := j - dl. a := 0. 1 to: divLen do: [:i | hi := (pDiv at: i - 1) * (q bitShift: -8). lo := a + (pRem at: l - 1) - ((pDiv at: i - 1) * (q bitAnd: 255)). "pRem at: l - 1 put: lo - (lo // 256 * 256)." "sign-tolerant form of (lo bitAnd: 255) -> obsolete..." pRem at: l - 1 put: (lo bitAnd: 255). "... is sign-tolerant!! [sr]" a := lo // 256 - hi. l := l + 1]. a < 0 ifTrue: ["Add div back into rem, decrease q by 1" q := q - 1. l := j - dl. a := 0. 1 to: divLen do: [:i | a := (a bitShift: -8) + (pRem at: l - 1) + (pDiv at: i - 1). pRem at: l - 1 put: (a bitAnd: 255). l := l + 1]]. pQuo at: quoLen - k put: q]! ! !LargeIntegersPlugin methodsFor: 'C core' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:58'! cDigitAdd: pByteShort len: shortLen with: pByteLong len: longLen into: pByteRes "pByteRes len = longLen; returns over.." | accum limit | accum := 0. limit := shortLen - 1. 0 to: limit do: [:i | accum := (accum bitShift: -8) + (pByteShort at: i) + (pByteLong at: i). pByteRes at: i put: (accum bitAnd: 255)]. limit := longLen - 1. shortLen to: limit do: [:i | accum := (accum bitShift: -8) + (pByteLong at: i). pByteRes at: i put: (accum bitAnd: 255)]. ^ accum bitShift: -8! ! !LargeIntegersPlugin methodsFor: 'C core' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:57'! cDigitCompare: pFirst with: pSecond len: len "Precondition: pFirst len = pSecond len." | secondDigit ix firstDigit | ix := len - 1. [ix >= 0] whileTrue: [(secondDigit := pSecond at: ix) ~= (firstDigit := pFirst at: ix) ifTrue: [secondDigit < firstDigit ifTrue: [^ 1] ifFalse: [^ -1]]. ix := ix - 1]. ^ 0! ! !LargeIntegersPlugin methodsFor: 'C core util' stamp: 'tpr 12/29/2005 16:59'! cDigitLengthOfCSI: csi "Answer the number of indexable fields of a CSmallInteger. This value is the same as the largest legal subscript." (csi < 256 and: [csi > -256]) ifTrue: [^ 1]. (csi < 65536 and: [csi > -65536]) ifTrue: [^ 2]. (csi < 16777216 and: [csi > -16777216]) ifTrue: [^ 3]. ^ 4! ! !LargeIntegersPlugin methodsFor: 'C core' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:58'! cDigitMultiply: pByteShort len: shortLen with: pByteLong len: longLen into: pByteRes | limitLong digit k carry limitShort ab | (shortLen = 1 and: [(pByteShort at: 0) = 0]) ifTrue: [^ 0]. (longLen = 1 and: [(pByteLong at: 0) = 0]) ifTrue: [^ 0]. "prod starts out all zero" limitShort := shortLen - 1. 0 to: limitShort do: [:i | (digit := pByteShort at: i) ~= 0 ifTrue: [k := i. carry := 0. "Loop invariant: 0<=carry<=0377, k=i+j-1 (ST)" "-> Loop invariant: 0<=carry<=0377, k=i+j (C) (?)" limitLong := longLen - 1. 0 to: limitLong do: [:j | ab := (pByteLong at: j) * digit + carry + (pByteRes at: k). carry := ab bitShift: -8. pByteRes at: k put: (ab bitAnd: 255). k := k + 1]. pByteRes at: k put: carry]]. ^ 0! ! !LargeIntegersPlugin methodsFor: 'C core util' stamp: 'sr 12/23/1999 15:12'! cDigitOfCSI: csi at: ix "Answer the value of an indexable field in the receiver. LargePositiveInteger uses bytes of base two number, and each is a 'digit' base 256." "ST indexed!!" ix < 0 ifTrue: [interpreterProxy primitiveFail]. ix > 4 ifTrue: [^ 0]. csi < 0 ifTrue: [self cCode: '' inSmalltalk: [csi = -1073741824 ifTrue: ["SmallInteger minVal" "Can't negate minVal -- treat specially" ^ #(0 0 0 64 ) at: ix]]. ^ (0 - csi bitShift: 1 - ix * 8) bitAnd: 255] ifFalse: [^ (csi bitShift: 1 - ix * 8) bitAnd: 255]! ! !LargeIntegersPlugin methodsFor: 'C core' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:59'! cDigitSub: pByteSmall len: smallLen with: pByteLarge len: largeLen into: pByteRes | z limit | z := 0. "Loop invariant is -1<=z<=1" limit := smallLen - 1. 0 to: limit do: [:i | z := z + (pByteLarge at: i) - (pByteSmall at: i). pByteRes at: i put: z - (z // 256 * 256). "sign-tolerant form of (z bitAnd: 255)" z := z // 256]. limit := largeLen - 1. smallLen to: limit do: [:i | z := z + (pByteLarge at: i) . pByteRes at: i put: z - (z // 256 * 256). "sign-tolerant form of (z bitAnd: 255)" z := z // 256]. ! ! !LargeIntegersPlugin methodsFor: 'C core util' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:00'! cHighBit: uint "Answer the index of the high order bit of the argument, or zero if the argument is zero." "For 64 bit uints there could be added a 32-shift." | shifted bitNo | shifted := uint. bitNo := 0. shifted < (1 << 16) ifFalse: [shifted := shifted bitShift: -16. bitNo := bitNo + 16]. shifted < (1 << 8) ifFalse: [shifted := shifted bitShift: -8. bitNo := bitNo + 8]. shifted < (1 << 4) ifFalse: [shifted := shifted bitShift: -4. bitNo := bitNo + 4]. shifted < (1 << 2) ifFalse: [shifted := shifted bitShift: -2. bitNo := bitNo + 2]. shifted < (1 << 1) ifFalse: [shifted := shifted bitShift: -1. bitNo := bitNo + 1]. "shifted 0 or 1 now" ^ bitNo + shifted! ! !LargeIntegersPlugin methodsFor: 'oop util' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:00'! createLargeFromSmallInteger: anOop "anOop has to be a SmallInteger!!" | val class size res pByte | val := interpreterProxy integerValueOf: anOop. val < 0 ifTrue: [class := interpreterProxy classLargeNegativeInteger] ifFalse: [class := interpreterProxy classLargePositiveInteger]. size := self cDigitLengthOfCSI: val. res := interpreterProxy instantiateClass: class indexableSize: size. pByte := interpreterProxy firstIndexableField: res. 1 to: size do: [:ix | pByte at: ix - 1 put: (self cDigitOfCSI: val at: ix)]. ^ res! ! !LargeIntegersPlugin methodsFor: 'oop functions' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:00'! digitAddLarge: firstInteger with: secondInteger "Does not need to normalize!!" | over firstLen secondLen shortInt shortLen longInt longLen sum newSum resClass | firstLen := self byteSizeOfBytes: firstInteger. secondLen := self byteSizeOfBytes: secondInteger. resClass := interpreterProxy fetchClassOf: firstInteger. firstLen <= secondLen ifTrue: [shortInt := firstInteger. shortLen := firstLen. longInt := secondInteger. longLen := secondLen] ifFalse: [shortInt := secondInteger. shortLen := secondLen. longInt := firstInteger. longLen := firstLen]. " sum := Integer new: len neg: firstInteger negative." self remapOop: #(shortInt longInt ) in: [sum := interpreterProxy instantiateClass: resClass indexableSize: longLen]. over := self cDigitAdd: (interpreterProxy firstIndexableField: shortInt) len: shortLen with: (interpreterProxy firstIndexableField: longInt) len: longLen into: (interpreterProxy firstIndexableField: sum). over > 0 ifTrue: ["sum := sum growby: 1." interpreterProxy remapOop: sum in: [newSum := interpreterProxy instantiateClass: resClass indexableSize: longLen + 1]. self cBytesCopyFrom: (interpreterProxy firstIndexableField: sum) to: (interpreterProxy firstIndexableField: newSum) len: longLen. sum := newSum. "C index!!" (self cCoerce: (interpreterProxy firstIndexableField: sum) to: 'unsigned char *') at: longLen put: over]. ^ sum! ! !LargeIntegersPlugin methodsFor: 'oop functions' stamp: 'sr 6/8/2004 05:09'! digitBitLogic: firstInteger with: secondInteger opIndex: opIx "Bit logic here is only implemented for positive integers or Zero; if rec or arg is negative, it fails." | firstLarge secondLarge firstLen secondLen shortLen shortLarge longLen longLarge result | (interpreterProxy isIntegerObject: firstInteger) ifTrue: [(interpreterProxy integerValueOf: firstInteger) < 0 ifTrue: [^ interpreterProxy primitiveFail]. "convert it to a not normalized LargeInteger" self remapOop: secondInteger in: [firstLarge := self createLargeFromSmallInteger: firstInteger]] ifFalse: [(interpreterProxy fetchClassOf: firstInteger) = interpreterProxy classLargeNegativeInteger ifTrue: [^ interpreterProxy primitiveFail]. firstLarge := firstInteger]. (interpreterProxy isIntegerObject: secondInteger) ifTrue: [(interpreterProxy integerValueOf: secondInteger) < 0 ifTrue: [^ interpreterProxy primitiveFail]. "convert it to a not normalized LargeInteger" self remapOop: firstLarge in: [secondLarge := self createLargeFromSmallInteger: secondInteger]] ifFalse: [(interpreterProxy fetchClassOf: secondInteger) = interpreterProxy classLargeNegativeInteger ifTrue: [^ interpreterProxy primitiveFail]. secondLarge := secondInteger]. firstLen := self byteSizeOfBytes: firstLarge. secondLen := self byteSizeOfBytes: secondLarge. firstLen < secondLen ifTrue: [shortLen := firstLen. shortLarge := firstLarge. longLen := secondLen. longLarge := secondLarge] ifFalse: [shortLen := secondLen. shortLarge := secondLarge. longLen := firstLen. longLarge := firstLarge]. self remapOop: #(shortLarge longLarge ) in: [result := interpreterProxy instantiateClass: interpreterProxy classLargePositiveInteger indexableSize: longLen]. self cByteOp: opIx short: (interpreterProxy firstIndexableField: shortLarge) len: shortLen long: (interpreterProxy firstIndexableField: longLarge) len: longLen into: (interpreterProxy firstIndexableField: result). interpreterProxy failed ifTrue: [^ 0]. ^ self normalizePositive: result! ! !LargeIntegersPlugin methodsFor: 'oop functions' stamp: 'sr 3/11/2000 19:45'! digitCompareLarge: firstInteger with: secondInteger "Compare the magnitude of firstInteger with that of secondInteger. Return a code of 1, 0, -1 for firstInteger >, = , < secondInteger" | firstLen secondLen | firstLen := self byteSizeOfBytes: firstInteger. secondLen := self byteSizeOfBytes: secondInteger. secondLen ~= firstLen ifTrue: [secondLen > firstLen ifTrue: [^ -1 asOop: SmallInteger] ifFalse: [^ 1 asOop: SmallInteger]]. ^ (self cDigitCompare: (interpreterProxy firstIndexableField: firstInteger) with: (interpreterProxy firstIndexableField: secondInteger) len: firstLen) asOop: SmallInteger! ! !LargeIntegersPlugin methodsFor: 'oop functions' stamp: 'sr 3/11/2000 19:45'! digitDivLarge: firstInteger with: secondInteger negative: neg "Does not normalize." "Division by zero has to be checked in caller." | firstLen secondLen resultClass l d div rem quo result | firstLen := self byteSizeOfBytes: firstInteger. secondLen := self byteSizeOfBytes: secondInteger. neg ifTrue: [resultClass := interpreterProxy classLargeNegativeInteger] ifFalse: [resultClass := interpreterProxy classLargePositiveInteger]. l := firstLen - secondLen + 1. l <= 0 ifTrue: [self remapOop: firstInteger in: [result := interpreterProxy instantiateClass: interpreterProxy classArray indexableSize: 2]. result stAt: 1 put: (0 asOop: SmallInteger). result stAt: 2 put: firstInteger. ^ result]. "set rem and div to copies of firstInteger and secondInteger, respectively. However, to facilitate use of Knuth's algorithm, multiply rem and div by 2 (that is, shift) until the high byte of div is >=128" d := 8 - (self cHighBit: (self unsafeByteOf: secondInteger at: secondLen)). self remapOop: firstInteger in: [div := self bytes: secondInteger Lshift: d. div := self bytesOrInt: div growTo: (self digitLength: div) + 1]. self remapOop: div in: [rem := self bytes: firstInteger Lshift: d. (self digitLength: rem) = firstLen ifTrue: [rem := self bytesOrInt: rem growTo: firstLen + 1]]. self remapOop: #(div rem ) in: [quo := interpreterProxy instantiateClass: resultClass indexableSize: l]. self cCoreDigitDivDiv: (interpreterProxy firstIndexableField: div) len: (self digitLength: div) rem: (interpreterProxy firstIndexableField: rem) len: (self digitLength: rem) quo: (interpreterProxy firstIndexableField: quo) len: (self digitLength: quo). self remapOop: #(quo ) in: [rem := self bytes: rem Rshift: d bytes: 0 lookfirst: (self digitLength: div) - 1]. "^ Array with: quo with: rem" self remapOop: #(quo rem ) in: [result := interpreterProxy instantiateClass: interpreterProxy classArray indexableSize: 2]. result stAt: 1 put: quo. result stAt: 2 put: rem. ^ result! ! !LargeIntegersPlugin methodsFor: 'util' stamp: 'sr 3/11/2000 19:46'! digitLength: oop (interpreterProxy isIntegerObject: oop) ifTrue: [^ self cDigitLengthOfCSI: (interpreterProxy integerValueOf: oop)] ifFalse: [^ self byteSizeOfBytes: oop]! ! !LargeIntegersPlugin methodsFor: 'oop functions' stamp: 'sr 3/11/2000 19:46'! digitMultiplyLarge: firstInteger with: secondInteger negative: neg "Normalizes." | firstLen secondLen shortInt shortLen longInt longLen prod resultClass | firstLen := self byteSizeOfBytes: firstInteger. secondLen := self byteSizeOfBytes: secondInteger. firstLen <= secondLen ifTrue: [shortInt := firstInteger. shortLen := firstLen. longInt := secondInteger. longLen := secondLen] ifFalse: [shortInt := secondInteger. shortLen := secondLen. longInt := firstInteger. longLen := firstLen]. neg ifTrue: [resultClass := interpreterProxy classLargeNegativeInteger] ifFalse: [resultClass := interpreterProxy classLargePositiveInteger]. self remapOop: #(shortInt longInt ) in: [prod := interpreterProxy instantiateClass: resultClass indexableSize: longLen + shortLen]. self cDigitMultiply: (interpreterProxy firstIndexableField: shortInt) len: shortLen with: (interpreterProxy firstIndexableField: longInt) len: longLen into: (interpreterProxy firstIndexableField: prod). ^ self normalize: prod! ! !LargeIntegersPlugin methodsFor: 'util' stamp: 'sr 1/23/2000 18:10'! digitOf: oop at: ix (interpreterProxy isIntegerObject: oop) ifTrue: [^ self cDigitOfCSI: (interpreterProxy integerValueOf: oop) at: ix] ifFalse: [^ self digitOfBytes: oop at: ix]! ! !LargeIntegersPlugin methodsFor: 'util' stamp: 'sr 3/11/2000 19:46'! digitOfBytes: aBytesOop at: ix "Argument has to be aLargeInteger!!" ix > (self byteSizeOfBytes: aBytesOop) ifTrue: [^ 0] ifFalse: [^ self unsafeByteOf: aBytesOop at: ix]! ! !LargeIntegersPlugin methodsFor: 'oop functions' stamp: 'eem 10/4/2010 10:19'! digitSubLarge: firstInteger with: secondInteger "Normalizes." | firstLen secondLen larger largerLen smaller smallerLen neg resLen res firstNeg | firstNeg := (interpreterProxy fetchClassOf: firstInteger) = interpreterProxy classLargeNegativeInteger. firstLen := self byteSizeOfBytes: firstInteger. secondLen := self byteSizeOfBytes: secondInteger. firstLen = secondLen ifTrue: [[firstLen > 1 and: [(self digitOfBytes: firstInteger at: firstLen) = (self digitOfBytes: secondInteger at: firstLen)]] whileTrue: [firstLen := firstLen - 1]. secondLen := firstLen]. (firstLen < secondLen or: [firstLen = secondLen and: [(self digitOfBytes: firstInteger at: firstLen) < (self digitOfBytes: secondInteger at: firstLen)]]) ifTrue: [larger := secondInteger. largerLen := secondLen. smaller := firstInteger. smallerLen := firstLen. neg := firstNeg == false] ifFalse: [larger := firstInteger. largerLen := firstLen. smaller := secondInteger. smallerLen := secondLen. neg := firstNeg]. resLen := largerLen. self remapOop: #(smaller larger) in: [res := interpreterProxy instantiateClass: (neg ifTrue: [interpreterProxy classLargeNegativeInteger] ifFalse: [interpreterProxy classLargePositiveInteger]) indexableSize: resLen]. self cDigitSub: (interpreterProxy firstIndexableField: smaller) len: smallerLen with: (interpreterProxy firstIndexableField: larger) len: largerLen into: (interpreterProxy firstIndexableField: res). ^neg ifTrue: [self normalizeNegative: res] ifFalse: [self normalizePositive: res]! ! !LargeIntegersPlugin methodsFor: 'util' stamp: 'sr 6/9/2000 00:24'! highBitOfBytes: aBytesOop ^ self cBytesHighBit: (interpreterProxy firstIndexableField: aBytesOop) len: (self byteSizeOfBytes: aBytesOop)! ! !LargeIntegersPlugin methodsFor: 'ST initialize' stamp: 'sr (auto pragmas 12/08) 3/15/2000 00:57'! initialize "Initializes ST constants; C's are set by class>>declareCVarsIn:." self cCode: '"nothing to do here"' inSmalltalk: [andOpIndex := 0. orOpIndex := 1. xorOpIndex := 2]! ! !LargeIntegersPlugin methodsFor: 'oop functions' stamp: 'sr 5/28/2004 16:25'! isNormalized: anInteger | len maxVal minVal sLen | (interpreterProxy isIntegerObject: anInteger) ifTrue: [^ true]. "Check for leading zero of LargeInteger" len := self digitLength: anInteger. len = 0 ifTrue: [^ false]. (self unsafeByteOf: anInteger at: len) = 0 ifTrue: [^ false]. "no leading zero, now check if anInteger is in SmallInteger range or not" sLen := 4. "maximal digitLength of aSmallInteger" len > sLen ifTrue: [^ true]. len < sLen ifTrue: [^ false]. "len = sLen" (interpreterProxy fetchClassOf: anInteger) = interpreterProxy classLargePositiveInteger ifTrue: [maxVal := 1073741823. "SmallInteger maxVal" "all bytes of maxVal but the highest one are just FF's" ^ (self unsafeByteOf: anInteger at: sLen) > (self cDigitOfCSI: maxVal at: sLen)] ifFalse: [minVal := -1073741824. "SmallInteger minVal" "all bytes of minVal but the highest one are just 00's" (self unsafeByteOf: anInteger at: sLen) < (self cDigitOfCSI: minVal at: sLen) ifTrue: [^ false] ifFalse: ["if just one digit differs, then anInteger < minval (the corresponding digit byte is greater!!) and therefore a LargeNegativeInteger" 1 to: sLen do: [:ix | (self unsafeByteOf: anInteger at: ix) = (self cDigitOfCSI: minVal at: ix) ifFalse: [^ true]]]]. ^ false! ! !LargeIntegersPlugin methodsFor: 'util' stamp: 'sr 6/9/2000 00:31'! negative: aLarge ^ (interpreterProxy fetchClassOf: aLarge) = interpreterProxy classLargeNegativeInteger! ! !LargeIntegersPlugin methodsFor: 'oop functions' stamp: 'sr 6/9/2000 04:02'! normalize: aLargeInteger "Check for leading zeroes and return shortened copy if so." self debugCode: [self msg: 'normalize: aLargeInteger']. (interpreterProxy fetchClassOf: aLargeInteger) = interpreterProxy classLargePositiveInteger ifTrue: [^ self normalizePositive: aLargeInteger] ifFalse: [^ self normalizeNegative: aLargeInteger]! ! !LargeIntegersPlugin methodsFor: 'oop functions' stamp: 'sr 6/8/2004 05:08'! normalizeNegative: aLargeNegativeInteger "Check for leading zeroes and return shortened copy if so." "First establish len = significant length." | sLen val len oldLen minVal | len := oldLen := self digitLength: aLargeNegativeInteger. [len ~= 0 and: [(self unsafeByteOf: aLargeNegativeInteger at: len) = 0]] whileTrue: [len := len - 1]. len = 0 ifTrue: [^ 0 asOop: SmallInteger]. "Now check if in SmallInteger range" sLen := 4. "SmallInteger minVal digitLength" len <= sLen ifTrue: ["SmallInteger minVal" minVal := -1073741824. (len < sLen or: [(self digitOfBytes: aLargeNegativeInteger at: sLen) < (self cDigitOfCSI: minVal at: sLen) "minVal lastDigit"]) ifTrue: ["If high digit less, then can be small" val := 0. len to: 1 by: -1 do: [:i | val := val * 256 - (self unsafeByteOf: aLargeNegativeInteger at: i)]. ^ val asOop: SmallInteger]. 1 to: sLen do: [:i | "If all digits same, then = minVal (sr: minVal digits 1 to 3 are 0)" (self digitOfBytes: aLargeNegativeInteger at: i) = (self cDigitOfCSI: minVal at: i) ifFalse: ["Not so; return self shortened" len < oldLen ifTrue: ["^ self growto: len" ^ self bytes: aLargeNegativeInteger growTo: len] ifFalse: [^ aLargeNegativeInteger]]]. ^ minVal asOop: SmallInteger]. "Return self, or a shortened copy" len < oldLen ifTrue: ["^ self growto: len" ^ self bytes: aLargeNegativeInteger growTo: len] ifFalse: [^ aLargeNegativeInteger]! ! !LargeIntegersPlugin methodsFor: 'oop functions' stamp: 'sr 6/8/2004 05:08'! normalizePositive: aLargePositiveInteger "Check for leading zeroes and return shortened copy if so." "First establish len = significant length." | sLen val len oldLen | len := oldLen := self digitLength: aLargePositiveInteger. [len ~= 0 and: [(self unsafeByteOf: aLargePositiveInteger at: len) = 0]] whileTrue: [len := len - 1]. len = 0 ifTrue: [^ 0 asOop: SmallInteger]. "Now check if in SmallInteger range" sLen := 4. "SmallInteger maxVal digitLength." (len <= sLen and: [(self digitOfBytes: aLargePositiveInteger at: sLen) <= (self cDigitOfCSI: 1073741823 at: sLen) "SmallInteger maxVal"]) ifTrue: ["If so, return its SmallInt value" val := 0. len to: 1 by: -1 do: [:i | val := val * 256 + (self unsafeByteOf: aLargePositiveInteger at: i)]. ^ val asOop: SmallInteger]. "Return self, or a shortened copy" len < oldLen ifTrue: ["^ self growto: len" ^ self bytes: aLargePositiveInteger growTo: len] ifFalse: [^ aLargePositiveInteger]! ! !LargeIntegersPlugin methodsFor: 'Integer primitives' stamp: 'sr 6/9/2000 10:25'! primAnyBitFrom: from to: to | integer large | self debugCode: [self msg: 'primAnyBitFrom: from to: to']. integer := self primitive: 'primAnyBitFromTo' parameters: #(#SmallInteger #SmallInteger ) receiver: #Integer. (interpreterProxy isIntegerObject: integer) ifTrue: ["convert it to a not normalized LargeInteger" large := self createLargeFromSmallInteger: integer] ifFalse: [large := integer]. ^ (self anyBitOfBytes: large from: from to: to) asOop: Boolean! ! !LargeIntegersPlugin methodsFor: 'control & support primitives' stamp: 'sr 4/8/2000 02:13'! primAsLargeInteger: anInteger "Converts a SmallInteger into a - non normalized!! - LargeInteger; aLargeInteger will be returned unchanged." "Do not check for forced fail, because we need this conversion to test the plugin in ST during forced fail, too." self debugCode: [self msg: 'primAsLargeInteger: anInteger']. self primitive: 'primAsLargeInteger' parameters: #(Integer ) receiver: #Oop. (interpreterProxy isIntegerObject: anInteger) ifTrue: [^ self createLargeFromSmallInteger: anInteger] ifFalse: [^ anInteger]! ! !LargeIntegersPlugin methodsFor: 'obsolete' stamp: 'sr 12/27/1999 19:00'! primCheckIfCModuleExists "If calling this primitive fails, then C module does not exist. Do not check for forced fail, because we want to know if module exists during forced fail, too." self primitive: 'primCheckIfCModuleExists' parameters: #() receiver: #Oop. ^ true asOop: Boolean! ! !LargeIntegersPlugin methodsFor: 'development primitives' stamp: 'ar 4/4/2006 20:56'! primDigit: anInteger bitShift: shiftCount | rShift aLarge | self debugCode: [self msg: 'primDigit: anInteger bitShift: shiftCount']. self primitive: '_primDigitBitShift' parameters: #(Integer SmallInteger ) receiver: #Oop. (interpreterProxy isIntegerObject: anInteger) ifTrue: ["convert it to a not normalized LargeInteger" aLarge := self createLargeFromSmallInteger: anInteger] ifFalse: [aLarge := anInteger]. shiftCount >= 0 ifTrue: [^ self bytes: aLarge Lshift: shiftCount] ifFalse: [rShift := 0 - shiftCount. ^ self normalize: (self bytes: aLarge Rshift: (rShift bitAnd: 7) bytes: (rShift bitShift: -3) lookfirst: (self byteSizeOfBytes: aLarge))]! ! !LargeIntegersPlugin methodsFor: 'Integer primitives' stamp: 'sr 6/8/2004 04:49'! primDigitAdd: secondInteger | firstLarge secondLarge firstInteger | self debugCode: [self msg: 'primDigitAdd: secondInteger']. firstInteger := self primitive: 'primDigitAdd' parameters: #(Integer ) receiver: #Integer. (interpreterProxy isIntegerObject: firstInteger) ifTrue: ["convert it to a not normalized LargeInteger" self remapOop: secondInteger in: [firstLarge := self createLargeFromSmallInteger: firstInteger]] ifFalse: [firstLarge := firstInteger]. (interpreterProxy isIntegerObject: secondInteger) ifTrue: ["convert it to a not normalized LargeInteger" self remapOop: firstLarge in: [secondLarge := self createLargeFromSmallInteger: secondInteger]] ifFalse: [secondLarge := secondInteger]. ^ self digitAddLarge: firstLarge with: secondLarge! ! !LargeIntegersPlugin methodsFor: 'development primitives' stamp: 'sr 6/8/2004 04:59'! primDigitAdd: firstInteger with: secondInteger | firstLarge secondLarge | self debugCode: [self msg: 'primDigitAdd: firstInteger with: secondInteger']. self primitive: 'primDigitAddWith' parameters: #(Integer Integer ) receiver: #Oop. (interpreterProxy isIntegerObject: firstInteger) ifTrue: ["convert it to a not normalized LargeInteger" self remapOop: secondInteger in: [firstLarge := self createLargeFromSmallInteger: firstInteger]] ifFalse: [firstLarge := firstInteger]. (interpreterProxy isIntegerObject: secondInteger) ifTrue: ["convert it to a not normalized LargeInteger" self remapOop: firstLarge in: [secondLarge := self createLargeFromSmallInteger: secondInteger]] ifFalse: [secondLarge := secondInteger]. ^ self digitAddLarge: firstLarge with: secondLarge! ! !LargeIntegersPlugin methodsFor: 'Integer primitives' stamp: 'sr 4/8/2000 02:07'! primDigitBitAnd: secondInteger "Bit logic here is only implemented for positive integers or Zero; if rec or arg is negative, it fails." | firstInteger | self debugCode: [self msg: 'primDigitBitAnd: secondInteger']. firstInteger := self primitive: 'primDigitBitAnd' parameters: #(Integer ) receiver: #Integer. ^ self digitBitLogic: firstInteger with: secondInteger opIndex: andOpIndex! ! !LargeIntegersPlugin methodsFor: 'development primitives' stamp: 'sr 4/8/2000 02:07'! primDigitBitLogic: firstInteger with: secondInteger op: opIndex "Bit logic here is only implemented for positive integers or Zero; if any arg is negative, it fails." self debugCode: [self msg: 'primDigitBitLogic: firstInteger with: secondInteger op: opIndex']. self primitive: 'primDigitBitLogicWithOp' parameters: #(Integer Integer SmallInteger ) receiver: #Oop. ^ self digitBitLogic: firstInteger with: secondInteger opIndex: opIndex! ! !LargeIntegersPlugin methodsFor: 'Integer primitives' stamp: 'sr 4/8/2000 02:07'! primDigitBitOr: secondInteger "Bit logic here is only implemented for positive integers or Zero; if rec or arg is negative, it fails." | firstInteger | self debugCode: [self msg: 'primDigitBitOr: secondInteger']. firstInteger := self primitive: 'primDigitBitOr' parameters: #(Integer ) receiver: #Integer. ^ self digitBitLogic: firstInteger with: secondInteger opIndex: orOpIndex! ! !LargeIntegersPlugin methodsFor: 'obsolete' stamp: 'sr 4/8/2000 02:08'! primDigitBitShift: shiftCount | rShift aLarge anInteger | self debugCode: [self msg: 'primDigitBitShift: shiftCount']. anInteger := self primitive: 'primDigitBitShift' parameters: #(SmallInteger ) receiver: #Integer. (interpreterProxy isIntegerObject: anInteger) ifTrue: ["convert it to a not normalized LargeInteger" aLarge := self createLargeFromSmallInteger: anInteger] ifFalse: [aLarge := anInteger]. shiftCount >= 0 ifTrue: [^ self bytes: aLarge Lshift: shiftCount] ifFalse: [rShift := 0 - shiftCount. ^ self normalize: (self bytes: aLarge Rshift: (rShift bitAnd: 7) bytes: (rShift bitShift: -3) lookfirst: (self byteSizeOfBytes: aLarge))]! ! !LargeIntegersPlugin methodsFor: 'Integer primitives' stamp: 'sr 6/9/2000 10:49'! primDigitBitShiftMagnitude: shiftCount | rShift aLarge anInteger | self debugCode: [self msg: 'primDigitBitShiftMagnitude: shiftCount']. anInteger := self primitive: 'primDigitBitShiftMagnitude' parameters: #(#SmallInteger ) receiver: #Integer. (interpreterProxy isIntegerObject: anInteger) ifTrue: ["convert it to a not normalized LargeInteger" aLarge := self createLargeFromSmallInteger: anInteger] ifFalse: [aLarge := anInteger]. shiftCount >= 0 ifTrue: [^ self bytes: aLarge Lshift: shiftCount] ifFalse: [rShift := 0 - shiftCount. ^ self normalize: (self bytes: aLarge Rshift: (rShift bitAnd: 7) bytes: (rShift bitShift: -3) lookfirst: (self byteSizeOfBytes: aLarge))]! ! !LargeIntegersPlugin methodsFor: 'Integer primitives' stamp: 'sr 4/8/2000 02:08'! primDigitBitXor: secondInteger "Bit logic here is only implemented for positive integers or Zero; if rec or arg is negative, it fails." | firstInteger | self debugCode: [self msg: 'primDigitBitXor: secondInteger']. firstInteger := self primitive: 'primDigitBitXor' parameters: #(Integer ) receiver: #Integer. ^ self digitBitLogic: firstInteger with: secondInteger opIndex: xorOpIndex! ! !LargeIntegersPlugin methodsFor: 'Integer primitives' stamp: 'sr 6/8/2004 04:50'! primDigitCompare: secondInteger | firstVal secondVal firstInteger | self debugCode: [self msg: 'primDigitCompare: secondInteger']. firstInteger := self primitive: 'primDigitCompare' parameters: #(#Integer ) receiver: #Integer. "shortcut: aSmallInteger has to be smaller in Magnitude as aLargeInteger" (interpreterProxy isIntegerObject: firstInteger) ifTrue: ["first" (interpreterProxy isIntegerObject: secondInteger) ifTrue: ["second" (firstVal := interpreterProxy integerValueOf: firstInteger) > (secondVal := interpreterProxy integerValueOf: secondInteger) ifTrue: [^ 1 asOop: SmallInteger"first > second"] ifFalse: [firstVal < secondVal ifTrue: [^ -1 asOop: SmallInteger"first < second"] ifFalse: [^ 0 asOop: SmallInteger"first = second"]]] ifFalse: ["SECOND" ^ -1 asOop: SmallInteger"first < SECOND"]] ifFalse: ["FIRST" (interpreterProxy isIntegerObject: secondInteger) ifTrue: ["second" ^ 1 asOop: SmallInteger"FIRST > second"] ifFalse: ["SECOND" ^ self digitCompareLarge: firstInteger with: secondInteger]]! ! !LargeIntegersPlugin methodsFor: 'development primitives' stamp: 'sr 4/8/2000 02:08'! primDigitCompare: firstInteger with: secondInteger | firstVal secondVal | self debugCode: [self msg: 'primDigitCompare: firstInteger with: secondInteger']. self primitive: 'primDigitCompareWith' parameters: #(Integer Integer ) receiver: #Oop. "shortcut: aSmallInteger has to be smaller in Magnitude as aLargeInteger" (interpreterProxy isIntegerObject: firstInteger) ifTrue: ["first" (interpreterProxy isIntegerObject: secondInteger) ifTrue: ["second" (firstVal := interpreterProxy integerValueOf: firstInteger) > (secondVal := interpreterProxy integerValueOf: secondInteger) ifTrue: [^ 1 asOop: SmallInteger"first > second"] ifFalse: [firstVal < secondVal ifTrue: [^ -1 asOop: SmallInteger"first < second"] ifFalse: [^ 0 asOop: SmallInteger"first = second"]]] ifFalse: ["SECOND" ^ -1 asOop: SmallInteger"first < SECOND"]] ifFalse: ["FIRST" (interpreterProxy isIntegerObject: secondInteger) ifTrue: ["second" ^ 1 asOop: SmallInteger"FIRST > second"] ifFalse: ["SECOND" ^ self digitCompareLarge: firstInteger with: secondInteger]]! ! !LargeIntegersPlugin methodsFor: 'Integer primitives' stamp: 'sr 6/8/2004 04:51'! primDigitDiv: secondInteger negative: neg "Answer the result of dividing firstInteger by secondInteger. Fail if parameters are not integers, not normalized or secondInteger is zero. " | firstAsLargeInteger secondAsLargeInteger firstInteger | self debugCode: [self msg: 'primDigitDiv: secondInteger negative: neg']. firstInteger := self primitive: 'primDigitDivNegative' parameters: #(#Integer #Boolean ) receiver: #Integer. "Avoid crashes in case of getting unnormalized args." (self isNormalized: firstInteger) ifFalse: [self debugCode: [self msg: 'ERROR in primDigitDiv: secondInteger negative: neg'. self msg: '------> receiver *not* normalized!!']. ^ interpreterProxy primitiveFail]. (self isNormalized: secondInteger) ifFalse: [self debugCode: [self msg: 'ERROR in primDigitDiv: secondInteger negative: neg'. self msg: '------> argument *not* normalized!!']. ^ interpreterProxy primitiveFail]. "Coerce SmallIntegers to corresponding (not normalized) large integers and check for zerodivide." (interpreterProxy isIntegerObject: firstInteger) ifTrue: ["convert to LargeInteger" self remapOop: secondInteger in: [firstAsLargeInteger := self createLargeFromSmallInteger: firstInteger]] ifFalse: [firstAsLargeInteger := firstInteger]. (interpreterProxy isIntegerObject: secondInteger) ifTrue: ["check for zerodivide and convert to LargeInteger" (interpreterProxy integerValueOf: secondInteger) = 0 ifTrue: [^ interpreterProxy primitiveFail]. self remapOop: firstAsLargeInteger in: [secondAsLargeInteger := self createLargeFromSmallInteger: secondInteger]] ifFalse: [secondAsLargeInteger := secondInteger]. ^ self digitDivLarge: firstAsLargeInteger with: secondAsLargeInteger negative: neg! ! !LargeIntegersPlugin methodsFor: 'development primitives' stamp: 'sr 6/8/2004 04:59'! primDigitDiv: firstInteger with: secondInteger negative: neg "Answer the result of dividing firstInteger by secondInteger. Fail if parameters are not integers or secondInteger is zero." | firstAsLargeInteger secondAsLargeInteger | self debugCode: [self msg: 'primDigitDiv: firstInteger with: secondInteger negative: neg']. self primitive: 'primDigitDivWithNegative' parameters: #(Integer Integer Boolean ) receiver: #Oop. "Coerce SmallIntegers to corresponding (not normalized) large integers and check for zerodivide." (interpreterProxy isIntegerObject: firstInteger) ifTrue: ["convert to LargeInteger" self remapOop: secondInteger in: [firstAsLargeInteger := self createLargeFromSmallInteger: firstInteger]] ifFalse: [firstAsLargeInteger := firstInteger]. (interpreterProxy isIntegerObject: secondInteger) ifTrue: ["check for zerodivide and convert to LargeInteger" (interpreterProxy integerValueOf: secondInteger) = 0 ifTrue: [^ interpreterProxy primitiveFail]. self remapOop: firstAsLargeInteger in: [secondAsLargeInteger := self createLargeFromSmallInteger: secondInteger]] ifFalse: [secondAsLargeInteger := secondInteger]. ^ self digitDivLarge: firstAsLargeInteger with: secondAsLargeInteger negative: neg! ! !LargeIntegersPlugin methodsFor: 'Integer primitives' stamp: 'sr 6/8/2004 04:53'! primDigitMultiply: secondInteger negative: neg | firstLarge secondLarge firstInteger | self debugCode: [self msg: 'primDigitMultiply: secondInteger negative: neg']. firstInteger := self primitive: 'primDigitMultiplyNegative' parameters: #(#Integer #Boolean ) receiver: #Integer. (interpreterProxy isIntegerObject: firstInteger) ifTrue: ["convert it to a not normalized LargeInteger" self remapOop: secondInteger in: [firstLarge := self createLargeFromSmallInteger: firstInteger]] ifFalse: [firstLarge := firstInteger]. (interpreterProxy isIntegerObject: secondInteger) ifTrue: ["convert it to a not normalized LargeInteger" self remapOop: firstLarge in: [secondLarge := self createLargeFromSmallInteger: secondInteger]] ifFalse: [secondLarge := secondInteger]. ^ self digitMultiplyLarge: firstLarge with: secondLarge negative: neg! ! !LargeIntegersPlugin methodsFor: 'development primitives' stamp: 'sr 6/8/2004 04:58'! primDigitMultiply: firstInteger with: secondInteger negative: neg | firstLarge secondLarge | self debugCode: [self msg: 'primDigitMultiply: firstInteger with: secondInteger negative: neg']. self primitive: 'primDigitMultiplyWithNegative' parameters: #(Integer Integer Boolean ) receiver: #Oop. (interpreterProxy isIntegerObject: firstInteger) ifTrue: ["convert it to a not normalized LargeInteger" self remapOop: secondInteger in: [firstLarge := self createLargeFromSmallInteger: firstInteger]] ifFalse: [firstLarge := firstInteger]. (interpreterProxy isIntegerObject: secondInteger) ifTrue: ["convert it to a not normalized LargeInteger" self remapOop: firstLarge in: [secondLarge := self createLargeFromSmallInteger: secondInteger]] ifFalse: [secondLarge := secondInteger]. ^ self digitMultiplyLarge: firstLarge with: secondLarge negative: neg! ! !LargeIntegersPlugin methodsFor: 'Integer primitives' stamp: 'sr 6/8/2004 05:01'! primDigitSubtract: secondInteger | firstLarge secondLarge firstInteger | self debugCode: [self msg: 'primDigitSubtract: secondInteger']. firstInteger := self primitive: 'primDigitSubtract' parameters: #(#Integer ) receiver: #Integer. (interpreterProxy isIntegerObject: firstInteger) ifTrue: ["convert it to a not normalized LargeInteger" self remapOop: secondInteger in: [firstLarge := self createLargeFromSmallInteger: firstInteger]] ifFalse: [firstLarge := firstInteger]. (interpreterProxy isIntegerObject: secondInteger) ifTrue: ["convert it to a not normalized LargeInteger" self remapOop: firstLarge in: [secondLarge := self createLargeFromSmallInteger: secondInteger]] ifFalse: [secondLarge := secondInteger]. ^ self digitSubLarge: firstLarge with: secondLarge! ! !LargeIntegersPlugin methodsFor: 'development primitives' stamp: 'sr 6/8/2004 04:58'! primDigitSubtract: firstInteger with: secondInteger | firstLarge secondLarge | self debugCode: [self msg: 'primDigitSubtract: firstInteger with: secondInteger']. self primitive: 'primDigitSubtractWith' parameters: #(Integer Integer ) receiver: #Oop. (interpreterProxy isIntegerObject: firstInteger) ifTrue: ["convert it to a not normalized LargeInteger" self remapOop: secondInteger in: [firstLarge := self createLargeFromSmallInteger: firstInteger]] ifFalse: [firstLarge := firstInteger]. (interpreterProxy isIntegerObject: secondInteger) ifTrue: ["convert it to a not normalized LargeInteger" self remapOop: firstLarge in: [secondLarge := self createLargeFromSmallInteger: secondInteger]] ifFalse: [secondLarge := secondInteger]. ^ self digitSubLarge: firstLarge with: secondLarge! ! !LargeIntegersPlugin methodsFor: 'control & support primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:00'! primGetModuleName "If calling this primitive fails, then C module does not exist." | strLen strOop strPtr | self debugCode: [self msg: 'primGetModuleName']. self primitive: 'primGetModuleName' parameters: #() receiver: #Oop. strLen := self strlen: self getModuleName. strOop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: strLen. strPtr := interpreterProxy firstIndexableField: strOop. 0 to: strLen - 1 do: [:i | strPtr at: i put: (self getModuleName at: i)]. ^ strOop! ! !LargeIntegersPlugin methodsFor: 'development primitives' stamp: 'sr 4/8/2000 02:11'! primNormalize: anInteger "Parameter specification #(Integer) doesn't convert!!" self debugCode: [self msg: 'primNormalize: anInteger']. self primitive: 'primNormalize' parameters: #(Integer ) receiver: #Oop. (interpreterProxy isIntegerObject: anInteger) ifTrue: [^ anInteger]. ^ self normalize: anInteger! ! !LargeIntegersPlugin methodsFor: 'Integer primitives' stamp: 'sr 6/8/2004 05:01'! primNormalizeNegative | rcvr | self debugCode: [self msg: 'primNormalizeNegative']. rcvr := self primitive: 'primNormalizeNegative' parameters: #() receiver: #LargeNegativeInteger. ^ self normalizeNegative: rcvr! ! !LargeIntegersPlugin methodsFor: 'Integer primitives' stamp: 'sr 6/8/2004 05:01'! primNormalizePositive | rcvr | self debugCode: [self msg: 'primNormalizePositive']. rcvr := self primitive: 'primNormalizePositive' parameters: #() receiver: #LargePositiveInteger. ^ self normalizePositive: rcvr! ! !LargeIntegersPlugin methodsFor: 'debugging' stamp: 'tpr 11/1/2004 20:20'! think "Flag for marking methods for later thinking." self debugCode: [self msg: '#think should not be called']. ^nil! ! !LargeIntegersPlugin methodsFor: 'util' stamp: 'eem 10/2/2010 13:17'! unsafeByteOf: bytesOop at: ix "Argument bytesOop must not be aSmallInteger!!" | pointer | ^(pointer := interpreterProxy firstIndexableField: bytesOop) at: ix - 1! ! SmartSyntaxInterpreterPlugin subclass: #LocalePlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !LocalePlugin commentStamp: '' prior: 0! LocalePlugin provides access to some localization info. primLanguage - returns a string describing the language in use as per ISO 639 primCountry - returns a string with country tag as per ISO 639 primVMOffsetToUTC - returns offset from UTC to time as provided by the VM. integer of minutes to allow for those odd places with halkf-hour offeset. primTimeZone - returns UTC offset (? why two?) primDST - returns boolean to indicate DST in use primDecimalSymbol - return string with '.' or ',' etc primDigitGrouping - return string with ',' or '.' etc for thousands type separation primTimeFormat - return string with time dispaly format string - eg 'hh:mm:ss' etc primLongDateFOrmat - return string with long date formatting - eg 'dd/mm/yyyy' primShortDateFOrmat - similar but shortform primCurrencySymbol - return string of currency name primCurrencyNotation - return boolean for pre or postfix currency symbol primMeasurement - return boolean for imperial or metric ! !LocalePlugin class methodsFor: 'translation' stamp: 'tpr 5/31/2005 18:41'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !LocalePlugin class methodsFor: 'translation' stamp: 'tpr 5/31/2005 17:00'! requiresPlatformFiles "this plugin requires platform specific files in order to work" ^true! ! !LocalePlugin methodsFor: 'initialize' stamp: 'tpr (auto pragmas 12/08) 6/1/2005 18:20'! initialiseModule ^self sqLocInitialize! ! !LocalePlugin methodsFor: 'system primitives' stamp: 'tpr 5/31/2005 18:59'! primitiveCountry "return a 3 char string describing the country in use. ISO 3166 is the relevant source here; see http://www.unicode.org/onlinedat/countries.html for details. Using the 3 character Alpha-3 codes" | oop | self primitive:'primitiveCountry'. oop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: 3. self sqLocGetCountryInto: (interpreterProxy firstIndexableField: oop). ^oop ! ! !LocalePlugin methodsFor: 'system primitives' stamp: 'tpr 5/31/2005 18:25'! primitiveCurrencyNotation "return a boolean specifying whether the currency symbol is pre or post fix. true -> pre" self primitive:'primitiveCurrencyNotation'. ^self sqLocCurrencyNotation asOop: Boolean! ! !LocalePlugin methodsFor: 'system primitives' stamp: 'tpr 6/1/2005 13:22'! primitiveCurrencySymbol "return a string describing the currency symbol used Still need to find details on standard symbols - ISO 4217 is supposed to be it but cannot find on web" | oop length | self primitive:'primitiveCurrencySymbol'. length := self sqLocCurrencySymbolSize. oop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: length. self sqLocGetCurrencySymbolInto: (interpreterProxy firstIndexableField: oop). ^oop ! ! !LocalePlugin methodsFor: 'system primitives' stamp: 'tpr 5/31/2005 18:24'! primitiveDaylightSavings "return a boolean specifying the DST setting. true -> active" self primitive:'primitiveDaylightSavings'. ^self sqLocDaylightSavings asOop: Boolean! ! !LocalePlugin methodsFor: 'system primitives' stamp: 'tpr 6/1/2005 12:23'! primitiveDecimalSymbol "return a 1 char string describing the decimal symbol used - usually a . or a ," | oop | self primitive:'primitiveDecimalSymbol'. oop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: 1. self sqLocGetDecimalSymbolInto: (interpreterProxy firstIndexableField: oop). ^oop ! ! !LocalePlugin methodsFor: 'system primitives' stamp: 'tpr 6/1/2005 12:24'! primitiveDigitGroupingSymbol "return a 1 char string describing the digitGrouping symbol used - usually a . or a , between triples of digits" | oop | self primitive:'primitiveDigitGroupingSymbol'. oop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: 1. self sqLocGetDigitGroupingSymbolInto: (interpreterProxy firstIndexableField: oop). ^oop ! ! !LocalePlugin methodsFor: 'system primitives' stamp: 'tpr 6/1/2005 12:24'! primitiveLanguage "return a 3 char string describing the language in use. ISO 639 is the relevant source here; see http://www.w3.org/WAI/ER/IG/ert/iso639.html for details" | oop | self primitive:'primitiveLanguage'. oop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: 3. self sqLocGetLanguageInto: (interpreterProxy firstIndexableField: oop). ^oop ! ! !LocalePlugin methodsFor: 'system primitives' stamp: 'tpr 6/1/2005 12:24'! primitiveLongDateFormat "return a string describing the long date formatting. Format is made up of d day, m month, y year, double symbol is null padded, single not padded (m=6, mm=06) dddd weekday mmmm month name " | oop length | self primitive:'primitiveLongDateFormat'. length := self sqLocLongDateFormatSize. oop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: length. self sqLocGetLongDateFormatInto: (interpreterProxy firstIndexableField: oop). ^oop ! ! !LocalePlugin methodsFor: 'system primitives' stamp: 'tpr 5/31/2005 18:28'! primitiveMeasurementMetric "return a boolean specifying whether the currency symbol is pre or post fix. true -> pre" self primitive:'primitiveMeasurementMetric'. ^self sqLocMeasurementMetric asOop: Boolean! ! !LocalePlugin methodsFor: 'system primitives' stamp: 'tpr 6/1/2005 12:25'! primitiveShortDateFormat "return a string describing the long date formatting. Format is made up of d day, m month, y year, double symbol is null padded, single not padded (m=6, mm=06) dddd weekday mmmm month name " | oop length | self primitive:'primitiveShortDateFormat'. length := self sqLocShortDateFormatSize. oop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: length. self sqLocGetShortDateFormatInto: (interpreterProxy firstIndexableField: oop). ^oop ! ! !LocalePlugin methodsFor: 'system primitives' stamp: 'tpr 6/1/2005 12:25'! primitiveTimeFormat "return a string describing the time formatting. Format is made up of h hour (h 12, H 24), m minute, s seconds, x (am/pm String) double symbol is null padded, single not padded (h=6, hh=06)" | oop length | self primitive:'primitiveTimeFormat'. length := self sqLocTimeFormatSize. oop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: length. self sqLocGetTimeFormatInto: (interpreterProxy firstIndexableField: oop). ^oop ! ! !LocalePlugin methodsFor: 'system primitives' stamp: 'tpr 6/1/2005 19:43'! primitiveTimezoneOffset "return the number of minutes this VM's time value is offset from UTC" self primitive:'primitiveTimezoneOffset'. ^self sqLocGetTimezoneOffset asSmallIntegerObj ! ! !LocalePlugin methodsFor: 'system primitives' stamp: 'tpr 6/1/2005 19:04'! primitiveVMOffsetToUTC "return the number of minutes this VM's time value is offset from UTC" self primitive:'primitiveVMOffsetToUTC'. ^self sqLocGetVMOffsetToUTC asSmallIntegerObj ! ! SmartSyntaxInterpreterPlugin subclass: #MIDIPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !MIDIPlugin commentStamp: 'tpr 5/5/2003 12:15' prior: 0! Provide MIDI support, if your platform provides it. ! !MIDIPlugin class methodsFor: 'translation' stamp: 'tpr 5/23/2001 17:10'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !MIDIPlugin class methodsFor: 'translation' stamp: 'tpr 11/29/2000 22:38'! requiresPlatformFiles "this plugin requires platform specific files in order to work" ^true! ! !MIDIPlugin methodsFor: 'initialize-release' stamp: 'ar (auto pragmas 12/08) 5/12/2000 16:53'! initialiseModule ^self cCode: 'midiInit()' inSmalltalk:[true]! ! !MIDIPlugin methodsFor: 'primitives' stamp: 'ar 5/12/2000 17:14'! primitiveMIDIClosePort: portNum self primitive: 'primitiveMIDIClosePort' parameters: #(SmallInteger). self sqMIDIClosePort: portNum! ! !MIDIPlugin methodsFor: 'primitives' stamp: 'ar 5/12/2000 17:14'! primitiveMIDIGetClock "Return the value of the MIDI clock as a SmallInteger. The range is limited to SmallInteger maxVal / 2 to allow scheduling MIDI events into the future without overflowing a SmallInteger. The sqMIDIGetClock function is assumed to wrap at or before 16r20000000." | clockValue | self primitive: 'primitiveMIDIGetClock'. clockValue := self sqMIDIGetClock bitAnd: 16r1FFFFFFF. ^clockValue asSmallIntegerObj! ! !MIDIPlugin methodsFor: 'primitives' stamp: 'ar 5/12/2000 17:14'! primitiveMIDIGetPortCount | n | self primitive: 'primitiveMIDIGetPortCount'. n := self sqMIDIGetPortCount. ^n asSmallIntegerObj ! ! !MIDIPlugin methodsFor: 'primitives' stamp: 'ar 5/12/2000 17:14'! primitiveMIDIGetPortDirectionality: portNum | dir | self primitive: 'primitiveMIDIGetPortDirectionality' parameters: #(SmallInteger). dir := self sqMIDIGetPortDirectionality: portNum. ^dir asSmallIntegerObj! ! !MIDIPlugin methodsFor: 'primitives' stamp: 'John M McIntosh (auto pragmas dtl 2010-09-28) 12/1/2009 21:40'! primitiveMIDIGetPortName: portNum | portName sz nameObj namePtr | self primitive: 'primitiveMIDIGetPortName' parameters: #(SmallInteger). sz := self cCode: 'sqMIDIGetPortName(portNum, &portName, 255)'. nameObj := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: sz. interpreterProxy failed ifTrue:[^nil]. namePtr := nameObj asValue: String . self cCode: 'memcpy(namePtr, portName, sz)'. ^nameObj! ! !MIDIPlugin methodsFor: 'primitives' stamp: 'ar 5/12/2000 17:15'! primitiveMIDIOpenPort: portNum sema: semaIndex speed: clockRate self primitive: 'primitiveMIDIOpenPort' parameters: #(SmallInteger SmallInteger SmallInteger). self cCode: 'sqMIDIOpenPort(portNum, semaIndex, clockRate)'! ! !MIDIPlugin methodsFor: 'primitives' stamp: 'ar 5/12/2000 17:15'! primitiveMIDIParameterGet: whichParameter | currentValue | "read parameter" self primitive: 'primitiveMIDIParameterGet' parameters: #(SmallInteger). currentValue := self cCode: 'sqMIDIParameterGet(whichParameter)'. ^currentValue asSmallIntegerObj! ! !MIDIPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 5/12/2000 17:15'! primitiveMIDIParameterGetOrSet "Backward compatibility" interpreterProxy methodArgumentCount = 1 ifTrue:[^self primitiveMIDIParameterGet] ifFalse:[^self primitiveMIDIParameterSet]! ! !MIDIPlugin methodsFor: 'primitives' stamp: 'ar 5/12/2000 17:15'! primitiveMIDIParameterSet: whichParameter value: newValue "write parameter" self primitive:'primitiveMIDIParameterSet' parameters:#(SmallInteger SmallInteger). self cCode: 'sqMIDIParameterSet(whichParameter, newValue)'! ! !MIDIPlugin methodsFor: 'primitives' stamp: 'ar 5/12/2000 17:15'! primitiveMIDIRead: portNum into: array | arrayLength bytesRead | self primitive: 'primitiveMIDIRead' parameters: #(SmallInteger ByteArray). arrayLength := interpreterProxy byteSizeOf: array cPtrAsOop. bytesRead := self sqMIDIPort: portNum Read: arrayLength Into: array asInteger. ^bytesRead asSmallIntegerObj! ! !MIDIPlugin methodsFor: 'primitives' stamp: 'ar 5/12/2000 17:15'! primitiveMIDIWrite: portNum from: array at: time | arrayLength bytesWritten | self primitive: 'primitiveMIDIWrite' parameters: #(SmallInteger ByteArray SmallInteger). arrayLength := interpreterProxy byteSizeOf: array cPtrAsOop. bytesWritten := self sqMIDIPort: portNum Write: arrayLength From: array asInteger At: time. ^bytesWritten asSmallIntegerObj! ! !MIDIPlugin methodsFor: 'initialize-release' stamp: 'ar (auto pragmas 12/08) 5/12/2000 16:55'! shutdownModule ^self cCode: 'midiShutdown()' inSmalltalk:[true]! ! SmartSyntaxInterpreterPlugin subclass: #MacMenubarPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !MacMenubarPlugin class methodsFor: 'translation' stamp: 'JMM 8/27/2004 12:50'! hasHeaderFile ^true! ! !MacMenubarPlugin class methodsFor: 'translation' stamp: 'JMM 8/27/2004 12:50'! requiresCrossPlatformFiles ^false! ! !MacMenubarPlugin class methodsFor: 'translation' stamp: 'JMM 8/16/2004 13:17'! requiresPlatformFiles ^true! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:54'! primitiveAppendMenu: menuHandleOop data: str255 | menuHandle constStr255 | self primitive: 'primitiveAppendMenu' parameters: #(Oop ByteArray). self var: 'menuHandle' type: 'MenuHandle'. self var: 'constStr255' type: 'ConstStr255Param'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. constStr255 := self cCoerce: str255 to: 'ConstStr255Param'. self cCode: 'AppendMenu(menuHandle,constStr255)' inSmalltalk:[menuHandle]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:55'! primitiveAppendMenuItemText: menuHandleOop data: str255 | menuHandle constStr255 | self primitive: 'primitiveAppendMenuItemText' parameters: #(Oop ByteArray). self var: 'menuHandle' type: 'MenuHandle'. self var: 'constStr255' type: 'ConstStr255Param'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. constStr255 := self cCoerce: str255 to: 'ConstStr255Param'. self cCode: 'AppendMenuItemText(menuHandle,constStr255)' inSmalltalk:[menuHandle]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:55'! primitiveCheckMenuItem: menuHandleOop item: anInteger checked: aBoolean | menuHandle | self primitive: 'primitiveCheckMenuItem' parameters: #(Oop SmallInteger Boolean). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'CheckMenuItem(menuHandle,anInteger,aBoolean)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 8/16/2004 13:51'! primitiveClearMenuBar self primitive: 'primitiveClearMenuBar' parameters: #(). self cCode: 'ClearMenuBar()' inSmalltalk:[]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:55'! primitiveCountMenuItems: menuHandleOop | menuHandle returnValue | self primitive: 'primitiveCountMenuItems' parameters: #(Oop). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. returnValue := self cCode: 'CountMenuItems(menuHandle)' inSmalltalk:[0]. ^returnValue asSmallIntegerObj ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 6/5/2005 20:58'! primitiveCreateStandardWindowMenu: inOptions | menuHandle result | self primitive: 'primitiveCreateStandardWindowMenu' parameters: #(SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self cCode: '#if TARGET_API_MAC_CARBON '. result := self cCode: 'CreateStandardWindowMenu(inOptions,&menuHandle); #endif' inSmalltalk:[0]. ^interpreterProxy positive32BitIntegerFor: (self cCoerce: menuHandle to: 'long')! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 8/23/2004 16:55'! primitiveDeleteMenu: menuID self primitive: 'primitiveDeleteMenu' parameters: #(SmallInteger). self var: 'menuID' type: 'MenuID'. self cCode: 'DeleteMenu(menuID)' inSmalltalk:[]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:55'! primitiveDeleteMenuItem: menuHandleOop item: anInteger | menuHandle | self primitive: 'primitiveDeleteMenuItem' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'DeleteMenuItem(menuHandle,anInteger)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/7/2004 22:41'! primitiveDisableMenuCommand: menuHandleOop item: anInteger | menuHandle commandID | self primitive: 'primitiveDisableMenuCommand' parameters: #(Oop Oop). self var: 'menuHandle' type: 'MenuHandle'. self var: 'commandID' type: 'MenuCommand'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. commandID := self cCoerce: (interpreterProxy positive32BitValueOf: anInteger) to: 'MenuCommand'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: '#if TARGET_API_MAC_CARBON DisableMenuCommand(menuHandle,commandID); #endif' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:56'! primitiveDisableMenuItem: menuHandleOop item: anInteger | menuHandle | self primitive: 'primitiveDisableMenuItem' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'DisableMenuItem(menuHandle,anInteger)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:56'! primitiveDisableMenuItemIcon: menuHandleOop item: anInteger | menuHandle | self primitive: 'primitiveDisableMenuItemIcon' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'DisableMenuItemIcon(menuHandle,anInteger)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:56'! primitiveDisposeMenu: menuHandleOop | menuHandle | self primitive: 'primitiveDisposeMenu' parameters: #(Oop). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'DisposeMenu(menuHandle)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 14:21'! primitiveDisposeMenuBar: menuHandleOop | menuBarHandle | self primitive: 'primitiveDisposeMenuBar' parameters: #(Oop). self var: 'menuBarHandle' type: 'Handle'. menuBarHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'Handle'. self cCode: '#if TARGET_API_MAC_CARBON DisposeMenuBar(menuBarHandle); #else DisposeHandle(menuBarHandle); #endif ' inSmalltalk:[menuBarHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 8/16/2004 13:53'! primitiveDrawMenuBar self primitive: 'primitiveDrawMenuBar' parameters: #(). self cCode: 'DrawMenuBar()' inSmalltalk:[]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/7/2004 22:42'! primitiveEnableMenuCommand: menuHandleOop item: anInteger | menuHandle commandID | self primitive: 'primitiveEnableMenuCommand' parameters: #(Oop Oop). self var: 'menuHandle' type: 'MenuHandle'. self var: 'commandID' type: 'MenuCommand'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. commandID := self cCoerce: (interpreterProxy positive32BitValueOf: anInteger) to: 'MenuCommand'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: '#if TARGET_API_MAC_CARBON EnableMenuCommand(menuHandle,commandID); #endif' inSmalltalk:[menuHandle]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:56'! primitiveEnableMenuItem: menuHandleOop item: anInteger | menuHandle | self primitive: 'primitiveEnableMenuItem' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'EnableMenuItem(menuHandle,anInteger)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:56'! primitiveEnableMenuItemIcon: menuHandleOop item: anInteger | menuHandle | self primitive: 'primitiveEnableMenuItemIcon' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'EnableMenuItemIcon(menuHandle,anInteger)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/7/2004 22:42'! primitiveGetIndMenuItemWithCommandID: menuHandleOop commandID: aCommandID | menuHandle MenuItemIndex commandID applicationMenu outIndex | self primitive: 'primitiveGetIndMenuItemWithCommandID' parameters: #(Oop Oop). self var: 'menuHandle' type: 'MenuHandle'. self var: 'commandID' type: 'MenuCommand'. self var: 'applicationMenu' type: 'MenuHandle'. self var: 'outIndex' type: 'MenuItemIndex'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. commandID := self cCoerce: (interpreterProxy positive32BitValueOf: aCommandID) to: 'MenuCommand'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: '#if TARGET_API_MAC_CARBON GetIndMenuItemWithCommandID(menuHandle, kHICommandHide, 1, &applicationMenu, &outIndex); #endif' inSmalltalk:[menuHandle]. ^outIndex asSmallIntegerObj ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/7/2004 22:42'! primitiveGetIndMenuWithCommandID: menuHandleOop commandID: aCommandID | menuHandle MenuItemIndex commandID applicationMenu outIndex | self primitive: 'primitiveGetIndMenuWithCommandID' parameters: #(Oop Oop). self var: 'menuHandle' type: 'MenuHandle'. self var: 'commandID' type: 'MenuCommand'. self var: 'applicationMenu' type: 'MenuHandle'. self var: 'outIndex' type: 'MenuItemIndex'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. commandID := self cCoerce: (interpreterProxy positive32BitValueOf: aCommandID) to: 'MenuCommand'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: '#if TARGET_API_MAC_CARBON GetIndMenuItemWithCommandID(menuHandle, kHICommandHide, 1, &applicationMenu, &outIndex); #endif ' inSmalltalk:[menuHandle]. ^interpreterProxy positive32BitIntegerFor: (self cCoerce: applicationMenu to: 'long') ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'tpr 12/29/2005 17:00'! primitiveGetItemCmd: menuHandleOop item: anInteger | menuHandle aCharacter | self primitive: 'primitiveGetItemCmd' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: #aCharacter type: 'CharParameter '. self var: #ptr type: 'char *'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. aCharacter := 0. self cCode: 'GetItemCmd(menuHandle,anInteger,&aCharacter)' inSmalltalk:[menuHandle]. ^aCharacter asSmallIntegerObj ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:57'! primitiveGetItemIcon: menuHandleOop item: anInteger | menuHandle iconIndex | self primitive: 'primitiveGetItemIcon' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: 'iconIndex' type: 'short'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. iconIndex := 0. self cCode: 'GetItemIcon(menuHandle,anInteger,&iconIndex)' inSmalltalk:[menuHandle]. ^iconIndex asSmallIntegerObj ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'tpr 12/29/2005 17:01'! primitiveGetItemMark: menuHandleOop item: anInteger | menuHandle aCharacter | self primitive: 'primitiveGetItemMark' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: #aCharacter type: 'CharParameter '. self var: #ptr type: 'char *'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. aCharacter := 0. self cCode: 'GetItemMark(menuHandle,anInteger,&aCharacter)' inSmalltalk:[menuHandle]. ^aCharacter asSmallIntegerObj ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:57'! primitiveGetItemStyle: menuHandleOop item: anInteger | menuHandle chStyle | self primitive: 'primitiveGetItemStyle' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: 'chStyle' type: 'Style'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. chStyle := 0. self cCode: 'GetItemStyle(menuHandle,anInteger,&chStyle)' inSmalltalk:[menuHandle]. ^chStyle asSmallIntegerObj ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 8/17/2004 20:18'! primitiveGetMenuBar | menuHandle | self primitive: 'primitiveGetMenuBar' parameters: #(). self var: 'menuHandle' type: 'Handle'. menuHandle := self cCode: 'GetMenuBar()' inSmalltalk:[0]. ^interpreterProxy positive32BitIntegerFor: (self cCoerce: menuHandle to: 'long')! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 8/23/2004 16:56'! primitiveGetMenuHandle: menuID | menuHandle | self primitive: 'primitiveGetMenuHandle' parameters: #(SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: 'menuID' type: 'MenuID'. menuHandle := self cCode: 'GetMenuHandle(menuID)' inSmalltalk:[0]. ^interpreterProxy positive32BitIntegerFor: (self cCoerce: menuHandle to: 'long')! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:57'! primitiveGetMenuID: menuHandleOop | menuHandle menuID | self primitive: 'primitiveGetMenuID' parameters: #(Oop ). self var: 'menuHandle' type: 'MenuHandle'. self var: 'menuID' type: 'MenuID'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'menuID = GetMenuID(menuHandle)' inSmalltalk:[menuHandle]. ^menuID asSmallIntegerObj ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:57'! primitiveGetMenuItemCommandID: menuHandleOop item: anInteger | menuHandle outCommandID | self primitive: 'primitiveGetMenuItemCommandID' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: 'outCommandID' type: 'MenuCommand'. outCommandID := 0. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'GetMenuItemCommandID(menuHandle,anInteger,&outCommandID)' inSmalltalk:[menuHandle]. ^interpreterProxy positive32BitIntegerFor: outCommandID ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:57'! primitiveGetMenuItemFontID: menuHandleOop item: anInteger | menuHandle outFontID | self primitive: 'primitiveGetMenuItemFontID' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: 'outFontID' type: 'SInt16'. outFontID := 0. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'GetMenuItemFontID(menuHandle,anInteger,&outFontID)' inSmalltalk:[menuHandle]. ^outFontID asSmallIntegerObj ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:58'! primitiveGetMenuItemHierarchicalID: menuHandleOop item: anInteger | menuHandle outHierID | self primitive: 'primitiveGetMenuItemHierarchicalID' parameters: #(Oop SmallInteger ). self var: 'menuHandle' type: 'MenuHandle'. self var: 'outHierID' type: 'MenuID'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. outHierID := 0. self cCode: 'GetMenuItemHierarchicalID(menuHandle,anInteger,&outHierID)' inSmalltalk:[menuHandle]. ^outHierID asSmallIntegerObj ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:58'! primitiveGetMenuItemKeyGlyph: menuHandleOop item: anInteger | menuHandle outGlyph | self primitive: 'primitiveGetMenuItemKeyGlyph' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: 'outGlyph' type: 'SInt16'. outGlyph := 0. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'GetMenuItemKeyGlyph(menuHandle,anInteger,&outGlyph)' inSmalltalk:[menuHandle]. ^interpreterProxy positive32BitIntegerFor: outGlyph ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:58'! primitiveGetMenuItemModifiers: menuHandleOop item: anInteger | menuHandle outModifers | self primitive: 'primitiveGetMenuItemModifiers' parameters: #(Oop SmallInteger ). self var: 'menuHandle' type: 'MenuHandle'. self var: 'outModifers' type: 'Style'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. outModifers := 0. self cCode: 'GetMenuItemModifiers(menuHandle,anInteger,&outModifers)' inSmalltalk:[menuHandle]. ^outModifers asSmallIntegerObj ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'tpr 12/29/2005 17:01'! primitiveGetMenuItemText: menuHandleOop item: anInteger | menuHandle size oop ptr aString | self primitive: 'primitiveGetMenuItemText' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: #aString type: 'Str255 '. self var: #ptr type: 'char *'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. aString at: 0 put: 0. self cCode: 'GetMenuItemText(menuHandle,anInteger,aString)' inSmalltalk:[menuHandle]. size := self cCode: 'aString[0]' inSmalltalk: [0]. oop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: size. ptr := interpreterProxy firstIndexableField: oop. 0 to: size-1 do:[:i| ptr at: i put: (aString at: (i+1))]. ^oop ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:58'! primitiveGetMenuItemTextEncoding: menuHandleOop item: anInteger | menuHandle outScriptID | self primitive: 'primitiveGetMenuItemTextEncoding' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: 'outScriptID' type: 'TextEncoding'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'GetMenuItemTextEncoding(menuHandle,anInteger,&outScriptID)' inSmalltalk:[menuHandle]. ^interpreterProxy positive32BitIntegerFor: outScriptID! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'tpr 12/29/2005 17:01'! primitiveGetMenuTitle: menuHandleOop | menuHandle size oop ptr aString | self primitive: 'primitiveGetMenuTitle' parameters: #(Oop). self var: 'menuHandle' type: 'MenuHandle'. self var: #aString type: 'Str255 '. self var: #ptr type: 'char *'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. aString at: 0 put: 0. self cCode: 'GetMenuTitle(menuHandle,aString)' inSmalltalk:[menuHandle]. size := self cCode: 'aString[0]' inSmalltalk: [0]. oop := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: size. ptr := interpreterProxy firstIndexableField: oop. 0 to: size-1 do:[:i| ptr at: i put: (aString at: (i+1))]. ^oop ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 8/17/2004 16:29'! primitiveHideMenuBar self primitive: 'primitiveHideMenuBar' parameters: #(). self cCode: 'HideMenuBar()' inSmalltalk:[]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 8/23/2004 16:56'! primitiveHiliteMenu: menuID self primitive: 'primitiveHiliteMenu' parameters: #(SmallInteger). self var: 'menuID' type: 'MenuID'. self cCode: 'HiliteMenu(menuID)' inSmalltalk:[]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:58'! primitiveInsertFontResMenu: menuHandleOop afterItem: afterItemInteger scriptFilter: scriptFilterInteger | menuHandle | self primitive: 'primitiveInsertFontResMenu' parameters: #(Oop SmallInteger SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'InsertFontResMenu(menuHandle,afterItemInteger,scriptFilterInteger)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:58'! primitiveInsertIntlResMenu: menuHandleOop theType: aResType afterItem: afterItemInteger scriptFilter: scriptFilterInteger | menuHandle resType | self primitive: 'primitiveInsertIntlResMenu' parameters: #(Oop SmallInteger SmallInteger SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: 'resType' type: 'ResType'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. resType := self cCoerce: (interpreterProxy positive32BitValueOf: aResType) to: 'ResType'. self cCode: 'InsertIntlResMenu(menuHandle,resType,afterItemInteger,scriptFilterInteger)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:58'! primitiveInsertMenu: menuHandleOop beforeID: anInteger | menuHandle | self primitive: 'primitiveInsertMenu' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: 'anInteger' type: 'MenuID'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'InsertMenu(menuHandle,anInteger)' inSmalltalk:[menuHandle]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:59'! primitiveInsertMenuItem: menuHandleOop itemString: str255 afterItem: anInteger | menuHandle constStr255 | self primitive: 'primitiveInsertMenuItem' parameters: #(Oop ByteArray SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: 'constStr255' type: 'ConstStr255Param'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. constStr255 := self cCoerce: str255 to: 'ConstStr255Param'. self cCode: 'InsertMenuItem(menuHandle,constStr255,anInteger)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 8/16/2004 13:54'! primitiveInvalMenuBar self primitive: 'primitiveInvalMenuBar' parameters: #(). self cCode: 'InvalMenuBar()' inSmalltalk:[]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 8/17/2004 16:58'! primitiveIsMenuBarVisible | result | self primitive: 'primitiveIsMenuBarVisible' parameters: #(). result := self cCode: 'IsMenuBarVisible()' inSmalltalk:[true]. ^result asOop: Boolean! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:59'! primitiveIsMenuItemEnabled: menuHandleOop item: anInteger | menuHandle result | self primitive: 'primitiveIsMenuItemEnabled' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. result := self cCode: 'IsMenuItemEnabled(menuHandle,anInteger)' inSmalltalk:[0]. ^result asOop: Boolean! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 14:03'! primitiveIsMenuItemIconEnabled: menuHandleOop item: anInteger | menuHandle result | self primitive: 'primitiveIsMenuItemIconEnabled' parameters: #(Oop SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. result := self cCode: 'IsMenuItemIconEnabled(menuHandle,anInteger)' inSmalltalk:[0]. ^result asOop: Boolean! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 8/23/2004 16:57'! primitiveNewMenu: menuID menuTitle: menuTitle | menuHandle constStr255 | self primitive: 'primitiveNewMenu' parameters: #(SmallInteger ByteArray). self var: 'menuHandle' type: 'MenuHandle'. self var: 'constStr255' type: 'ConstStr255Param'. self var: 'menuID' type: 'MenuID'. constStr255 := self cCoerce: menuTitle to: 'ConstStr255Param'. menuHandle := self cCode: 'NewMenu(menuID,constStr255)' inSmalltalk:[0]. ^interpreterProxy positive32BitIntegerFor: (self cCoerce: menuHandle to: 'long')! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'tpr 12/29/2005 17:01'! primitiveSetItemCmd: menuHandleOop item: anInteger cmdChar: anIntegerCmdChar | menuHandle aCharacter | self primitive: 'primitiveSetItemCmd' parameters: #(Oop SmallInteger SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: #aCharacter type: 'CharParameter '. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. aCharacter := anIntegerCmdChar. self cCode: 'SetItemCmd(menuHandle,anInteger,aCharacter)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:59'! primitiveSetItemIcon: menuHandleOop item: anInteger iconIndex: aIconIndexInteger | menuHandle | self primitive: 'primitiveSetItemIcon' parameters: #(Oop SmallInteger SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'SetItemIcon(menuHandle,anInteger,aIconIndexInteger)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'tpr 12/29/2005 17:02'! primitiveSetItemMark: menuHandleOop item: anInteger markChar: aMarkChar | menuHandle aCharacter | self primitive: 'primitiveSetItemMark' parameters: #(Oop SmallInteger SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: #aCharacter type: 'CharParameter '. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. aCharacter := aMarkChar. self cCode: 'SetItemMark(menuHandle,anInteger,aCharacter)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:59'! primitiveSetItemStyle: menuHandleOop item: anInteger styleParameter: chStyleInteger | menuHandle | self primitive: 'primitiveSetItemStyle' parameters: #(Oop SmallInteger SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'SetItemStyle(menuHandle,anInteger,chStyleInteger)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 14:25'! primitiveSetMenuBar: menuHandleOop | menuBarHandle | self primitive: 'primitiveSetMenuBar' parameters: #(Oop). self var: 'menuBarHandle' type: 'MenuBarHandle'. menuBarHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuBarHandle'. self cCode: 'SetMenuBar(menuBarHandle)' inSmalltalk:[menuBarHandle]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/7/2004 23:26'! primitiveSetMenuItemCommandID: menuHandleOop item: anInteger menuCommand: inCommandID | menuHandle commandID | self primitive: 'primitiveSetMenuItemCommandID' parameters: #(Oop SmallInteger Oop). self var: 'menuHandle' type: 'MenuHandle'. self var: 'commandID' type: 'MenuCommand'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. commandID := self cCoerce: (interpreterProxy positive32BitValueOf: inCommandID) to: 'MenuCommand'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'SetMenuItemCommandID(menuHandle,anInteger,commandID)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 13:59'! primitiveSetMenuItemFontID: menuHandleOop item: anInteger fontID: aFontIDInteger | menuHandle | self primitive: 'primitiveSetMenuItemFontID' parameters: #(Oop SmallInteger SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'SetMenuItemFontID(menuHandle,anInteger,aFontIDInteger)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 14:00'! primitiveSetMenuItemHierarchicalID: menuHandleOop item: anInteger hierID: aMenuID | menuHandle | self primitive: 'primitiveSetMenuItemHierarchicalID' parameters: #(Oop SmallInteger SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. self var: 'menuID' type: 'MenuID'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'SetMenuItemHierarchicalID(menuHandle,anInteger,aMenuID)' inSmalltalk:[menuHandle]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 14:00'! primitiveSetMenuItemKeyGlyph: menuHandleOop item: anInteger glyph: inGlyphInteger | menuHandle | self primitive: 'primitiveSetMenuItemKeyGlyph' parameters: #(Oop SmallInteger SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'SetMenuItemKeyGlyph(menuHandle,anInteger,inGlyphInteger)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 14:00'! primitiveSetMenuItemModifiers: menuHandleOop item: anInteger inModifiers: aUInt8 | menuHandle | self primitive: 'primitiveSetMenuItemModifiers' parameters: #(Oop SmallInteger SmallInteger). self var: 'menuHandle' type: 'MenuHandle'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. self cCode: 'SetMenuItemModifiers(menuHandle,anInteger,aUInt8)' inSmalltalk:[menuHandle]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 14:00'! primitiveSetMenuItemText: menuHandleOop item: anInteger itemString: str255 | menuHandle constStr255 | self primitive: 'primitiveSetMenuItemText' parameters: #(Oop SmallInteger ByteArray). self var: 'menuHandle' type: 'MenuHandle'. self var: 'constStr255' type: 'ConstStr255Param'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. constStr255 := self cCoerce: str255 to: 'ConstStr255Param'. self cCode: 'SetMenuItemText(menuHandle,anInteger,constStr255)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 14:00'! primitiveSetMenuItemTextEncoding: menuHandleOop item: anInteger inScriptID: aTextEncodingOop | menuHandle inScriptID | self primitive: 'primitiveSetMenuItemTextEncoding' parameters: #(Oop SmallInteger Oop). self var: 'menuHandle' type: 'MenuHandle'. self var: 'inScriptID' type: 'TextEncoding'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. inScriptID := self cCoerce: (interpreterProxy positive32BitValueOf: aTextEncodingOop) to: 'TextEncoding'. self cCode: 'SetMenuItemTextEncoding(menuHandle,anInteger,inScriptID)' inSmalltalk:[menuHandle]. ^nil! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 10/1/2004 14:00'! primitiveSetMenuTitle: menuHandleOop title: str255 | menuHandle constStr255 | self primitive: 'primitiveSetMenuTitle' parameters: #(Oop ByteArray). self var: 'menuHandle' type: 'MenuHandle'. self var: 'constStr255' type: 'ConstStr255Param'. menuHandle := self cCoerce: (interpreterProxy positive32BitValueOf: menuHandleOop) to: 'MenuHandle'. (self ioCheckMenuHandle: menuHandle) ifFalse: [^interpreterProxy success: false]. constStr255 := self cCoerce: str255 to: 'ConstStr255Param'. self cCode: 'SetMenuTitle(menuHandle,constStr255)' inSmalltalk:[menuHandle]. ^nil ! ! !MacMenubarPlugin methodsFor: 'system primitives' stamp: 'JMM 8/17/2004 16:29'! primitiveShowMenuBar self primitive: 'primitiveShowMenuBar' parameters: #(). self cCode: 'ShowMenuBar()' inSmalltalk:[]. ^nil! ! SmartSyntaxInterpreterPlugin subclass: #Mpeg3Plugin instanceVariableNames: 'maximumNumberOfFilesToWatch mpegFiles' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !Mpeg3Plugin commentStamp: '' prior: 0! /******************************************************** * An interface to LibMPEG3 * Author: Adam Williams * Page: heroine.linuxbox.com * * Changed for Squeak to work with Squeak and to work on the Macintosh * Sept 2000, by John M McIntosh johnmci@smalltalkconsulting.com * The smalltalk code and the C code it produces is released under the * Squeak licence. The libmpeg3 C code is co-licenced under either the Squeak licence or * the GNU LGPL! !Mpeg3Plugin class methodsFor: 'initialize-release' stamp: 'JMM 10/2/2000 12:56'! declareCVarsIn: cg super declareCVarsIn: cg. cg var: 'mpegFiles' declareC: 'mpeg3_t *mpegFiles[1024+1]'. ! ! !Mpeg3Plugin class methodsFor: 'initialize-release' stamp: 'tpr 5/23/2001 17:10'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !Mpeg3Plugin class methodsFor: 'initialize-release' stamp: 'tpr 7/4/2001 15:13'! requiresCrossPlatformFiles "If there cross platform files to be associated with the plugin, here is where you want to flag" ^true! ! !Mpeg3Plugin class methodsFor: 'initialize-release' stamp: 'tpr 3/13/2002 18:05'! requiresPlatformFiles "If there platform files to be associated with the plugin, here is where you want to flag" ^true! ! !Mpeg3Plugin methodsFor: 'support' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:05'! checkFileEntry: aMpegFile 1 to: maximumNumberOfFilesToWatch do: [:i | ((mpegFiles at: i) = aMpegFile) ifTrue: [^true]]. ^false. ! ! !Mpeg3Plugin methodsFor: 'support' stamp: 'JMM (auto pragmas 12/08) 10/2/2000 11:44'! initialiseModule maximumNumberOfFilesToWatch := 1024. 1 to: maximumNumberOfFilesToWatch do: [:i | mpegFiles at: i put: 0]. ^self cCode: 'true' inSmalltalk:[true]! ! !Mpeg3Plugin methodsFor: 'support' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:05'! makeFileEntry: aMpegFile 1 to: maximumNumberOfFilesToWatch do: [:i | ((mpegFiles at: i) = 0) ifTrue: [mpegFiles at: i put: aMpegFile. ^true]]. ^false "Ok no room just ignore, we'll get a primitive failure later" ! ! !Mpeg3Plugin methodsFor: 'support' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:02'! mpeg3tValueOf: mpeg3tHandle "Return a pointer to the first byte of of the mpeg3_t record within the given Smalltalk object, or nil if socketOop is not a mpeg3_t record." | index check | interpreterProxy success: ((interpreterProxy isBytes: mpeg3tHandle) and: [(interpreterProxy byteSizeOf: mpeg3tHandle) = 4]). interpreterProxy failed ifTrue: [^ nil] ifFalse: [index := self cCoerce: (interpreterProxy firstIndexableField: mpeg3tHandle) to: 'mpeg3_t **'. self cCode: 'check = checkFileEntry(*index)'. check = 0 ifTrue: [^nil]. ^ self cCode: '*index']! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:03'! primitiveMPEG3AudioChannels: fileHandle stream: aNumber | file result | "int mpeg3_audio_channels(mpeg3_t *file,int stream)" self primitive: 'primitiveMPEG3AudioChannels' parameters: #(Oop SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^0]. aNumber >= (self cCode: 'mpeg3_total_astreams(file)') ifTrue: [ interpreterProxy success: false. ^0. ]. result := self cCode: 'mpeg3_audio_channels(file,aNumber)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:00'! primitiveMPEG3AudioSamples: fileHandle stream: aNumber | file result | "long mpeg3_audio_samples(mpeg3_t *file, int stream)" self primitive: 'primitiveMPEG3AudioSamples' parameters: #(Oop SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'mpeg3_total_astreams(file)') ifTrue: [ interpreterProxy success: false. ^0. ]. self cCode: 'result = mpeg3_audio_samples(file,aNumber)'. ^result asOop: Float ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas dtl 2010-09-28) 4/12/2006 12:08'! primitiveMPEG3CheckSig: path | result sz storage | "int mpeg3_check_sig(char *path)" self primitive: 'primitiveMPEG3CheckSig' parameters: #(String). sz := interpreterProxy byteSizeOf: path cPtrAsOop. interpreterProxy ioFilename: storage fromString: path ofLength: sz resolveAliases: true. self cCode: 'result = mpeg3_check_sig(storage)'. ^result asOop: Boolean ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:00'! primitiveMPEG3Close: fileHandle | file index | "int mpeg3_close(mpeg3_t *file)" self primitive: 'primitiveMPEG3Close' parameters: #(Oop). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^nil]. self cCode: 'removeFileEntry(file); mpeg3_close(file)'. index := self cCoerce: (interpreterProxy firstIndexableField: fileHandle) to: 'mpeg3_t **'. self cCode: '*index = 0'. ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:01'! primitiveMPEG3DropFrames: fileHandle frames: aFrameNumber stream: aNumber | file result | "int mpeg3_drop_frames(mpeg3_t *file, long frames, int stream)" self primitive: 'primitiveMPEG3DropFrames' parameters: #(Oop SmallInteger SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_vstreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. self cCode: 'result = mpeg3_drop_frames(file,aFrameNumber,aNumber)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:03'! primitiveMPEG3EndOfAudio: fileHandle stream: aNumber | file result | "int mpeg3_end_of_audio(mpeg3_t *file, int stream)" self primitive: 'primitiveMPEG3EndOfAudio' parameters: #(Oop SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_astreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. self cCode: 'result = mpeg3_end_of_audio(file,aNumber)'. ^result asOop: Boolean ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas dtl 2010-09-28) 4/12/2006 12:13'! primitiveMPEG3EndOfVideo: fileHandle stream: aNumber | file result | "int mpeg3_end_of_video(mpeg3_t *file, int stream)" self primitive: 'primitiveMPEG3EndOfVideo' parameters: #(Oop SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_vstreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. self cCode: 'result = mpeg3_end_of_video(file,aNumber)'. ^result asOop: Boolean ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:03'! primitiveMPEG3FrameRate: fileHandle stream: aNumber | file result | "float mpeg3_frame_rate(mpeg3_t *file, int stream)" self primitive: 'primitiveMPEG3FrameRate' parameters: #(Oop SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_vstreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. self cCode: 'result = mpeg3_frame_rate(file,aNumber)'. ^result asOop: Float ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:58'! primitiveMPEG3GenerateToc: fileHandle useSearch: timecode doStreams: streams buffer: aString | file bufferSize | "int mpeg3_generate_toc_for_Squeak(FILE *output, char *path, int timecode_search, int print_streams, char *buffer)" self primitive: 'primitiveMPEG3GenerateToc' parameters: #(Oop SmallInteger Boolean String). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^nil]. bufferSize := interpreterProxy slotSizeOf: (interpreterProxy stackValue: 0). self cCode: 'mpeg3_generate_toc_for_Squeak(file,timecode,streams,aString,bufferSize)'. ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:59'! primitiveMPEG3GetFrame: fileHandle stream: aNumber | file result | "long mpeg3_get_frame(mpeg3_t *file,int stream)" self primitive: 'primitiveMPEG3GetFrame' parameters: #(Oop SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_vstreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. self cCode: 'result = mpeg3_get_frame(file,aNumber)'. ^result asOop: Float. ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:59'! primitiveMPEG3GetSample: fileHandle stream: aNumber | file result | "int mpeg3_video_width(mpeg3_t *file, int stream)" self primitive: 'primitiveMPEG3GetSample' parameters: #(Oop SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_astreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. self cCode: 'result = mpeg3_get_sample(file,aNumber)'. ^result asOop: Float ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas dtl 2010-09-28) 4/12/2006 12:07'! primitiveMPEG3GetTime: fileHandle | file result | "double mpeg3_get_time(mpeg3_t *file)" self primitive: 'primitiveMPEG3GetTime' parameters: #(Oop). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^nil]. self cCode: 'result = mpeg3_get_time(file)'. ^result asOop: Float. ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:01'! primitiveMPEG3HasAudio: fileHandle | file result | "int mpeg3_has_audio(mpeg3_t *file)" self primitive: 'primitiveMPEG3HasAudio' parameters: #(Oop). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^nil]. self cCode: 'result = mpeg3_has_audio(file)'. ^result asOop: Boolean ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:59'! primitiveMPEG3HasVideo: fileHandle | file result | "int mpeg3_has_video(mpeg3_t *file)" self primitive: 'primitiveMPEG3HasVideo' parameters: #(Oop). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^nil]. self cCode: 'result = mpeg3_has_video(file)'. ^result asOop: Boolean ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'JMM (auto pragmas dtl 2010-09-28) 3/29/2006 16:50'! primitiveMPEG3Open: path | mpeg3Oop index sz storage | "mpeg3_t* mpeg3_open(char *path)" self primitive: 'primitiveMPEG3Open' parameters: #(String). sz := interpreterProxy byteSizeOf: path cPtrAsOop. interpreterProxy ioFilename: storage fromString: path ofLength: sz resolveAliases: true. mpeg3Oop := interpreterProxy instantiateClass: interpreterProxy classByteArray indexableSize: 4. index := self cCoerce: (interpreterProxy firstIndexableField: mpeg3Oop) to: 'mpeg3_t **'. self cCode: '*index = mpeg3_open(storage,0); makeFileEntry(*index)'. ^mpeg3Oop. ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'JMM (auto pragmas 12/08) 1/20/2006 18:38'! primitiveMPEG3OpenABuffer: path size: size | mpeg3Oop index | self primitive: 'primitiveMPEG3OpenABuffer' parameters: #(String SmallInteger). mpeg3Oop := interpreterProxy instantiateClass: interpreterProxy classByteArray indexableSize: 4. index := self cCoerce: (interpreterProxy firstIndexableField: mpeg3Oop) to: 'mpeg3_t **'. self cCode: '*index = mpeg3_open(path,size); makeFileEntry(*index)'. ^mpeg3Oop. ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:01'! primitiveMPEG3PreviousFrame: fileHandle stream: aNumber | file result | "int mpeg3_previous_frame(mpeg3_t *file, int stream)" self primitive: 'primitiveMPEG3PreviousFrame' parameters: #(Oop SmallInteger). file := self mpeg3tValueOf: fileHandle. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. file = nil ifTrue: [^nil]. aNumber >= (self cCode: 'result = mpeg3_total_vstreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. self cCode: 'result = mpeg3_previous_frame(file,aNumber)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:58'! primitiveMPEG3ReReadAudio: fileHandle shortArray: anArray channel: aChannelNumber samples: aSampleNumber stream: aNumber | file result arrayBase | "int mpeg3_reread_audio(mpeg3_t *file, float *output_f, short *output_i, int channel, long samples, int stream)" self primitive: 'primitiveMPEG3ReReadAudio' parameters: #(Oop Array SmallInteger SmallInteger SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_astreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. arrayBase := self cCoerce: anArray to: 'short *'. interpreterProxy failed ifTrue: [^nil]. self cCode: 'result = mpeg3_reread_audio(file,(float *) NULL,arrayBase,aChannelNumber,aSampleNumber,aNumber)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:01'! primitiveMPEG3ReadAudio: fileHandle shortArray: anArray channel: aChannelNumber samples: aSampleNumber stream: aNumber | file result arrayBase | "int mpeg3_read_audio(mpeg3_t *file, float *output_f, short *output_i, int channel, long samples, int stream)" self primitive: 'primitiveMPEG3ReadAudio' parameters: #(Oop Array SmallInteger SmallInteger SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_astreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. arrayBase := self cCoerce: anArray to: 'short *'. interpreterProxy failed ifTrue: [^nil]. self cCode: 'result = mpeg3_read_audio(file,(float *) NULL,arrayBase,aChannelNumber,aSampleNumber,aNumber)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'dtl 9/28/2010 19:17'! primitiveMPEG3ReadFrame: fileHandle buffer: aBuffer bufferOffset: aBufferOffset x: xNumber y: yNumber w: width h: height ow: outWidth oh: outHeight colorModel: model stream: aNumber bytesPerRow: aByteNumber | file result outputRowsPtr bufferBaseAddr | "int mpeg3_read_frame(mpeg3_t *file, unsigned char **output_rows, int in_x, int in_y, int in_w, int in_h, int out_w, int out_h, int color_model, int stream)" self primitive: 'primitiveMPEG3ReadFrameBufferOffset' parameters: #(Oop WordArray SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [ interpreterProxy success: false. ^nil ]. aNumber >= (self cCode: 'result = mpeg3_total_vstreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. bufferBaseAddr := self cCoerce: aBuffer to: 'unsigned char *'. self cCode: 'outputRowsPtr = (unsigned char **) memoryAllocate(1,sizeof(unsigned char*) * outHeight)'. 0 to: outHeight-1 do: [:i | outputRowsPtr at: i put: (bufferBaseAddr + aBufferOffset + (aByteNumber*i))]. self cCode: 'result = mpeg3_read_frame(file,outputRowsPtr,xNumber,yNumber,width,height,outWidth,outHeight,model,aNumber)'. self cCode: 'memoryFree(outputRowsPtr)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'dtl 9/28/2010 19:17'! primitiveMPEG3ReadFrame: fileHandle buffer: aBuffer x: xNumber y: yNumber w: width h: height ow: outWidth oh: outHeight colorModel: model stream: aNumber bytesPerRow: aByteNumber | file result outputRowsPtr bufferBaseAddr | "int mpeg3_read_frame(mpeg3_t *file, unsigned char **output_rows, int in_x, int in_y, int in_w, int in_h, int out_w, int out_h, int color_model, int stream)" self primitive: 'primitiveMPEG3ReadFrame' parameters: #(Oop WordArray SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [ interpreterProxy success: false. ^nil ]. aNumber >= (self cCode: 'result = mpeg3_total_vstreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. bufferBaseAddr := self cCoerce: aBuffer to: 'unsigned char *'. self cCode: 'outputRowsPtr = (unsigned char **) memoryAllocate(1,sizeof(unsigned char*) * outHeight)'. 0 to: outHeight-1 do: [:i | outputRowsPtr at: i put: (bufferBaseAddr + (aByteNumber*i))]. self cCode: 'result = mpeg3_read_frame(file,outputRowsPtr,xNumber,yNumber,width,height,outWidth,outHeight,model,aNumber)'. self cCode: 'memoryFree(outputRowsPtr)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:02'! primitiveMPEG3SampleRate: fileHandle stream: aNumber | file result | "int mpeg3_sample_rate(mpeg3_t *file,int stream)" self primitive: 'primitiveMPEG3SampleRate' parameters: #(Oop SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_astreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. self cCode: 'result = mpeg3_sample_rate(file,aNumber)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:03'! primitiveMPEG3SeekPercentage: fileHandle percentage: aNumber | file result | "int mpeg3_seek_percentage(mpeg3_t *file, double percentage)" self primitive: 'primitiveMPEG3SeekPercentage' parameters: #(Oop Float). file := self mpeg3tValueOf: fileHandle. aNumber < 0.0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber > 1.0 ifTrue: [interpreterProxy success: false. ^nil]. file = nil ifTrue: [^nil]. self cCode: 'result = mpeg3_seek_percentage(file,aNumber)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:00'! primitiveMPEG3SetCpus: fileHandle number: cpus | file | "int mpeg3_set_cpus(mpeg3_t *file, int cpus)" self primitive: 'primitiveMPEG3SetCpus' parameters: #(Oop SmallInteger). file := self mpeg3tValueOf: fileHandle. cpus < 0 ifTrue: [interpreterProxy success: false. ^nil]. file = nil ifTrue: [^nil]. self cCode: 'mpeg3_set_cpus(file,cpus)'. ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:58'! primitiveMPEG3SetFrame: fileHandle frame: aFrameNumber stream: aNumber | file result | "int mpeg3_set_frame(mpeg3_t *file, long frame, int stream)" self primitive: 'primitiveMPEG3SetFrame' parameters: #(Oop Float SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_vstreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. self cCode: 'result = mpeg3_set_frame(file,(long) aFrameNumber,aNumber)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:59'! primitiveMPEG3SetMmx: fileHandle useMmx: mmx | file | "int mpeg3_set_mmx(mpeg3_t *file, int use_mmx)" self primitive: 'primitiveMPEG3SetMmx' parameters: #(Oop Boolean). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^nil]. self cCode: 'mpeg3_set_mmx(file,mmx)'. ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:02'! primitiveMPEG3SetSample: fileHandle sample: aSampleNumber stream: aNumber | file result | "int mpeg3_set_sample(mpeg3_t *file, long sample, int stream)" self primitive: 'primitiveMPEG3SetSample' parameters: #(Oop Float SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_astreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. aSampleNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. self cCode: 'result = mpeg3_set_sample(file,aSampleNumber,aNumber)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas dtl 2010-09-28) 4/12/2006 12:11'! primitiveMPEG3TellPercentage: fileHandle | file result | "double mpeg3_tell_percentage(mpeg3_t *file)" self primitive: 'primitiveMPEG3TellPercentage' parameters: #(Oop). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^nil]. self cCode: 'result = mpeg3_tell_percentage(file)'. ^result asOop: Float. ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:00'! primitiveMPEG3TotalAStreams: fileHandle | file result | "int mpeg3_total_astreams(mpeg3_t *file)" self primitive: 'primitiveMPEG3TotalAStreams' parameters: #(Oop). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. self cCode: 'result = mpeg3_total_astreams(file)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:03'! primitiveMPEG3TotalVStreams: fileHandle | file result | "int mpeg3_total_vstreams(mpeg3_t *file)" self primitive: 'primitiveMPEG3TotalVStreams' parameters: #(Oop). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^nil]. self cCode: 'result = mpeg3_total_vstreams(file)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 20:58'! primitiveMPEG3VideoFrames: fileHandle stream: aNumber | file result | "long mpeg3_video_frames(mpeg3_t *file, int stream)" self primitive: 'primitiveMPEG3VideoFrames' parameters: #(Oop SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_vstreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. self cCode: 'result = mpeg3_video_frames(file,aNumber)'. ^result asOop: Float. ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:01'! primitiveMPEG3VideoHeight: fileHandle stream: aNumber | file result | "int mpeg3_video_height(mpeg3_t *file,int stream)" self primitive: 'primitiveMPEG3VideoHeight' parameters: #(Oop SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_vstreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. self cCode: 'result = mpeg3_video_height(file,aNumber)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:01'! primitiveMPEG3VideoWidth: fileHandle stream: aNumber | file result | "int mpeg3_video_width(mpeg3_t *file, int stream)" self primitive: 'primitiveMPEG3VideoWidth' parameters: #(Oop SmallInteger). file := self mpeg3tValueOf: fileHandle. file = nil ifTrue: [^0]. aNumber < 0 ifTrue: [interpreterProxy success: false. ^nil]. aNumber >= (self cCode: 'result = mpeg3_total_vstreams(file)') ifTrue: [ interpreterProxy success: false. ^0 ]. self cCode: 'result = mpeg3_video_width(file,aNumber)'. ^result asSmallIntegerObj ! ! !Mpeg3Plugin methodsFor: 'support' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:12'! removeFileEntry: aMpegFile 1 to: maximumNumberOfFilesToWatch do: [:i | ((mpegFiles at: i) = aMpegFile) ifTrue: [mpegFiles at: i put: 0. ^true]]. "Just ignore" ^false ! ! !Mpeg3Plugin methodsFor: 'support' stamp: 'JMM (auto pragmas 12/08) 10/2/2000 12:03'! shutdownModule 1 to: maximumNumberOfFilesToWatch do: [:i | ((mpegFiles at: i) ~= 0) ifTrue: [self cCode: 'mpeg3_close(mpegFiles[i])'. mpegFiles at: i put: 0]]. ^self cCode: 'true' inSmalltalk:[true]! ! SmartSyntaxInterpreterPlugin subclass: #QuicktimePlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !QuicktimePlugin class methodsFor: 'translation' stamp: 'JMM 1/17/2006 20:24'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !QuicktimePlugin class methodsFor: 'translation' stamp: 'JMM 1/17/2006 20:24'! requiresCrossPlatformFiles "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !QuicktimePlugin methodsFor: 'system primitives' stamp: 'JMM (auto pragmas 12/08) 1/17/2006 15:53'! initialiseModule ^self sqQuicktimeInitialize ! ! !QuicktimePlugin methodsFor: 'system primitives' stamp: 'JMM (auto pragmas 12/08) 1/17/2006 15:53'! moduleUnloaded: aModuleName "The module with the given name was just unloaded. Make sure we have no dangling references." (aModuleName strcmp: 'QuicktimePlugin') = 0 ifTrue: [self sqQuicktimeShutdown]! ! !QuicktimePlugin methodsFor: 'system primitives' stamp: 'JMM 1/17/2006 23:05'! primitiveClearFrameCompletedSemaphore: data self primitive: 'primitiveClearFrameCompletedSemaphore' parameters: #(SmallInteger). self stQuicktimeClearSemaphore: data. ^nil! ! !QuicktimePlugin methodsFor: 'system primitives' stamp: 'JMM 1/17/2006 23:05'! primitiveDestroyHandle: data self primitive: 'primitiveDestroyHandle' parameters: #(SmallInteger). self stQuicktimeDestroy: data. ^nil! ! !QuicktimePlugin methodsFor: 'system primitives' stamp: 'JMM 3/16/2006 09:32'! primitiveDestroySurface: data self primitive: 'primitiveDestroySurface' parameters: #(SmallInteger). self stQuicktimeDestroySurface: data. ^nil! ! !QuicktimePlugin methodsFor: 'system primitives' stamp: 'JMM 1/17/2006 23:06'! primitiveSetFrameCompletedSemaphore: semaIndex for: data self primitive: 'primitiveSetFrameCompletedSemaphore' parameters:#(SmallInteger SmallInteger). self stQuicktimeSetSemaphore: semaIndex for: data. ^nil! ! !QuicktimePlugin methodsFor: 'system primitives' stamp: 'JMM 3/16/2006 11:30'! primitiveSetGWorldPtrOntoExistingSurface: surfaceID gWorld: bitMapPtr width: width height: height rowBytes: rowBytes depth: depth movie: moviePtr | buffer movie | self primitive: 'primitiveSetGWorldPtrOntoExistingSurface' parameters:#(SmallInteger Oop SmallInteger SmallInteger SmallInteger SmallInteger Oop). buffer := self cCoerce: (interpreterProxy positive32BitValueOf: bitMapPtr) to: 'char *'. movie := self cCoerce: (interpreterProxy positive32BitValueOf: moviePtr) to: 'long'. self stQuicktimeSetToExistingSurface: surfaceID gworld: buffer width: width height: height rowBytes: rowBytes depth: depth movie: movie. ! ! !QuicktimePlugin methodsFor: 'system primitives' stamp: 'JMM 3/16/2006 11:30'! primitiveSetGWorldPtrOntoSurface: bitMapPtr width: width height: height rowBytes: rowBytes depth: depth movie: moviePtr | buffer movie results | self primitive: 'primitiveSetGWorldPtrOntoSurface' parameters:#(Oop SmallInteger SmallInteger SmallInteger SmallInteger Oop). buffer := self cCoerce: (interpreterProxy positive32BitValueOf: bitMapPtr) to: 'char *'. movie := self cCoerce: (interpreterProxy positive32BitValueOf: moviePtr) to: 'long'. results := self stQuicktimeSetSurface: buffer width: width height: height rowBytes: rowBytes depth: depth movie: movie. ^results asOop: SmallInteger ! ! SmartSyntaxInterpreterPlugin subclass: #RePlugin instanceVariableNames: 'netMemory numAllocs numFrees lastAlloc patternStr rcvr compileFlags pcrePtr extraPtr errorStr errorOffset matchFlags patternStrPtr errorStrBuffer' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !RePlugin commentStamp: '' prior: 0! /* Regular Expression Plugin (This class comment becomes part of rePlugin.c) RePlugin translate: 'RePlugin.c' doInlining: true. See documentation and source code for the PCRE C Library Code. This plugin is designed to serve an object such as RePattern: patternStr A 0-terminated string comprising the pattern to be compiled. compileFlags An Integer representing re compiler options PCREBuffer A ByteArray of regular expression bytecodes extraPtr A ByteArray of match optimization data (or nil) errorString A String Object For Holding an Error Message (when compile failed) errorOffset The index in patternStr (0-based) where the error ocurred (when compile failed) matchFlags An Integer representing re matcher options matchSpaceObj An Integer array for match results and workspace during matching. The instance variables must appear in the preceding order. MatchSpaceObj must be allocated by the calling routine and contain at least 6*(numGroups+1) bytes. */ #include "pcre.h" #include "internal.h" /* Slight machine-specific hack for MacOS Memory Management */ #ifdef TARGET_OS_MAC #define malloc(ptr) NewPtr(ptr) #define free(ptr) DisposePtr(aPointer) #endif /* Adjust malloc and free routines as used by PCRE */ void rePluginFree(void * aPointer); void * rePluginMalloc(size_t anInteger); void *(*pcre_malloc)(size_t) = rePluginMalloc; void (*pcre_free)(void *) = rePluginFree; ! !RePlugin class methodsFor: 'plugin code generation' stamp: 'tpr 12/29/2005 17:16'! declareCVarsIn: cg cg addHeaderFile:'"rePlugin.h"'. "Memory Management Error Checking" cg var: 'netMemory' declareC: 'int netMemory = 0'. cg var: 'numAllocs' declareC: 'int numAllocs = 0'. cg var: 'numFrees' declareC: 'int numFrees = 0'. cg var: 'lastAlloc' declareC: 'int lastAlloc = 0'. "Support Variables for Access to Receiver Instance Variables" cg var: 'patternStrPtr' type: 'const char * '. cg var: 'errorStrBuffer' type: 'const char * '.! ! !RePlugin class methodsFor: 'plugin code generation' stamp: 'acg 8/16/2002 22:51'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !RePlugin class methodsFor: 'plugin code generation' stamp: 'nk 11/21/2002 15:54'! moduleName ^'RePlugin'! ! !RePlugin class methodsFor: 'plugin code generation' stamp: 'acg 7/27/2002 20:09'! requiresCrossPlatformFiles "default is ok for most, any plugin needing cross platform files must say so" ^true! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:07'! allocateByteArrayAndSetRcvrExtraPtrFrom: anExtraPtr | extraObject extraByteArrayPtr | anExtraPtr ifFalse: [extraObject := interpreterProxy nilObject] ifTrue: [ "Allocate a Smalltalk ByteArray -- lastAlloc contains the length" extraObject := interpreterProxy instantiateClass: (interpreterProxy classByteArray) indexableSize: (self cCode: 'sizeof(real_pcre_extra)'). self loadRcvrFromStackAt: 0. "Assume garbage collection after instantiation" "Copy from the C bytecode buffer to the Smalltalk ByteArray" extraByteArrayPtr := interpreterProxy arrayValueOf: extraObject. self cCode:'memcpy(extraByteArrayPtr, (void *) anExtraPtr, sizeof(real_pcre_extra))']. "Set rcvrErrorStr from errorStr and Return" self rcvrExtraPtrFrom: extraObject. self touch: extraByteArrayPtr. ^extraObject. ! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:13'! allocateByteArrayAndSetRcvrPCREPtrFromPCRE: aPCREPtr | patObject patByteArrayPtr | "Allocate a Smalltalk ByteArray -- lastAlloc contains the length" patObject := interpreterProxy instantiateClass: (interpreterProxy classByteArray) indexableSize: lastAlloc. self loadRcvrFromStackAt: 0. "Assume garbage collection after instantiation" "Copy from the C bytecode buffer to the Smalltalk ByteArray" patByteArrayPtr := interpreterProxy arrayValueOf: patObject. self cCode:'memcpy(patByteArrayPtr, (void *) aPCREPtr, lastAlloc)'. "Set rcvrErrorStr from errorStr and Return" self rcvrPCREBufferFrom: patObject. self touch: patByteArrayPtr. ^patObject. ! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:13'! allocateStringAndSetRcvrErrorStrFromCStr: aCStrBuffer |length errorStrObj errorStrObjPtr | "Allocate errorStrObj" length := self cCode: 'strlen(aCStrBuffer)'. errorStrObj := interpreterProxy instantiateClass: (interpreterProxy classString) indexableSize: length. self loadRcvrFromStackAt: 0. "Assume garbage collection after instantiation" "Copy aCStrBuffer to errorStrObj's buffer" errorStrObjPtr := interpreterProxy arrayValueOf: errorStrObj. self cCode:'memcpy(errorStrObjPtr,aCStrBuffer,length)'. self touch: errorStrObjPtr; touch: errorStrObj. "Set rcvrErrorStr from errorStrObj and Return" self rcvrErrorStrFrom: errorStrObj. ^errorStrObj.! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'acg (auto pragmas dtl 2010-09-28) 2/21/1999 22:58'! loadRcvrFromStackAt: stackInteger rcvr := interpreterProxy stackObjectValue: stackInteger. ! ! !RePlugin methodsFor: 'memory management' stamp: 'acg (auto pragmas 12/08) 2/25/1999 08:36'! primLastAlloc interpreterProxy pop:1; pushInteger: lastAlloc ! ! !RePlugin methodsFor: 'memory management' stamp: 'acg (auto pragmas 12/08) 2/21/1999 23:20'! primNetMemory interpreterProxy pop:1; pushInteger: netMemory ! ! !RePlugin methodsFor: 'memory management' stamp: 'acg (auto pragmas 12/08) 2/21/1999 23:20'! primNumAllocs interpreterProxy pop:1; pushInteger: numAllocs ! ! !RePlugin methodsFor: 'memory management' stamp: 'acg (auto pragmas 12/08) 2/21/1999 23:20'! primNumFrees interpreterProxy pop:1; pushInteger: numFrees ! ! !RePlugin methodsFor: 're primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:08'! primPCRECompile ", where rcvr is an object with instance variables: 'patternStr compileFlags pcrePtr extraPtr errorStr errorOffset matchFlags' Compile the regular expression in patternStr, and if the compilation is successful, attempt to optimize the compiled expression. Store the results in and , or fill errorStr with a meaningful errorString and errorOffset with an indicator where the error was found, applying compileFlags throughout. Answer nil with a clean compile (regardless of whether an optimization is possible, and answer with the string otherwise." self loadRcvrFromStackAt: 0. patternStrPtr := self rcvrPatternStrPtr. compileFlags := self rcvrCompileFlags. interpreterProxy failed ifTrue:[^ nil]. pcrePtr := self cCode: '(int) pcre_compile(patternStrPtr, compileFlags, &errorStrBuffer, &errorOffset, NULL)'. pcrePtr ifTrue: [ self allocateByteArrayAndSetRcvrPCREPtrFromPCRE: pcrePtr. extraPtr := self cCode: '(int) pcre_study((pcre *)pcrePtr, compileFlags, &errorStrBuffer)'. self allocateByteArrayAndSetRcvrExtraPtrFrom: extraPtr. self rePluginFree: (self cCoerce: pcrePtr to: 'void *'). extraPtr ifTrue: [self rePluginFree: (self cCoerce: extraPtr to: 'void *')]. interpreterProxy failed ifTrue:[^ nil]. interpreterProxy pop: 1 thenPush: interpreterProxy nilObject] ifFalse: [ errorStr := self allocateStringAndSetRcvrErrorStrFromCStr: errorStrBuffer. self rcvrErrorOffsetFrom: errorOffset. interpreterProxy failed ifTrue:[^ nil]. interpreterProxy pop: 1 thenPush: errorStr].! ! !RePlugin methodsFor: 're primitives' stamp: 'tpr (auto pragmas dtl 2010-09-28) 4/12/2006 12:15'! primPCREExec ", where rcvr is an object with instance variables: 'patternStr compileFlags pcrePtr extraPtr errorStr errorOffset matchFlags' Apply the regular expression (stored in and , generated from calls to primPCRECompile), to smalltalk String searchObject using . If there is no match, answer nil. Otherwise answer a ByteArray of offsets representing the results of the match." | searchObject searchBuffer length result matchSpacePtr matchSpaceSize | "Load Parameters" searchObject := interpreterProxy stackObjectValue: 0. searchBuffer := interpreterProxy arrayValueOf: searchObject. length := interpreterProxy byteSizeOf: searchObject. self loadRcvrFromStackAt: 1. "Load Instance Variables" pcrePtr := self rcvrPCREBufferPtr. extraPtr := self rcvrExtraPtr. matchFlags := self rcvrMatchFlags. matchSpacePtr := self rcvrMatchSpacePtr. matchSpaceSize := self rcvrMatchSpaceSize. interpreterProxy failed ifTrue:[^ nil]. result := self cCode: 'pcre_exec((pcre *)pcrePtr, (pcre_extra *)extraPtr, searchBuffer, length, 0, matchFlags, matchSpacePtr, matchSpaceSize)'. interpreterProxy pop: 2; pushInteger: result. "empty call so compiler doesn't bug me about variables not used" self touch: searchBuffer; touch: matchSpacePtr; touch: matchSpaceSize; touch: length ! ! !RePlugin methodsFor: 're primitives' stamp: 'tpr (auto pragmas dtl 2010-09-28) 4/12/2006 12:16'! primPCREExecfromto " from: fromInteger to: toInteger>, where rcvr is an object with instance variables: 'patternStr compileFlags pcrePtr extraPtr errorStr errorOffset matchFlags' Apply the regular expression (stored in and , generated from calls to primPCRECompile), to smalltalk String searchObject using , beginning at offset and continuing until offset . If there is no match, answer nil. Otherwise answer a ByteArray of offsets representing the results of the match." | searchObject searchBuffer length result matchSpacePtr matchSpaceSize fromInteger toInteger | "Load Parameters" toInteger := interpreterProxy stackIntegerValue: 0. fromInteger := interpreterProxy stackIntegerValue: 1. searchObject := interpreterProxy stackObjectValue: 2. searchBuffer := interpreterProxy arrayValueOf: searchObject. length := interpreterProxy byteSizeOf: searchObject. self loadRcvrFromStackAt: 3. "Validate parameters" interpreterProxy success: (1 <= fromInteger). interpreterProxy success: (toInteger<=length). fromInteger := fromInteger - 1. "Smalltalk offsets are 1-based" interpreterProxy success: (fromInteger<=toInteger). "adjust length, searchBuffer" length := toInteger - fromInteger. searchBuffer := searchBuffer + fromInteger. "Load Instance Variables" pcrePtr := self rcvrPCREBufferPtr. extraPtr := self rcvrExtraPtr. matchFlags := self rcvrMatchFlags. matchSpacePtr := self rcvrMatchSpacePtr. matchSpaceSize := self rcvrMatchSpaceSize. interpreterProxy failed ifTrue:[^ nil]. result := self cCode: 'pcre_exec((pcre *)pcrePtr, (pcre_extra *)extraPtr, searchBuffer, length, 0, matchFlags, matchSpacePtr, matchSpaceSize)'. interpreterProxy pop: 2; pushInteger: result. "empty call so compiler doesn't bug me about variables not used" self touch: searchBuffer; touch: matchSpacePtr; touch: matchSpaceSize; touch: length ! ! !RePlugin methodsFor: 're primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:08'! primPCRENumSubPatterns ", where rcvr is an object with instance variables: 'patternStr compileFlags pcrePtr extraPtr errorStr errorOffset matchFlags' Return the number of subpatterns captured by the compiled pattern." "Load Parameters" self loadRcvrFromStackAt: 0. "Load Instance Variables" pcrePtr := self rcvrPCREBufferPtr. interpreterProxy pop: 1; pushInteger: (self cCode: 'pcre_info((pcre *)pcrePtr, NULL, NULL)'). ! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'acg (auto pragmas dtl 2010-09-28) 2/21/1999 21:20'! rcvrCompileFlags ^interpreterProxy fetchInteger: 1 ofObject: rcvr. ! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'acg (auto pragmas 12/08) 2/21/1999 22:46'! rcvrErrorOffsetFrom: anInteger interpreterProxy storeInteger: 5 ofObject: rcvr withValue: anInteger. ! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'acg (auto pragmas 12/08) 2/24/1999 20:53'! rcvrErrorStrFrom: aString interpreterProxy storePointer: 4 ofObject: rcvr withValue: aString. ! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'John M McIntosh (auto pragmas dtl 2010-09-28) 12/1/2009 21:40'! rcvrExtraPtr |extraObj| extraObj := interpreterProxy fetchPointer: 3 ofObject: rcvr. (extraObj = (interpreterProxy nilObject)) ifTrue: [^ self cCode: ' NULL']. ^self cCoerce:(interpreterProxy arrayValueOf: extraObj) to: 'int'.! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'acg (auto pragmas 12/08) 2/27/1999 23:42'! rcvrExtraPtrFrom: aByteArrayOrNilObject interpreterProxy storePointer: 3 ofObject: rcvr withValue: aByteArrayOrNilObject! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'acg (auto pragmas 12/08) 2/21/1999 21:19'! rcvrMatchFlags ^interpreterProxy fetchInteger: 6 ofObject: rcvr. ! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'acg (auto pragmas 12/08) 2/25/1999 00:49'! rcvrMatchSpacePtr ^self cCoerce: (interpreterProxy fetchArray: 7 ofObject: rcvr) to: 'int *'.! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'acg (auto pragmas 12/08) 2/25/1999 00:52'! rcvrMatchSpaceSize ^(interpreterProxy byteSizeOf: (interpreterProxy fetchPointer: 7 ofObject: rcvr))//4.! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'acg (auto pragmas 12/08) 2/24/1999 21:33'! rcvrPCREBufferFrom: aByteArray interpreterProxy storePointer: 2 ofObject: rcvr withValue: aByteArray! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'acg (auto pragmas 12/08) 2/24/1999 21:33'! rcvrPCREBufferPtr ^self cCoerce: (interpreterProxy fetchArray: 2 ofObject: rcvr) to: 'int'.! ! !RePlugin methodsFor: 'rcvr linkage' stamp: 'acg (auto pragmas 12/08) 2/24/1999 21:34'! rcvrPatternStrPtr ^self cCoerce: (interpreterProxy fetchArray: 0 ofObject: rcvr) to: 'char *'.! ! !RePlugin methodsFor: 'memory management' stamp: 'dtl (auto pragmas dtl 2010-09-28) 9/14/2008 21:41'! rePluginFree: aPointer "Free a block of fixed memory allocated with rePluginMalloc. Instrumented version of C free() to facilitate leak analysis from Smalltalk. OS-specific variations on malloc/free, such as with MacOS, are handled by adding a C macro to the header file redefining malloc/free -- see the class comment" numFrees := numFrees + 1. (aPointer) ifTrue: [self cCode: 'free(aPointer)'] ! ! !RePlugin methodsFor: 'memory management' stamp: 'dtl (auto pragmas dtl 2010-09-28) 9/14/2008 21:42'! rePluginMalloc: anInteger "Allocate a block of fixed memory using C calls to malloc(). Instrumented to facilitate leak analysis from Smalltalk. Set global lastAlloc to anInteger. OS-specific variations on malloc/free, such as with MacOS, are handled by adding a C macro to the header file redefining malloc/free -- see the class comment" | aPointer | numAllocs := numAllocs + 1. (aPointer := self cCode: 'malloc(anInteger)') ifTrue: [lastAlloc := anInteger]. ^aPointer ! ! SmartSyntaxInterpreterPlugin subclass: #SerialPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !SerialPlugin commentStamp: 'tpr 5/2/2003 15:49' prior: 0! Implement the serial port primitives. Since it requires platform support it will only be built when supported on your platform! !SerialPlugin class methodsFor: 'translation' stamp: 'tpr 5/23/2001 17:11'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !SerialPlugin class methodsFor: 'translation' stamp: 'tpr 11/29/2000 22:38'! requiresPlatformFiles "this plugin requires platform specific files in order to work" ^true! ! !SerialPlugin methodsFor: 'private' stamp: 'dtl (auto pragmas dtl 2010-09-28) 4/21/2009 00:04'! allocateTerminatedString: unterminatedCharactersInStringObject "Allocate a C string with contents of a String value. May cause garbage collection." | len terminatedString p | len := interpreterProxy sizeOfSTArrayFromCPrimitive: unterminatedCharactersInStringObject. terminatedString := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: len + 1. p := interpreterProxy arrayValueOf: terminatedString. p at: len put: 0. "null terminator" [len >= 0] whileTrue: [len := len - 1. p at: len put: (unterminatedCharactersInStringObject at: len)]. ^ p ! ! !SerialPlugin methodsFor: 'initialize-release' stamp: 'ar (auto pragmas 12/08) 5/12/2000 16:53'! initialiseModule ^self cCode: 'serialPortInit()' inSmalltalk:[true]! ! !SerialPlugin methodsFor: 'primitives' stamp: 'TPR 2/17/2000 18:16'! primitiveSerialPortClose: portNum self primitive: 'primitiveSerialPortClose' parameters: #(SmallInteger). self serialPortClose: portNum! ! !SerialPlugin methodsFor: 'primitives' stamp: 'dtl 9/28/2010 19:48'! primitiveSerialPortCloseByName: deviceName | cString | self primitive: 'primitiveSerialPortCloseByName' parameters: #(ByteArray). cString := self allocateTerminatedString: deviceName. self serialPortCloseByName: cString! ! !SerialPlugin methodsFor: 'primitives' stamp: 'TPR 2/11/2000 16:08'! primitiveSerialPortOpen: portNum baudRate: baudRate stopBitsType: stopBitsType parityType: parityType dataBits: dataBits inFlowControlType: inFlowControl outFlowControlType: outFlowControl xOnByte: xOnChar xOffByte: xOffChar self primitive: 'primitiveSerialPortOpen' parameters: #(SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger ). self cCode: 'serialPortOpen( portNum, baudRate, stopBitsType, parityType, dataBits, inFlowControl, outFlowControl, xOnChar, xOffChar)'! ! !SerialPlugin methodsFor: 'primitives' stamp: 'dtl 9/28/2010 19:48'! primitiveSerialPortOpenByName: deviceName baudRate: baudRate stopBitsType: stopBitsType parityType: parityType dataBits: dataBits inFlowControlType: inFlowControl outFlowControlType: outFlowControl xOnByte: xOnChar xOffByte: xOffChar | cString | self primitive: 'primitiveSerialPortOpenByName' parameters: #(ByteArray SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger ). cString := self allocateTerminatedString: deviceName. self cCode: 'serialPortOpenByName( cString, baudRate, stopBitsType, parityType, dataBits, inFlowControl, outFlowControl, xOnChar, xOffChar)'! ! !SerialPlugin methodsFor: 'primitives' stamp: 'dtl 4/20/2009 23:04'! primitiveSerialPortRead: portNum into: array startingAt: startIndex count: count | bytesRead | self primitive: 'primitiveSerialPortRead' parameters: #(SmallInteger ByteArray SmallInteger SmallInteger ). interpreterProxy success: (startIndex >= 1 and: [startIndex + count - 1 <= (interpreterProxy byteSizeOf: array cPtrAsOop)]). "adjust for zero-origin indexing" bytesRead := self serialPort: portNum Read: count Into: array + startIndex - 1. ^ bytesRead asSmallIntegerObj! ! !SerialPlugin methodsFor: 'primitives' stamp: 'dtl 9/28/2010 19:46'! primitiveSerialPortReadByName: deviceName into: array startingAt: startIndex count: count | bytesRead cString | self primitive: 'primitiveSerialPortReadByName' parameters: #(ByteArray ByteArray SmallInteger SmallInteger ). interpreterProxy success: (startIndex >= 1 and: [startIndex + count - 1 <= (interpreterProxy byteSizeOf: array cPtrAsOop)]). cString := self allocateTerminatedString: deviceName. "adjust for zero-origin indexing" bytesRead := self serialPort: cString Read: count IntoByName: array + startIndex - 1. ^ bytesRead asSmallIntegerObj! ! !SerialPlugin methodsFor: 'primitives' stamp: 'dtl 4/20/2009 23:02'! primitiveSerialPortWrite: portNum from: array startingAt: startIndex count: count | bytesWritten | self primitive: 'primitiveSerialPortWrite' parameters: #(SmallInteger ByteArray SmallInteger SmallInteger ). interpreterProxy success: (startIndex >= 1 and: [startIndex + count - 1 <= (interpreterProxy byteSizeOf: array cPtrAsOop)]). interpreterProxy failed ifFalse: [bytesWritten := self serialPort: portNum Write: count From: array + startIndex - 1]. ^ bytesWritten asSmallIntegerObj! ! !SerialPlugin methodsFor: 'primitives' stamp: 'dtl 9/28/2010 19:47'! primitiveSerialPortWriteByName: deviceName from: array startingAt: startIndex count: count | bytesWritten cString | self primitive: 'primitiveSerialPortWriteByName' parameters: #(ByteArray ByteArray SmallInteger SmallInteger ). interpreterProxy success: (startIndex >= 1 and: [startIndex + count - 1 <= (interpreterProxy byteSizeOf: array cPtrAsOop)]). interpreterProxy failed ifFalse: [cString := self allocateTerminatedString: deviceName. bytesWritten := self serialPort: cString Write: count FromByName: array + startIndex - 1]. ^ bytesWritten asSmallIntegerObj! ! !SerialPlugin methodsFor: 'initialize-release' stamp: 'ar (auto pragmas 12/08) 5/12/2000 16:55'! shutdownModule ^self cCode: 'serialPortShutdown()' inSmalltalk:[true]! ! SmartSyntaxInterpreterPlugin subclass: #SlangTestSupportSSIP instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Tests'! !SlangTestSupportSSIP commentStamp: 'dtl 9/19/2010 11:38' prior: 0! SlangTestSupportSSIP implements translatable methods for use in SlangTest unit tests. It is a subclass of SmartSyntaxInterpreterPlugin, which requires additional test coverage. "VMMaker clearCacheEntriesFor: SlangTestSupportSSIP. SlangTestSupportSSIP asCString"! !SlangTestSupportSSIP methodsFor: 'export declaration' stamp: 'dtl 9/19/2010 12:29'! declareExportFalseByMethod "SlangTestSupportSSIP asCString: #declareExportFalseByMethod" self export: false ! ! !SlangTestSupportSSIP methodsFor: 'export declaration' stamp: 'dtl 9/19/2010 12:29'! declareExportFalseByPragma "SlangTestSupportSSIP asCString: #declareExportFalseByPragma" ! ! !SlangTestSupportSSIP methodsFor: 'export declaration' stamp: 'dtl 9/19/2010 12:21'! declareExportTrueByMethod "SlangTestSupportSSIP asCString: #declareExportTrueByMethod" self export: true ! ! !SlangTestSupportSSIP methodsFor: 'export declaration' stamp: 'dtl 9/19/2010 12:21'! declareExportTrueByPragma "SlangTestSupportSSIP asCString: #declareExportTrueByPragma" ! ! !SlangTestSupportSSIP methodsFor: 'static declaration' stamp: 'dtl 9/19/2010 12:29'! declareStaticFalseByMethod "SlangTestSupportSSIP asCString: #declareStaticFalseByMethod" self static: false ! ! !SlangTestSupportSSIP methodsFor: 'static declaration' stamp: 'dtl 9/19/2010 12:30'! declareStaticFalseByPragma "SlangTestSupportSSIP asCString: #declareStaticFalseByPragma" ! ! !SlangTestSupportSSIP methodsFor: 'static declaration' stamp: 'dtl 9/19/2010 12:29'! declareStaticTrueByMethod "SlangTestSupportSSIP asCString: #declareStaticTrueByMethod" self static: true ! ! !SlangTestSupportSSIP methodsFor: 'static declaration' stamp: 'dtl 9/19/2010 12:30'! declareStaticTrueByPragma "SlangTestSupportSSIP asCString: #declareStaticTrueByPragma" ! ! !SlangTestSupportSSIP methodsFor: 'inlining' stamp: 'dtl 9/19/2010 11:50'! inlineByMethod "SlangTestSupportSSIP asCString: #inlineByMethod" "SlangTestSupportSSIP asInlinedCString: #inlineByMethod" | bar foo | foo := self methodThatShouldBeInlinedByMethod. bar := self methodThatShouldNotBeInlinedByMethod! ! !SlangTestSupportSSIP methodsFor: 'inlining' stamp: 'dtl 9/19/2010 11:50'! inlineByPragma "SlangTestSupportSSIP asCString: #inlineByPragma" "SlangTestSupportSSIP asInlinedCString: #inlineByPragma" | bar foo | foo := self methodThatShouldBeInlinedByPragma. bar := self methodThatShouldNotBeInlinedByPragma! ! !SlangTestSupportSSIP methodsFor: 'inlining' stamp: 'dtl 9/18/2010 17:59'! methodThatShouldBeInlinedByMethod self inline: true. ^ #foo! ! !SlangTestSupportSSIP methodsFor: 'inlining' stamp: 'dtl 9/18/2010 18:01'! methodThatShouldBeInlinedByPragma ^ #foo! ! !SlangTestSupportSSIP methodsFor: 'inlining' stamp: 'dtl 9/18/2010 18:01'! methodThatShouldNotBeInlinedByMethod self inline: false. ^ #bar! ! !SlangTestSupportSSIP methodsFor: 'inlining' stamp: 'dtl 9/18/2010 18:01'! methodThatShouldNotBeInlinedByPragma ^ #bar! ! !SlangTestSupportSSIP methodsFor: 'type declaration' stamp: 'dtl 9/19/2010 11:50'! returnTypeByMethod "SlangTestSupportSSIP asCString: #returnTypeByMethod" self returnTypeC: 'char *'. ! ! !SlangTestSupportSSIP methodsFor: 'type declaration' stamp: 'dtl 9/19/2010 11:51'! returnTypeByPragma "SlangTestSupportSSIP asCString: #returnTypeByPragma" ! ! !SlangTestSupportSSIP methodsFor: 'type declaration' stamp: 'dtl 9/19/2010 11:51'! varDefByMethod "SlangTestSupportSSIP asCString: #varDefByMethod" | foo bar | self var: #foo type: 'char *'. self var: #bar declareC: 'unsigned int * bar' ! ! !SlangTestSupportSSIP methodsFor: 'type declaration' stamp: 'dtl 9/19/2010 22:25'! varDefByMethodAndPragma "SlangTestSupportSSIP asCString: #varDefByMethodAndPragma" | foo bar baz fum | self var: #foo type: 'char *'. self var: #bar declareC: 'unsigned int * bar' ! ! !SlangTestSupportSSIP methodsFor: 'type declaration' stamp: 'dtl 9/19/2010 12:05'! varDefByPragma "SlangTestSupportSSIP asCString: #varDefByPragma" | foo bar | ! ! !SmartSyntaxInterpreterPlugin class methodsFor: 'private' stamp: 'tpr 6/9/2003 16:36'! codeGeneratorClass "return the appropriate class of code generator for this kind ofplugin" ^SmartSyntaxPluginCodeGenerator! ! !SmartSyntaxInterpreterPlugin class methodsFor: 'instance creation' stamp: 'tpr 6/28/2003 17:28'! doPrimitive: primitiveName withArguments: argArray | proxy plugin | proxy := InterpreterProxy new. proxy loadStackFrom: thisContext sender. plugin := (self simulatorClass ifNil: [self]) new. plugin setInterpreter: proxy. ^plugin perform: primitiveName asSymbol withArguments: argArray! ! !SmartSyntaxInterpreterPlugin class methodsFor: 'translation' stamp: 'tpr 6/9/2003 16:44'! shouldBeTranslated "SmartSyntaxInterpreterPlugin should not be translated but its subclasses should" ^self ~= SmartSyntaxInterpreterPlugin! ! !SmartSyntaxInterpreterPlugin class methodsFor: 'instance creation' stamp: 'tpr 6/28/2003 17:28'! simulatorClass "For running from Smalltalk - answer a class that can be used to simulate the receiver, or nil if you want the primitives in this module to always fail, causing simulation to fall through to the Smalltalk code. By default SmartSyntaxInterpreterPlugin answers nil because methods in these plugins are intended to be embedded in code that pushes and pops from the stack and therefore cannot be run independently. This wrapper code is generated when translated to C. But, unfortunately, this code is missing during simulation. There was an attempt to simulate this, but only the prologue code (getting arg from the stack) is simulated (see simulatePrologInContext:). The epologue code (popping args and pushing result) is not. So I am making this nil until this can be fixed. Also, beware that primitive methods that take no args exactly match their primitive name (faking out InterpreterSimulator>>callExternalPrimitive:). They should only be called from within wrapper code that simulates the prologue and epilogue. Primitive method that take args don't have this accidental matching problem since their names contain colons while their primitive names do not. - ajh 8/21/2002" ^ nil! ! !SmartSyntaxInterpreterPlugin class methodsFor: 'translation' stamp: 'sr 12/23/2001 22:24'! translateDoInlining: inlineFlag locally: localFlag debug: debugFlag ^ self translate: self moduleName , '.c' doInlining: inlineFlag locally: localFlag debug: debugFlag! ! !SmartSyntaxInterpreterPlugin methodsFor: 'debugging' stamp: 'sr 12/24/2001 00:29'! sqAssert: aBool self debugCode: [aBool ifFalse: [self error: 'Assertion failed!!']. ^ aBool]! ! SmartSyntaxInterpreterPlugin subclass: #SocketPlugin instanceVariableNames: 'sDSAfn sHSAfn sCCTPfn sCCLOPfn sCCSOTfn' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !SocketPlugin commentStamp: 'tpr 5/2/2003 15:49' prior: 0! Implement the socket and resolver primitives. Since it requires platform support it will only be built when supported on your platform! !SocketPlugin class methodsFor: 'translation' stamp: 'ikp 3/31/2005 13:43'! declareCVarsIn: aCCodeGenerator aCCodeGenerator var: 'sDSAfn' type: 'void *'. aCCodeGenerator var: 'sHSAfn' type: 'void *'. aCCodeGenerator var: 'sCCTPfn' type: 'void *'. aCCodeGenerator var: 'sCCLOPfn' type: 'void *'. aCCodeGenerator var: 'sCCSOTfn' type: 'void *'. aCCodeGenerator addHeaderFile: '"SocketPlugin.h"'! ! !SocketPlugin class methodsFor: 'translation' stamp: 'tpr 5/23/2001 17:11'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !SocketPlugin class methodsFor: 'translation' stamp: 'tpr 11/29/2000 22:38'! requiresPlatformFiles "this plugin requires platform specific files in order to work" ^true! ! !SocketPlugin methodsFor: 'initialize-release' stamp: 'JMM (auto pragmas 12/08) 1/21/2002 11:09'! initialiseModule sDSAfn := interpreterProxy ioLoadFunction: 'secDisableSocketAccess' From: 'SecurityPlugin'. sHSAfn := interpreterProxy ioLoadFunction: 'secHasSocketAccess' From: 'SecurityPlugin'. sCCTPfn := interpreterProxy ioLoadFunction: 'secCanConnectToPort' From: 'SecurityPlugin'. sCCLOPfn := interpreterProxy ioLoadFunction: 'secCanListenOnPort' From: 'SecurityPlugin'. sCCSOTfn := interpreterProxy ioLoadFunction: 'secCanCreateSocketOfType' From: 'SecurityPlugin'. ^self cCode: 'socketInit()' inSmalltalk:[true]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:16'! intToNetAddress: addr "Convert the given 32-bit integer into an internet network address represented as a four-byte ByteArray." | netAddressOop naPtr | netAddressOop := interpreterProxy instantiateClass: interpreterProxy classByteArray indexableSize: 4. naPtr := netAddressOop asCharPtr. naPtr at: 0 put: (self cCoerce: ((addr >> 24) bitAnd: 16rFF) to: 'char'). naPtr at: 1 put: (self cCoerce: ((addr >> 16) bitAnd: 16rFF) to: 'char'). naPtr at: 2 put: (self cCoerce: ((addr >> 8) bitAnd: 16rFF) to: 'char'). naPtr at: 3 put: (self cCoerce: (addr bitAnd: 16rFF) to: 'char'). ^ netAddressOop! ! !SocketPlugin methodsFor: 'initialize-release' stamp: 'JMM (auto pragmas 12/08) 1/21/2002 11:10'! moduleUnloaded: aModuleName "The module with the given name was just unloaded. Make sure we have no dangling references." (aModuleName strcmp: 'SecurityPlugin') = 0 ifTrue:[ "The security plugin just shut down. How odd." sDSAfn := sHSAfn := sCCTPfn := sCCLOPfn := sCCSOTfn := 0. ].! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:16'! netAddressToInt: ptrToByteArray "Convert the given internet network address (represented as a four-byte ByteArray) into a 32-bit integer. Fail if the given ptrToByteArray does not appear to point to a four-byte ByteArray." | sz | sz := interpreterProxy byteSizeOf: ptrToByteArray cPtrAsOop. sz = 4 ifFalse: [^ interpreterProxy primitiveFail]. ^ (ptrToByteArray at: 3 ) + ((ptrToByteArray at: 2) <<8) + ((ptrToByteArray at: 1) <<16) + ((ptrToByteArray at: 0) <<24)! ! !SocketPlugin methodsFor: 'security primitives' stamp: 'eem 7/10/2009 12:11'! primitiveDisableSocketAccess "If the security plugin can be loaded, use it to turn off socket access If not, assume it's ok" sDSAfn ~= 0 ifTrue: [self cCode: '((int (*) (void)) sDSAfn)()']! ! !SocketPlugin methodsFor: 'security primitives' stamp: 'John M McIntosh (auto pragmas dtl 2010-09-28) 5/5/2009 11:03'! primitiveHasSocketAccess | hasAccess | "If the security plugin can be loaded, use it to check . If not, assume it's ok" sHSAfn ~= 0 ifTrue: [hasAccess := self cCode: ' ((int (*) (void)) sHSAfn)()' inSmalltalk:[true]] ifFalse: [hasAccess := true]. interpreterProxy pop: 1. interpreterProxy pushBool: hasAccess! ! !SocketPlugin methodsFor: 'primitives' stamp: 'TPR 2/18/2000 10:39'! primitiveInitializeNetwork: resolverSemaIndex | err | self primitive: 'primitiveInitializeNetwork' parameters: #(SmallInteger). err := self sqNetworkInit: resolverSemaIndex. interpreterProxy success: err = 0! ! !SocketPlugin methodsFor: 'primitives' stamp: 'TPR 2/18/2000 11:47'! primitiveResolverAbortLookup self primitive: 'primitiveResolverAbortLookup'. self sqResolverAbort! ! !SocketPlugin methodsFor: 'primitives' stamp: 'TPR 3/21/2000 16:47'! primitiveResolverAddressLookupResult | sz s | self primitive: 'primitiveResolverAddressLookupResult'. sz := self sqResolverAddrLookupResultSize. interpreterProxy failed ifFalse: [s := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: sz. self sqResolverAddrLookup: s asCharPtr Result: sz]. ^ s! ! !SocketPlugin methodsFor: 'primitives' stamp: 'TPR 2/18/2000 10:10'! primitiveResolverError self primitive: 'primitiveResolverError'. ^ self sqResolverError asSmallIntegerObj! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp 6/8/2007 18:01'! primitiveResolverGetAddressInfoFamily | family | self primitive: 'primitiveResolverGetAddressInfoFamily' parameters: #(). interpreterProxy failed ifFalse: [family := self sqResolverGetAddressInfoFamily. ^family asSmallIntegerObj]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp 6/8/2007 17:23'! primitiveResolverGetAddressInfoHost: hostName service: servName flags: flags family: family type: type protocol: protocol | hostSize servSize | self primitive: 'primitiveResolverGetAddressInfo' parameters: #(String String SmallInteger SmallInteger SmallInteger SmallInteger). interpreterProxy failed ifFalse: [hostSize := interpreterProxy byteSizeOf: hostName cPtrAsOop. servSize := interpreterProxy byteSizeOf: servName cPtrAsOop. self sqResolverGetAddressInfoHost: hostName Size: hostSize Service: servName Size: servSize Flags: flags Family: family Type: type Protocol: protocol]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp 6/8/2007 18:17'! primitiveResolverGetAddressInfoNext | more | self primitive: 'primitiveResolverGetAddressInfoNext' parameters: #(). more := self sqResolverGetAddressInfoNext. interpreterProxy failed ifTrue: [^nil]. ^more asBooleanObj! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp 6/8/2007 18:01'! primitiveResolverGetAddressInfoProtocol | protocol | self primitive: 'primitiveResolverGetAddressInfoProtocol' parameters: #(). interpreterProxy failed ifFalse: [protocol := self sqResolverGetAddressInfoProtocol. ^protocol asSmallIntegerObj]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp 6/8/2007 17:33'! primitiveResolverGetAddressInfoResult: socketAddress | addrSize | self primitive: 'primitiveResolverGetAddressInfoResult' parameters: #(ByteArray). interpreterProxy failed ifFalse: [addrSize := interpreterProxy byteSizeOf: socketAddress cPtrAsOop. self sqResolverGetAddressInfoResult: socketAddress Size: addrSize]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp 6/8/2007 17:40'! primitiveResolverGetAddressInfoSize | size | self primitive: 'primitiveResolverGetAddressInfoSize' parameters: #(). interpreterProxy failed ifFalse: [size := self sqResolverGetAddressInfoSize. ^size asSmallIntegerObj]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp 6/8/2007 18:01'! primitiveResolverGetAddressInfoType | type | self primitive: 'primitiveResolverGetAddressInfoType' parameters: #(). interpreterProxy failed ifFalse: [type := self sqResolverGetAddressInfoType. ^type asSmallIntegerObj]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp (auto pragmas dtl 2010-09-28) 6/8/2007 18:59'! primitiveResolverGetNameInfo: socketAddress flags: flags | addrSize addrBase | self primitive: 'primitiveResolverGetNameInfo' parameters: #(Oop SmallInteger). interpreterProxy failed ifFalse: [addrSize := interpreterProxy byteSizeOf: socketAddress. addrBase := self cCoerce: (interpreterProxy firstIndexableField: socketAddress) to: 'char *'. self sqResolverGetNameInfo: addrBase Size: addrSize Flags: flags]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp 6/8/2007 18:49'! primitiveResolverGetNameInfoHostResult: socketName | addrSize | self primitive: 'primitiveResolverGetNameInfoHostResult' parameters: #(String). interpreterProxy failed ifFalse: [addrSize := interpreterProxy byteSizeOf: socketName cPtrAsOop. self sqResolverGetNameInfoHostResult: socketName Size: addrSize]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp 6/8/2007 18:38'! primitiveResolverGetNameInfoHostSize | size | self primitive: 'primitiveResolverGetNameInfoHostSize' parameters: #(). interpreterProxy failed ifFalse: [size := self sqResolverGetNameInfoHostSize. ^size asSmallIntegerObj]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp 6/8/2007 18:50'! primitiveResolverGetNameInfoServiceResult: socketName | addrSize | self primitive: 'primitiveResolverGetNameInfoServiceResult' parameters: #(String). interpreterProxy failed ifFalse: [addrSize := interpreterProxy byteSizeOf: socketName cPtrAsOop. self sqResolverGetNameInfoServiceResult: socketName Size: addrSize]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp 6/8/2007 18:38'! primitiveResolverGetNameInfoServiceSize | size | self primitive: 'primitiveResolverGetNameInfoServiceSize' parameters: #(). interpreterProxy failed ifFalse: [size := self sqResolverGetNameInfoServiceSize. ^size asSmallIntegerObj]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp 6/9/2007 09:03'! primitiveResolverHostNameResult: nameString | nameSize | self primitive: 'primitiveResolverHostNameResult' parameters: #(String). interpreterProxy failed ifFalse: [nameSize := interpreterProxy byteSizeOf: nameString cPtrAsOop. self sqResolverHostNameResult: nameString Size: nameSize]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp 6/9/2007 09:00'! primitiveResolverHostNameSize | size | self primitive: 'primitiveResolverHostNameSize' parameters: #(). interpreterProxy failed ifFalse: [size := self sqResolverHostNameSize. interpreterProxy failed ifFalse: [^size asSmallIntegerObj]]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'TPR 2/18/2000 10:10'! primitiveResolverLocalAddress | addr | self primitive: 'primitiveResolverLocalAddress'. addr := self sqResolverLocalAddress. ^self intToNetAddress: addr! ! !SocketPlugin methodsFor: 'primitives' stamp: 'TPR 2/18/2000 10:11'! primitiveResolverNameLookupResult | addr | self primitive: 'primitiveResolverNameLookupResult'. addr := self sqResolverNameLookupResult. ^self intToNetAddress: addr! ! !SocketPlugin methodsFor: 'primitives' stamp: 'TPR 4/25/2000 14:42'! primitiveResolverStartAddressLookup: address | addr | self primitive: 'primitiveResolverStartAddressLookup' parameters: #(ByteArray). addr := self netAddressToInt: (self cCoerce: address to: 'unsigned char *'). interpreterProxy failed ifFalse: [ self sqResolverStartAddrLookup: addr]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'TPR 2/18/2000 10:19'! primitiveResolverStartNameLookup: name | sz | self primitive: 'primitiveResolverStartNameLookup' parameters: #(String). interpreterProxy failed ifFalse: [ sz := interpreterProxy byteSizeOf: name cPtrAsOop. self sqResolverStartName: name Lookup: sz]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'TPR 2/18/2000 10:20'! primitiveResolverStatus | status | self primitive: 'primitiveResolverStatus'. status := self sqResolverStatus. ^status asSmallIntegerObj! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp (auto pragmas dtl 2010-09-28) 6/9/2007 09:36'! primitiveSocket: socket bindTo: socketAddress | addrSize addrBase s | self primitive: 'primitiveSocketBindTo' parameters: #(#Oop #Oop). s := self socketValueOf: socket. addrSize := interpreterProxy byteSizeOf: socketAddress. addrBase := self cCoerce: (interpreterProxy firstIndexableField: socketAddress) to: 'char *'. interpreterProxy failed ifFalse: [self sqSocket: s BindToAddress: addrBase Size: addrSize]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 3/26/2006 21:32'! primitiveSocket: socket bindTo: address port: port | addr s | self primitive: 'primitiveSocketBindToPort' parameters: #(#Oop #ByteArray #SmallInteger ). addr := self netAddressToInt: (self cCoerce: address to: 'unsigned char *'). s := self socketValueOf: socket. interpreterProxy failed ifFalse:[self sqSocket: s BindTo: addr Port: port]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp (auto pragmas dtl 2010-09-28) 6/8/2007 22:21'! primitiveSocket: socket connectTo: socketAddress | addrSize addrBase s | self primitive: 'primitiveSocketConnectTo' parameters: #(#Oop #Oop). s := self socketValueOf: socket. addrSize := interpreterProxy byteSizeOf: socketAddress. addrBase := self cCoerce: (interpreterProxy firstIndexableField: socketAddress) to: 'char *'. interpreterProxy failed ifFalse: [self sqSocket: s ConnectToAddress: addrBase Size: addrSize]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:19'! primitiveSocket: socket connectTo: address port: port | addr s okToConnect | self primitive: 'primitiveSocketConnectToPort' parameters: #(#Oop #ByteArray #SmallInteger ). addr := self netAddressToInt: (self cCoerce: address to: 'unsigned char *'). "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCCTPfn ~= 0 ifTrue: [okToConnect := self cCode: ' ((int (*) (int, int)) sCCTPfn)(addr, port)'. okToConnect ifFalse: [^ interpreterProxy primitiveFail]]. s := self socketValueOf: socket. interpreterProxy failed ifFalse: [self sqSocket: s ConnectTo: addr Port: port]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:19'! primitiveSocket: socket getOptions: optionName | s optionNameStart optionNameSize returnedValue errorCode results | self primitive: 'primitiveSocketGetOptions' parameters: #(Oop Oop). s := self socketValueOf: socket. interpreterProxy success: (interpreterProxy isBytes: optionName). optionNameStart := self cCoerce: (interpreterProxy firstIndexableField: optionName) to: 'char *'. optionNameSize := interpreterProxy slotSizeOf: optionName. interpreterProxy failed ifTrue: [^nil]. returnedValue := 0. errorCode := self sqSocketGetOptions: s optionNameStart: optionNameStart optionNameSize: optionNameSize returnedValue: (self cCode: '&returnedValue'). interpreterProxy pushRemappableOop: returnedValue asSmallIntegerObj. interpreterProxy pushRemappableOop: errorCode asSmallIntegerObj. interpreterProxy pushRemappableOop: (interpreterProxy instantiateClass: (interpreterProxy classArray) indexableSize: 2). results := interpreterProxy popRemappableOop. interpreterProxy storePointer: 0 ofObject: results withValue: interpreterProxy popRemappableOop. interpreterProxy storePointer: 1 ofObject: results withValue: interpreterProxy popRemappableOop. ^ results! ! !SocketPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas dtl 2010-09-28) 8/12/2009 21:25'! primitiveSocket: socket listenOnPort: port "one part of the wierdass dual prim primitiveSocketListenOnPort which was warped by some demented evil person determined to twist the very nature of reality" | s okToListen | self primitive: 'primitiveSocketListenOnPort' parameters: #(#Oop #SmallInteger ). s := self socketValueOf: socket. "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCCLOPfn ~= 0 ifTrue: [okToListen := self cCode: ' ((int (*) (SocketPtr, int)) sCCLOPfn)(s, port)'. okToListen ifFalse: [^ interpreterProxy primitiveFail]]. interpreterProxy failed ifFalse:[self sqSocket: s ListenOnPort: port]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:20'! primitiveSocket: socket listenOnPort: port backlogSize: backlog "second part of the wierdass dual prim primitiveSocketListenOnPort which was warped by some demented evil person determined to twist the very nature of reality" | s okToListen | self primitive: 'primitiveSocketListenOnPortBacklog' parameters: #(#Oop #SmallInteger #SmallInteger ). s := self socketValueOf: socket. "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCCLOPfn ~= 0 ifTrue: [okToListen := self cCode: ' ((int (*) (SocketPtr, int)) sCCLOPfn)(s, port)'. okToListen ifFalse: [^ interpreterProxy primitiveFail]]. self sqSocket: s ListenOnPort: port BacklogSize: backlog! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:20'! primitiveSocket: socket listenOnPort: port backlogSize: backlog interface: ifAddr "Bind a socket to the given port and interface address with no more than backlog pending connections. The socket can be UDP, in which case the backlog should be specified as zero." | s okToListen addr | self primitive: 'primitiveSocketListenOnPortBacklogInterface' parameters: #(#Oop #SmallInteger #SmallInteger #ByteArray). s := self socketValueOf: socket. "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCCLOPfn ~= 0 ifTrue: [okToListen := self cCode: ' ((int (*) (SocketPtr, int)) sCCLOPfn)(s, port)'. okToListen ifFalse: [^ interpreterProxy primitiveFail]]. addr := self netAddressToInt: (self cCoerce: ifAddr to: 'unsigned char *'). self sqSocket: s ListenOnPort: port BacklogSize: backlog Interface: addr! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp (auto pragmas dtl 2010-09-28) 6/9/2007 09:46'! primitiveSocket: socket listenWithBacklog: backlogSize | s | self primitive: 'primitiveSocketListenWithBacklog' parameters: #(#Oop #SmallInteger). s := self socketValueOf: socket. interpreterProxy failed ifFalse: [self sqSocket: s ListenBacklog: backlogSize]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp (auto pragmas dtl 2010-09-28) 6/9/2007 10:26'! primitiveSocket: socket localAddressResult: socketAddress | addrSize addrBase s | self primitive: 'primitiveSocketLocalAddressResult' parameters: #(#Oop #Oop). s := self socketValueOf: socket. addrSize := interpreterProxy byteSizeOf: socketAddress. addrBase := self cCoerce: (interpreterProxy firstIndexableField: socketAddress) to: 'char *'. interpreterProxy failed ifFalse: [self sqSocket: s LocalAddressResult: addrBase Size: addrSize]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:20'! primitiveSocket: socket receiveDataBuf: array start: startIndex count: count | s byteSize arrayBase bufStart bytesReceived | self primitive: 'primitiveSocketReceiveDataBufCount' parameters: #(Oop Oop SmallInteger SmallInteger ). s := self socketValueOf: socket. "buffer can be any indexable words or bytes object" interpreterProxy success: (interpreterProxy isWordsOrBytes: array). (interpreterProxy isWords: array) ifTrue: [byteSize := 4] ifFalse: [byteSize := 1]. interpreterProxy success: (startIndex >= 1 and: [count >= 0 and: [startIndex + count - 1 <= (interpreterProxy slotSizeOf: array)]]). interpreterProxy failed ifFalse: ["Note: adjust bufStart for zero-origin indexing" arrayBase := self cCoerce: (interpreterProxy firstIndexableField: array) to: 'char *'. bufStart := arrayBase + (startIndex - 1 * byteSize). bytesReceived := self sqSocket: s ReceiveDataBuf: bufStart Count: count * byteSize]. ^ (bytesReceived // byteSize) asSmallIntegerObj! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:20'! primitiveSocket: socket receiveUDPDataBuf: array start: startIndex count: count | s byteSize arrayBase bufStart bytesReceived results address port moreFlag | self primitive: 'primitiveSocketReceiveUDPDataBufCount' parameters: #(Oop Oop SmallInteger SmallInteger ). s := self socketValueOf: socket. "buffer can be any indexable words or bytes object" interpreterProxy success: (interpreterProxy isWordsOrBytes: array). (interpreterProxy isWords: array) ifTrue: [byteSize := 4] ifFalse: [byteSize := 1]. interpreterProxy success: (startIndex >= 1 and: [count >= 0 and: [startIndex + count - 1 <= (interpreterProxy slotSizeOf: array)]]). interpreterProxy failed ifFalse: ["Note: adjust bufStart for zero-origin indexing" arrayBase := self cCoerce: (interpreterProxy firstIndexableField: array) to: 'char *'. bufStart := arrayBase + (startIndex - 1 * byteSize). "allocate storage for results, remapping newly allocated oops in case GC happens during allocation" address := 0. port := 0. moreFlag := 0. bytesReceived := self sqSocket: s ReceiveUDPDataBuf: bufStart Count: count * byteSize address: (self cCode: '&address') port: (self cCode: '&port') moreFlag: (self cCode: '&moreFlag'). interpreterProxy pushRemappableOop: port asSmallIntegerObj. interpreterProxy pushRemappableOop: (self intToNetAddress: address). interpreterProxy pushRemappableOop: (bytesReceived // byteSize) asSmallIntegerObj. interpreterProxy pushRemappableOop: (interpreterProxy instantiateClass: (interpreterProxy classArray) indexableSize: 4). results := interpreterProxy popRemappableOop. interpreterProxy storePointer: 0 ofObject: results withValue: interpreterProxy popRemappableOop. interpreterProxy storePointer: 1 ofObject: results withValue: interpreterProxy popRemappableOop. interpreterProxy storePointer: 2 ofObject: results withValue: interpreterProxy popRemappableOop. moreFlag ifTrue: [ interpreterProxy storePointer: 3 ofObject: results withValue: interpreterProxy trueObject ] ifFalse: [ interpreterProxy storePointer: 3 ofObject: results withValue: interpreterProxy falseObject ]. ]. ^ results! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp (auto pragmas dtl 2010-09-28) 6/9/2007 10:26'! primitiveSocket: socket remoteAddressResult: socketAddress | addrSize addrBase s | self primitive: 'primitiveSocketRemoteAddressResult' parameters: #(#Oop #Oop). s := self socketValueOf: socket. addrSize := interpreterProxy byteSizeOf: socketAddress. addrBase := self cCoerce: (interpreterProxy firstIndexableField: socketAddress) to: 'char *'. interpreterProxy failed ifFalse: [self sqSocket: s RemoteAddressResult: addrBase Size: addrSize]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:21'! primitiveSocket: socket sendData: array start: startIndex count: count | s byteSize arrayBase bufStart bytesSent | self primitive: 'primitiveSocketSendDataBufCount' parameters: #(Oop Oop SmallInteger SmallInteger ). s := self socketValueOf: socket. "buffer can be any indexable words or bytes object except CompiledMethod " interpreterProxy success: (interpreterProxy isWordsOrBytes: array). (interpreterProxy isWords: array) ifTrue: [byteSize := 4] ifFalse: [byteSize := 1]. interpreterProxy success: (startIndex >= 1 and: [count >= 0 and: [startIndex + count - 1 <= (interpreterProxy slotSizeOf: array)]]). interpreterProxy failed ifFalse: ["Note: adjust bufStart for zero-origin indexing" arrayBase := self cCoerce: (interpreterProxy firstIndexableField: array) to: 'char *'. bufStart := arrayBase + (startIndex - 1 * byteSize). bytesSent := self sqSocket: s SendDataBuf: bufStart Count: count * byteSize]. ^ (bytesSent // byteSize) asSmallIntegerObj! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:21'! primitiveSocket: socket sendUDPData: array toHost: hostAddress port: portNumber start: startIndex count: count | s byteSize arrayBase bufStart bytesSent address | self primitive: 'primitiveSocketSendUDPDataBufCount' parameters: #(Oop Oop ByteArray SmallInteger SmallInteger SmallInteger ). s := self socketValueOf: socket. "buffer can be any indexable words or bytes object except CompiledMethod " interpreterProxy success: (interpreterProxy isWordsOrBytes: array). (interpreterProxy isWords: array) ifTrue: [byteSize := 4] ifFalse: [byteSize := 1]. interpreterProxy success: (startIndex >= 1 and: [count >= 0 and: [startIndex + count - 1 <= (interpreterProxy slotSizeOf: array)]]). interpreterProxy failed ifFalse: ["Note: adjust bufStart for zero-origin indexing" arrayBase := self cCoerce: (interpreterProxy firstIndexableField: array) to: 'char *'. bufStart := arrayBase + (startIndex - 1 * byteSize). address := self netAddressToInt: (self cCoerce: hostAddress to: 'unsigned char *'). bytesSent := self sqSocket: s toHost: address port: portNumber SendDataBuf: bufStart Count: count * byteSize]. ^ (bytesSent // byteSize) asSmallIntegerObj! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:21'! primitiveSocket: socket setOptions: optionName value: optionValue | s optionNameStart optionNameSize optionValueStart optionValueSize returnedValue errorCode results | self primitive: 'primitiveSocketSetOptions' parameters: #(Oop Oop Oop). s := self socketValueOf: socket. interpreterProxy success: (interpreterProxy isBytes: optionName). optionNameStart := self cCoerce: (interpreterProxy firstIndexableField: optionName) to: 'char *'. optionNameSize := interpreterProxy slotSizeOf: optionName. interpreterProxy success: (interpreterProxy isBytes: optionValue). optionValueStart:= self cCoerce: (interpreterProxy firstIndexableField: optionValue) to: 'char *'. optionValueSize := interpreterProxy slotSizeOf: optionValue. interpreterProxy failed ifTrue: [^nil]. returnedValue := 0. errorCode := self sqSocketSetOptions: s optionNameStart: optionNameStart optionNameSize: optionNameSize optionValueStart: optionValueStart optionValueSize: optionValueSize returnedValue: (self cCode: '&returnedValue'). interpreterProxy pushRemappableOop: returnedValue asSmallIntegerObj. interpreterProxy pushRemappableOop: errorCode asSmallIntegerObj. interpreterProxy pushRemappableOop: (interpreterProxy instantiateClass: (interpreterProxy classArray) indexableSize: 2). results := interpreterProxy popRemappableOop. interpreterProxy storePointer: 0 ofObject: results withValue: interpreterProxy popRemappableOop. interpreterProxy storePointer: 1 ofObject: results withValue: interpreterProxy popRemappableOop. ^ results! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:17'! primitiveSocketAbortConnection: socket | s | self primitive: 'primitiveSocketAbortConnection' parameters: #(Oop). s := self socketValueOf: socket. interpreterProxy failed ifFalse: [ self sqSocketAbortConnection: s]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:17'! primitiveSocketAcceptFrom: sockHandle rcvBufferSize: recvBufSize sndBufSize: sendBufSize semaIndex: semaIndex | socketOop s serverSocket | self primitive: 'primitiveSocketAccept' parameters: #(Oop SmallInteger SmallInteger SmallInteger ). serverSocket := self socketValueOf: sockHandle. interpreterProxy failed ifFalse: [socketOop := interpreterProxy instantiateClass: interpreterProxy classByteArray indexableSize: self socketRecordSize. s := self socketValueOf: socketOop. self sqSocket: s AcceptFrom: serverSocket RecvBytes: recvBufSize SendBytes: sendBufSize SemaID: semaIndex]. ^ socketOop! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:17'! primitiveSocketAcceptFrom: sockHandle rcvBufferSize: recvBufSize sndBufSize: sendBufSize semaIndex: semaIndex readSemaIndex: aReadSema writeSemaIndex: aWriteSema | socketOop s serverSocket | self primitive: 'primitiveSocketAccept3Semaphores' parameters: #(Oop SmallInteger SmallInteger SmallInteger SmallInteger SmallInteger). serverSocket := self socketValueOf: sockHandle. interpreterProxy failed ifFalse: [socketOop := interpreterProxy instantiateClass: interpreterProxy classByteArray indexableSize: self socketRecordSize. s := self socketValueOf: socketOop. self sqSocket: s AcceptFrom: serverSocket RecvBytes: recvBufSize SendBytes: sendBufSize SemaID: semaIndex ReadSemaID: aReadSema WriteSemaID: aWriteSema]. ^ socketOop! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'dtl (auto pragmas dtl 2010-09-28) 9/28/2010 20:15'! primitiveSocketAddressGetPort | addr addrSize addrBase port | addr := self primitive: 'primitiveSocketAddressGetPort' parameters: #() receiver: #Oop. addrSize := interpreterProxy byteSizeOf: addr. addrBase := self cCoerce: (interpreterProxy firstIndexableField: addr) to: 'char *'. interpreterProxy failed ifFalse: [port := self sqSocketAddress: addrBase SizeGetPort: addrSize. interpreterProxy failed ifFalse: [^port asSmallIntegerObj]]! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'dtl (auto pragmas dtl 2010-09-28) 9/28/2010 20:16'! primitiveSocketAddressSetPort: portNumber | addr addrSize addrBase | addr := self primitive: 'primitiveSocketAddressSetPort' parameters: #(SmallInteger) receiver: #Oop. addrSize := interpreterProxy byteSizeOf: addr. addrBase := self cCoerce: (interpreterProxy firstIndexableField: addr) to: 'char *'. interpreterProxy failed ifFalse: [self sqSocketAddress: addrBase Size: addrSize SetPort: portNumber]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:17'! primitiveSocketCloseConnection: socket | s | self primitive: 'primitiveSocketCloseConnection' parameters: #(Oop). s := self socketValueOf: socket. interpreterProxy failed ifFalse: [ self sqSocketCloseConnection: s]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:17'! primitiveSocketConnectionStatus: socket | s status | self primitive: 'primitiveSocketConnectionStatus' parameters: #(Oop). s := self socketValueOf: socket. interpreterProxy failed ifFalse: [ status := self sqSocketConnectionStatus: s]. ^ status asSmallIntegerObj! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/30/2005 15:57'! primitiveSocketCreateNetwork: netType type: socketType receiveBufferSize: recvBufSize sendBufSize: sendBufSize semaIndex: semaIndex | socketOop s okToCreate | self primitive: 'primitiveSocketCreate' parameters: #(#SmallInteger #SmallInteger #SmallInteger #SmallInteger #SmallInteger ). "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCCSOTfn ~= 0 ifTrue: [okToCreate := self cCode: ' ((int (*) (int, int)) sCCSOTfn)(netType, socketType)'. okToCreate ifFalse: [^ interpreterProxy primitiveFail]]. socketOop := interpreterProxy instantiateClass: interpreterProxy classByteArray indexableSize: self socketRecordSize. s := self socketValueOf: socketOop. self sqSocket: s CreateNetType: netType SocketType: socketType RecvBytes: recvBufSize SendBytes: sendBufSize SemaID: semaIndex. ^ socketOop! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/30/2005 15:57'! primitiveSocketCreateNetwork: netType type: socketType receiveBufferSize: recvBufSize sendBufSize: sendBufSize semaIndex: semaIndex readSemaIndex: aReadSema writeSemaIndex: aWriteSema | socketOop s okToCreate | self primitive: 'primitiveSocketCreate3Semaphores' parameters: #(#SmallInteger #SmallInteger #SmallInteger #SmallInteger #SmallInteger #SmallInteger #SmallInteger ). "If the security plugin can be loaded, use it to check for permission. If not, assume it's ok" sCCSOTfn ~= 0 ifTrue: [okToCreate := self cCode: ' ((int (*) (int, int)) sCCSOTfn)(netType, socketType)'. okToCreate ifFalse: [^ interpreterProxy primitiveFail]]. socketOop := interpreterProxy instantiateClass: interpreterProxy classByteArray indexableSize: self socketRecordSize. s := self socketValueOf: socketOop. self sqSocket: s CreateNetType: netType SocketType: socketType RecvBytes: recvBufSize SendBytes: sendBufSize SemaID: semaIndex ReadSemaID: aReadSema WriteSemaID: aWriteSema. ^ socketOop! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:18'! primitiveSocketDestroy: socket | s | self primitive: 'primitiveSocketDestroy' parameters: #(Oop). s := self socketValueOf: socket. interpreterProxy failed ifFalse: [ self sqSocketDestroy: s]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:18'! primitiveSocketError: socket | s err | self primitive: 'primitiveSocketError' parameters: #(Oop). s := self socketValueOf: socket. interpreterProxy failed ifFalse: [ err := self sqSocketError: s]. ^err asSmallIntegerObj! ! !SocketPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 5/24/2000 13:38'! primitiveSocketListenWithOrWithoutBacklog "Backward compatibility" interpreterProxy methodArgumentCount = 2 ifTrue:[^self primitiveSocketListenOnPort] ifFalse:[^self primitiveSocketListenOnPortBacklog] ! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:18'! primitiveSocketLocalAddress: socket | s addr | self primitive: 'primitiveSocketLocalAddress' parameters: #(Oop). s := self socketValueOf: socket. addr := self sqSocketLocalAddress: s. ^self intToNetAddress: addr! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp (auto pragmas dtl 2010-09-28) 6/9/2007 10:30'! primitiveSocketLocalAddressSize: socket | s size | self primitive: 'primitiveSocketLocalAddressSize' parameters: #(#Oop). s := self socketValueOf: socket. interpreterProxy failed ifTrue: [^nil]. size := self sqSocketLocalAddressSize: s. interpreterProxy failed ifTrue: [^nil]. ^size asSmallIntegerObj! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:18'! primitiveSocketLocalPort: socket | s port | self primitive: 'primitiveSocketLocalPort' parameters: #(Oop). s := self socketValueOf: socket. port := self sqSocketLocalPort: s. ^port asSmallIntegerObj! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:18'! primitiveSocketReceiveDataAvailable: socket | s dataIsAvailable | self primitive: 'primitiveSocketReceiveDataAvailable' parameters: #(Oop). s := self socketValueOf: socket. dataIsAvailable := self sqSocketReceiveDataAvailable: s. ^dataIsAvailable asBooleanObj! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:18'! primitiveSocketRemoteAddress: socket | s addr | self primitive: 'primitiveSocketRemoteAddress' parameters: #(Oop). s := self socketValueOf: socket. addr := self sqSocketRemoteAddress: s. ^self intToNetAddress: addr! ! !SocketPlugin methodsFor: 'ipv6 primitives' stamp: 'ikp (auto pragmas dtl 2010-09-28) 6/9/2007 10:30'! primitiveSocketRemoteAddressSize: socket | s size | self primitive: 'primitiveSocketRemoteAddressSize' parameters: #(#Oop). s := self socketValueOf: socket. interpreterProxy failed ifTrue: [^nil]. size := self sqSocketRemoteAddressSize: s. interpreterProxy failed ifTrue: [^nil]. ^size asSmallIntegerObj! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:18'! primitiveSocketRemotePort: socket | s port | self primitive: 'primitiveSocketRemotePort' parameters: #(Oop). s := self socketValueOf: socket. port := self sqSocketRemotePort: s. ^port asSmallIntegerObj! ! !SocketPlugin methodsFor: 'primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:18'! primitiveSocketSendDone: socket | s done | self primitive: 'primitiveSocketSendDone' parameters: #(Oop). s := self socketValueOf: socket. done := self sqSocketSendDone: s. ^done asBooleanObj! ! !SocketPlugin methodsFor: 'initialize-release' stamp: 'ar (auto pragmas 12/08) 5/12/2000 16:55'! shutdownModule ^self cCode: 'socketShutdown()' inSmalltalk:[true]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'TPR 2/22/2000 17:26'! socketRecordSize "Return the size of a Smalltalk socket record in bytes." ^ self cCode: 'sizeof(SQSocket)' inSmalltalk: [12]! ! !SocketPlugin methodsFor: 'primitives' stamp: 'ikp (auto pragmas dtl 2010-09-28) 3/31/2005 14:08'! socketValueOf: socketOop "Return a pointer to the first byte of of the socket record within the given Smalltalk object, or nil if socketOop is not a socket record." | socketIndex | interpreterProxy success: ((interpreterProxy isBytes: socketOop) and: [(interpreterProxy byteSizeOf: socketOop) = self socketRecordSize]). interpreterProxy failed ifTrue: [^ nil] ifFalse: [socketIndex := self cCoerce: (interpreterProxy firstIndexableField: socketOop) to: 'void *'. ^ self cCode: '(SQSocket *) socketIndex']! ! SmartSyntaxInterpreterPlugin subclass: #SoundPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !SoundPlugin commentStamp: 'tpr 5/2/2003 15:50' prior: 0! This plugin implements the main sound related primiives. Since it requires platform support it will only be built when supported on your platform FORMAT OF SOUND DATA Squeak uses 16-bit signed samples encoded in the host's endian order. A sound buffer is a sequence of "frames", or "slices", where each frame usually includes one sample per channel. The exception is that for playback, each frame always includes 2 samples; for monaural playback, every other sample is ignored. ! !SoundPlugin class methodsFor: 'translation' stamp: 'tpr 5/23/2001 17:12'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !SoundPlugin class methodsFor: 'translation' stamp: 'tpr 11/29/2000 22:38'! requiresPlatformFiles "this plugin requires platform specific files in order to work" ^true! ! !SoundPlugin methodsFor: 'initialize-release' stamp: 'ar (auto pragmas 12/08) 5/12/2000 16:54'! initialiseModule ^self cCode: 'soundInit()' inSmalltalk:[true]! ! !SoundPlugin methodsFor: 'primitives' stamp: 'ar 4/4/2006 21:11'! primitiveSoundAvailableSpace "Returns the number of bytes of available sound output buffer space. This should be (frames*4) if the device is in stereo mode, or (frames*2) otherwise" | frames | self primitive: 'primitiveSoundAvailableSpace'. frames := self cCode: 'snd_AvailableSpace()'. "-1 if sound output not started" interpreterProxy success: frames >= 0. ^frames asPositiveIntegerObj! ! !SoundPlugin methodsFor: 'primitives' stamp: 'ar (auto pragmas 12/08) 4/4/2006 21:10'! primitiveSoundGetRecordingSampleRate "Return a float representing the actual sampling rate during recording. Fail if not currently recording." | rate | self primitive: 'primitiveSoundGetRecordingSampleRate'. rate := self cCode: 'snd_GetRecordingSampleRate()'. "fail if not recording" ^rate asFloatObj! ! !SoundPlugin methodsFor: 'primitives' stamp: 'ar 4/4/2006 21:11'! primitiveSoundGetVolume "Set the sound input recording level." | left right results | self primitive: 'primitiveSoundGetVolume' parameters: #( ). self var: #left type: 'double '. self var: #right type: 'double '. left := 0. right := 0. self cCode: 'snd_Volume((double *) &left,(double *) &right)'. interpreterProxy pushRemappableOop: (right asOop: Float). interpreterProxy pushRemappableOop: (left asOop: Float). interpreterProxy pushRemappableOop: (interpreterProxy instantiateClass: (interpreterProxy classArray) indexableSize: 2). results := interpreterProxy popRemappableOop. interpreterProxy storePointer: 0 ofObject: results withValue: interpreterProxy popRemappableOop. interpreterProxy storePointer: 1 ofObject: results withValue: interpreterProxy popRemappableOop. ^ results! ! !SoundPlugin methodsFor: 'primitives' stamp: 'dtl 4/26/2009 12:20'! primitiveSoundInsertSamples: frameCount from: buf leadTime: leadTime "Insert a buffer's worth of sound samples into the currently playing buffer. Used to make a sound start playing as quickly as possible. The new sound is mixed with the previously buffered sampled." "Details: Unlike primitiveSoundPlaySamples, this primitive always starts with the first sample the given sample buffer. Its third argument specifies the number of samples past the estimated sound output buffer position the inserted sound should start. If successful, it returns the number of samples inserted." | framesPlayed | self primitive: 'primitiveSoundInsertSamples' parameters: #(SmallInteger WordArray SmallInteger ). interpreterProxy success: frameCount <= (interpreterProxy slotSizeOf: buf cPtrAsOop). interpreterProxy failed ifFalse: [framesPlayed := self cCode: 'snd_InsertSamplesFromLeadTime(frameCount, (void *)buf, leadTime)'. interpreterProxy success: framesPlayed >= 0]. ^ framesPlayed asPositiveIntegerObj! ! !SoundPlugin methodsFor: 'primitives' stamp: 'dtl 4/26/2009 11:19'! primitiveSoundPlaySamples: frameCount from: buf startingAt: startIndex "Output a buffer's worth of sound samples." | framesPlayed | self primitive: 'primitiveSoundPlaySamples' parameters: #(SmallInteger WordArray SmallInteger ). interpreterProxy success: (startIndex >= 1 and: [startIndex + frameCount - 1 <= (interpreterProxy slotSizeOf: buf cPtrAsOop)]). interpreterProxy failed ifFalse: [framesPlayed := self cCode: 'snd_PlaySamplesFromAtLength(frameCount, (void *)buf, startIndex - 1)'. interpreterProxy success: framesPlayed >= 0]. ^ framesPlayed asPositiveIntegerObj! ! !SoundPlugin methodsFor: 'primitives' stamp: 'ar 4/4/2006 21:11'! primitiveSoundPlaySilence "Output a buffer's worth of silence. Returns the number of sample frames played." | framesPlayed | self primitive: 'primitiveSoundPlaySilence'. framesPlayed := self cCode: 'snd_PlaySilence()'. "-1 if sound output not started" interpreterProxy success: framesPlayed >= 0. ^framesPlayed asPositiveIntegerObj! ! !SoundPlugin methodsFor: 'primitives' stamp: 'ar 3/31/2010 09:41'! primitiveSoundRecordSamplesInto: buf startingAt: startWordIndex "Record a buffer's worth of 16-bit sound samples." | bufSizeInBytes samplesRecorded bufPtr byteOffset bufLen | self var: #bufPtr type: 'char*'. self primitive: 'primitiveSoundRecordSamples' parameters: #(WordArray SmallInteger ). interpreterProxy failed ifFalse: [bufSizeInBytes := (interpreterProxy slotSizeOf: buf cPtrAsOop) * 4. interpreterProxy success: (startWordIndex >= 1 and: [startWordIndex - 1 * 2 < bufSizeInBytes])]. interpreterProxy failed ifFalse:[ byteOffset := (startWordIndex - 1) * 2. bufPtr := (self cCoerce: buf to: 'char*') + byteOffset. bufLen := bufSizeInBytes - byteOffset. samplesRecorded := self cCode: 'snd_RecordSamplesIntoAtLength(bufPtr, 0, bufLen)' inSmalltalk:[bufPtr. bufLen. 0]. ]. ^ samplesRecorded asPositiveIntegerObj! ! !SoundPlugin methodsFor: 'primitives' stamp: 'JMM 11/6/2000 11:06'! primitiveSoundSetLeftVolume: aLeftVolume rightVolume: aRightVolume "Set the sound input recording level." self primitive: 'primitiveSoundSetLeftVolume' parameters: #(Float Float). interpreterProxy failed ifFalse: [self cCode: 'snd_SetVolume(aLeftVolume,aRightVolume)']. ! ! !SoundPlugin methodsFor: 'primitives' stamp: 'TPR 3/21/2000 16:39'! primitiveSoundSetRecordLevel: level "Set the sound input recording level." self primitive: 'primitiveSoundSetRecordLevel' parameters: #(SmallInteger ). interpreterProxy failed ifFalse: [self cCode: 'snd_SetRecordLevel(level)']! ! !SoundPlugin methodsFor: 'primitives' stamp: 'TPR 2/25/2000 14:58'! primitiveSoundStartBufferSize: bufFrames rate: samplesPerSec stereo: stereoFlag "Start the double-buffered sound output with the given buffer size, sample rate, and stereo flag." self primitive: 'primitiveSoundStart' parameters: #(SmallInteger SmallInteger Boolean). interpreterProxy success: (self cCode: 'snd_Start(bufFrames, samplesPerSec, stereoFlag, 0)')! ! !SoundPlugin methodsFor: 'primitives' stamp: 'TPR 2/25/2000 12:57'! primitiveSoundStartBufferSize: bufFrames rate: samplesPerSec stereo: stereoFlag semaIndex: semaIndex "Start the double-buffered sound output with the given buffer size, sample rate, stereo flag, and semaphore index." self primitive: 'primitiveSoundStartWithSemaphore' parameters: #(SmallInteger SmallInteger Boolean SmallInteger). interpreterProxy success: (self cCode: 'snd_Start(bufFrames, samplesPerSec, stereoFlag, semaIndex)')! ! !SoundPlugin methodsFor: 'primitives' stamp: 'TPR 2/25/2000 12:55'! primitiveSoundStartRecordingDesiredSampleRate: desiredSamplesPerSec stereo: stereoFlag semaIndex: semaIndex "Start recording sound with the given parameters." self primitive: 'primitiveSoundStartRecording' parameters: #(SmallInteger Boolean SmallInteger). self cCode: 'snd_StartRecording(desiredSamplesPerSec, stereoFlag, semaIndex)'! ! !SoundPlugin methodsFor: 'primitives' stamp: 'TPR 2/25/2000 12:58'! primitiveSoundStop "Stop double-buffered sound output." self primitive: 'primitiveSoundStop'. self cCode: 'snd_Stop()'. "leave rcvr on stack"! ! !SoundPlugin methodsFor: 'primitives' stamp: 'TPR 2/25/2000 12:58'! primitiveSoundStopRecording "Stop recording sound." self primitive: 'primitiveSoundStopRecording'. self cCode: 'snd_StopRecording()'. "leave rcvr on stack"! ! !SoundPlugin methodsFor: 'initialize-release' stamp: 'ar (auto pragmas 12/08) 5/12/2000 16:55'! shutdownModule ^self cCode: 'soundShutdown()' inSmalltalk:[true]! ! SmartSyntaxInterpreterPlugin subclass: #TestOSAPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !TestOSAPlugin commentStamp: 'tpr 5/2/2003 15:51' prior: 0! I am the Plugin for the Squeak/Applescript Interface. Since it requires platform support it will only be built when supported on your platform! !TestOSAPlugin class methodsFor: 'as yet unclassified' stamp: 'acg 9/21/1999 01:29'! declareCVarsIn: cg cg addHeaderFile: ''. cg addHeaderFile: ''. cg addHeaderFile: ''. cg addHeaderFile: ''. cg addHeaderFile: ''.! ! !TestOSAPlugin class methodsFor: 'translation' stamp: 'JMM 5/30/2001 19:43'! requiresPlatformFiles "this plugin requires platform specific files in order to work" ^true! ! !TestOSAPlugin methodsFor: 'AppleEvents prims' stamp: 'acg 9/23/1999 22:49'! primAECoerceDesc: typeCode to: result |rcvr | rcvr := self primitive: 'primAECoerceDesc' parameters: #(DescType AEDesc) receiver: #AEDesc. ^(self cCode: 'AECoerceDesc(rcvr,*typeCode,result)' inSmalltalk: [[rcvr]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'AppleEvents prims' stamp: 'acg 9/20/1999 12:37'! primAECreateDesc: typeCode from: aString |rcvr size | rcvr := self primitive: 'primAECreateDesc' parameters: #(DescType String) receiver: #AEDesc. size := aString size. ^(self cCode: 'AECreateDesc(*typeCode, aString, size, rcvr)' inSmalltalk: [[rcvr. size]. -1]) asOop: Unsigned ! ! !TestOSAPlugin methodsFor: 'AppleEvents prims' stamp: 'acg 9/20/1999 14:16'! primAEDescToString: aString | rcvr size | rcvr := self primitive: 'primAEDescToString' parameters: #(String) receiver: #AEDesc. size := aString size. self cCode: 'BlockMove(*(rcvr->dataHandle), aString, size)' inSmalltalk: [rcvr. size]. ^aString asOop: String ! ! !TestOSAPlugin methodsFor: 'AppleEvents prims' stamp: 'acg 9/20/1999 12:38'! primAEDisposeDesc |rcvr| rcvr := self primitive: 'primAEDisposeDesc' parameters: #() receiver: #AEDesc. ^(self cCode: 'AEDisposeDesc(rcvr)' inSmalltalk: [[rcvr]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'AppleEvents prims' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:22'! primAEGetKeyPtr: key type: type actual: ignoreDesc to: bytes | rcvr size ignoreSize | rcvr := self primitive: 'primAEGetKeyPtr' parameters: #(DescType DescType DescType ByteArray) receiver: #AEDesc. size := ignoreSize := bytes size. ^(self cCode: 'AEGetKeyPtr(rcvr, *key, *type, ignoreDesc, bytes, size, &ignoreSize)' inSmalltalk: [[rcvr. size. ignoreSize]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'Gen''l Mac OS prims' stamp: 'acg 9/20/1999 12:56'! primGetHandleSize: anIndex |rcvr| rcvr := self primitive: 'primGetHandleSize' parameters: #(SmallInteger) receiver: #WordArray. ^(self cCode: 'GetHandleSize((Handle) *(rcvr+anIndex))' inSmalltalk: [[rcvr]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'OSA prims' stamp: 'acg 9/20/1999 16:08'! primOSACompile: source mode: mode to: object |component| component := self primitive: 'primOSACompile' parameters: #(AEDesc SmallInteger OSAID) receiver: #ComponentInstance. ^(self cCode: 'OSACompile(*component,source,mode,object)' inSmalltalk: [[component]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'OSA prims' stamp: 'acg 9/20/1999 16:08'! primOSADisplay: source as: type mode: mode to: result |component| component := self primitive: 'primOSADisplay' parameters: #(OSAID DescType SmallInteger AEDesc) receiver: #ComponentInstance. ^(self cCode: 'OSADisplay(*component,*source,*type,mode,result)' inSmalltalk: [[component]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'OSA prims' stamp: 'acg 9/20/1999 15:39'! primOSADispose: anOSAID |component| component := self primitive: 'primOSADispose' parameters: #(OSAID) receiver: #ComponentInstance. ^(self cCode: 'OSADispose(*component,*anOSAID)' inSmalltalk: [[component]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'OSA prims' stamp: 'JMM 10/31/2005 11:59'! primOSADoScript: source in: context mode: mode resultType: type to: result |component resultsOfCall giLocker | component := self primitive: 'primOSADoScript' parameters: #(AEDesc OSAID SmallInteger DescType AEDesc) receiver: #ComponentInstance. self cCode: ' giLocker = interpreterProxy->ioLoadFunctionFrom("getUIToLock", ""); if (giLocker !!= 0) { long *foo; foo = malloc(sizeof(long)*9); foo[0] = 6; foo[1] = OSADoScript; foo[2] = *component; foo[3] = source; foo[4] = *context; foo[5] = *type; foo[6] = mode; foo[7] = result; foo[8] = 0; ((int (*) (void *)) giLocker)(foo); resultsOfCall = interpreterProxy->positive32BitIntegerFor(foo[8]); free(foo);}' inSmalltalk: [[component. giLocker]. resultsOfCall := -1]. ^resultsOfCall asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'OSA prims' stamp: 'JMM 10/31/2005 11:59'! primOSAExecute: script in: context mode: mode to: result |component giLocker resultsOfCall | component := self primitive: 'primOSAExecute' parameters: #(OSAID OSAID SmallInteger OSAID) receiver: #ComponentInstance. self cCode: ' giLocker = interpreterProxy->ioLoadFunctionFrom("getUIToLock", ""); if (giLocker !!= 0) { long *foo; foo = malloc(sizeof(long)*8); foo[0] = 5; foo[1] = OSAExecute; foo[2] = *component; foo[3] = *script; foo[4] = *context; foo[5] = mode; foo[6] = result; foo[7] = 0; ((int (*) (void *)) giLocker)(foo); resultsOfCall = interpreterProxy->positive32BitIntegerFor(foo[7]); free(foo); } ' inSmalltalk: [[component. giLocker]. resultsOfCall := -1]. ^resultsOfCall asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'OSA prims' stamp: 'acg 9/25/1999 15:01'! primOSAGetScriptInfo: aScriptID type: aDescType to: resultData |component| component := self primitive: 'primOSAGetScriptInfo' parameters: #(OSAID DescType IntegerArray) receiver: #ComponentInstance. ^(self cCode: 'OSAGetScriptInfo(*component,*aScriptID,*aDescType, (long *)resultData)' inSmalltalk: [[component]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'OSA prims' stamp: 'acg 9/25/1999 17:25'! primOSAGetSource: aScriptID type: aDescType to: resultData |component| component := self primitive: 'primOSAGetSource' parameters: #(OSAID DescType AEDesc) receiver: #ComponentInstance. ^(self cCode: 'OSAGetSource(*component,*aScriptID,*aDescType, resultData)' inSmalltalk: [[component]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'OSA prims' stamp: 'acg 9/22/1999 03:08'! primOSALoad: source mode: mode to: result |component| component := self primitive: 'primOSALoad' parameters: #(AEDesc SmallInteger OSAID) receiver: #ComponentInstance. ^(self cCode: 'OSALoad(*component,source,mode,result)' inSmalltalk: [[component]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'OSA prims' stamp: 'acg 9/25/1999 22:55'! primOSAMakeContext: name parent: parent to: result |component| component := self primitive: #primOSAMakeContext parameters: #(AEDesc OSAID OSAID) receiver: #ComponentInstance. ^(self cCode: 'OSAMakeContext(*component,name,*parent,result)' inSmalltalk: [[component]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'OSA prims' stamp: 'acg 9/23/1999 20:39'! primOSAScriptError: selector type: type to: result |component| component := self primitive: 'primOSAScriptError' parameters: #(DescType DescType AEDesc) receiver: #ComponentInstance. ^(self cCode: 'OSAScriptError(*component,*selector,*type,result)' inSmalltalk: [[component]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'OSA prims' stamp: 'acg 9/20/1999 21:53'! primOSAScriptingComponentNameTo: anAEDesc |component| component := self primitive: 'primOSAScriptingComponentName' parameters: #(AEDesc) receiver: #ComponentInstance. ^(self cCode: 'OSAScriptingComponentName(*component,anAEDesc)' inSmalltalk: [[component]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'OSA prims' stamp: 'acg 9/22/1999 07:51'! primOSAStore: source resultType: type mode: mode to: result |component| component := self primitive: #primOSAStore parameters: #(OSAID DescType SmallInteger AEDesc) receiver: #ComponentInstance. ^(self cCode: 'OSAStore(*component,*source,*type,mode,result)' inSmalltalk: [[component]. -1]) asOop: Unsigned! ! !TestOSAPlugin methodsFor: 'Component Mgr prims' stamp: 'acg 9/20/1999 23:42'! primOpenDefaultConfiguration: type subtype: subtype | component | component := self primitive: 'primOpenDefaultConfiguration' parameters: #(DescType DescType) receiver: #ComponentInstance. self cCode: '*component = OpenDefaultComponent(*type,*subtype)' inSmalltalk: [component at: 0 put: 0]. ^component asOop: ComponentInstance! ! SmartSyntaxInterpreterPlugin subclass: #UUIDPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !UUIDPlugin commentStamp: 'tpr 5/2/2003 15:52' prior: 0! A class to generate UUID by John M McIntosh johnmci@smalltalkconsulting.com, since it requires platform support it will only be built when supported on your platform. See http://www.webdav.org/specs/draft-leach-uuids-guids-01.txt If a plugin does not exist then we generate a UUID version 4 type GUUID in Smalltalk! !UUIDPlugin class methodsFor: 'translation' stamp: 'JMM 10/9/2001 12:46'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !UUIDPlugin class methodsFor: 'translation' stamp: 'JMM 10/9/2001 13:37'! requiresPlatformFiles "this plugin requires platform specific files in order to work" ^true! ! !UUIDPlugin methodsFor: 'initialize' stamp: 'JMM (auto pragmas 12/08) 10/9/2001 12:47'! initialiseModule ^self cCode: 'sqUUIDInit()' inSmalltalk:[true]! ! !UUIDPlugin methodsFor: 'system primitives' stamp: 'eem 3/4/2009 17:48'! primitiveMakeUUID | oop location | interpreterProxy methodArgumentCount = 0 ifFalse:[^interpreterProxy primitiveFail]. oop := interpreterProxy stackObjectValue: 0. interpreterProxy failed ifTrue:[^nil]. (interpreterProxy isBytes: oop) ifFalse:[^interpreterProxy primitiveFail]. (interpreterProxy byteSizeOf: oop) = 16 ifFalse:[^interpreterProxy primitiveFail]. location := interpreterProxy firstIndexableField: oop. ^self cCode: 'MakeUUID(location)' inSmalltalk: [location. interpreterProxy primitiveFail]. ! ! !UUIDPlugin methodsFor: 'initialize' stamp: 'ar (auto pragmas 12/08) 2/3/2002 20:03'! shutdownModule ^self cCode: 'sqUUIDShutdown()' inSmalltalk:[true]! ! InterpreterPlugin subclass: #SoundCodecPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !SoundCodecPlugin commentStamp: 'tpr 5/5/2003 12:20' prior: 0! This plugin provide GSM typecodec capabilities.! !SoundCodecPlugin class methodsFor: 'accessing' stamp: 'tpr 5/23/2001 17:11'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !SoundCodecPlugin class methodsFor: 'accessing' stamp: 'tpr 4/18/2002 15:56'! moduleName ^ 'SoundCodecPrims' "Needs to be the name used for module specification..." ! ! !SoundCodecPlugin class methodsFor: 'accessing' stamp: 'tpr 7/2/2001 16:34'! requiresCrossPlatformFiles "If there cross platform files to be associated with the plugin, here is where you want to flag" ^true! ! !SoundCodecPlugin methodsFor: 'gsm 6.10 codec' stamp: 'jm (auto pragmas 12/08) 2/4/1999 08:38'! primitiveGSMDecode | dstIndex dst srcIndex src frameCount state srcSize dstSize result srcDelta dstDelta | dstIndex := interpreterProxy stackIntegerValue: 0. dst := interpreterProxy stackObjectValue: 1. srcIndex := interpreterProxy stackIntegerValue: 2. src := interpreterProxy stackObjectValue: 3. frameCount := interpreterProxy stackIntegerValue: 4. state := interpreterProxy stackObjectValue: 5. interpreterProxy success: (interpreterProxy isWords: dst). interpreterProxy success: (interpreterProxy isBytes: src). interpreterProxy success: (interpreterProxy isBytes: state). interpreterProxy failed ifTrue:[^ nil]. srcSize := interpreterProxy slotSizeOf: src. dstSize := (interpreterProxy slotSizeOf: dst) * 2. self cCode: 'gsmDecode(state + 4, frameCount, src, srcIndex, srcSize, dst, dstIndex, dstSize, &srcDelta, &dstDelta)'. interpreterProxy failed ifTrue:[^ nil]. result := interpreterProxy makePointwithxValue: srcDelta yValue: dstDelta. interpreterProxy failed ifTrue:[^ nil]. interpreterProxy pop: 6. interpreterProxy push: result. ! ! !SoundCodecPlugin methodsFor: 'gsm 6.10 codec' stamp: 'jm (auto pragmas 12/08) 2/4/1999 08:37'! primitiveGSMEncode | dstIndex dst srcIndex src frameCount state srcSize dstSize result srcDelta dstDelta | dstIndex := interpreterProxy stackIntegerValue: 0. dst := interpreterProxy stackObjectValue: 1. srcIndex := interpreterProxy stackIntegerValue: 2. src := interpreterProxy stackObjectValue: 3. frameCount := interpreterProxy stackIntegerValue: 4. state := interpreterProxy stackObjectValue: 5. interpreterProxy success: (interpreterProxy isBytes: dst). interpreterProxy success: (interpreterProxy isWords: src). interpreterProxy success: (interpreterProxy isBytes: state). interpreterProxy failed ifTrue:[^ nil]. srcSize := (interpreterProxy slotSizeOf: src) * 2. dstSize := interpreterProxy slotSizeOf: dst. self cCode: 'gsmEncode(state + 4, frameCount, src, srcIndex, srcSize, dst, dstIndex, dstSize, &srcDelta, &dstDelta)'. interpreterProxy failed ifTrue:[^ nil]. result := interpreterProxy makePointwithxValue: srcDelta yValue: dstDelta. interpreterProxy failed ifTrue:[^ nil]. interpreterProxy pop: 6. interpreterProxy push: result. ! ! !SoundCodecPlugin methodsFor: 'gsm 6.10 codec' stamp: 'bgf 2/25/2009 21:40'! primitiveGSMNewState | stateBytes state | stateBytes := self cCode: 'gsmStateBytes()'. state := interpreterProxy instantiateClass: interpreterProxy classByteArray indexableSize: stateBytes. self cCode: 'gsmInitState(state + 4)'. interpreterProxy pop: 1. interpreterProxy push: state. ! ! InterpreterPlugin subclass: #SoundGenerationPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !SoundGenerationPlugin commentStamp: '' prior: 0! This class is a stub for the directly generated primitives in AbstractSound and subclasses.! !SoundGenerationPlugin class methodsFor: 'translation' stamp: 'ar 2/3/2001 18:16'! declareCVarsIn: cg cg addHeaderFile: '"SoundGenerationPlugin.h"'.! ! !SoundGenerationPlugin class methodsFor: 'accessing' stamp: 'tpr 5/23/2001 17:11'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !SoundGenerationPlugin class methodsFor: 'accessing' stamp: 'tpr 4/9/2002 16:15'! translateInDirectory: directory doInlining: inlineFlag "handle a special case code string rather than generated code. NB sqOldSoundsPrims IS NOT FULLY INTEGRATED - it still isn't included in the exports list" | cg | self initialize. cg := self buildCodeGeneratorUpTo: InterpreterPlugin. cg addMethodsForPrimitives: AbstractSound translatedPrimitives. self storeString: cg generateCodeStringForPrimitives onFileNamed: (directory fullNameFor: self moduleName, '.c'). "What we need here is some way to derive the prim names from sqOldSoundPrims - or dump it entirely. Perhaps add this class (without then generating the file again) using fake entry points like SurfacePlugin does" ^cg exportedPrimitiveNames asArray ! ! !SoundGenerationPlugin methodsFor: 'obsolete primitives' stamp: 'ar (auto pragmas 12/08) 2/3/2001 15:58'! primitiveFMSoundMix ^self primFMSoundmixSampleCountintostartingAtpan! ! !SoundGenerationPlugin methodsFor: 'obsolete primitives' stamp: 'ar (auto pragmas 12/08) 2/3/2001 15:59'! primitiveOldSampledSoundMix ^self oldprimSampledSoundmixSampleCountintostartingAtleftVolrightVol! ! !SoundGenerationPlugin methodsFor: 'obsolete primitives' stamp: 'ar (auto pragmas 12/08) 2/3/2001 15:58'! primitivePluckedSoundMix ^self primPluckedSoundmixSampleCountintostartingAtpan! ! !SoundGenerationPlugin methodsFor: 'obsolete primitives' stamp: 'ar (auto pragmas 12/08) 2/3/2001 15:58'! primitiveSampledSoundMix ^self primSampledSoundmixSampleCountintostartingAtpan! ! !SoundGenerationPlugin methodsFor: 'obsolete primitives' stamp: 'ar (auto pragmas 12/08) 2/3/2001 15:57'! primitiveWaveTableSoundMix ^self primWaveTableSoundmixSampleCountintostartingAtpan! ! InterpreterPlugin subclass: #StarSqueakPlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !StarSqueakPlugin commentStamp: '' prior: 0! This plugin defines primitives accelerators to support StarSqueak. The plugin library, usually named "StarSqueakPlugin", should be put in the same folder as the Squeak interpreter. If this plugin is not available the primitives will still work, but they will be run much more slowly, since they will be running as Squeak code. ! !StarSqueakPlugin methodsFor: 'all' stamp: 'jm (auto pragmas 12/08) 1/20/2001 11:01'! checkedUnsignedIntPtrOf: oop "Return an unsigned int pointer to the first indexable word of oop, which must be a words object." interpreterProxy success: (interpreterProxy isWords: oop). interpreterProxy failed ifTrue: [^ 0]. ^ self cCoerce: (interpreterProxy firstIndexableField: oop) to: 'unsigned int *' ! ! !StarSqueakPlugin methodsFor: 'all' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:22'! primitiveDiffuseFromToWidthHeightDelta "Diffuse the integer values of the source patch variable Bitmap into the output Bitmap. Each cell of the output is the average of the NxN area around it in the source, where N = (2 * delta) + 1." | srcOop dstOop height width delta src dst area startY endY startX endX sum rowStart | srcOop := interpreterProxy stackValue: 4. dstOop := interpreterProxy stackValue: 3. width := interpreterProxy stackIntegerValue: 2. height := interpreterProxy stackIntegerValue: 1. delta := interpreterProxy stackIntegerValue: 0. src := self checkedUnsignedIntPtrOf: srcOop. dst := self checkedUnsignedIntPtrOf: dstOop. interpreterProxy success: (interpreterProxy stSizeOf: srcOop) = (interpreterProxy stSizeOf: dstOop). interpreterProxy success: (interpreterProxy stSizeOf: srcOop) = (width * height). interpreterProxy failed ifTrue: [^ nil]. area := ((2 * delta) + 1) * ((2 * delta) + 1). 0 to: height - 1 do: [:y | startY := y - delta. startY < 0 ifTrue: [startY := 0]. endY := y + delta. endY >= height ifTrue: [endY := height - 1]. 0 to: width - 1 do: [:x | startX := x - delta. startX < 0 ifTrue: [startX := 0]. endX := x + delta. endX >= width ifTrue: [endX := width - 1]. sum := 0. startY to: endY do: [:y2 | rowStart := y2 * width. startX to: endX do: [:x2 | sum := sum + (src at: rowStart + x2)]]. dst at: ((y * width) + x) put: (sum // area)]]. interpreterProxy pop: 5. "pop args, leave rcvr on stack" ! ! !StarSqueakPlugin methodsFor: 'all' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:22'! primitiveEvaporateRate "Evaporate the integer values of the source Bitmap at the given rate. The rate is an integer between 0 and 1024, where 1024 is a scale factor of 1.0 (i.e., no evaporation)." | patchVarOop rate patchVar sz | patchVarOop := interpreterProxy stackValue: 1. rate := interpreterProxy stackIntegerValue: 0. patchVar := self checkedUnsignedIntPtrOf: patchVarOop. sz := interpreterProxy stSizeOf: patchVarOop. interpreterProxy failed ifTrue: [^ nil]. 0 to: sz - 1 do: [:i | patchVar at: i put: (((patchVar at: i) * rate) >> 10)]. interpreterProxy pop: 2. "pop args, leave rcvr on stack" ! ! !StarSqueakPlugin methodsFor: 'all' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:22'! primitiveMapFromToWidthHeightPatchSizeRgbFlagsShift | srcOop dstOop w h patchSize rgbFlags shiftAmount src dst rgbMult srcIndex level pixel offset | srcOop := interpreterProxy stackValue: 6. dstOop := interpreterProxy stackValue: 5. w := interpreterProxy stackIntegerValue: 4. h := interpreterProxy stackIntegerValue: 3. patchSize := interpreterProxy stackIntegerValue: 2. rgbFlags := interpreterProxy stackIntegerValue: 1. shiftAmount := interpreterProxy stackIntegerValue: 0. src := self checkedUnsignedIntPtrOf: srcOop. dst := self checkedUnsignedIntPtrOf: dstOop. interpreterProxy success: (interpreterProxy stSizeOf: dstOop) = (w * h). interpreterProxy success: (interpreterProxy stSizeOf: dstOop) = ((interpreterProxy stSizeOf: srcOop) * patchSize * patchSize). interpreterProxy failed ifTrue: [^ nil]. rgbMult := 0. (rgbFlags bitAnd: 2r100) > 0 ifTrue: [rgbMult := rgbMult + 16r10000]. (rgbFlags bitAnd: 2r10) > 0 ifTrue: [rgbMult := rgbMult + 16r100]. (rgbFlags bitAnd: 2r1) > 0 ifTrue: [rgbMult := rgbMult + 16r1]. srcIndex := -1. 0 to: (h // patchSize) - 1 do: [:y | 0 to: (w // patchSize) - 1 do: [:x | level := (src at: (srcIndex := srcIndex + 1)) bitShift: shiftAmount. level > 255 ifTrue: [level := 255]. level <= 0 ifTrue: [pixel := 1] "non-transparent black" ifFalse: [pixel := level * rgbMult]. "fill a patchSize x patchSize square with the pixel value" offset := ((y * w) + x) * patchSize. offset to: offset + ((patchSize - 1) * w) by: w do: [:rowStart | rowStart to: rowStart + patchSize - 1 do: [:dstIndex | dst at: dstIndex put: pixel]] ]]. interpreterProxy pop: 7. "pop args, leave rcvr on stack" ! ! InterpreterPlugin subclass: #SurfacePlugin instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !SurfacePlugin commentStamp: '' prior: 0! This plugin is a fake. It doesn't do anything useful. It's sole purpose is to wrap the C code that's associated with the SurfacePlugin into the main VM generation process. Since the C code isn't easily generated from ST code this is (unfortunately) necessary. But look on the bright side - you don't have to define any weird stuff for the C compiler. Isn't that great?!! (just kidding...) ! !SurfacePlugin class methodsFor: 'translation' stamp: 'tpr 5/23/2001 17:12'! hasHeaderFile "If there is a single intrinsic header file to be associated with the plugin, here is where you want to flag" ^true! ! !SurfacePlugin class methodsFor: 'translation' stamp: 'tpr 7/4/2001 15:15'! requiresCrossPlatformFiles "If there cross platform files to be associated with the plugin, here is where you want to flag" ^true! ! !SurfacePlugin class methodsFor: 'translation' stamp: 'tpr 4/9/2002 16:15'! translateInDirectory: directory doInlining: inlineFlag "handle a special case external file rather than normal generated code." | cg | self initialize. cg := self buildCodeGeneratorUpTo: self. "We rely on the fake entry points implemented on the instance side to allow the export list to be accurate. Please update them if you change the code" ^cg exportedPrimitiveNames asArray! ! !SurfacePlugin methodsFor: 'fake entry points' stamp: 'ar (auto pragmas 12/08) 5/26/2000 22:33'! initialiseModule "Fake entry point" ! ! !SurfacePlugin methodsFor: 'fake entry points' stamp: 'ar (auto pragmas 12/08) 5/26/2000 22:34'! ioFindSurface "Fake entry point" ! ! !SurfacePlugin methodsFor: 'fake entry points' stamp: 'ar (auto pragmas 12/08) 5/26/2000 22:34'! ioGetSurfaceFormat "Fake entry point" ! ! !SurfacePlugin methodsFor: 'fake entry points' stamp: 'ar (auto pragmas 12/08) 5/26/2000 22:34'! ioLockSurface "Fake entry point" ! ! !SurfacePlugin methodsFor: 'fake entry points' stamp: 'ar (auto pragmas 12/08) 5/26/2000 22:34'! ioRegisterSurface "Fake entry point" ! ! !SurfacePlugin methodsFor: 'fake entry points' stamp: 'ar (auto pragmas 12/08) 5/26/2000 22:34'! ioShowSurface "Fake entry point" ! ! !SurfacePlugin methodsFor: 'fake entry points' stamp: 'ar (auto pragmas 12/08) 5/26/2000 22:34'! ioUnlockSurface "Fake entry point" ! ! !SurfacePlugin methodsFor: 'fake entry points' stamp: 'ar (auto pragmas 12/08) 5/26/2000 22:34'! ioUnregisterSurface "Fake entry point" ! ! !SurfacePlugin methodsFor: 'fake entry points' stamp: 'ar (auto pragmas 12/08) 5/26/2000 22:33'! shutdownModule "Fake entry point" ! ! Object subclass: #InterpreterProxy instanceVariableNames: 'successFlag remapBuffer stack method argumentCount bb thisSessionID primFailCode' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-InterpreterSimulation'! !InterpreterProxy commentStamp: '' prior: 0! This class should provide the definition of what interpreter support plugins need and can have access to. Note that the proxy related files platforms - Cross - vm - sqVirtualMachine.[ch] are kept under the SVN tree at www.squeakvm.org . The main use of the class is to support the vm simulator! !InterpreterProxy class methodsFor: 'private' stamp: 'tpr 12/22/2005 17:13'! validateProxyImplementation: anInterpreter "InterpreterProxy validateProxyImplementation: Interpreter" | proxyClass catList | proxyClass := InterpreterProxy. catList := proxyClass organization categories copy asOrderedCollection. catList remove: 'initialize' ifAbsent:[]. catList remove: 'private' ifAbsent:[]. catList do:[:categ| (proxyClass organization listAtCategoryNamed: categ) do:[:selector| (anInterpreter canUnderstand: selector) ifFalse: [self notifyWithLabel: selector, ' is not implemented in ', anInterpreter name]]]! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 9/16/1998 01:40'! argumentCountOf: methodPointer ^methodPointer numArgs! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar (auto pragmas 12/08) 10/11/1998 03:01'! arrayValueOf: oop self success: (self isWordsOrBytes: oop). ^CArrayAccessor on: oop.! ! !InterpreterProxy methodsFor: 'other' stamp: 'ar 9/16/1998 20:51'! become: array1 with: array2 array1 elementsExchangeIdentityWith: array2! ! !InterpreterProxy methodsFor: 'converting' stamp: 'ar 10/10/1998 21:27'! booleanValueOf: obj obj == true ifTrue:[^true]. obj == false ifTrue:[^false]. self primitiveFail. ^nil! ! !InterpreterProxy methodsFor: 'private' stamp: 'ar 9/18/1998 21:11'! byteAt: accessor ^accessor byteAt: 0! ! !InterpreterProxy methodsFor: 'private' stamp: 'ar 9/18/1998 21:12'! byteAt: accessor put: value ^accessor byteAt: 0 put: value! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 10/7/1998 18:23'! byteSizeOf: oop "Return the size of the receiver in bytes" ^oop class isBytes ifTrue:[(self slotSizeOf: oop)] ifFalse:[(self slotSizeOf: oop) * 4]! ! !InterpreterProxy methodsFor: 'other' stamp: 'ar 9/16/1998 20:51'! byteSwapped: w "Return the given integer with its bytes in the reverse order." ^ ((w bitShift: -24) bitAnd: 16rFF) + ((w bitShift: -8) bitAnd: 16rFF00) + ((w bitShift: 8) bitAnd: 16rFF0000) + ((w bitShift: 24) bitAnd: 16rFF000000) ! ! !InterpreterProxy methodsFor: 'special objects' stamp: 'ar 9/16/1998 21:43'! characterTable ^Character characterTable! ! !InterpreterProxy methodsFor: 'converting' stamp: 'ar 10/4/1998 15:47'! checkedIntegerValueOf: intOop (self isIntegerObject: intOop) ifTrue:[^self integerValueOf: intOop] ifFalse:[self primitiveFail. ^0].! ! !InterpreterProxy methodsFor: 'FFI support' stamp: 'eem 11/26/2007 17:47'! classAlien ^Smalltalk at: #Alien ifAbsent: [nil]! ! !InterpreterProxy methodsFor: 'special classes' stamp: 'ar 9/16/1998 20:42'! classArray ^Array! ! !InterpreterProxy methodsFor: 'special classes' stamp: 'ar 9/16/1998 20:43'! classBitmap ^Bitmap! ! !InterpreterProxy methodsFor: 'special classes' stamp: 'ar 9/16/1998 20:43'! classByteArray ^ByteArray! ! !InterpreterProxy methodsFor: 'special classes' stamp: 'ar 9/16/1998 20:43'! classCharacter ^Character! ! !InterpreterProxy methodsFor: 'FFI support' stamp: 'ar 11/29/1999 22:03'! classExternalAddress ^Smalltalk at: #ExternalAddress ifAbsent:[nil]! ! !InterpreterProxy methodsFor: 'FFI support' stamp: 'ar 11/29/1999 22:03'! classExternalData ^Smalltalk at: #ExternalData ifAbsent:[nil]! ! !InterpreterProxy methodsFor: 'FFI support' stamp: 'ar 11/29/1999 22:03'! classExternalFunction ^Smalltalk at: #ExternalFunction ifAbsent:[nil]! ! !InterpreterProxy methodsFor: 'FFI support' stamp: 'ar 11/29/1999 22:04'! classExternalLibrary ^Smalltalk at: #ExternalLibrary ifAbsent:[nil]! ! !InterpreterProxy methodsFor: 'FFI support' stamp: 'ar 11/29/1999 22:04'! classExternalStructure ^Smalltalk at: #ExternalStructure ifAbsent:[nil]! ! !InterpreterProxy methodsFor: 'special classes' stamp: 'ar 9/16/1998 20:43'! classFloat ^Float! ! !InterpreterProxy methodsFor: 'special classes' stamp: 'ar 11/19/1999 14:29'! classLargeNegativeInteger ^LargeNegativeInteger! ! !InterpreterProxy methodsFor: 'special classes' stamp: 'ar 9/16/1998 20:43'! classLargePositiveInteger ^LargePositiveInteger! ! !InterpreterProxy methodsFor: 'special classes' stamp: 'ar 9/16/1998 20:43'! classPoint ^Point! ! !InterpreterProxy methodsFor: 'special classes' stamp: 'ar 9/16/1998 20:43'! classSemaphore ^Semaphore! ! !InterpreterProxy methodsFor: 'special classes' stamp: 'ar 9/16/1998 21:43'! classSmallInteger ^SmallInteger! ! !InterpreterProxy methodsFor: 'special classes' stamp: 'ar 9/16/1998 20:43'! classString ^String! ! !InterpreterProxy methodsFor: 'FFI support' stamp: 'eem 4/18/2008 15:17'! classUnsafeAlien ^Smalltalk at: #UnsafeAlien ifAbsent: [nil]! ! !InterpreterProxy methodsFor: 'instance creation' stamp: 'ar 9/18/1998 20:11'! clone: oop ^oop clone! ! !InterpreterProxy methodsFor: 'BitBlt support' stamp: 'ar 4/12/1999 23:29'! copyBits bb copyBits.! ! !InterpreterProxy methodsFor: 'BitBlt support' stamp: 'ar 4/12/1999 23:29'! copyBitsFrom: leftX to: rightX at: yValue bb copyBitsFrom: leftX to: rightX at: yValue.! ! !InterpreterProxy methodsFor: 'special objects' stamp: 'ar 9/16/1998 21:42'! displayObject ^Display! ! !InterpreterProxy methodsFor: 'other' stamp: 'ar 9/16/1998 20:51'! failed ^successFlag not! ! !InterpreterProxy methodsFor: 'special objects' stamp: 'ar 9/16/1998 20:40'! falseObject ^false! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar (auto pragmas 12/08) 10/10/1998 21:22'! fetchArray: fieldIndex ofObject: objectPointer "Fetch the instance variable at the given index of the given object. Return the address of first indexable field of resulting array object, or fail if the instance variable does not contain an indexable bytes or words object." "Note: May be called by translated primitive code." | arrayOop | arrayOop := self fetchPointer: fieldIndex ofObject: objectPointer. ^ self arrayValueOf: arrayOop ! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 9/16/1998 01:07'! fetchClassOf: oop ^oop class! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar (auto pragmas 12/08) 10/10/1998 21:21'! fetchFloat: fieldIndex ofObject: objectPointer "Fetch the instance variable at the given index of the given object. Return the C double precision floating point value of that instance variable, or fail if it is not a Float." "Note: May be called by translated primitive code." | floatOop | floatOop := self fetchPointer: fieldIndex ofObject: objectPointer. ^ self floatValueOf: floatOop! ! !InterpreterProxy methodsFor: 'object access' stamp: 'tpr (auto pragmas 12/08) 3/15/2004 20:20'! fetchInteger: fieldIndex ofObject: objectPointer "Note: May be called by translated primitive code." | intOop | intOop := self fetchPointer: fieldIndex ofObject: objectPointer. ^self checkedIntegerValueOf: intOop! ! !InterpreterProxy methodsFor: 'private' stamp: 'ar 10/27/1999 14:13'! fetchIntegerOrTruncFloat: fieldIndex ofObject: objectPointer "Support for BitBlt simulation only" | intOrFloat | intOrFloat := self fetchPointer: fieldIndex ofObject: objectPointer. (self isIntegerObject: intOrFloat) ifTrue: [^ self integerValueOf: intOrFloat]. intOrFloat isFloat ifTrue:[^intOrFloat truncated]. ^self primitiveFail.! ! !InterpreterProxy methodsFor: 'object access' stamp: 'tpr 6/6/2005 19:11'! fetchLong32: fieldIndex ofObject: oop "fetchWord:ofObject: is rescinded as of VMMaker 3.8 64bit VM. This is the same code as used therein and may need revision for 64 bit cleanliness" ^oop instVarAt: fieldIndex+1! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 10/10/1998 16:04'! fetchPointer: index ofObject: oop ^oop instVarAt: index+1! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar (auto pragmas dtl 2010-09-28) 9/18/1998 20:26'! firstFixedField: oop ^CObjectAccessor on: oop! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar (auto pragmas dtl 2010-09-28) 10/10/1998 16:22'! firstIndexableField: oop ^CArrayAccessor on: oop! ! !InterpreterProxy methodsFor: 'converting' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:35'! floatObjectOf: aFloat aFloat class == Float ifFalse:[self error:'Not a float object']. ^aFloat! ! !InterpreterProxy methodsFor: 'converting' stamp: 'ar (auto pragmas dtl 2010-09-28) 10/10/1998 16:09'! floatValueOf: oop oop class == Float ifTrue:[^oop] ifFalse:[self primitiveFail. ^0.0].! ! !InterpreterProxy methodsFor: 'other' stamp: 'ar 9/16/1998 20:52'! fullDisplayUpdate Display display! ! !InterpreterProxy methodsFor: 'other' stamp: 'ar 9/16/1998 20:51'! fullGC Smalltalk garbageCollect.! ! !InterpreterProxy methodsFor: 'other' stamp: 'eem 11/2/2007 13:25'! getStackPointer self error: 'not yet implemented in Smalltalk'! ! !InterpreterProxy methodsFor: 'other' stamp: 'tpr 12/21/2005 18:49'! getThisSessionID "Answer a session identifier which represents the current instance of Squeak. The identifier is expected to be unique among all instances of Squeak on a network at any point in time." [thisSessionID = 0] whileTrue: [thisSessionID := (Random new next * SmallInteger maxVal) asInteger]. ^ thisSessionID ! ! !InterpreterProxy methodsFor: 'testing' stamp: 'ar 11/17/1999 22:04'! includesBehavior: aClass ThatOf: aSuperclass ^aClass includesBehavior: aSuperclass! ! !InterpreterProxy methodsFor: 'other' stamp: 'ar 9/16/1998 20:52'! incrementalGC Smalltalk garbageCollectMost.! ! !InterpreterProxy methodsFor: 'initialize' stamp: 'ar 9/16/1998 01:35'! initialize successFlag := true. remapBuffer := OrderedCollection new. stack := OrderedCollection new.! ! !InterpreterProxy methodsFor: 'instance creation' stamp: 'ar 9/16/1998 01:11'! instantiateClass: classPointer indexableSize: size ^size = 0 ifTrue:[classPointer basicNew] ifFalse:[classPointer basicNew: size]! ! !InterpreterProxy methodsFor: 'converting' stamp: 'ar 10/10/1998 16:13'! integerObjectOf: value value class == SmallInteger ifFalse:[self error:'Not a SmallInteger object']. ^value! ! !InterpreterProxy methodsFor: 'converting' stamp: 'ar 10/10/1998 16:10'! integerValueOf: oop oop class == SmallInteger ifFalse:[self error:'Not a SmallInteger']. ^oop! ! !InterpreterProxy methodsFor: 'object access' stamp: 'eem 6/27/2007 14:44'! internalIsImutable: oop ^oop isImmutable! ! !InterpreterProxy methodsFor: 'object access' stamp: 'eem 6/27/2007 14:44'! internalIsMutable: oop ^oop isImmutable not! ! !InterpreterProxy methodsFor: 'converting' stamp: 'tpr 12/29/2005 17:35'! ioFilename: aCharBuffer fromString: aFilenameString ofLength: filenameLength resolveAliases: aBoolean "the vm has to convert aFilenameString via any canonicalization and char-mapping and put the result in aCharBuffer. This doesn't translate well in Smalltalk since we know how long strings are rather than considering them terminated by a 0 char. Do the best we can. Note the resolveAliases flag - this is an awful artefact of OSX and Apples demented alias handling. When opening a file, the flag must be true, when closing or renaming it must be false. Sigh." aCharBuffer replaceFrom:1 to: filenameLength with: aFilenameString! ! !InterpreterProxy methodsFor: 'FFI support' stamp: 'ar 5/11/2000 20:05'! ioLoadFunction: functionName From: moduleName "Dummy - provided by support code" ^0! ! !InterpreterProxy methodsFor: 'FFI support' stamp: 'ar 11/28/1999 18:33'! ioLoadModule: moduleNameIndex OfLength: moduleLength "Dummy - provided by support code" ^0! ! !InterpreterProxy methodsFor: 'FFI support' stamp: 'ar 11/28/1999 18:34'! ioLoadSymbol: functionNameIndex OfLength: functionLength FromModule: moduleHandle "Dummy - provided by support code" ^0! ! !InterpreterProxy methodsFor: 'other' stamp: 'ar 5/13/2000 14:55'! ioMicroMSecs ^Time millisecondClockValue! ! !InterpreterProxy methodsFor: 'testing' stamp: 'tpr (auto pragmas dtl 2010-09-28) 12/29/2005 16:35'! is: oop KindOf: aString "InterpreterProxy new is: 42 KindOf: 'Number'" | theClass | theClass := Smalltalk at: aString asSymbol ifAbsent:[nil]. ^theClass isNil ifTrue:[false] ifFalse:[^oop isKindOf: theClass]! ! !InterpreterProxy methodsFor: 'testing' stamp: 'tpr (auto pragmas dtl 2010-09-28) 12/29/2005 16:35'! is: oop MemberOf: aString "InterpreterProxy new is: 42 MemberOf:'SmallInteger'" | theClass | theClass := Smalltalk at: aString asSymbol ifAbsent:[nil]. ^theClass isNil ifTrue:[false] ifFalse:[^oop isMemberOf: theClass]! ! !InterpreterProxy methodsFor: 'testing' stamp: 'ar 12/5/2003 20:17'! isArray: oop ^(self isIntegerObject: oop) not and:[(oop class format bitAnd: 15) = 2] ! ! !InterpreterProxy methodsFor: 'testing' stamp: 'ar 9/16/1998 01:04'! isBytes: oop ^oop class isBytes! ! !InterpreterProxy methodsFor: 'testing' stamp: 'ar 9/16/1998 21:44'! isFloatObject: oop ^oop class == Float! ! !InterpreterProxy methodsFor: 'FFI support' stamp: 'ar 11/28/1999 19:04'! isInMemory: address "Return true if the given address is in ST object memory" ^true! ! !InterpreterProxy methodsFor: 'testing' stamp: 'acg 9/19/1999 13:11'! isIndexable: oop ^oop class isVariable! ! !InterpreterProxy methodsFor: 'testing' stamp: 'ar 9/16/1998 01:12'! isIntegerObject: objectPointer ^objectPointer class == SmallInteger! ! !InterpreterProxy methodsFor: 'testing' stamp: 'ar 9/16/1998 01:13'! isIntegerValue: intValue ^intValue class == SmallInteger! ! !InterpreterProxy methodsFor: 'private' stamp: 'ar 10/27/1999 14:21'! isInterpreterProxy "Return true since I am not a real Interpreter simulation" ^true! ! !InterpreterProxy methodsFor: 'testing' stamp: 'ar 9/16/1998 01:04'! isPointers: oop ^oop class isPointers! ! !InterpreterProxy methodsFor: 'testing' stamp: 'ar 9/16/1998 01:16'! isWeak: oop ^oop class isWeak! ! !InterpreterProxy methodsFor: 'testing' stamp: 'ar 10/9/1998 22:19'! isWords: oop ^oop class isPointers not and:[oop class isBytes not]! ! !InterpreterProxy methodsFor: 'testing' stamp: 'ar 9/16/1998 01:05'! isWordsOrBytes: oop ^(self isBytes: oop) or:[self isWords: oop]! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 9/16/1998 01:38'! literal: offset ofMethod: methodPointer ^methodPointer literals at: offset+1! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 9/16/1998 01:40'! literalCountOf: methodPointer ^methodPointer numLiterals! ! !InterpreterProxy methodsFor: 'BitBlt support' stamp: 'ar 4/12/1999 23:29'! loadBitBltFrom: bbOop bb := bbOop.! ! !InterpreterProxy methodsFor: 'initialize' stamp: 'ar 10/3/1998 18:50'! loadStackFrom: aContext self push: aContext receiver. method := aContext method. argumentCount := method numArgs. 1 to: argumentCount do:[:i| self push: (aContext at: i) ].! ! !InterpreterProxy methodsFor: 'private' stamp: 'ar 9/18/1998 21:11'! longAt: accessor ^accessor longAt: 0! ! !InterpreterProxy methodsFor: 'private' stamp: 'ar 9/18/1998 21:11'! longAt: accessor put: value ^accessor longAt: 0 put: value! ! !InterpreterProxy methodsFor: 'instance creation' stamp: 'ar 10/10/1998 16:14'! makePointwithxValue: xValue yValue: yValue (xValue class == SmallInteger and:[yValue class == SmallInteger]) ifFalse:[self error:'Not SmallInteger objects']. ^xValue@yValue! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 10/7/1998 18:43'! methodArgumentCount ^argumentCount! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 10/7/1998 18:43'! methodPrimitiveIndex ^method primitive! ! !InterpreterProxy methodsFor: 'special objects' stamp: 'ar 9/16/1998 20:40'! nilObject ^nil! ! !InterpreterProxy methodsFor: 'object access' stamp: 'tpr 6/6/2005 19:28'! obsoleteDontUseThisFetchWord: fieldIndex ofObject: oop "fetchWord:ofObject: is rescinded as of VMMaker 3.8 64bit VM. This is a placeholder to sit in the sqVirtualMachine structure to support older plugins for a while" self halt: 'deprecated method'! ! !InterpreterProxy methodsFor: 'stack access' stamp: 'ar 9/16/1998 01:41'! pop: nItems 1 to: nItems do:[:i| stack removeLast].! ! !InterpreterProxy methodsFor: 'stack access' stamp: 'ar 9/16/1998 01:41'! pop: nItems thenPush: oop self pop: nItems. self push: oop.! ! !InterpreterProxy methodsFor: 'instance creation' stamp: 'ar 9/16/1998 01:14'! popRemappableOop ^remapBuffer removeLast! ! !InterpreterProxy methodsFor: 'converting' stamp: 'ar 10/10/1998 16:11'! positive32BitIntegerFor: integerValue integerValue isInteger ifFalse:[self error:'Not an Integer object']. ^integerValue > 0 ifTrue:[integerValue] ifFalse:[ (1 bitShift: 32) + integerValue]! ! !InterpreterProxy methodsFor: 'converting' stamp: 'ar 10/10/1998 16:12'! positive32BitValueOf: oop oop isInteger ifFalse:[self error:'Not an integer object']. oop < 0 ifTrue:[self primitiveFail. ^0] ifFalse:[^oop]! ! !InterpreterProxy methodsFor: 'converting' stamp: 'JMM 11/8/2001 15:26'! positive64BitIntegerFor: integerValue integerValue isInteger ifFalse:[self error:'Not an Integer object']. ^integerValue > 0 ifTrue:[integerValue] ifFalse:[ (1 bitShift: 64) + integerValue]! ! !InterpreterProxy methodsFor: 'converting' stamp: 'JMM 11/8/2001 15:27'! positive64BitValueOf: oop oop isInteger ifFalse:[self error:'Not an integer object']. oop < 0 ifTrue:[self primitiveFail. ^0] ifFalse:[^oop]! ! !InterpreterProxy methodsFor: 'other' stamp: 'ar 9/16/1998 20:51'! primitiveFail (self confirm:'A primitive is failing -- Stop simulation?') ifTrue:[self halt]. successFlag := false.! ! !InterpreterProxy methodsFor: 'other' stamp: 'eem 11/1/2007 16:08'! primitiveFailFor: reasonCode "Set specific primitive failure." (self confirm:'A primitive is failing -- Stop simulation?') ifTrue:[self halt]. primFailCode := reasonCode! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 9/16/1998 01:39'! primitiveIndexOf: methodPointer ^methodPointer primitive! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 11/28/1999 17:43'! primitiveMethod "Return the method an external primitive was defined in" ^method! ! !InterpreterProxy methodsFor: 'stack access' stamp: 'ar 9/16/1998 01:42'! push: object stack addLast: object! ! !InterpreterProxy methodsFor: 'stack access' stamp: 'ar 10/10/1998 21:16'! pushBool: trueOrFalse (trueOrFalse == true or:[trueOrFalse == false]) ifFalse:[self error:'Not a Boolean']. self push: trueOrFalse! ! !InterpreterProxy methodsFor: 'stack access' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:35'! pushFloat: f f class == Float ifFalse:[^self error:'Not a Float']. self push: f.! ! !InterpreterProxy methodsFor: 'stack access' stamp: 'ar 10/10/1998 21:20'! pushInteger: integerValue self push: (self integerObjectOf: integerValue).! ! !InterpreterProxy methodsFor: 'instance creation' stamp: 'ar 9/16/1998 01:14'! pushRemappableOop: oop remapBuffer addLast: oop! ! !InterpreterProxy methodsFor: 'other' stamp: 'ar 9/16/1998 20:52'! showDisplayBits: aForm Left: l Top: t Right: r Bottom: b aForm == Display ifTrue:[ Display forceToScreen: (Rectangle left: l right: r top: t bottom: b)].! ! !InterpreterProxy methodsFor: 'other' stamp: 'JMM 6/6/2000 21:00'! signalSemaphoreWithIndex: semaIndex ((Smalltalk externalObjects) at: semaIndex) signal! ! !InterpreterProxy methodsFor: 'converting' stamp: 'ar 11/29/1999 22:01'! signed32BitIntegerFor: integerValue integerValue isInteger ifFalse:[self error:'Not an Integer object']. ^integerValue! ! !InterpreterProxy methodsFor: 'converting' stamp: 'ar 11/29/1999 22:00'! signed32BitValueOf: oop oop isInteger ifFalse:[self error:'Not an integer object']. ^oop! ! !InterpreterProxy methodsFor: 'converting' stamp: 'JMM 11/8/2001 15:27'! signed64BitIntegerFor: integerValue integerValue isInteger ifFalse:[self error:'Not an Integer object']. ^integerValue! ! !InterpreterProxy methodsFor: 'converting' stamp: 'JMM 11/8/2001 15:27'! signed64BitValueOf: oop oop isInteger ifFalse:[self error:'Not an integer object']. ^oop! ! !InterpreterProxy methodsFor: 'object access' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:35'! sizeOfSTArrayFromCPrimitive: cPtr "Note: Only called by translated primitive code." ^self shouldNotImplement! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 10/7/1998 18:24'! slotSizeOf: oop "Returns the number of slots in the receiver. If the receiver is a byte object, return the number of bytes. Otherwise return the number of words." ^(oop basicSize) + (oop class instSize)! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 9/16/1998 01:53'! stObject: array at: index ^array at: index! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 9/16/1998 01:53'! stObject: array at: index put: value ^array at: index put: value! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 10/7/1998 18:26'! stSizeOf: oop "Return the number of indexable fields in the receiver" ^oop basicSize! ! !InterpreterProxy methodsFor: 'stack access' stamp: 'ar (auto pragmas 12/08) 9/27/1998 15:22'! stackFloatValue: offset | oop | oop := self stackValue: offset. (self isFloatObject: oop) ifFalse: [self primitiveFail. ^0.0]. ^oop! ! !InterpreterProxy methodsFor: 'stack access' stamp: 'ar 9/16/1998 22:07'! stackIntegerValue: offset | oop | oop := self stackValue: offset. (self isIntegerObject: oop) ifFalse: [self primitiveFail. ^0]. ^oop! ! !InterpreterProxy methodsFor: 'stack access' stamp: 'ar 9/16/1998 22:07'! stackObjectValue: offset | oop | oop := self stackValue: offset. (self isIntegerObject: oop) ifTrue: [self primitiveFail. ^ nil]. ^oop! ! !InterpreterProxy methodsFor: 'stack access' stamp: 'ar 9/16/1998 11:47'! stackValue: offset ^stack at: stack size - offset.! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 10/25/1998 16:16'! storeInteger: index ofObject: oop withValue: integer (self isIntegerValue: integer) ifTrue:[^self storePointer: index ofObject: oop withValue: integer] ifFalse:[^self primitiveFail]! ! !InterpreterProxy methodsFor: 'object access' stamp: 'ar 10/10/1998 21:25'! storePointer: index ofObject: oop withValue: valuePointer ^oop instVarAt: index+1 put: valuePointer! ! !InterpreterProxy methodsFor: 'other' stamp: 'ar 9/19/1998 13:30'! success: aBoolean successFlag not ifTrue:[^self]. successFlag := successFlag and:[aBoolean]. successFlag not ifTrue:[ (self confirm:'A primitive is failing -- Stop simulation?') ifTrue:[self halt]].! ! !InterpreterProxy methodsFor: 'other' stamp: 'ar 9/16/1998 20:51'! superclassOf: classPointer ^classPointer superclass! ! !InterpreterProxy methodsFor: 'special objects' stamp: 'ar 9/16/1998 20:41'! trueObject ^true! ! !InterpreterProxy methodsFor: 'other' stamp: 'tpr 12/22/2005 17:48'! vmEndianness "return 0 for little endian, 1 for big endian" ^SmalltalkImage current endianness =#big ifTrue:[1] ifFalse:[0]! ! Object subclass: #InterpreterSimulationObject instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'VMMaker-Plugins'! !InterpreterSimulationObject methodsFor: 'simulation' stamp: 'di 8/5/2004 18:55'! cCoerce: value to: cTypeString "Here the Simulator has a chance to create properly typed flavors of CArray access." value isCObjectAccessor ifTrue: [^ self getInterpreter cCoerce: value to: cTypeString]. (value isMemberOf: CArray) ifTrue: [^ self getInterpreter cCoerce: value to: cTypeString]. ^ value! ! !InterpreterSimulationObject methodsFor: 'memory access' stamp: 'di 8/5/2004 20:56'! long32At: byteAddress "Simulation support. Answer the 32-bit word at byteAddress which must be 0 mod 4." ^self getInterpreter long32At: byteAddress! ! !InterpreterSimulationObject methodsFor: 'memory access' stamp: 'di 8/5/2004 20:56'! long32At: byteAddress put: a32BitValue "Simulation support. Store the 32-bit value at byteAddress which must be 0 mod 4." ^self getInterpreter long32At: byteAddress put: a32BitValue! ! !InterpreterSimulationObject methodsFor: 'memory access' stamp: 'ikp 8/3/2004 15:56'! oopForPointer: aPointer "Simulation support. Pointers and oops are the same when simulating; answer aPointer." ^aPointer! ! !InterpreterSimulationObject methodsFor: 'memory access' stamp: 'ikp 8/3/2004 15:56'! pointerForOop: anOop "Simulation support. Pointers and oops are the same when simulating; answer anOop." ^anOop! ! !Object class methodsFor: '*VMMaker-plugin generation' stamp: 'acg 9/17/1999 01:05'! ccg: cg emitLoadFor: aString from: anInteger on: aStream cg emitLoad: aString asNakedOopFrom: anInteger on: aStream! ! !Object class methodsFor: '*VMMaker-plugin generation' stamp: 'acg 9/20/1999 13:01'! ccg: cg generateCoerceToOopFrom: aNode on: aStream cg emitCExpression: aNode on: aStream! ! !Object class methodsFor: '*VMMaker-plugin generation' stamp: 'acg 10/5/1999 06:10'! ccg: cg generateCoerceToValueFrom: aNode on: aStream cg emitCExpression: aNode on: aStream! ! !Object class methodsFor: '*VMMaker-plugin generation' stamp: 'acg 9/18/1999 16:09'! ccg: cg prolog: aBlock expr: aString index: anInteger ^cg ccgLoad: aBlock expr: aString asKindOf: self from: anInteger! ! !Object class methodsFor: '*VMMaker-plugin generation' stamp: 'acg 9/20/1999 11:12'! ccgCanConvertFrom: anObject ^anObject isKindOf: self! ! !Object class methodsFor: '*VMMaker-plugin generation' stamp: 'ikp 3/31/2005 14:20'! ccgDeclareCForVar: aSymbolOrString ^'sqInt ', aSymbolOrString! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'acg 9/19/1999 20:39'! asIf: aClass var: aString |index| index := aClass allInstVarNames indexOf: aString ifAbsent: [self error: 'must use instVar name']. ^self instVarAt: index ! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'acg 10/5/1999 06:35'! asIf: aClass var: aString asValue: someClass ^(self asIf: aClass var: aString) asValue: someClass ! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'acg 9/19/1999 20:40'! asIf: aClass var: aString put: aValue |index| index := aClass allInstVarNames indexOf: aString ifAbsent: [self error: 'must use instVar name']. ^self instVarAt: index put: aValue ! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'acg 9/20/1999 11:30'! asOop: aClass (self class isVariable and: [self class instSize > 0]) ifTrue: [self error: 'cannot auto-coerce indexable objects with named instance variables']. (aClass ccgCanConvertFrom: self) ifFalse: [self error: 'incompatible object for this coercion']. ^self! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'acg 9/19/1999 20:21'! asSmallIntegerObj ^self! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'acg 10/5/1999 06:21'! asValue: aClass ^self! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'dtl 10/12/2010 20:16'! buildCodeGeneratorUpTo: aClass "Build a CCodeGenerator for this class. By default, generate only the the methods for aClass." | cg | cg := self codeGeneratorClass new initialize. cg declareModuleName: self name. cg addClass: aClass. ^cg ! ! !Object methodsFor: '*VMMaker-translation support'! cCode: codeString "For translation only; noop when running in Smalltalk."! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'eem 9/16/2009 18:08'! cCode: codeStringOrBlock inSmalltalk: aBlock "Support for Smalltalk-to-C translation. The first argument is output when generating C code. But if this code is being simulated in Smalltalk, answer the result of evaluating the given block. If the first argument is a string it is output literally, and if it is a block it is translated." ^aBlock value ! ! !Object methodsFor: '*VMMaker-translation support'! cCoerce: value to: cType "Type coercion for translation only; just return the value when running in Smalltalk." ^ value! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'dtl 10/12/2010 20:16'! codeGeneratorClass ^CCodeGenerator! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'sr 12/23/2001 21:38'! debugCode: aBlock "Sending this message tells the code generator that there is debug code in aBlock. Debug code will be be generated only, if the correponding flag has been set by TestCodeGenerator>>generateDebugCode:. In ST simulation just perform the debug code." aBlock value! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'ar 9/18/1998 23:27'! export: aBoolean "For translation only; noop when running in Smalltalk."! ! !Object methodsFor: '*VMMaker-translation support' stamp: '' prior: 25009951! inline: inlineFlag "For translation only; noop when running in Smalltalk."! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'di 7/14/2004 12:15'! isCObjectAccessor ^ false! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'dtl 11/9/2006 19:37'! isDefined: directiveString inSmalltalk: conditionBlock comment: commentStringOrNil ifTrue: trueExpressionOrBlock "When translated, produces #ifdef #endif CPP directives. Example usage: self isDefined: 'HAVE_FOO' inSmalltalk: [self isFoo] comment: 'some platforms do not support foo properly' ifTrue: [self doThingsThatWorkIfFooIsPresent] Generated C code: # ifdef HAVE_FOO // some platforms do not support foo properly doThingsThatWorkIfFooIsPresent(); # endif // HAVE_FOO " ^ self isDefined: directiveString inSmalltalk: conditionBlock comment: commentStringOrNil ifTrue: trueExpressionOrBlock ifFalse: [] ! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'dtl 11/9/2006 19:59'! isDefined: directiveString inSmalltalk: conditionBlock comment: commentStringOrNil ifTrue: trueExpressionOrBlock ifFalse: falseExpressionOrBlockOrNil "When translated, produces #ifdef #else #endif CPP directives. Example usage: Smalltalk Slang: self isDefined: 'HAVE_FOO' inSmalltalk: [self isFoo] comment: 'some platforms do not support foo properly' ifTrue: [self doThingsThatWorkIfFooIsPresent] ifFalse: [self doSomethingElseInstead] Generated C code: # ifdef HAVE_FOO // some platforms do not support foo properly doThingsThatWorkIfFooIsPresent(); # else doSomethingElseInstead(); # endif // HAVE_FOO Smalltalk Slang: hasFoo := self isDefined: 'HAVE_FOO' inSmalltalk: [self isFoo] comment: 'some platforms do not support foo properly' ifTrue: [true] ifFalse: [false]. Generated C code: hasFoo = # ifdef HAVE_FOO // some platforms do not support foo properly 1 # else 0 # endif // HAVE_FOO ; " ^ conditionBlock value ifTrue: [trueExpressionOrBlock value] ifFalse: [falseExpressionOrBlockOrNil value] ! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'dtl 5/17/2010 15:14'! isDefinedTrueExpression: condition inSmalltalk: conditionBlock comment: commentStringOrNil ifTrue: trueExpressionOrBlock ifFalse: falseExpressionOrBlockOrNil "When translated, produces #if (condition) #else #endif CPP directives. Example usage: self isDefinedTrueExpression: 'BytesPerWord == 8' inSmalltalk: [BytesPerWord = 8] comment: 'conditional on object word size' ifTrue: [self doSomethingFor64BitWord] ifFalse: [self doSomethingFor32BitWord]" ^ conditionBlock value ifTrue: [trueExpressionOrBlock value] ifFalse: [falseExpressionOrBlockOrNil value] ! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'dtl 8/14/2009 09:31'! preprocessorExpression: directive "For translation only; noop when running in Smalltalk. When translated, emits directive as a C preprocessor directive. Example usage: self preprocessorExpression: 'ifdef HAS_FOO'. self doFooStuff. self preprocessorExpression: 'endif'. Generated C code: # ifdef HAS_FOO doFooStuff(); # endif "! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'nk 4/5/2005 20:50'! primitive: primName "For translation only; noop when running in Smalltalk."! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'nk 4/5/2005 20:50'! primitive: primName parameters: parms "For translation only; noop when running in Smalltalk."! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'tpr 6/9/2003 16:40'! primitive: primID parameters: parmSpecs receiver: rcvrSpec "belongs in CCG package" | tMethod | tMethod := SmartSyntaxPluginTMethod new fromContext: thisContext sender primitive: primID parameters: parmSpecs receiver: rcvrSpec. ^tMethod simulatePrologInContext: thisContext sender! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'acg 1/1/2000 12:45'! remapOop: oopOrList in: aBlock "For translation only; noop when running in Smalltalk." ^aBlock value! ! !Object methodsFor: '*VMMaker-translation support'! returnTypeC: typeString "For translation only; noop when running in Smalltalk."! ! !Object methodsFor: '*VMMaker-translation support'! sharedCodeNamed: label inCase: caseNumber "For translation only; noop when running in Smalltalk."! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'acg 1/1/2000 12:46'! stAt: index ^self at: index! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'acg 1/1/2000 12:46'! stAt: index put: value ^self at: index put: value! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'acg 1/1/2000 22:42'! stSize ^self size! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'ar 2/21/2000 00:42'! static: aBoolean "For translation only; noop when running in Smalltalk."! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'acg 12/18/1999 11:31'! suppressFailureGuards: failureGuardFlag "For translation only; noop when running in Smalltalk."! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'nk 4/5/2005 20:45'! touch: something "For translation only; eliminated by CCodeGenerator"! ! !Object methodsFor: '*VMMaker-translation support' stamp: '' prior: 25010074! var: varSymbol declareC: declString "For translation only; noop when running in Smalltalk."! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'sma 3/3/2000 12:06'! var: varSymbol type: typeString "For translation only; noop when running in Smalltalk."! ! !Object methodsFor: '*VMMaker-translation support' stamp: 'sma 3/3/2000 12:06'! var: varSymbol type: typeString array: array "For translation only; noop when running in Smalltalk."! ! Object subclass: #ObjectMemory instanceVariableNames: 'memory youngStart endOfMemory memoryLimit nilObj falseObj trueObj specialObjectsOop rootTable rootTableCount extraRoots extraRootCount weakRoots weakRootCount child field parentField freeBlock lastHash allocationCount lowSpaceThreshold signalLowSpace compStart compEnd fwdTableNext fwdTableLast remapBuffer remapBufferCount allocationsBetweenGCs tenuringThreshold gcSemaphoreIndex gcBiasToGrow gcBiasToGrowGCLimit gcBiasToGrowThreshold statFullGCs statFullGCMSecs statIncrGCs statIncrGCMSecs statTenures statRootTableOverflows freeContexts freeLargeContexts interruptCheckCounter totalObjectCount shrinkThreshold growHeadroom headerTypeBytes youngStartLocal statMarkCount statSweepCount statMkFwdCount statCompMoveCount statGrowMemory statShrinkMemory statRootTableCount statAllocationCount statSurvivorCount statGCTime statSpecialMarkCount statIGCDeltaTime statpendingFinalizationSignals forceTenureFlag' classVariableNames: 'BlockContextProto Byte0Mask Byte0Shift Byte1Mask Byte1Shift Byte1ShiftNegated Byte2Mask Byte2Shift Byte3Mask Byte3Shift Byte3ShiftNegated Byte4Mask Byte4Shift Byte4ShiftNegated Byte5Mask Byte5Shift Byte5ShiftNegated Byte6Mask Byte6Shift Byte7Mask Byte7Shift Byte7ShiftNegated Bytes3to0Mask Bytes7to4Mask CharacterTable ClassAlien ClassArray ClassBitmap ClassBlockClosure ClassBlockContext ClassByteArray ClassCharacter ClassCompiledMethod ClassExternalAddress ClassExternalData ClassExternalFunction ClassExternalLibrary ClassExternalStructure ClassFloat ClassInteger ClassLargeNegativeInteger ClassLargePositiveInteger ClassMessage ClassMethodContext ClassPoint ClassProcess ClassPseudoContext ClassSemaphore ClassString ClassTranslatedMethod ClassUnsafeAlien ClassWeakFinalizer CompactClassMask CompactClasses ConstMinusOne ConstOne ConstTwo ConstZero ContextFixedSizePlusHeader CtxtTempFrameStart DoAssertionChecks DoBalanceChecks Done ExternalObjectsArray ExtraRootSize FalseObject GCTopMarker HashBits HashBitsOffset HeaderTypeClass HeaderTypeFree HeaderTypeGC HeaderTypeShort HeaderTypeSizeAndClass InvokeCallbackSelector LargeContextBit MethodContextProto NilContext NilObject ProcessSignalingLowSpace RemapBufferSize RootTableRedZone RootTableSize SchedulerAssociation SelectorAboutToReturn SelectorAttemptToAssign SelectorCannotInterpret SelectorCannotReturn SelectorDoesNotUnderstand SelectorMustBeBoolean SelectorRunWithIn SpecialSelectors StackStart StartField StartObj TheDisplay TheFinalizationSemaphore TheInputSemaphore TheInterruptSemaphore TheLowSpaceSemaphore TheTimerSemaphore TrueObject TypeMask Upward' poolDictionaries: '' category: 'VMMaker-Interpreter'! ObjectMemory class instanceVariableNames: 'timeStamp'! !ObjectMemory commentStamp: '' prior: 0! This class describes a 32-bit direct-pointer object memory for Smalltalk. The model is very simple in principle: a pointer is either a SmallInteger or a 32-bit direct object pointer. SmallIntegers are tagged with a low-order bit equal to 1, and an immediate 31-bit 2s-complement signed value in the rest of the word. All object pointers point to a header, which may be followed by a number of data fields. This object memory achieves considerable compactness by using a variable header size (the one complexity of the design). The format of the 0th header word is as follows: 3 bits reserved for gc (mark, root, unused) 12 bits object hash (for HashSets) 5 bits compact class index 4 bits object format 6 bits object size in 32-bit words 2 bits header type (0: 3-word, 1: 2-word, 2: forbidden, 3: 1-word) If a class is in the compact class table, then this is the only header information needed. If it is not, then it will have another header word at offset -4 bytes with its class in the high 30 bits, and the header type repeated in its low 2 bits. It the objects size is greater than 255 bytes, then it will have yet another header word at offset -8 bytes with its full word size in the high 30 bits and its header type repeated in the low two bits. The object format field provides the remaining information as given in the formatOf: method (including isPointers, isVariable, isBytes, and the low 2 size bits of byte-sized objects). This implementation includes incremental (2-generation) and full garbage collection, each with compaction and rectification of direct pointers. It also supports a bulk-become (exchange object identity) feature that allows many objects to be becomed at once, as when all instances of a class must be grown or shrunk. There is now a simple 64-bit version of the object memory. It is the simplest possible change that could work. It merely sign-extends all integer oops, and extends all object headers and oops by adding 32 zeroes in the high bits. The format of the base header word is changed in one minor, not especially elegant, way. Consider the old 32-bit header: ggghhhhhhhhhhhhcccccffffsssssstt The 64-bit header is almost identical, except that the size field (now being in units of 8 bytes, has a zero in its low-order bit. At the same time, the byte-size residue bits for byte objects, which are in the low order bits of formats 8-11 and 12-15, are now in need of another bit of residue. So, the change is as follows: ggghhhhhhhhhhhhcccccffffsssssrtt where bit r supplies the 4's bit of the byte size residue for byte objects. Oh, yes, this is also needed now for 'variableWord' objects, since their size in 32-bit words requires a low-order bit. See the comment in formatOf: for the change allowing for 64-bit wide bitmaps, now dubbed 'variableLong'.! ObjectMemory class instanceVariableNames: 'timeStamp'! ObjectMemory subclass: #Interpreter instanceVariableNames: 'activeContext theHomeContext method receiver instructionPointer stackPointer localIP localSP localHomeContext localReturnContext localReturnValue messageSelector argumentCount newMethod currentBytecode successFlag primitiveIndex primitiveFunctionPointer methodCache atCache lkupClass reclaimableContextCount nextPollTick nextWakeupTick lastTick interruptKeycode interruptPending semaphoresToSignalA semaphoresUseBufferA semaphoresToSignalCountA semaphoresToSignalB semaphoresToSignalCountB processSignalingLowSpace savedWindowSize fullScreenFlag deferDisplayUpdates pendingFinalizationSignals compilerInitialized compilerHooks extraVMMemory newNativeMethod methodClass receiverClass interpreterVersion imageFormatVersionNumber interpreterProxy showSurfaceFn interruptCheckCounterFeedBackReset interruptChecksEveryNms externalPrimitiveTable primitiveTable globalSessionID jmpBuf jmpDepth jmpMax suspendedCallbacks suspendedMethods primFailCode imageFormatInitialVersion' classVariableNames: 'ActiveProcessIndex AtCacheEntries AtCacheFixedFields AtCacheFmt AtCacheMask AtCacheOop AtCacheSize AtCacheTotalSize AtPutBase BlockArgumentCountIndex BlockMethodIndex BytecodeTable CacheProbeMax CallerIndex CharacterValueIndex ClosureCopiedValuesIndex ClosureFirstCopiedValueIndex ClosureIndex ClosureMethodIndex ClosureNumArgsIndex ClosureOuterContextIndex ClosureStartPCIndex CompilerHooksSize CrossedX DirBadPath DirEntryFound DirNoMoreEntries EndOfRun ExcessSignalsIndex FirstLinkIndex HeaderIndex HomeIndex InitialIPIndex InstanceSpecificationIndex InstructionPointerIndex InterpreterSourceVersion JitterTable LastLinkIndex LiteralStart MaxExternalPrimitiveTableSize MaxJumpBuf MaxPrimitiveIndex MessageArgumentsIndex MessageDictionaryIndex MessageLookupClassIndex MessageSelectorIndex MethodArrayIndex MethodCacheClass MethodCacheEntries MethodCacheEntrySize MethodCacheMask MethodCacheMethod MethodCacheNative MethodCachePrim MethodCachePrimFunction MethodCacheSelector MethodCacheSize MethodIndex MillisecondClockMask MyListIndex NextLinkIndex PrimErrBadArgument PrimErrBadIndex PrimErrBadNumArgs PrimErrBadReceiver PrimErrGenericFailure PrimErrInappropriate PrimErrNoCMemory PrimErrNoMemory PrimErrNoModification PrimErrNotFound PrimErrTableIndex PrimErrUnsupported PrimNoErr PrimitiveExternalCallIndex PrimitiveTable PriorityIndex ProcessListsIndex ReceiverIndex SelectorStart SemaphoresToSignalSize SenderIndex StackPointerIndex StreamArrayIndex StreamIndexIndex StreamReadLimitIndex StreamWriteLimitIndex SuperclassIndex SuspendedContextIndex TempFrameStart ValueIndex XIndex YIndex' poolDictionaries: '' category: 'VMMaker-Interpreter'! !Interpreter commentStamp: '' prior: 0! This class is a complete implementation of the Smalltalk-80 virtual machine, derived originally from the Blue Book specification but quite different in some areas. It has been modernized with 32-bit pointers, better management of Contexts, and attention to variable use that allows the CCodeGenerator (qv) to keep, eg, the instruction pointer and stack pointer in registers as well as keeping most simple variables in a global array that seems to improve performance for most platforms. In addition to SmallInteger arithmetic and Floats, it supports logic on 32-bit PositiveLargeIntegers, thus allowing it to simulate itself much more effectively than would otherwise be the case. NOTE: Here follows a list of things to be borne in mind when working on this code, or when making changes for the future. 1. There are a number of things that should be done the next time we plan to release a copletely incompatible image format. These include unifying the instanceSize field of the class format word -- see instantiateClass:indexableSize:, and unifying the bits of the method primitive index (if we decide we need more than 512, after all) -- see primitiveIndexOf:. Also, contexts should be given a special format code (see next item). 2. There are several fast checks for contexts (see isContextHeader: and isMethodContextHeader:) which will fail if the compact class indices of BlockContext or MethodContext change. This is necessary because the oops may change during a compaction when the oops are being adjusted. It's important to be aware of this when writing a new image using the systemTracer. A better solution would be to reserve one of the format codes for Contexts only. 3. We have made normal files tolerant to size and positions up to 32 bits. This has not been done for async files, since they are still experimental. The code in size, at: and at:put: should work with sizes and indices up to 31 bits, although I have not tested it (di 12/98); it might or might not work with 32-bit sizes. 4. Note that 0 is used in a couple of places as an impossible oop. This should be changed to a constant that really is impossible (or perhaps there is code somewhere that guarantees it --if so it should be put in this comment). The places include the method cache and the at cache. ! !Interpreter class methodsFor: 'constants'! bytecodeTable ^ BytecodeTable! ! !Interpreter class methodsFor: 'translation' stamp: 'dtl 10/5/2010 23:19'! declareCVarsIn: aCCodeGenerator aCCodeGenerator addHeaderFile:''. aCCodeGenerator var: #interpreterProxy type: #'struct VirtualMachine*'. aCCodeGenerator var: #primitiveTable declareC: 'void *primitiveTable[', (MaxPrimitiveIndex +2) printString, '] = ', self primitiveTableString. aCCodeGenerator var: #primitiveFunctionPointer declareC: 'void *primitiveFunctionPointer' . "xxxx FIX THIS STUPIDITY xxxx - ikp. What he means is use a better type than void *, apparently - tpr" aCCodeGenerator var: #methodCache declareC: 'long methodCache[', (MethodCacheSize + 1) printString, ']'. aCCodeGenerator var: #atCache declareC: 'sqInt atCache[', (AtCacheTotalSize + 1) printString, ']'. aCCodeGenerator var: #statGCTime type: #'sqLong'. aCCodeGenerator var: #statFullGCMSecs type: #'sqLong'. aCCodeGenerator var: #statIGCDeltaTime type: #'sqLong'. aCCodeGenerator var: #statIncrGCMSecs type: #'sqLong'. aCCodeGenerator var: #localIP type: #'char*'. aCCodeGenerator var: #localSP type: #'char*'. aCCodeGenerator var: #showSurfaceFn type: #'void*'. aCCodeGenerator var: 'semaphoresToSignalA' declareC: 'sqInt semaphoresToSignalA[', (SemaphoresToSignalSize + 1) printString, ']'. aCCodeGenerator var: 'semaphoresToSignalB' declareC: 'sqInt semaphoresToSignalB[', (SemaphoresToSignalSize + 1) printString, ']'. aCCodeGenerator var: #compilerHooks declareC: 'sqInt (*compilerHooks[', (CompilerHooksSize + 1) printString, '])()'. aCCodeGenerator var: #interpreterVersion declareC: 'const char *interpreterVersion = "', SmalltalkImage current datedVersion, ' [', SmalltalkImage current lastUpdateString,']"'. aCCodeGenerator var: #obsoleteIndexedPrimitiveTable declareC: 'char* obsoleteIndexedPrimitiveTable[][3] = ', self obsoleteIndexedPrimitiveTableString. aCCodeGenerator var: #obsoleteNamedPrimitiveTable declareC: 'const char* obsoleteNamedPrimitiveTable[][3] = ', self obsoleteNamedPrimitiveTableString. aCCodeGenerator var: #externalPrimitiveTable declareC: 'void *externalPrimitiveTable[', (MaxExternalPrimitiveTableSize + 1) printString, ']'. self declareCAsOop: { #instructionPointer . #method . #newMethod . #activeContext . #theHomeContext . #stackPointer } in: aCCodeGenerator. aCCodeGenerator var: #jmpBuf declareC: 'jmp_buf jmpBuf[', (MaxJumpBuf + 1) printString, ']'. aCCodeGenerator var: #suspendedCallbacks declareC: 'sqInt suspendedCallbacks[', (MaxJumpBuf + 1) printString, ']'. aCCodeGenerator var: #suspendedMethods declareC: 'sqInt suspendedMethods[', (MaxJumpBuf + 1) printString, ']'. "Reinitialized at interpreter entry by #initializeImageFormatVersion" aCCodeGenerator var: #imageFormatVersionNumber declareC: 'sqInt imageFormatVersionNumber = 0'. "Declared here to prevent inclusion in foo struct by CCodeGeneratorGlobalStructure" aCCodeGenerator var: #imageFormatInitialVersion declareC: 'sqInt imageFormatInitialVersion = 0' ! ! !Interpreter class methodsFor: 'initialization' stamp: 'dtl 1/19/2011 19:40'! initialize "Interpreter initialize" super initialize. "initialize ObjectMemory constants" self initializeAssociationIndex. self initializeBytecodeTable. self initializeCaches. self initializeCharacterIndex. self initializeCharacterScannerIndices. self initializeClassIndices. self initializeCompilerHooks. self initializeContextIndices. self initializeDirectoryLookupResultCodes. self initializeMessageIndices. self initializeMethodIndices. self initializePointIndices. self initializePrimitiveTable. self initializeSchedulerIndices. self initializeSmallIntegers. self initializeStreamIndices. self initializeInterpreterSourceVersion. SemaphoresToSignalSize := 500. PrimitiveExternalCallIndex := 117. "Primitive index for #primitiveExternalCall" MillisecondClockMask := 16r1FFFFFFF. "Note: The external primitive table should actually be dynamically sized but for the sake of inferior platforms (e.g., Mac :-) who cannot allocate memory in any reasonable way, we keep it static (and cross our fingers...)" MaxExternalPrimitiveTableSize := 4096. "entries" MaxJumpBuf := 32. "max. callback depth"! ! !Interpreter class methodsFor: 'initialization'! initializeAssociationIndex ValueIndex := 1! ! !Interpreter class methodsFor: 'initialization' stamp: 'eem 6/16/2008 10:07'! initializeBytecodeTable "Interpreter initializeBytecodeTable" "Note: This table will be used to generate a C switch statement." BytecodeTable := Array new: 256. self table: BytecodeTable from: #( ( 0 15 pushReceiverVariableBytecode) ( 16 31 pushTemporaryVariableBytecode) ( 32 63 pushLiteralConstantBytecode) ( 64 95 pushLiteralVariableBytecode) ( 96 103 storeAndPopReceiverVariableBytecode) (104 111 storeAndPopTemporaryVariableBytecode) (112 pushReceiverBytecode) (113 pushConstantTrueBytecode) (114 pushConstantFalseBytecode) (115 pushConstantNilBytecode) (116 pushConstantMinusOneBytecode) (117 pushConstantZeroBytecode) (118 pushConstantOneBytecode) (119 pushConstantTwoBytecode) (120 returnReceiver) (121 returnTrue) (122 returnFalse) (123 returnNil) (124 returnTopFromMethod) (125 returnTopFromBlock) (126 127 unknownBytecode) (128 extendedPushBytecode) (129 extendedStoreBytecode) (130 extendedStoreAndPopBytecode) (131 singleExtendedSendBytecode) (132 doubleExtendedDoAnythingBytecode) (133 singleExtendedSuperBytecode) (134 secondExtendedSendBytecode) (135 popStackBytecode) (136 duplicateTopBytecode) (137 pushActiveContextBytecode) (138 pushNewArrayBytecode) (139 unknownBytecode) (140 pushRemoteTempLongBytecode) (141 storeRemoteTempLongBytecode) (142 storeAndPopRemoteTempLongBytecode) (143 pushClosureCopyCopiedValuesBytecode) (144 151 shortUnconditionalJump) (152 159 shortConditionalJump) (160 167 longUnconditionalJump) (168 171 longJumpIfTrue) (172 175 longJumpIfFalse) "176-191 were sendArithmeticSelectorBytecode" (176 bytecodePrimAdd) (177 bytecodePrimSubtract) (178 bytecodePrimLessThan) (179 bytecodePrimGreaterThan) (180 bytecodePrimLessOrEqual) (181 bytecodePrimGreaterOrEqual) (182 bytecodePrimEqual) (183 bytecodePrimNotEqual) (184 bytecodePrimMultiply) (185 bytecodePrimDivide) (186 bytecodePrimMod) (187 bytecodePrimMakePoint) (188 bytecodePrimBitShift) (189 bytecodePrimDiv) (190 bytecodePrimBitAnd) (191 bytecodePrimBitOr) "192-207 were sendCommonSelectorBytecode" (192 bytecodePrimAt) (193 bytecodePrimAtPut) (194 bytecodePrimSize) (195 bytecodePrimNext) (196 bytecodePrimNextPut) (197 bytecodePrimAtEnd) (198 bytecodePrimEquivalent) (199 bytecodePrimClass) (200 bytecodePrimBlockCopy) (201 bytecodePrimValue) (202 bytecodePrimValueWithArg) (203 bytecodePrimDo) (204 bytecodePrimNew) (205 bytecodePrimNewWithArg) (206 bytecodePrimPointX) (207 bytecodePrimPointY) (208 255 sendLiteralSelectorBytecode) ).! ! !Interpreter class methodsFor: 'initialization' stamp: 'tpr 3/17/2005 10:40'! initializeCaches | atCacheEntrySize | MethodCacheEntries := 512. MethodCacheSelector := 1. MethodCacheClass := 2. MethodCacheMethod := 3. MethodCachePrim := 4. MethodCacheNative := 5. MethodCachePrimFunction := 6. MethodCacheEntrySize := 8. "Must be power of two for masking scheme." MethodCacheMask := (MethodCacheEntries - 1) * MethodCacheEntrySize. MethodCacheSize := MethodCacheEntries * MethodCacheEntrySize. CacheProbeMax := 3. AtCacheEntries := 8. "Must be a power of two" AtCacheOop := 1. AtCacheSize := 2. AtCacheFmt := 3. AtCacheFixedFields := 4. atCacheEntrySize := 4. "Must be power of two for masking scheme." AtCacheMask := (AtCacheEntries-1) * atCacheEntrySize. AtPutBase := AtCacheEntries * atCacheEntrySize. AtCacheTotalSize := AtCacheEntries * atCacheEntrySize * 2. ! ! !Interpreter class methodsFor: 'initialization'! initializeCharacterIndex CharacterValueIndex := 0! ! !Interpreter class methodsFor: 'initialization' stamp: 'tpr 4/29/2003 12:10'! initializeCharacterScannerIndices CrossedX := 258. EndOfRun := 257 ! ! !Interpreter class methodsFor: 'initialization'! initializeClassIndices "Class Class" SuperclassIndex := 0. MessageDictionaryIndex := 1. InstanceSpecificationIndex := 2. "Fields of a message dictionary" MethodArrayIndex := 1. SelectorStart := 2! ! !Interpreter class methodsFor: 'initialization' stamp: 'ikp 10/27/2000 14:47'! initializeCompilerHooks "Interpreter initializeCompilerHooks" "compilerHooks[] indices: 1 void compilerTranslateMethodHook(void) 2 void compilerFlushCacheHook(CompiledMethod *oldMethod) 3 void compilerPreGCHook(int fullGCFlag) 4 void compilerMapHook(int memStart, int memEnd) 5 void compilerPostGCHook(void) 6 void compilerProcessChangeHook(void) 7 void compilerPreSnapshotHook(void) 8 void compilerPostSnapshotHook(void) 9 void compilerMarkHook(void) 10 void compilerActivateMethodHook(void) 11 void compilerNewActiveContextHook(int sendFlag) 12 void compilerGetInstructionPointerHook(void) 13 void compilerSetInstructionPointerHook(void) 14 void compilerCreateActualMessageHook(void)" CompilerHooksSize := 15.! ! !Interpreter class methodsFor: 'initialization' stamp: 'eem 9/8/2008 16:32'! initializeContextIndices "Class MethodContext" SenderIndex := 0. InstructionPointerIndex := 1. StackPointerIndex := 2. MethodIndex := 3. ClosureIndex := 4. "N.B. Called receiverMap in the image." ReceiverIndex := 5. TempFrameStart := 6. "Note this is in two places!!" "Class BlockContext" CallerIndex := 0. BlockArgumentCountIndex := 3. InitialIPIndex := 4. HomeIndex := 5. "Class BlockClosure" ClosureOuterContextIndex := 0. ClosureStartPCIndex := 1. ClosureNumArgsIndex := 2. ClosureFirstCopiedValueIndex := 3! ! !Interpreter class methodsFor: 'initialization'! initializeDirectoryLookupResultCodes DirEntryFound := 0. DirNoMoreEntries := 1. DirBadPath := 2.! ! !Interpreter class methodsFor: 'initialization' stamp: 'dtl 4/10/2010 12:19'! initializeInterpreterSourceVersion "Identify the VMMaker source version that generated the C code for an interpreter. Provides a runtime version identification test." Smalltalk at: #VMMaker ifPresent: [:vmm | ^ InterpreterSourceVersion := vmm versionString]. ^ InterpreterSourceVersion := ''! ! !Interpreter class methodsFor: 'initialization' stamp: 'di 3/25/1999 22:09'! initializeMessageIndices MessageSelectorIndex := 0. MessageArgumentsIndex := 1. MessageLookupClassIndex := 2.! ! !Interpreter class methodsFor: 'initialization'! initializeMethodIndices "Class CompiledMethod" HeaderIndex := 0. LiteralStart := 1! ! !Interpreter class methodsFor: 'initialization'! initializePointIndices XIndex := 0. YIndex := 1! ! !Interpreter class methodsFor: 'initialization' stamp: 'dtl 12/11/2010 13:08'! initializePrimitiveTable "This table generates a C function address table use in primitiveResponse along with dispatchFunctionPointerOn:in:" "NOTE: The real limit here is 2047 because of the method header layout but there is no point in going over the needed size" MaxPrimitiveIndex := 575. PrimitiveTable := Array new: MaxPrimitiveIndex + 1. self table: PrimitiveTable from: #( "Integer Primitives (0-19)" (0 primitiveFail) (1 primitiveAdd) (2 primitiveSubtract) (3 primitiveLessThan) (4 primitiveGreaterThan) (5 primitiveLessOrEqual) (6 primitiveGreaterOrEqual) (7 primitiveEqual) (8 primitiveNotEqual) (9 primitiveMultiply) (10 primitiveDivide) (11 primitiveMod) (12 primitiveDiv) (13 primitiveQuo) (14 primitiveBitAnd) (15 primitiveBitOr) (16 primitiveBitXor) (17 primitiveBitShift) (18 primitiveMakePoint) (19 primitiveFail) "Guard primitive for simulation -- *must* fail" "LargeInteger Primitives (20-39)" (20 primitiveFail) (21 primitiveAddLargeIntegers) (22 primitiveSubtractLargeIntegers) (23 primitiveLessThanLargeIntegers) (24 primitiveGreaterThanLargeIntegers) (25 primitiveLessOrEqualLargeIntegers) (26 primitiveGreaterOrEqualLargeIntegers) (27 primitiveEqualLargeIntegers) (28 primitiveNotEqualLargeIntegers) (29 primitiveMultiplyLargeIntegers) (30 primitiveDivideLargeIntegers) (31 primitiveModLargeIntegers) (32 primitiveDivLargeIntegers) (33 primitiveQuoLargeIntegers) (34 primitiveBitAndLargeIntegers) (35 primitiveBitOrLargeIntegers) (36 primitiveBitXorLargeIntegers) (37 primitiveBitShiftLargeIntegers) (38 primitiveFail) (39 primitiveFail) "Float Primitives (40-59)" (40 primitiveAsFloat) (41 primitiveFloatAdd) (42 primitiveFloatSubtract) (43 primitiveFloatLessThan) (44 primitiveFloatGreaterThan) (45 primitiveFloatLessOrEqual) (46 primitiveFloatGreaterOrEqual) (47 primitiveFloatEqual) (48 primitiveFloatNotEqual) (49 primitiveFloatMultiply) (50 primitiveFloatDivide) (51 primitiveTruncated) (52 primitiveFractionalPart) (53 primitiveExponent) (54 primitiveTimesTwoPower) (55 primitiveSquareRoot) (56 primitiveSine) (57 primitiveArctan) (58 primitiveLogN) (59 primitiveExp) "Subscript and Stream Primitives (60-67)" (60 primitiveAt) (61 primitiveAtPut) (62 primitiveSize) (63 primitiveStringAt) (64 primitiveStringAtPut) (65 primitiveFail) "was primitiveNext which no longer pays its way (normal Smalltalk code is faster)" (66 primitiveFail) "was primitiveNextPut which no longer pays its way (normal Smalltalk code is faster)" (67 primitiveFail) "was primitiveAtEnd which no longer pays its way (normal Smalltalk code is faster)" "StorageManagement Primitives (68-79)" (68 primitiveObjectAt) (69 primitiveObjectAtPut) (70 primitiveNew) (71 primitiveNewWithArg) (72 primitiveArrayBecomeOneWay) "Blue Book: primitiveBecome" (73 primitiveInstVarAt) (74 primitiveInstVarAtPut) (75 primitiveAsOop) (76 primitiveStoreStackp) "Blue Book: primitiveAsObject" (77 primitiveSomeInstance) (78 primitiveNextInstance) (79 primitiveNewMethod) "Control Primitives (80-89)" (80 primitiveBlockCopy) (81 primitiveValue) (82 primitiveValueWithArgs) (83 primitivePerform) (84 primitivePerformWithArgs) (85 primitiveSignal) (86 primitiveWait) (87 primitiveResume) (88 primitiveSuspend) (89 primitiveFlushCache) "Input/Output Primitives (90-109)" (90 primitiveMousePoint) (91 primitiveTestDisplayDepth) "Blue Book: primitiveCursorLocPut" (92 primitiveSetDisplayMode) "Blue Book: primitiveCursorLink" (93 primitiveInputSemaphore) (94 primitiveGetNextEvent) "Blue Book: primitiveSampleInterval" (95 primitiveInputWord) (96 primitiveFail) "primitiveCopyBits" (97 primitiveSnapshot) (98 primitiveStoreImageSegment) (99 primitiveLoadImageSegment) (100 primitivePerformInSuperclass) "Blue Book: primitiveSignalAtTick" (101 primitiveBeCursor) (102 primitiveBeDisplay) (103 primitiveScanCharacters) (104 primitiveFail) "primitiveDrawLoop" (105 primitiveStringReplace) (106 primitiveScreenSize) (107 primitiveMouseButtons) (108 primitiveKbdNext) (109 primitiveKbdPeek) "System Primitives (110-119)" (110 primitiveEquivalent) (111 primitiveClass) (112 primitiveBytesLeft) (113 primitiveQuit) (114 primitiveExitToDebugger) (115 primitiveChangeClass) "Blue Book: primitiveOopsLeft" (116 primitiveFlushCacheByMethod) (117 primitiveExternalCall) (118 primitiveDoPrimitiveWithArgs) (119 primitiveFlushCacheSelective) "Squeak 2.2 and earlier use 119. Squeak 2.3 and later use 116. Both are supported for backward compatibility." "Miscellaneous Primitives (120-127)" (120 primitiveCalloutToFFI) (121 primitiveImageName) (122 primitiveNoop) "Blue Book: primitiveImageVolume" (123 primitiveValueUninterruptably) "@@@: Remove this when all VMs have support" (124 primitiveLowSpaceSemaphore) (125 primitiveSignalAtBytesLeft) "Squeak Primitives Start Here" "Squeak Miscellaneous Primitives (128-149)" (126 primitiveDeferDisplayUpdates) (127 primitiveShowDisplayRect) (128 primitiveArrayBecome) (129 primitiveSpecialObjectsOop) (130 primitiveFullGC) (131 primitiveIncrementalGC) (132 primitiveObjectPointsTo) (133 primitiveSetInterruptKey) (134 primitiveInterruptSemaphore) (135 primitiveMillisecondClock) (136 primitiveSignalAtMilliseconds) (137 primitiveSecondsClock) (138 primitiveSomeObject) (139 primitiveNextObject) (140 primitiveBeep) (141 primitiveClipboardText) (142 primitiveVMPath) (143 primitiveShortAt) (144 primitiveShortAtPut) (145 primitiveConstantFill) "NOTE: When removing the obsolete indexed primitives, the following two should go become #primitiveIntegerAt / atPut" (146 primitiveFail) "primitiveReadJoystick" (147 primitiveFail) "primitiveWarpBits" (148 primitiveClone) (149 primitiveGetAttribute) "File Primitives (150-169) - NO LONGER INDEXED" (150 159 primitiveFail) (160 primitiveAdoptInstance) (161 164 primitiveFail) (165 primitiveIntegerAt) "hacked in here for now" (166 primitiveIntegerAtPut) (167 primitiveYield) (168 primitiveCopyObject) (169 primitiveFail) "Sound Primitives (170-199) - NO LONGER INDEXED" (170 185 primitiveFail) "Old closure primitives" (186 primitiveFail) "was primitiveClosureValue" (187 primitiveFail) "was primitiveClosureValueWithArgs" "Perform method directly" (188 primitiveExecuteMethodArgsArray) (189 primitiveExecuteMethod) "Sound Primitives (continued) - NO LONGER INDEXED" (190 194 primitiveFail) "Unwind primitives" (195 primitiveFindNextUnwindContext) (196 primitiveTerminateTo) (197 primitiveFindHandlerContext) (198 primitiveMarkUnwindMethod) (199 primitiveMarkHandlerMethod) "new closure primitives (were Networking primitives)" (200 primitiveClosureCopyWithCopiedValues) (201 primitiveClosureValue) "value" (202 primitiveClosureValue) "value:" (203 primitiveClosureValue) "value:value:" (204 primitiveClosureValue) "value:value:value:" (205 primitiveClosureValue) "value:value:value:value:" (206 primitiveClosureValueWithArgs) "valueWithArguments:" (207 209 primitiveFail) "reserved for Cog primitives" (210 primitiveAt) "Compatibility with Cog StackInterpreter Context primitives" (211 primitiveAtPut) "Compatibility with Cog StackInterpreter Context primitives" (212 primitiveSize) "Compatibility with Cog StackInterpreter Context primitives" (213 219 primitiveFail) "reserved for Cog primitives" (220 primitiveFail) "reserved for Cog primitives" (221 primitiveClosureValueNoContextSwitch) "valueNoContextSwitch" (222 primitiveClosureValueNoContextSwitch) "valueNoContextSwitch:" (223 229 primitiveFail) "reserved for Cog primitives" (230 primitiveRelinquishProcessor) (231 primitiveForceDisplayUpdate) (232 primitiveFormPrint) (233 primitiveSetFullScreen) (234 primitiveFail) "primBitmapdecompressfromByteArrayat" (235 primitiveFail) "primStringcomparewithcollated" (236 primitiveFail) "primSampledSoundconvert8bitSignedFromto16Bit" (237 primitiveFail) "primBitmapcompresstoByteArray" (238 241 primitiveFail) "serial port primitives" (242 primitiveFail) (243 primitiveFail) "primStringtranslatefromtotable" (244 primitiveFail) "primStringfindFirstInStringinSetstartingAt" (245 primitiveFail) "primStringindexOfAsciiinStringstartingAt" (246 primitiveFail) "primStringfindSubstringinstartingAtmatchTable" (247 primitiveSnapshotEmbedded) (248 primitiveInvokeObjectAsMethod) (249 primitiveArrayBecomeOneWayCopyHash) "VM Implementor Primitives (250-255)" (250 clearProfile) (251 dumpProfile) (252 startProfiling) (253 stopProfiling) (254 primitiveVMParameter) (255 primitiveInstVarsPutFromStack) "Never used except in Disney tests. Remove after 2.3 release." "Quick Push Const Methods" (256 primitivePushSelf) (257 primitivePushTrue) (258 primitivePushFalse) (259 primitivePushNil) (260 primitivePushMinusOne) (261 primitivePushZero) (262 primitivePushOne) (263 primitivePushTwo) "Quick Push Const Methods" (264 519 primitiveLoadInstVar) "These ranges used to be used by obsiolete indexed primitives." (520 529 primitiveFail) (530 539 primitiveFail) (540 549 primitiveFail) (550 559 primitiveFail) (560 569 primitiveFail) "External primitive support primitives" (570 primitiveFlushExternalPrimitives) (571 primitiveUnloadModule) (572 primitiveListBuiltinModule) (573 primitiveListExternalModule) (574 primitiveFail) "reserved for addl. external support prims" "Unassigned Primitives" (575 primitiveFail)). ! ! !Interpreter class methodsFor: 'initialization'! initializeSchedulerIndices "Class ProcessorScheduler" ProcessListsIndex := 0. ActiveProcessIndex := 1. "Class LinkedList" FirstLinkIndex := 0. LastLinkIndex := 1. "Class Semaphore" ExcessSignalsIndex := 2. "Class Link" NextLinkIndex := 0. "Class Process" SuspendedContextIndex := 1. PriorityIndex := 2. MyListIndex := 3! ! !Interpreter class methodsFor: 'initialization'! initializeSmallIntegers "SmallIntegers" ConstMinusOne := Interpreter new integerObjectOf: -1. ConstZero := Interpreter new integerObjectOf: 0. ConstOne := Interpreter new integerObjectOf: 1. ConstTwo := Interpreter new integerObjectOf: 2! ! !Interpreter class methodsFor: 'initialization'! initializeStreamIndices StreamArrayIndex := 0. StreamIndexIndex := 1. StreamReadLimitIndex := 2. StreamWriteLimitIndex := 3.! ! !Interpreter class methodsFor: 'translation' stamp: 'eem 6/19/2008 22:16'! isNonArgumentImplicitReceiverVariableName: aString aString = 'interpreterProxy' ifTrue: [self halt]. ^'self' = aString! ! !Interpreter class methodsFor: 'translation' stamp: 'eem 12/15/2008 18:32'! isTypePointerToStruct: type "" ^false! ! !Interpreter class methodsFor: 'initialization' stamp: 'JMM 10/25/2004 16:36'! obsoleteIndexedPrimitiveTable "Interpreter obsoleteIndexedPrimitiveTableString" "Initialize the links from the (now obsolete) indexed primitives to the new named primitives." | table | table := Array new: MaxPrimitiveIndex+1. #( (96 (BitBltPlugin primitiveCopyBits)) (104 (BitBltPlugin primitiveDrawLoop)) (147 (BitBltPlugin primitiveWarpBits)) (146 (JoystickTabletPlugin primitiveReadJoystick)) "File Primitives (150-169)" (150 (FilePlugin primitiveFileAtEnd)) (151 (FilePlugin primitiveFileClose)) (152 (FilePlugin primitiveFileGetPosition)) (153 (FilePlugin primitiveFileOpen)) (154 (FilePlugin primitiveFileRead)) (155 (FilePlugin primitiveFileSetPosition)) (156 (FilePlugin primitiveFileDelete)) (157 (FilePlugin primitiveFileSize)) (158 (FilePlugin primitiveFileWrite)) (159 (FilePlugin primitiveFileRename)) (160 (FilePlugin primitiveDirectoryCreate)) (161 (FilePlugin primitiveDirectoryDelimitor)) (162 (FilePlugin primitiveDirectoryLookup)) (163 (FilePlugin primitiveDirectoryDelete)) (164 (FilePlugin primitiveDirectoryGetMacTypeAndCreator)) (169 (FilePlugin primitiveDirectorySetMacTypeAndCreator)) "Sound Primitives (170-199)" (170 (SoundPlugin primitiveSoundStart)) (171 (SoundPlugin primitiveSoundStartWithSemaphore)) (172 (SoundPlugin primitiveSoundStop)) (173 (SoundPlugin primitiveSoundAvailableSpace)) (174 (SoundPlugin primitiveSoundPlaySamples)) (175 (SoundPlugin primitiveSoundPlaySilence)) (176 (SoundGenerationPlugin primitiveWaveTableSoundMix)) (177 (SoundGenerationPlugin primitiveFMSoundMix)) (178 (SoundGenerationPlugin primitivePluckedSoundMix)) (179 (SoundGenerationPlugin primitiveSampledSoundMix)) (180 (SoundGenerationPlugin primitiveMixFMSound)) (181 (SoundGenerationPlugin primitiveMixPluckedSound)) (182 (SoundGenerationPlugin primitiveOldSampledSoundMix)) (183 (SoundGenerationPlugin primitiveApplyReverb)) (184 (SoundGenerationPlugin primitiveMixLoopedSampledSound)) (185 (SoundGenerationPlugin primitiveMixSampledSound)) (189 (SoundPlugin primitiveSoundInsertSamples)) (190 (SoundPlugin primitiveSoundStartRecording)) (191 (SoundPlugin primitiveSoundStopRecording)) (192 (SoundPlugin primitiveSoundGetRecordingSampleRate)) (193 (SoundPlugin primitiveSoundRecordSamples)) (194 (SoundPlugin primitiveSoundSetRecordLevel)) "Networking Primitives (200-229)" (200 (SocketPlugin primitiveInitializeNetwork)) (201 (SocketPlugin primitiveResolverStartNameLookup)) (202 (SocketPlugin primitiveResolverNameLookupResult)) (203 (SocketPlugin primitiveResolverStartAddressLookup)) (204 (SocketPlugin primitiveResolverAddressLookupResult)) (205 (SocketPlugin primitiveResolverAbortLookup)) (206 (SocketPlugin primitiveResolverLocalAddress)) (207 (SocketPlugin primitiveResolverStatus)) (208 (SocketPlugin primitiveResolverError)) (209 (SocketPlugin primitiveSocketCreate)) (210 (SocketPlugin primitiveSocketDestroy)) (211 (SocketPlugin primitiveSocketConnectionStatus)) (212 (SocketPlugin primitiveSocketError)) (213 (SocketPlugin primitiveSocketLocalAddress)) (214 (SocketPlugin primitiveSocketLocalPort)) (215 (SocketPlugin primitiveSocketRemoteAddress)) (216 (SocketPlugin primitiveSocketRemotePort)) (217 (SocketPlugin primitiveSocketConnectToPort)) (218 (SocketPlugin primitiveSocketListenWithOrWithoutBacklog)) (219 (SocketPlugin primitiveSocketCloseConnection)) (220 (SocketPlugin primitiveSocketAbortConnection)) (221 (SocketPlugin primitiveSocketReceiveDataBufCount)) (222 (SocketPlugin primitiveSocketReceiveDataAvailable)) (223 (SocketPlugin primitiveSocketSendDataBufCount)) (224 (SocketPlugin primitiveSocketSendDone)) (225 (SocketPlugin primitiveSocketAccept)) "Other Primitives (230-249)" (234 (MiscPrimitivePlugin primitiveDecompressFromByteArray)) (235 (MiscPrimitivePlugin primitiveCompareString)) (236 (MiscPrimitivePlugin primitiveConvert8BitSigned)) (237 (MiscPrimitivePlugin primitiveCompressToByteArray)) (238 (SerialPlugin primitiveSerialPortOpen)) (239 (SerialPlugin primitiveSerialPortClose)) (240 (SerialPlugin primitiveSerialPortWrite)) (241 (SerialPlugin primitiveSerialPortRead)) (243 (MiscPrimitivePlugin primitiveTranslateStringWithTable)) (244 (MiscPrimitivePlugin primitiveFindFirstInString)) (245 (MiscPrimitivePlugin primitiveIndexOfAsciiInString)) (246 (MiscPrimitivePlugin primitiveFindSubstring)) "MIDI Primitives (521-539)" (521 (MIDIPlugin primitiveMIDIClosePort)) (522 (MIDIPlugin primitiveMIDIGetClock)) (523 (MIDIPlugin primitiveMIDIGetPortCount)) (524 (MIDIPlugin primitiveMIDIGetPortDirectionality)) (525 (MIDIPlugin primitiveMIDIGetPortName)) (526 (MIDIPlugin primitiveMIDIOpenPort)) (527 (MIDIPlugin primitiveMIDIParameterGetOrSet)) (528 (MIDIPlugin primitiveMIDIRead)) (529 (MIDIPlugin primitiveMIDIWrite)) "Experimental Asynchrous File Primitives" (540 (AsynchFilePlugin primitiveAsyncFileClose)) (541 (AsynchFilePlugin primitiveAsyncFileOpen)) (542 (AsynchFilePlugin primitiveAsyncFileReadResult)) (543 (AsynchFilePlugin primitiveAsyncFileReadStart)) (544 (AsynchFilePlugin primitiveAsyncFileWriteResult)) (545 (AsynchFilePlugin primitiveAsyncFileWriteStart)) "Pen Tablet Primitives" (548 (JoystickTabletPlugin primitiveGetTabletParameters)) (549 (JoystickTabletPlugin primitiveReadTablet)) "Sound Codec Primitives" (550 (ADPCMCodecPlugin primitiveDecodeMono)) (551 (ADPCMCodecPlugin primitiveDecodeStereo)) (552 (ADPCMCodecPlugin primitiveEncodeMono)) (553 (ADPCMCodecPlugin primitiveEncodeStereo)) ) do:[:spec| table at: spec first+1 put: spec second]. ^table! ! !Interpreter class methodsFor: 'initialization' stamp: 'tpr 3/24/2004 21:26'! obsoleteIndexedPrimitiveTableString "Interpreter obsoleteIndexedPrimitiveTableString" "Initialize the links from the (now obsolete) indexed primitives to the new named primitives." | table | table := self obsoleteIndexedPrimitiveTable. ^ String streamContents: [:s | s nextPutAll: '{'; cr. table doWithIndex: [:primSpec :idx | primSpec ifNil: [s nextPutAll: '{ NULL, NULL, NULL }'] ifNotNil: [s nextPutAll: '{ "'; nextPutAll: primSpec first; nextPutAll: '", "'; nextPutAll: primSpec last; nextPutAll: '", NULL }']. idx < table size ifTrue: [s nextPut: $,; cr]]. s cr; nextPutAll: '}']! ! !Interpreter class methodsFor: 'initialization' stamp: 'ar 5/3/2001 13:02'! obsoleteNamedPrimitiveTable "Interpreter obsoleteNamedPrimitiveTableString" "Initialize the links from the (now obsolete) named primitives to the new named primitives." ^#( (gePrimitiveMergeFillFrom B2DPlugin primitiveMergeFillFrom) (gePrimitiveSetClipRect B2DPlugin primitiveSetClipRect) (gePrimitiveDoProfileStats B2DPlugin primitiveDoProfileStats) (gePrimitiveAddCompressedShape B2DPlugin primitiveAddCompressedShape) (gePrimitiveFinishedProcessing B2DPlugin primitiveFinishedProcessing) (gePrimitiveGetBezierStats B2DPlugin primitiveGetBezierStats) (gePrimitiveSetDepth B2DPlugin primitiveSetDepth) (gePrimitiveAbortProcessing B2DPlugin primitiveAbortProcessing) (gePrimitiveGetTimes B2DPlugin primitiveGetTimes) (gePrimitiveNextActiveEdgeEntry B2DPlugin primitiveNextActiveEdgeEntry) (gePrimitiveAddBezier B2DPlugin primitiveAddBezier) (gePrimitiveRenderScanline B2DPlugin primitiveRenderScanline) (gePrimitiveAddBezierShape B2DPlugin primitiveAddBezierShape) (gePrimitiveAddLine B2DPlugin primitiveAddLine) (gePrimitiveRenderImage B2DPlugin primitiveRenderImage) (gePrimitiveGetAALevel B2DPlugin primitiveGetAALevel) (gePrimitiveRegisterExternalEdge B2DPlugin primitiveRegisterExternalEdge) (gePrimitiveInitializeBuffer B2DPlugin primitiveInitializeBuffer) (gePrimitiveAddRect B2DPlugin primitiveAddRect) (gePrimitiveInitializeProcessing B2DPlugin primitiveInitializeProcessing) (gePrimitiveAddBitmapFill B2DPlugin primitiveAddBitmapFill) (gePrimitiveGetClipRect B2DPlugin primitiveGetClipRect) (gePrimitiveGetFailureReason B2DPlugin primitiveGetFailureReason) (gePrimitiveNextGlobalEdgeEntry B2DPlugin primitiveNextGlobalEdgeEntry) (gePrimitiveNextFillEntry B2DPlugin primitiveNextFillEntry) (gePrimitiveSetColorTransform B2DPlugin primitiveSetColorTransform) (gePrimitiveDisplaySpanBuffer B2DPlugin primitiveDisplaySpanBuffer) (gePrimitiveGetOffset B2DPlugin primitiveGetOffset) (gePrimitiveAddPolygon B2DPlugin primitiveAddPolygon) (gePrimitiveNeedsFlush B2DPlugin primitiveNeedsFlush) (gePrimitiveAddOval B2DPlugin primitiveAddOval) (gePrimitiveSetAALevel B2DPlugin primitiveSetAALevel) (gePrimitiveCopyBuffer B2DPlugin primitiveCopyBuffer) (gePrimitiveAddActiveEdgeEntry B2DPlugin primitiveAddActiveEdgeEntry) (gePrimitiveGetCounts B2DPlugin primitiveGetCounts) (gePrimitiveSetOffset B2DPlugin primitiveSetOffset) (gePrimitiveAddGradientFill B2DPlugin primitiveAddGradientFill) (gePrimitiveChangedActiveEdgeEntry B2DPlugin primitiveChangedActiveEdgeEntry) (gePrimitiveRegisterExternalFill B2DPlugin primitiveRegisterExternalFill) (gePrimitiveGetDepth B2DPlugin primitiveGetDepth) (gePrimitiveSetEdgeTransform B2DPlugin primitiveSetEdgeTransform) (gePrimitiveNeedsFlushPut B2DPlugin primitiveNeedsFlushPut) (primitiveFloatArrayAt FloatArrayPlugin primitiveAt) (primitiveFloatArrayMulFloatArray FloatArrayPlugin primitiveMulFloatArray) (primitiveFloatArrayAddScalar FloatArrayPlugin primitiveAddScalar) (primitiveFloatArrayDivFloatArray FloatArrayPlugin primitiveDivFloatArray) (primitiveFloatArrayDivScalar FloatArrayPlugin primitiveDivScalar) (primitiveFloatArrayHash FloatArrayPlugin primitiveHashArray) (primitiveFloatArrayAtPut FloatArrayPlugin primitiveAtPut) (primitiveFloatArrayMulScalar FloatArrayPlugin primitiveMulScalar) (primitiveFloatArrayAddFloatArray FloatArrayPlugin primitiveAddFloatArray) (primitiveFloatArraySubScalar FloatArrayPlugin primitiveSubScalar) (primitiveFloatArraySubFloatArray FloatArrayPlugin primitiveSubFloatArray) (primitiveFloatArrayEqual FloatArrayPlugin primitiveEqual) (primitiveFloatArrayDotProduct FloatArrayPlugin primitiveDotProduct) (m23PrimitiveInvertRectInto Matrix2x3Plugin primitiveInvertRectInto) (m23PrimitiveTransformPoint Matrix2x3Plugin primitiveTransformPoint) (m23PrimitiveIsPureTranslation Matrix2x3Plugin primitiveIsPureTranslation) (m23PrimitiveComposeMatrix Matrix2x3Plugin primitiveComposeMatrix) (m23PrimitiveTransformRectInto Matrix2x3Plugin primitiveTransformRectInto) (m23PrimitiveIsIdentity Matrix2x3Plugin primitiveIsIdentity) (m23PrimitiveInvertPoint Matrix2x3Plugin primitiveInvertPoint) (primitiveDeflateBlock ZipPlugin primitiveDeflateBlock) (primitiveDeflateUpdateHashTable ZipPlugin primitiveDeflateUpdateHashTable) (primitiveUpdateGZipCrc32 ZipPlugin primitiveUpdateGZipCrc32) (primitiveInflateDecompressBlock ZipPlugin primitiveInflateDecompressBlock) (primitiveZipSendBlock ZipPlugin primitiveZipSendBlock) (primitiveFFTTransformData FFTPlugin primitiveFFTTransformData) (primitiveFFTScaleData FFTPlugin primitiveFFTScaleData) (primitiveFFTPermuteData FFTPlugin primitiveFFTPermuteData) )! ! !Interpreter class methodsFor: 'initialization' stamp: 'tpr 3/24/2004 21:27'! obsoleteNamedPrimitiveTableString "Interpreter obsoleteNamedPrimitiveTableString" "Initialize the links from the (now obsolete) indexed primitives to the new named primitives." | table | table := self obsoleteNamedPrimitiveTable. ^ String streamContents: [:s | s nextPutAll: '{'; cr. table do: [:primSpec | s nextPutAll: '{ "'; nextPutAll: primSpec first; nextPutAll: '", "'; nextPutAll: primSpec second; nextPutAll: '", "'; nextPutAll: primSpec third; nextPutAll: '" },'; cr]. s nextPutAll: '{ NULL, NULL, NULL }'. s cr; nextPutAll: '}']! ! !Interpreter class methodsFor: 'translation' stamp: 'sw 5/23/2001 14:33'! patchInterp: fileName "Interpreter patchInterp: 'Squeak VM PPC'" "This will patch out the unneccesary range check (a compare and branch) in the inner interpreter dispatch loop." "NOTE: You must edit in the Interpeter file name, and the number of instructions (delta) to count back to find the compare and branch that we want to get rid of." | delta f code len remnant i | delta := 6. f := FileStream fileNamed: fileName. f binary. code := Bitmap new: (len := f size) // 4. f nextInto: code. remnant := f next: len - (code size * 4). i := 0. ["Look for a BCTR instruction" (i := code indexOf: 16r4E800420 startingAt: i + 1 ifAbsent: [0]) > 0] whileTrue: ["Look for a CMPLWI FF, 6 instrs back" ((code at: i - delta) bitAnd: 16rFFE0FFFF) = 16r280000FF ifTrue: ["Copy dispatch instrs back over the compare" self inform: 'Patching at ', i hex. 0 to: delta - 2 do: [ :j | code at: (i - delta) + j put: (code at: (i - delta) + j + 2)]]]. f position: 0; nextPutAll: code; nextPutAll: remnant. f close. ! ! !Interpreter class methodsFor: 'translation' stamp: 'sw 5/23/2001 14:34'! patchInterpGCCPPC: fileName "Interpreter patchInterpGCCPPC: 'Squeak copy 1'" "This will patch out the unneccesary range check (a compare and branch) in the inner interpreter dispatch loop. for the PPC version of the GCC compiled version of Squeak under MPW" "NOTE: You must edit in the Interpeter file name" | delta f code len remnant i | delta := 7. f := FileStream fileNamed: fileName. f binary. code := Bitmap new: (len := f size) // 4. f nextInto: code. remnant := f next: len - (code size * 4). i := 0. ["Look for a BCTR instruction" (i := code indexOf: 16r4E800420 startingAt: i + 1 ifAbsent: [0]) > 0] whileTrue: ["Look for a CMPLWI cr1,rxx,FF, 7 instrs back" ((code at: i - delta) bitAnd: 16rFFE0FFFF) = 16r288000FF ifTrue: ["Copy dispatch instrs back over the compare" self inform: 'Patching at ', i hex. 0 to: delta - 2 do: [ :j | code at: (i - delta) + j put: (code at: (i - delta) + j + 2)]]]. f position: 0; nextPutAll: code; nextPutAll: remnant. f close! ! !Interpreter class methodsFor: 'constants'! primitiveTable ^ PrimitiveTable! ! !Interpreter class methodsFor: 'initialization' stamp: 'tpr 3/17/2005 11:32'! primitiveTableString "Interpreter initializePrimitiveTable primitiveTableString" | table | table := self primitiveTable. ^ String streamContents: [:s | s nextPut: ${. table withIndexDo: [:primSpec :index | s cr; tab; nextPutAll: '/* '; nextPutAll: (index - 1) printString; nextPutAll: '*/ '; nextPutAll: '(void *)'; nextPutAll: primSpec; nextPut: $,]. s cr; nextPutAll: ' 0 }']! ! !Interpreter class methodsFor: 'translation' stamp: 'dtl 3/28/2010 12:44'! requiredMethodNames "return the list of method names that should be retained for export or other support reasons" | requiredList | requiredList := Set new:400. "A number of methods required by VM support code, jitter, specific platforms etc" requiredList addAll: #(fullDisplayUpdate interpret printCallStack printAllStacks readImageFromFile:HeapSize:StartingAt: success: readableFormat: getCurrentBytecode characterForAscii: findClassOfMethod:forReceiver: findSelectorOfMethod:forReceiver: loadInitialContext nullCompilerHook primitiveFlushExternalPrimitives setCompilerInitialized: getFullScreenFlag getInterruptCheckCounter getInterruptKeycode getInterruptPending getNextWakeupTick getSavedWindowSize setFullScreenFlag: setInterruptCheckCounter: setInterruptKeycode: setInterruptPending: setNextWakeupTick: setSavedWindowSize: forceInterruptCheck getThisSessionID setMicroSeconds:andOffset:). "Nice to actually have all the primitives available" requiredList addAll: self primitiveTable. "InterpreterProxy is the internal analogue of sqVirtualMachine.c, so make sure to keep all those" InterpreterProxy organization categories do: [:cat | ((cat ~= 'initialize') and: [cat ~= 'private']) ifTrue: [ requiredList addAll: (InterpreterProxy organization listAtCategoryNamed: cat)]]. ^requiredList! ! !Interpreter class methodsFor: 'initialization' stamp: 'tpr 3/24/2004 21:29'! table: anArray from: specArray "SpecArray is an array of either (index selector) or (index1 index2 selector)." | contiguous | contiguous := 0. specArray do: [:spec | (spec at: 1) = contiguous ifFalse: [self error: 'Non-contiguous table entry']. spec size = 2 ifTrue: [anArray at: (spec at: 1) + 1 put: (spec at: 2). contiguous := contiguous + 1] ifFalse: [(spec at: 1) to: (spec at: 2) do: [:i | anArray at: i + 1 put: (spec at: 3)]. contiguous := contiguous + ((spec at: 2) - (spec at: 1)) + 1]]! ! !Interpreter methodsFor: 'control primitives' stamp: 'dtl 5/19/2010 11:04'! activateNewClosureMethod: blockClosure "Similar to activateNewMethod but for Closure and newMethod." | theBlockClosure closureMethod newContext methodHeader numCopied where outerContext | DoAssertionChecks ifTrue: [self okayOop: blockClosure]. outerContext := self fetchPointer: ClosureOuterContextIndex ofObject: blockClosure. DoAssertionChecks ifTrue: [self okayOop: outerContext]. closureMethod := self fetchPointer: MethodIndex ofObject: outerContext. methodHeader := self headerOf: closureMethod. self pushRemappableOop: blockClosure. newContext := self allocateOrRecycleContext: (methodHeader bitAnd: LargeContextBit). "All for one, and one for all!!" "allocateOrRecycleContext: may cause a GC; restore blockClosure and refetch outerContext et al" theBlockClosure := self popRemappableOop. outerContext := self fetchPointer: ClosureOuterContextIndex ofObject: theBlockClosure. numCopied := (self fetchWordLengthOf: theBlockClosure) - ClosureFirstCopiedValueIndex. "Assume: newContext will be recorded as a root if necessary by the call to newActiveContext: below, so we can use unchecked stores." where := newContext + self baseHeaderSize. self longAt: where + (SenderIndex << self shiftForWord) put: activeContext. self longAt: where + (InstructionPointerIndex << self shiftForWord) put: (self fetchPointer: ClosureStartPCIndex ofObject: theBlockClosure). self longAt: where + (StackPointerIndex << self shiftForWord) put: (self integerObjectOf: argumentCount + numCopied). self longAt: where + (MethodIndex << self shiftForWord) put: (self fetchPointer: MethodIndex ofObject: outerContext). self longAt: where + (ClosureIndex << self shiftForWord) put: theBlockClosure. self longAt: where + (ReceiverIndex << self shiftForWord) put: (self fetchPointer: ReceiverIndex ofObject: outerContext). "Copy the arguments..." 1 to: argumentCount do: [:i | self longAt: where + ((ReceiverIndex+i) << self shiftForWord) put: (self stackValue: argumentCount-i)]. "Copy the copied values..." where := newContext + self baseHeaderSize + ((ReceiverIndex + 1 + argumentCount) << self shiftForWord). 0 to: numCopied - 1 do: [:i| self longAt: where + (i << self shiftForWord) put: (self fetchPointer: i + ClosureFirstCopiedValueIndex ofObject: theBlockClosure)]. "The initial instructions in the block nil-out remaining temps." self pop: argumentCount + 1. self newActiveContext: newContext! ! !Interpreter methodsFor: 'message sending' stamp: 'dtl 5/19/2010 11:04'! activateNewMethod | newContext methodHeader initialIP tempCount nilOop where | methodHeader := self headerOf: newMethod. newContext := self allocateOrRecycleContext: (methodHeader bitAnd: LargeContextBit). initialIP := ((LiteralStart + (self literalCountOfHeader: methodHeader)) * self bytesPerWord) + 1. tempCount := (methodHeader >> 19) bitAnd: 16r3F. "Assume: newContext will be recorded as a root if necessary by the call to newActiveContext: below, so we can use unchecked stores." where := newContext + self baseHeaderSize. self longAt: where + (SenderIndex << self shiftForWord) put: activeContext. self longAt: where + (InstructionPointerIndex << self shiftForWord) put: (self integerObjectOf: initialIP). self longAt: where + (StackPointerIndex << self shiftForWord) put: (self integerObjectOf: tempCount). self longAt: where + (MethodIndex << self shiftForWord) put: newMethod. self longAt: where + (ClosureIndex << self shiftForWord) put: nilObj. "Copy the receiver and arguments..." 0 to: argumentCount do: [:i | self longAt: where + ((ReceiverIndex+i) << self shiftForWord) put: (self stackValue: argumentCount-i)]. "clear remaining temps to nil in case it has been recycled" nilOop := nilObj. argumentCount+1+ReceiverIndex to: tempCount+ReceiverIndex do: [:i | self longAt: where + (i << self shiftForWord) put: nilOop]. self pop: argumentCount + 1. reclaimableContextCount := reclaimableContextCount + 1. self newActiveContext: newContext.! ! !Interpreter methodsFor: 'process primitive support' stamp: 'tpr 3/24/2004 20:52'! addLastLink: proc toList: aList "Add the given process to the given linked list and set the backpointer of process to its new list." | lastLink | (self isEmptyList: aList) ifTrue: [self storePointer: FirstLinkIndex ofObject: aList withValue: proc] ifFalse: [lastLink := self fetchPointer: LastLinkIndex ofObject: aList. self storePointer: NextLinkIndex ofObject: lastLink withValue: proc]. self storePointer: LastLinkIndex ofObject: aList withValue: proc. self storePointer: MyListIndex ofObject: proc withValue: aList! ! !Interpreter methodsFor: 'method lookup cache' stamp: 'ikp (auto pragmas dtl 2010-09-26) 3/26/2005 13:35'! addNewMethodToCache "Add the given entry to the method cache. The policy is as follows: Look for an empty entry anywhere in the reprobe chain. If found, install the new entry there. If not found, then install the new entry at the first probe position and delete the entries in the rest of the reprobe chain. This has two useful purposes: If there is active contention over the first slot, the second or third will likely be free for reentry after ejection. Also, flushing is good when reprobe chains are getting full." | probe hash | self compilerTranslateMethodHook. "newMethod x lkupClass -> newNativeMethod (may cause GC !!)" hash := messageSelector bitXor: lkupClass. "drop low-order zeros from addresses" primitiveFunctionPointer := self functionPointerFor: primitiveIndex inClass: lkupClass. 0 to: CacheProbeMax-1 do: [:p | probe := (hash >> p) bitAnd: MethodCacheMask. (methodCache at: probe + MethodCacheSelector) = 0 ifTrue: ["Found an empty entry -- use it" methodCache at: probe + MethodCacheSelector put: messageSelector. methodCache at: probe + MethodCacheClass put: lkupClass. methodCache at: probe + MethodCacheMethod put: newMethod. methodCache at: probe + MethodCachePrim put: primitiveIndex. methodCache at: probe + MethodCacheNative put: newNativeMethod. methodCache at: probe + MethodCachePrimFunction put: (self cCoerce: primitiveFunctionPointer to: 'long'). ^ nil]]. "OK, we failed to find an entry -- install at the first slot..." probe := hash bitAnd: MethodCacheMask. "first probe" methodCache at: probe + MethodCacheSelector put: messageSelector. methodCache at: probe + MethodCacheClass put: lkupClass. methodCache at: probe + MethodCacheMethod put: newMethod. methodCache at: probe + MethodCachePrim put: primitiveIndex. methodCache at: probe + MethodCacheNative put: newNativeMethod. methodCache at: probe + MethodCachePrimFunction put: (self cCoerce: primitiveFunctionPointer to: 'long'). "...and zap the following entries" 1 to: CacheProbeMax-1 do: [:p | probe := (hash >> p) bitAnd: MethodCacheMask. methodCache at: probe + MethodCacheSelector put: 0]. ! ! !Interpreter methodsFor: 'plugin support' stamp: 'ikp (auto pragmas 12/08) 6/10/2004 12:26'! addToExternalPrimitiveTable: functionAddress "Add the given function address to the external primitive table and return the index where it's stored. This function doesn't need to be fast since it is only called when an external primitive has been looked up (which takes quite a bit of time itself). So there's nothing specifically complicated here. Note: Return index will be one-based (ST convention)" 0 to: MaxExternalPrimitiveTableSize-1 do: [ :i | (externalPrimitiveTable at: i) = 0 ifTrue: [ externalPrimitiveTable at: i put: functionAddress. ^i+1]]. "if no space left, return zero so it'll looked up again" ^0! ! !Interpreter methodsFor: 'debug support'! allAccessibleObjectsOkay "Ensure that all accessible objects in the heap are okay." | oop | oop := self firstAccessibleObject. [oop = nil] whileFalse: [ self okayFields: oop. oop := self accessibleObjectAfter: oop. ].! ! !Interpreter methodsFor: 'image save/restore' stamp: 'dtl (auto pragmas dtl 2010-09-26) 10/30/2008 07:13'! allocateMemory: heapSize minimum: minimumMemory imageFile: fileStream headerSize: headerSize "Translate to C function call with (case sensitive) camelCase. The purpose of this method is to document the translation. The default implementation is sqAllocateMemory(minimumMemory, heapSize). This may be redefined to make use of the image file and header size parameters for efficient implementation with mmap(). See CCodeGenerator>>writeDefaultMacrosOn: which specifies a default implementation." ^ self allocateMemory: heapSize Minimum: minimumMemory ImageFile: fileStream HeaderSize: headerSize! ! !Interpreter methodsFor: 'utilities' stamp: 'tpr 3/15/2004 19:35'! areIntegers: oop1 and: oop2 "Test oop1 and oop2 to make sure both are SmallIntegers." ^ ((oop1 bitAnd: oop2) bitAnd: 1) ~= 0! ! !Interpreter methodsFor: 'message sending'! argCount ^ argumentCount! ! !Interpreter methodsFor: 'compiled methods' stamp: 'ar 10/13/1998 13:50'! argumentCountOf: methodPointer ^ ((self headerOf: methodPointer) >> 25) bitAnd: 16r0F! ! !Interpreter methodsFor: 'contexts' stamp: 'tpr 3/24/2004 20:59'! argumentCountOfBlock: blockPointer | localArgCount | localArgCount := self fetchPointer: BlockArgumentCountIndex ofObject: blockPointer. ^self checkedIntegerValueOf: localArgCount! ! !Interpreter methodsFor: 'contexts' stamp: 'eem 6/20/2008 21:49'! argumentCountOfClosure: closurePointer ^self quickFetchInteger: ClosureNumArgsIndex ofObject: closurePointer! ! !Interpreter methodsFor: 'compiled methods' stamp: 'eem 6/20/2008 10:12'! argumentCountOfMethodHeader: header ^ (header >> 25) bitAnd: 16r0F! ! !Interpreter methodsFor: 'utilities' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/18/2010 21:41'! arrayValueOf: arrayOop "Return the address of first indexable field of resulting array object, or fail if the instance variable does not contain an indexable bytes or words object." "Note: May be called by translated primitive code." ((self isIntegerObject: arrayOop) not and: [self isWordsOrBytes: arrayOop]) ifTrue: [^ self pointerForOop: (arrayOop + self baseHeaderSize)]. self primitiveFail. ! ! !Interpreter methodsFor: 'array primitive support' stamp: '(auto pragmas 12/08) '! asciiOfCharacter: characterObj "Returns an integer object" self assertClassOf: characterObj is: (self splObj: ClassCharacter). successFlag ifTrue: [^ self fetchPointer: CharacterValueIndex ofObject: characterObj] ifFalse: [^ ConstZero] "in case some code needs an int"! ! !Interpreter methodsFor: 'utilities' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/19/2010 13:02'! assertClassOf: oop is: classOop "Succeed if the given (non-integer) object is an instance of the given class. Fail if the object is an integer." | ccIndex cl | (self isIntegerObject: oop) ifTrue: [ successFlag := false. ^ nil ]. ccIndex := ((self baseHeader: oop) >> 12) bitAnd: 16r1F. ccIndex = 0 ifTrue: [ cl := ((self classHeader: oop) bitAnd: self allButTypeMask) ] ifFalse: [ "look up compact class" cl := (self fetchPointer: (ccIndex - 1) ofObject: (self fetchPointer: CompactClasses ofObject: specialObjectsOop))]. self success: cl = classOop. ! ! !Interpreter methodsFor: 'debug support' stamp: 'dtl 5/18/2010 20:53'! balancedStack: delta afterPrimitive: primIdx withArgs: nArgs "Return true if the stack is still balanced after executing primitive primIndex with nArgs args. Delta is 'stackPointer - activeContext' which is a relative measure for the stack pointer (so we don't have to relocate it during the primitive)" (primIdx >= 81 and:[primIdx <= 88]) ifTrue:[^true]. "81-88 are control primitives after which the stack may look unbalanced" successFlag ifTrue:[ "Successful prim, stack must have exactly nArgs arguments popped off" ^(stackPointer - activeContext + (nArgs * self bytesPerWord)) = delta ]. "Failed prim must leave stack intact" ^(stackPointer - activeContext) = delta ! ! !Interpreter methodsFor: 'utilities' stamp: 'tpr (auto pragmas 12/08) 3/15/2004 19:44'! booleanCheat: cond "cheat the interpreter out of the pleasure of handling the next bytecode IFF it is a jump-on-boolean. Which it is, often enough when the current bytecode is something like bytecodePrimEqual" | bytecode offset | bytecode := self fetchByte. "assume next bytecode is jumpIfFalse (99%)" self internalPop: 2. (bytecode < 160 and: [bytecode > 151]) ifTrue: [ "short jumpIfFalse" cond ifTrue: [^ self fetchNextBytecode] ifFalse: [^ self jump: bytecode - 151]]. bytecode = 172 ifTrue: [ "long jumpIfFalse" offset := self fetchByte. cond ifTrue: [^ self fetchNextBytecode] ifFalse: [^ self jump: offset]]. "not followed by a jumpIfFalse; undo instruction fetch and push boolean result" localIP := localIP - 1. self fetchNextBytecode. cond ifTrue: [self internalPush: trueObj] ifFalse: [self internalPush: falseObj]. ! ! !Interpreter methodsFor: 'utilities' stamp: 'tpr 3/15/2004 19:46'! booleanValueOf: obj "convert true and false (Smalltalk) to true or false(C)" obj = trueObj ifTrue: [ ^ true ]. obj = falseObj ifTrue: [ ^ false ]. successFlag := false. ^ nil! ! !Interpreter methodsFor: 'array primitive support' stamp: 'dtl 5/19/2010 13:02'! byteLengthOf: oop "Return the number of indexable bytes in the given object. This is basically a special copy of lengthOf: for BitBlt." | header sz fmt | header := self baseHeader: oop. (header bitAnd: TypeMask) = HeaderTypeSizeAndClass ifTrue: [ sz := (self sizeHeader: oop) bitAnd: self allButTypeMask ] ifFalse: [ sz := header bitAnd: self sizeMask ]. fmt := (header >> 8) bitAnd: 16rF. fmt < 8 ifTrue: [ ^ (sz - self baseHeaderSize)] "words" ifFalse: [ ^ (sz - self baseHeaderSize) - (fmt bitAnd: 3)] "bytes"! ! !Interpreter methodsFor: 'object format' stamp: 'di 6/14/2004 16:37'! byteSizeOf: oop | slots | self flag: #Dan. (self isIntegerObject: oop) ifTrue:[^0]. slots := self slotSizeOf: oop. (self isBytesNonInt: oop) ifTrue:[^slots] ifFalse:[^slots * 4]! ! !Interpreter methodsFor: 'image save/restore' stamp: 'di 10/18/1999 16:58'! byteSwapByteObjects "Byte-swap the words of all bytes objects in the image. This returns these objects to their original byte ordering after blindly byte-swapping the entire image." self byteSwapByteObjectsFrom: self firstObject to: endOfMemory! ! !Interpreter methodsFor: 'image save/restore' stamp: 'dtl 5/18/2010 21:42'! byteSwapByteObjectsFrom: startOop to: stopAddr "Byte-swap the words of all bytes objects in a range of the image, including Strings, ByteArrays, and CompiledMethods. This returns these objects to their original byte ordering after blindly byte-swapping the entire image. For compiled methods, byte-swap only their bytecodes part." | oop fmt wordAddr methodHeader | oop := startOop. [self oop: oop isLessThan: stopAddr] whileTrue: [(self isFreeObject: oop) ifFalse: [fmt := self formatOf: oop. fmt >= 8 ifTrue: ["oop contains bytes" wordAddr := oop + self baseHeaderSize. fmt >= 12 ifTrue: ["compiled method; start after methodHeader and literals" methodHeader := self longAt: oop + self baseHeaderSize. wordAddr := wordAddr + self bytesPerWord + ((methodHeader >> 10 bitAnd: 255) * self bytesPerWord)]. self reverseBytesFrom: wordAddr to: oop + (self sizeBitsOf: oop)]. (fmt = 6 and: [self bytesPerWord = 8]) ifTrue: ["Object contains 32-bit half-words packed into 64-bit machine words." wordAddr := oop + self baseHeaderSize. self reverseWordsFrom: wordAddr to: oop + (self sizeBitsOf: oop)]]. oop := self objectAfter: oop]! ! !Interpreter methodsFor: 'image save/restore' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/18/2010 21:33'! byteSwapped: w "Answer the given integer with its bytes in the reverse order." self isDefinedTrueExpression: 'BYTES_PER_WORD == 4' inSmalltalk: [self bytesPerWord = 4] comment: 'swap bytes in an object word' ifTrue: [^ ((w bitShift: Byte3ShiftNegated) bitAnd: Byte0Mask) + ((w bitShift: Byte1ShiftNegated) bitAnd: Byte1Mask) + ((w bitShift: Byte1Shift ) bitAnd: Byte2Mask) + ((w bitShift: Byte3Shift ) bitAnd: Byte3Mask)] ifFalse: [^ ((w bitShift: Byte7ShiftNegated) bitAnd: Byte0Mask) + ((w bitShift: Byte5ShiftNegated) bitAnd: Byte1Mask) + ((w bitShift: Byte3ShiftNegated) bitAnd: Byte2Mask) + ((w bitShift: Byte1ShiftNegated) bitAnd: Byte3Mask) + ((w bitShift: Byte1Shift ) bitAnd: Byte4Mask) + ((w bitShift: Byte3Shift ) bitAnd: Byte5Mask) + ((w bitShift: Byte5Shift ) bitAnd: Byte6Mask) + ((w bitShift: Byte7Shift ) bitAnd: Byte7Mask)]! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 3/23/2004 18:23'! bytecodePrimAdd | rcvr arg result | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. (self areIntegers: rcvr and: arg) ifTrue: [result := (self integerValueOf: rcvr) + (self integerValueOf: arg). (self isIntegerValue: result) ifTrue: [self internalPop: 2 thenPush: (self integerObjectOf: result). ^ self fetchNextBytecode "success"]] ifFalse: [successFlag := true. self externalizeIPandSP. self primitiveFloatAdd: rcvr toArg: arg. self internalizeIPandSP. successFlag ifTrue: [^ self fetchNextBytecode "success"]]. messageSelector := self specialSelector: 0. argumentCount := 1. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 3/23/2004 18:24'! bytecodePrimAt "BytecodePrimAt will only succeed if the receiver is in the atCache. Otherwise it will fail so that the more general primitiveAt will put it in the cache after validating that message lookup results in a primitive response." | index rcvr result atIx | index := self internalStackTop. rcvr := self internalStackValue: 1. successFlag := (self isIntegerObject: rcvr) not and: [self isIntegerObject: index]. successFlag ifTrue: [atIx := rcvr bitAnd: AtCacheMask. "Index into atCache = 4N, for N = 0 ... 7" (atCache at: atIx+AtCacheOop) = rcvr ifTrue: [result := self commonVariableInternal: rcvr at: (self integerValueOf: index) cacheIndex: atIx. successFlag ifTrue: [self fetchNextBytecode. ^self internalPop: 2 thenPush: result]]]. messageSelector := self specialSelector: 16. argumentCount := 1. self normalSend. ! ! !Interpreter methodsFor: 'common selector sends' stamp: 'di 6/21/97 08:58'! bytecodePrimAtEnd messageSelector := self specialSelector: 21. argumentCount := 0. self normalSend.! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 3/23/2004 18:25'! bytecodePrimAtPut "BytecodePrimAtPut will only succeed if the receiver is in the atCache. Otherwise it will fail so that the more general primitiveAtPut will put it in the cache after validating that message lookup results in a primitive response." | index rcvr atIx value | value := self internalStackTop. index := self internalStackValue: 1. rcvr := self internalStackValue: 2. successFlag := (self isIntegerObject: rcvr) not and: [self isIntegerObject: index]. successFlag ifTrue: [atIx := (rcvr bitAnd: AtCacheMask) + AtPutBase. "Index into atPutCache" (atCache at: atIx+AtCacheOop) = rcvr ifTrue: [self commonVariable: rcvr at: (self integerValueOf: index) put: value cacheIndex: atIx. successFlag ifTrue: [self fetchNextBytecode. ^self internalPop: 3 thenPush: value]]]. messageSelector := self specialSelector: 17. argumentCount := 2. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'jm 12/10/1998 17:29'! bytecodePrimBitAnd successFlag := true. self externalizeIPandSP. self primitiveBitAnd. self internalizeIPandSP. successFlag ifTrue: [^ self fetchNextBytecode "success"]. messageSelector := self specialSelector: 14. argumentCount := 1. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'jm 12/10/1998 17:29'! bytecodePrimBitOr successFlag := true. self externalizeIPandSP. self primitiveBitOr. self internalizeIPandSP. successFlag ifTrue: [^ self fetchNextBytecode "success"]. messageSelector := self specialSelector: 15. argumentCount := 1. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'jm 12/10/1998 17:29'! bytecodePrimBitShift successFlag := true. self externalizeIPandSP. self primitiveBitShift. self internalizeIPandSP. successFlag ifTrue: [^ self fetchNextBytecode "success"]. messageSelector := self specialSelector: 12. argumentCount := 1. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 3/23/2004 18:26'! bytecodePrimBlockCopy | rcvr hdr | rcvr := self internalStackValue: 1. successFlag := true. hdr := self baseHeader: rcvr. self success: (self isContextHeader: hdr). successFlag ifTrue: [self externalizeIPandSP. self primitiveBlockCopy. self internalizeIPandSP]. successFlag ifFalse: [messageSelector := self specialSelector: 24. argumentCount := 1. ^ self normalSend]. self fetchNextBytecode. ! ! !Interpreter methodsFor: 'common selector sends' stamp: 'di 1/11/1999 00:09'! bytecodePrimClass | rcvr | rcvr := self internalStackTop. self internalPop: 1 thenPush: (self fetchClassOf: rcvr). self fetchNextBytecode. ! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 3/24/2004 18:26'! bytecodePrimDiv | quotient | successFlag := true. quotient := self doPrimitiveDiv: (self internalStackValue: 1) by: (self internalStackValue: 0). successFlag ifTrue: [self internalPop: 2 thenPush: (self integerObjectOf: quotient). ^ self fetchNextBytecode "success"]. messageSelector := self specialSelector: 13. argumentCount := 1. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 3/24/2004 18:27'! bytecodePrimDivide | rcvr arg result | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. (self areIntegers: rcvr and: arg) ifTrue: [rcvr := self integerValueOf: rcvr. arg := self integerValueOf: arg. (arg ~= 0 and: [rcvr \\ arg = 0]) ifTrue: [result := rcvr // arg. "generates C / operation" (self isIntegerValue: result) ifTrue: [self internalPop: 2 thenPush: (self integerObjectOf: result). ^ self fetchNextBytecode"success"]]] ifFalse: [successFlag := true. self externalizeIPandSP. self primitiveFloatDivide: rcvr byArg: arg. self internalizeIPandSP. successFlag ifTrue: [^ self fetchNextBytecode"success"]]. messageSelector := self specialSelector: 9. argumentCount := 1. self normalSend! ! !Interpreter methodsFor: 'common selector sends'! bytecodePrimDo messageSelector := self specialSelector: 27. argumentCount := 1. self normalSend. ! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 3/24/2004 18:28'! bytecodePrimEqual | rcvr arg aBool | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. (self areIntegers: rcvr and: arg) ifTrue: [^self booleanCheat: rcvr = arg]. successFlag := true. aBool := self primitiveFloatEqual: rcvr toArg: arg. successFlag ifTrue: [^self booleanCheat: aBool]. messageSelector := self specialSelector: 6. argumentCount := 1. self normalSend ! ! !Interpreter methodsFor: 'common selector sends'! bytecodePrimEquivalent | rcvr arg | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. self booleanCheat: rcvr = arg.! ! !Interpreter methodsFor: 'common selector sends' stamp: 'eem 9/18/2010 11:41'! bytecodePrimGreaterOrEqual | rcvr arg aBool | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. (self areIntegers: rcvr and: arg) ifTrue: [self cCode: '' inSmalltalk: [^self booleanCheat: (self integerValueOf: rcvr) >= (self integerValueOf: arg)]. ^self booleanCheat: rcvr >= arg]. successFlag := true. aBool := self primitiveFloatGreaterOrEqual: rcvr toArg: arg. successFlag ifTrue: [^self booleanCheat: aBool]. messageSelector := self specialSelector: 5. argumentCount := 1. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 3/24/2004 18:29'! bytecodePrimGreaterThan | rcvr arg aBool | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. (self areIntegers: rcvr and: arg) ifTrue: [self cCode: '' inSmalltalk: [^self booleanCheat: (self integerValueOf: rcvr) > (self integerValueOf: arg)]. ^self booleanCheat: rcvr > arg]. successFlag := true. aBool := self primitiveFloatGreater: rcvr thanArg: arg. successFlag ifTrue: [^self booleanCheat: aBool]. messageSelector := self specialSelector: 3. argumentCount := 1. self normalSend ! ! !Interpreter methodsFor: 'common selector sends' stamp: 'eem 9/18/2010 11:41'! bytecodePrimLessOrEqual | rcvr arg aBool | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. (self areIntegers: rcvr and: arg) ifTrue: [self cCode: '' inSmalltalk: [^self booleanCheat: (self integerValueOf: rcvr) <= (self integerValueOf: arg)]. ^ self booleanCheat: rcvr <= arg]. successFlag := true. aBool := self primitiveFloatLessOrEqual: rcvr toArg: arg. successFlag ifTrue: [^self booleanCheat: aBool]. messageSelector := self specialSelector: 4. argumentCount := 1. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 3/24/2004 18:30'! bytecodePrimLessThan | rcvr arg aBool | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. (self areIntegers: rcvr and: arg) ifTrue: [self cCode: '' inSmalltalk: [^self booleanCheat: (self integerValueOf: rcvr) < (self integerValueOf: arg)]. ^ self booleanCheat: rcvr < arg]. successFlag := true. aBool := self primitiveFloatLess: rcvr thanArg: arg. successFlag ifTrue: [^ self booleanCheat: aBool]. messageSelector := self specialSelector: 2. argumentCount := 1. self normalSend ! ! !Interpreter methodsFor: 'common selector sends' stamp: 'jm 12/10/1998 17:31'! bytecodePrimMakePoint successFlag := true. self externalizeIPandSP. self primitiveMakePoint. self internalizeIPandSP. successFlag ifTrue: [^ self fetchNextBytecode "success"]. messageSelector := self specialSelector: 11. argumentCount := 1. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 3/24/2004 18:31'! bytecodePrimMod | mod | successFlag := true. mod := self doPrimitiveMod: (self internalStackValue: 1) by: (self internalStackValue: 0). successFlag ifTrue: [self internalPop: 2 thenPush: (self integerObjectOf: mod). ^ self fetchNextBytecode "success"]. messageSelector := self specialSelector: 10. argumentCount := 1. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 3/24/2004 18:31'! bytecodePrimMultiply | rcvr arg result | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. (self areIntegers: rcvr and: arg) ifTrue: [rcvr := self integerValueOf: rcvr. arg := self integerValueOf: arg. result := rcvr * arg. ((arg = 0 or: [(result // arg) = rcvr]) and: [self isIntegerValue: result]) ifTrue: [self internalPop: 2 thenPush: (self integerObjectOf: result). ^ self fetchNextBytecode "success"]] ifFalse: [successFlag := true. self externalizeIPandSP. self primitiveFloatMultiply: rcvr byArg: arg. self internalizeIPandSP. successFlag ifTrue: [^ self fetchNextBytecode "success"]]. messageSelector := self specialSelector: 8. argumentCount := 1. self normalSend. ! ! !Interpreter methodsFor: 'common selector sends'! bytecodePrimNew messageSelector := self specialSelector: 28. argumentCount := 0. self normalSend. ! ! !Interpreter methodsFor: 'common selector sends'! bytecodePrimNewWithArg messageSelector := self specialSelector: 29. argumentCount := 1. self normalSend. ! ! !Interpreter methodsFor: 'common selector sends' stamp: 'di 6/21/97 08:58'! bytecodePrimNext messageSelector := self specialSelector: 19. argumentCount := 0. self normalSend.! ! !Interpreter methodsFor: 'common selector sends' stamp: 'di 6/21/97 10:12'! bytecodePrimNextPut messageSelector := self specialSelector: 20. argumentCount := 1. self normalSend.! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 3/24/2004 18:32'! bytecodePrimNotEqual | rcvr arg aBool | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. (self areIntegers: rcvr and: arg) ifTrue: [^self booleanCheat: rcvr ~= arg]. successFlag := true. aBool := self primitiveFloatEqual: rcvr toArg: arg. successFlag ifTrue: [^self booleanCheat: aBool not]. messageSelector := self specialSelector: 7. argumentCount := 1. self normalSend ! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 2/11/2004 20:33'! bytecodePrimPointX | rcvr | successFlag := true. rcvr := self internalStackTop. self assertClassOf: rcvr is: (self splObj: ClassPoint). successFlag ifTrue: [self internalPop: 1 thenPush: (self fetchPointer: XIndex ofObject: rcvr). ^ self fetchNextBytecode "success"]. messageSelector := self specialSelector: 30. argumentCount := 0. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 2/11/2004 20:34'! bytecodePrimPointY | rcvr | successFlag := true. rcvr := self internalStackTop. self assertClassOf: rcvr is: (self splObj: ClassPoint). successFlag ifTrue: [self internalPop: 1 thenPush: (self fetchPointer: YIndex ofObject: rcvr). ^ self fetchNextBytecode "success"]. messageSelector := self specialSelector: 31. argumentCount := 0. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'di 12/11/1998 10:22'! bytecodePrimSize messageSelector := self specialSelector: 18. argumentCount := 0. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'tpr 3/24/2004 18:32'! bytecodePrimSubtract | rcvr arg result | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. (self areIntegers: rcvr and: arg) ifTrue: [result := (self integerValueOf: rcvr) - (self integerValueOf: arg). (self isIntegerValue: result) ifTrue: [self internalPop: 2 thenPush: (self integerObjectOf: result). ^self fetchNextBytecode "success"]] ifFalse: [successFlag := true. self externalizeIPandSP. self primitiveFloatSubtract: rcvr fromArg: arg. self internalizeIPandSP. successFlag ifTrue: [^self fetchNextBytecode "success"]]. messageSelector := self specialSelector: 1. argumentCount := 1. self normalSend! ! !Interpreter methodsFor: 'common selector sends' stamp: 'eem 8/22/2008 15:20'! bytecodePrimValue "In-line value for BlockClosure and BlockContext" | maybeBlock rcvrClass | maybeBlock := self internalStackTop. argumentCount := 0. successFlag := true. (self isNonIntegerObject: maybeBlock) ifTrue: [rcvrClass := self fetchClassOfNonInt: maybeBlock. rcvrClass = (self splObj: ClassBlockClosure) ifTrue: [self externalizeIPandSP. self primitiveClosureValue. self internalizeIPandSP] ifFalse: [rcvrClass = (self splObj: ClassBlockContext) ifTrue: [self externalizeIPandSP. self primitiveValue. self internalizeIPandSP] ifFalse: [successFlag := false]]]. successFlag ifFalse: [messageSelector := self specialSelector: 25. ^self normalSend]. self fetchNextBytecode! ! !Interpreter methodsFor: 'common selector sends' stamp: 'eem 8/22/2008 15:37'! bytecodePrimValueWithArg "In-line value: for BlockClosure and BlockContext" | maybeBlock rcvrClass | maybeBlock := self internalStackValue: 1. argumentCount := 1. successFlag := true. (self isNonIntegerObject: maybeBlock) ifTrue: [rcvrClass := self fetchClassOfNonInt: maybeBlock. rcvrClass = (self splObj: ClassBlockClosure) ifTrue: [self externalizeIPandSP. self primitiveClosureValue. self internalizeIPandSP] ifFalse: [rcvrClass = (self splObj: ClassBlockContext) ifTrue: [self externalizeIPandSP. self primitiveValue. self internalizeIPandSP] ifFalse: [successFlag := false]]]. successFlag ifFalse: [messageSelector := self specialSelector: 26. ^self normalSend]. self fetchNextBytecode! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'tpr (auto pragmas 12/08) 5/12/2005 22:48'! callExternalPrimitive: functionID "Call the external plugin function identified. In the VM this is an address, see InterpreterSimulator for it's version. " self dispatchFunctionPointer: functionID! ! !Interpreter methodsFor: 'interpreter shell' stamp: 'dtl (auto pragmas dtl 2010-09-26) 9/29/2009 22:23'! callInterpreter "External call into the interpreter" self interpret.! ! !Interpreter methodsFor: 'callback support' stamp: 'ar (auto pragmas 12/08) 1/16/2007 11:47'! callbackEnter: callbackID "Re-enter the interpreter for executing a callback" | result activeProc | "For now, do not allow a callback unless we're in a primitiveResponse" primitiveIndex = 0 ifTrue:[^false]. "Check if we've exceeded the callback depth" jmpDepth >= jmpMax ifTrue:[^false]. jmpDepth := jmpDepth + 1. "Suspend the currently active process" activeProc := self fetchPointer: ActiveProcessIndex ofObject: self schedulerPointer. suspendedCallbacks at: jmpDepth put: activeProc. "We need to preserve newMethod explicitly since it is not activated yet and therefore no context has been created for it. If the caller primitive for any reason decides to fail we need to make sure we execute the correct method and not the one 'last used' in the call back" suspendedMethods at: jmpDepth put: newMethod. self transferTo: self wakeHighestPriority. "Typically, invoking the callback means that some semaphore has been signaled to indicate the callback. Force an interrupt check right away." self forceInterruptCheck. result := self setjmp: (jmpBuf at: jmpDepth). result == 0 ifTrue:["Fill in callbackID" callbackID at: 0 put: jmpDepth. "This is ugly but the inliner treats interpret() in very special and strange ways and calling any kind of 'self interpret' either directly or even via cCode:inSmalltalk: will cause this entire method to vanish." self cCode: 'interpret()'. ]. "Transfer back to the previous process so that caller can push result" activeProc := self fetchPointer: ActiveProcessIndex ofObject: self schedulerPointer. self putToSleep: activeProc. activeProc := suspendedCallbacks at: jmpDepth. newMethod := suspendedMethods at: jmpDepth. "see comment above" self transferTo: activeProc. jmpDepth := jmpDepth-1. ^true! ! !Interpreter methodsFor: 'callback support' stamp: 'ar (auto pragmas dtl 2010-09-26) 8/30/2006 11:26'! callbackLeave: cbID "Leave from a previous callback" "For now, do not allow a callback unless we're in a primitiveResponse" primitiveIndex = 0 ifTrue:[^false]. "Check if this is the top-level callback" cbID = jmpDepth ifFalse:[^false]. cbID < 1 ifTrue:[^false]. "This is ugly but necessary, or otherwise the Mac will not build" self long: (jmpBuf at: jmpDepth) jmp: 1. ! ! !Interpreter methodsFor: 'contexts' stamp: 'tpr 3/24/2004 20:59'! caller ^self fetchPointer: CallerIndex ofObject: activeContext! ! !Interpreter methodsFor: 'debug support' stamp: 'JMM 11/11/2004 11:06'! capturePendingFinalizationSignals statpendingFinalizationSignals := pendingFinalizationSignals. ! ! !Interpreter methodsFor: 'object access primitives' stamp: 'dtl 5/19/2010 11:40'! changeClassOf: rcvr to: argClass "Change the class of the receiver into the class specified by the argument given that the format of the receiver matches the format of the argument. Fail if receiver or argument are SmallIntegers, or the receiver is an instance of a compact class and the argument isn't, or when the argument's class is compact and the receiver isn't, or when the format of the receiver is different from the format of the argument's class, or when the arguments class is fixed and the receiver's size differs from the size that an instance of the argument's class should have." | classHdr sizeHiBits byteSize argFormat rcvrFormat ccIndex | "Check what the format of the class says" classHdr := self formatOfClass: argClass. "Low 2 bits are 0" "Compute the size of instances of the class (used for fixed field classes only)" sizeHiBits := (classHdr bitAnd: 16r60000) >> 9. classHdr := classHdr bitAnd: 16r1FFFF. byteSize := (classHdr bitAnd: self sizeMask) + sizeHiBits. "size in bytes -- low 2 bits are 0" "Check the receiver's format against that of the class" argFormat := (classHdr >> 8) bitAnd: 16rF. rcvrFormat := self formatOf: rcvr. argFormat = rcvrFormat ifFalse:[^self primitiveFail]. "no way" "For fixed field classes, the sizes must match. Note: byteSize-4 because base header is included in class size." argFormat < 2 ifTrue:[(byteSize - self baseHeaderSize) = (self byteSizeOf: rcvr) ifFalse:[^self primitiveFail]]. (self headerType: rcvr) = HeaderTypeShort ifTrue:[ "Compact classes. Check if the arg's class is compact and exchange ccIndex" ccIndex := classHdr bitAnd: CompactClassMask. ccIndex = 0 ifTrue:[^self primitiveFail]. "class is not compact" self longAt: rcvr put: (((self longAt: rcvr) bitAnd: CompactClassMask bitInvert32) bitOr: ccIndex)] ifFalse:["Exchange the class pointer, which could make rcvr a root for argClass" self longAt: rcvr - self baseHeaderSize put: (argClass bitOr: (self headerType: rcvr)). (self oop: rcvr isLessThan: youngStart) ifTrue: [self possibleRootStoreInto: rcvr value: argClass]]. "Flush cache because rcvr's class has changed" self flushMethodCache. ! ! !Interpreter methodsFor: 'array primitive support' stamp: 'di (auto pragmas 12/08) 12/10/1998 14:53'! characterForAscii: ascii "Arg must lie in range 0-255!!" ^ self fetchPointer: ascii ofObject: (self splObj: CharacterTable)! ! !Interpreter methodsFor: 'arithmetic primitive support' stamp: 'di 11/27/1998 15:38'! checkBooleanResult: result successFlag ifTrue: [self pushBool: result] ifFalse: [self unPop: 2]! ! !Interpreter methodsFor: 'process primitive support' stamp: 'tpr (auto pragmas dtl 2010-09-26) 3/22/2004 14:21'! checkForInterrupts "Check for possible interrupts and handle one if necessary." | sema now | "Mask so same wrapping as primitiveMillisecondClock" now := self ioMSecs bitAnd: MillisecondClockMask. self interruptCheckForced ifFalse: [ "don't play with the feedback if we forced a check. It only makes life difficult" now - lastTick < interruptChecksEveryNms ifTrue: ["wrapping is not a concern, it'll get caught quickly enough. This clause is trying to keep a reasonable guess of how many times per interruptChecksEveryNms we are calling quickCheckForInterrupts. Not sure how effective it really is." interruptCheckCounterFeedBackReset := interruptCheckCounterFeedBackReset + 10] ifFalse: [interruptCheckCounterFeedBackReset <= 1000 ifTrue: [interruptCheckCounterFeedBackReset := 1000] ifFalse: [interruptCheckCounterFeedBackReset := interruptCheckCounterFeedBackReset - 12]]]. "reset the interrupt check counter" interruptCheckCounter := interruptCheckCounterFeedBackReset. signalLowSpace ifTrue: [signalLowSpace := false. "reset flag" sema := self splObj: TheLowSpaceSemaphore. sema = nilObj ifFalse: [self synchronousSignal: sema]]. now < lastTick ifTrue: ["millisecond clock wrapped so correct the nextPollTick" nextPollTick := nextPollTick - MillisecondClockMask - 1]. now >= nextPollTick ifTrue: [self ioProcessEvents. "sets interruptPending if interrupt key pressed" nextPollTick := now + 200 "msecs to wait before next call to ioProcessEvents. Note that strictly speaking we might need to update 'now' at this point since ioProcessEvents could take a very long time on some platforms"]. interruptPending ifTrue: [interruptPending := false. "reset interrupt flag" sema := self splObj: TheInterruptSemaphore. sema = nilObj ifFalse: [self synchronousSignal: sema]]. nextWakeupTick ~= 0 ifTrue: [now < lastTick ifTrue: ["the clock has wrapped. Subtract the wrap interval from nextWakeupTick - this might just possibly result in 0. Since this is used as a flag value for 'no timer' we do the 0 check above" nextWakeupTick := nextWakeupTick - MillisecondClockMask - 1]. now >= nextWakeupTick ifTrue: [nextWakeupTick := 0. "set timer interrupt to 0 for 'no timer'" sema := self splObj: TheTimerSemaphore. sema = nilObj ifFalse: [self synchronousSignal: sema]]]. "signal any pending finalizations" pendingFinalizationSignals > 0 ifTrue: [sema := self splObj: TheFinalizationSemaphore. (self fetchClassOf: sema) = (self splObj: ClassSemaphore) ifTrue: [self synchronousSignal: sema]. pendingFinalizationSignals := 0]. "signal all semaphores in semaphoresToSignal" (semaphoresToSignalCountA > 0 or: [semaphoresToSignalCountB > 0]) ifTrue: [self signalExternalSemaphores]. "update the tracking value" lastTick := now! ! !Interpreter methodsFor: 'image save/restore' stamp: 'dtl 10/3/2010 10:40'! checkImageVersionFrom: f startingAt: imageOffset "Read and verify the image file version number and return true if the the given image file needs to be byte-swapped. As a side effect, position the file stream just after the version number of the image header. This code prints a warning and does a hard-exit if it cannot find a valid version number." "This code is based on C code by Ian Piumarta." | firstVersion | "check the version number" self sqImageFile: f Seek: imageOffset. imageFormatInitialVersion := firstVersion := self getLongFromFile: f swap: false. (self readableFormat: imageFormatInitialVersion) ifTrue: [^ false]. "try with bytes reversed" self sqImageFile: f Seek: imageOffset. imageFormatInitialVersion := self getLongFromFile: f swap: true. (self readableFormat: imageFormatInitialVersion) ifTrue: [^ true]. "Note: The following is only meaningful if not reading an embedded image" imageOffset = 0 ifTrue:[ "try skipping the first 512 bytes (prepended by certain Mac file transfer utilities)" self sqImageFile: f Seek: 512. imageFormatInitialVersion := self getLongFromFile: f swap: false. (self readableFormat: imageFormatInitialVersion) ifTrue: [^ false]. "try skipping the first 512 bytes with bytes reversed" self sqImageFile: f Seek: 512. imageFormatInitialVersion := self getLongFromFile: f swap: true. (self readableFormat: imageFormatInitialVersion) ifTrue: [^ true]]. "hard failure; abort" self print: 'This interpreter (vers. '. self printNum: self imageFormatVersion. self print: ') cannot read image file (vers. '. self printNum: firstVersion. self print: ').'. self cr. self print: 'Press CR to quit...'. self getchar. self ioExit. ! ! !Interpreter methodsFor: 'arithmetic primitive support' stamp: 'di 11/27/1998 15:26'! checkIntegerResult: integerResult (successFlag and: [self isIntegerValue: integerResult]) ifTrue: [self pushInteger: integerResult] ifFalse: [self unPop: 2]! ! !Interpreter methodsFor: 'utilities'! checkedIntegerValueOf: intOop "Note: May be called by translated primitive code." (self isIntegerObject: intOop) ifTrue: [ ^ self integerValueOf: intOop ] ifFalse: [ self primitiveFail. ^ 0 ]! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:23'! classNameOf: aClass Is: className "Check if aClass's name is className" | srcName name length | (self lengthOf: aClass) <= 6 ifTrue: [^ false]. "Not a class but might be behavior" name := self fetchPointer: 6 ofObject: aClass. (self isBytes: name) ifFalse: [^ false]. length := self stSizeOf: name. srcName := self cCoerce: (self arrayValueOf: name) to: 'char *'. 0 to: length - 1 do: [:i | (srcName at: i) = (className at: i) ifFalse: [^ false]]. "Check if className really ends at this point" ^ (className at: length) = 0! ! !Interpreter methodsFor: 'control primitives' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/18/2010 21:42'! closureNumArgs: numArgs instructionPointer: initialIP numCopiedValues: numCopied | newClosure | newClosure := self instantiateSmallClass: (self splObj: ClassBlockClosure) sizeInBytes: (self bytesPerWord * (ClosureFirstCopiedValueIndex + numCopied)) + self baseHeaderSize. "Assume: have just allocated a new closure; it must be young. Thus, can use unchecked stores." self storePointerUnchecked: ClosureStartPCIndex ofObject: newClosure withValue: (self integerObjectOf: initialIP). self storePointerUnchecked: ClosureNumArgsIndex ofObject: newClosure withValue: (self integerObjectOf: numArgs). "It is up to the caller to store the outer context and copiedValues." ^newClosure! ! !Interpreter methodsFor: 'array primitive support' stamp: 'tpr 3/15/2004 20:23'! commonAt: stringy "This code is called if the receiver responds primitively to at:. If this is so, it will be installed in the atCache so that subsequent calls of at: or next may be handled immediately in bytecode primitive routines." | index rcvr atIx result | index := self positive32BitValueOf: (self stackTop). "Sets successFlag" rcvr := self stackValue: 1. successFlag & (self isIntegerObject: rcvr) not ifFalse: [^ self primitiveFail]. "NOTE: The at-cache, since it is specific to the non-super response to #at:. Therefore we must determine that the message is #at: (not, eg, #basicAt:), and that the send is not a super-send, before using the at-cache." (messageSelector = (self specialSelector: 16) and: [lkupClass = (self fetchClassOfNonInt: rcvr)]) ifTrue: ["OK -- look in the at-cache" atIx := rcvr bitAnd: AtCacheMask. "Index into atCache = 4N, for N = 0 ... 7" (atCache at: atIx+AtCacheOop) = rcvr ifFalse: ["Rcvr not in cache. Install it..." self install: rcvr inAtCache: atCache at: atIx string: stringy]. successFlag ifTrue: [result := self commonVariable: rcvr at: index cacheIndex: atIx]. successFlag ifTrue: [^ self pop: argumentCount+1 thenPush: result]]. "The slow but sure way..." successFlag := true. result := self stObject: rcvr at: index. successFlag ifTrue: [stringy ifTrue: [result := self characterForAscii: (self integerValueOf: result)]. ^ self pop: argumentCount+1 thenPush: result]! ! !Interpreter methodsFor: 'array primitive support' stamp: 'tpr 3/15/2004 20:24'! commonAtPut: stringy "This code is called if the receiver responds primitively to at:Put:. If this is so, it will be installed in the atPutCache so that subsequent calls of at: or next may be handled immediately in bytecode primitive routines." | value index rcvr atIx | value := self stackTop. index := self positive32BitValueOf: (self stackValue: 1). "Sets successFlag" rcvr := self stackValue: 2. successFlag & (self isIntegerObject: rcvr) not ifFalse: [^ self primitiveFail]. "NOTE: The atPut-cache, since it is specific to the non-super response to #at:Put:. Therefore we must determine that the message is #at:Put: (not, eg, #basicAt:Put:), and that the send is not a super-send, before using the at-cache." (messageSelector = (self specialSelector: 17) and: [lkupClass = (self fetchClassOfNonInt: rcvr)]) ifTrue: ["OK -- look in the at-cache" atIx := (rcvr bitAnd: AtCacheMask) + AtPutBase. "Index into atPutCache" (atCache at: atIx+AtCacheOop) = rcvr ifFalse: ["Rcvr not in cache. Install it..." self install: rcvr inAtCache: atCache at: atIx string: stringy]. successFlag ifTrue: [self commonVariable: rcvr at: index put: value cacheIndex: atIx]. successFlag ifTrue: [^ self pop: argumentCount+1 thenPush: value]]. "The slow but sure way..." successFlag := true. stringy ifTrue: [self stObject: rcvr at: index put: (self asciiOfCharacter: value)] ifFalse: [self stObject: rcvr at: index put: value]. successFlag ifTrue: [^ self pop: argumentCount+1 thenPush: value]. ! ! !Interpreter methodsFor: 'return bytecodes' stamp: 'dtl (auto pragmas dtl 2010-09-26) 4/23/2007 09:01'! commonReturn "Note: Assumed to be inlined into the dispatch loop." | nilOop thisCntx contextOfCaller localCntx localVal unwindMarked | self sharedCodeNamed: 'commonReturn' inCase: 120. nilOop := nilObj. "keep in a register" thisCntx := activeContext. localCntx := localReturnContext. localVal := localReturnValue. "make sure we can return to the given context" ((localCntx = nilOop) or: [(self fetchPointer: InstructionPointerIndex ofObject: localCntx) = nilOop]) ifTrue: [ "error: sender's instruction pointer or context is nil; cannot return" ^self internalCannotReturn: localVal]. "If this return is not to our immediate predecessor (i.e. from a method to its sender, or from a block to its caller), scan the stack for the first unwind marked context and inform this context and let it deal with it. This provides a chance for ensure unwinding to occur." thisCntx := self fetchPointer: SenderIndex ofObject: activeContext. "Just possibly a faster test would be to compare the homeContext and activeContext - they are of course different for blocks. Thus we might be able to optimise a touch by having a different returnTo for the blockreteurn (since we know that must return to caller) and then if active ~= home we must be doing a non-local return. I think. Maybe." [thisCntx = localCntx] whileFalse: [ thisCntx = nilOop ifTrue:[ "error: sender's instruction pointer or context is nil; cannot return" ^self internalCannotReturn: localVal]. "Climb up stack towards localCntx. Break out to a send of #aboutToReturn:through: if an unwind marked context is found" unwindMarked := self isUnwindMarked: thisCntx. unwindMarked ifTrue:[ "context is marked; break out" ^self internalAboutToReturn: localVal through: thisCntx]. thisCntx := self fetchPointer: SenderIndex ofObject: thisCntx. ]. "If we get here there is no unwind to worry about. Simply terminate the stack up to the localCntx - often just the sender of the method" thisCntx := activeContext. [thisCntx = localCntx] whileFalse: ["climb up stack to localCntx" contextOfCaller := self fetchPointer: SenderIndex ofObject: thisCntx. "zap exited contexts so any future attempted use will be caught" self storePointerUnchecked: SenderIndex ofObject: thisCntx withValue: nilOop. self storePointerUnchecked: InstructionPointerIndex ofObject: thisCntx withValue: nilOop. reclaimableContextCount > 0 ifTrue: ["try to recycle this context" reclaimableContextCount := reclaimableContextCount - 1. self recycleContextIfPossible: thisCntx]. thisCntx := contextOfCaller]. activeContext := thisCntx. (self oop: thisCntx isLessThan: youngStart) ifTrue: [ self beRootIfOld: thisCntx ]. self internalFetchContextRegisters: thisCntx. "updates local IP and SP" self fetchNextBytecode. self internalPush: localVal. ! ! !Interpreter methodsFor: 'message sending' stamp: 'ar 7/6/2003 21:53'! commonSend "Send a message, starting lookup with the receiver's class." "Assume: messageSelector and argumentCount have been set, and that the receiver and arguments have been pushed onto the stack," "Note: This method is inlined into the interpreter dispatch loop." self sharedCodeNamed: 'commonSend' inCase: 131. self internalFindNewMethod. self internalExecuteNewMethod. self fetchNextBytecode! ! !Interpreter methodsFor: 'array primitive support' stamp: 'eem 7/18/2009 17:52'! commonVariable: rcvr at: index cacheIndex: atIx "This code assumes the receiver has been identified at location atIx in the atCache." | stSize fmt fixedFields result | stSize := atCache at: atIx+AtCacheSize. ((self oop: index isGreaterThanOrEqualTo: 1) and: [self oop: index isLessThanOrEqualTo: stSize]) ifTrue: [fmt := atCache at: atIx+AtCacheFmt. fmt <= 4 ifTrue: [fixedFields := atCache at: atIx+AtCacheFixedFields. ^ self fetchPointer: index + fixedFields - 1 ofObject: rcvr]. fmt < 8 ifTrue: "Bitmap" [result := self fetchLong32: index - 1 ofObject: rcvr. result := self positive32BitIntegerFor: result. ^ result]. fmt >= 16 "Note fmt >= 16 is an artificial flag for strings" ifTrue: "String" [^ self characterForAscii: (self fetchByte: index - 1 ofObject: rcvr)] ifFalse: "ByteArray" [^ self integerObjectOf: (self fetchByte: index - 1 ofObject: rcvr)]]. self primitiveFail! ! !Interpreter methodsFor: 'array primitive support' stamp: 'eem 7/18/2009 17:51'! commonVariable: rcvr at: index put: value cacheIndex: atIx "This code assumes the receiver has been identified at location atIx in the atCache." | stSize fmt fixedFields valToPut | stSize := atCache at: atIx+AtCacheSize. ((self oop: index isGreaterThanOrEqualTo: 1) and: [self oop: index isLessThanOrEqualTo: stSize]) ifTrue: [fmt := atCache at: atIx+AtCacheFmt. fmt <= 4 ifTrue: [fixedFields := atCache at: atIx+AtCacheFixedFields. ^ self storePointer: index + fixedFields - 1 ofObject: rcvr withValue: value]. fmt < 8 ifTrue: "Bitmap" [valToPut := self positive32BitValueOf: value. successFlag ifTrue: [self storeLong32: index - 1 ofObject: rcvr withValue: valToPut]. ^ nil]. fmt >= 16 "Note fmt >= 16 is an artificial flag for strings" ifTrue: [valToPut := self asciiOfCharacter: value. successFlag ifFalse: [^ nil]] ifFalse: [valToPut := value]. (self isIntegerObject: valToPut) ifTrue: [valToPut := self integerValueOf: valToPut. ((valToPut >= 0) and: [valToPut <= 255]) ifFalse: [^ self primitiveFail]. ^ self storeByte: index - 1 ofObject: rcvr withValue: valToPut]]. self primitiveFail! ! !Interpreter methodsFor: 'array primitive support' stamp: 'eem 7/18/2009 17:52'! commonVariableInternal: rcvr at: index cacheIndex: atIx "This code assumes the receiver has been identified at location atIx in the atCache." | stSize fmt fixedFields result | stSize := atCache at: atIx+AtCacheSize. ((self oop: index isGreaterThanOrEqualTo: 1) and: [self oop: index isLessThanOrEqualTo: stSize]) ifTrue: [fmt := atCache at: atIx+AtCacheFmt. fmt <= 4 ifTrue: [fixedFields := atCache at: atIx+AtCacheFixedFields. ^ self fetchPointer: index + fixedFields - 1 ofObject: rcvr]. fmt < 8 ifTrue: "Bitmap" [result := self fetchLong32: index - 1 ofObject: rcvr. self externalizeIPandSP. result := self positive32BitIntegerFor: result. self internalizeIPandSP. ^ result]. fmt >= 16 "Note fmt >= 16 is an artificial flag for strings" ifTrue: "String" [^ self characterForAscii: (self fetchByte: index - 1 ofObject: rcvr)] ifFalse: "ByteArray" [^ self integerObjectOf: (self fetchByte: index - 1 ofObject: rcvr)]]. self primitiveFail! ! !Interpreter methodsFor: 'arithmetic primitive support'! compare31or32Bits: obj1 equal: obj2 "May set success to false" "First compare two ST integers..." ((self isIntegerObject: obj1) and: [self isIntegerObject: obj2]) ifTrue: [^ obj1 = obj2]. "Now compare, assuming positive integers, but setting fail if not" ^ (self positive32BitValueOf: obj1) = (self positive32BitValueOf: obj2)! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 11/20/1999 05:05'! compilerCreateActualMessage: aMessage storingArgs: argArray ^self cCode: 'compilerHooks[14](aMessage, argArray)'! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 1/3/1999 18:00'! compilerFlushCache: aCompiledMethod ^self cCode: 'compilerHooks[2](aCompiledMethod)'! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp (auto pragmas 12/08) 1/3/1999 17:59'! compilerFlushCacheHook: aCompiledMethod compilerInitialized ifTrue: [self compilerFlushCache: aCompiledMethod]! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 12/12/1998 17:00'! compilerMapFrom: memStart to: memEnd ^self cCode: 'compilerHooks[4](memStart, memEnd)'! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp (auto pragmas 12/08) 12/12/1998 17:03'! compilerMapHookFrom: memStart to: memEnd compilerInitialized ifTrue: [self compilerMapFrom: memStart to: memEnd]! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 12/19/1998 17:08'! compilerMark ^self cCode: 'compilerHooks[9]()'! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp (auto pragmas 12/08) 12/19/1998 17:08'! compilerMarkHook compilerInitialized ifTrue: [self compilerMark]! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 12/12/1998 17:00'! compilerPostGC ^self cCode: 'compilerHooks[5]()'! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp (auto pragmas 12/08) 12/12/1998 17:04'! compilerPostGCHook compilerInitialized ifTrue: [self compilerPostGC]! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 12/15/1998 12:43'! compilerPostSnapshot ^self cCode: 'compilerHooks[8]()'! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp (auto pragmas 12/08) 12/15/1998 12:43'! compilerPostSnapshotHook compilerInitialized ifTrue: [self compilerPostSnapshot]! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 12/12/1998 17:01'! compilerPreGC: fullGCFlag ^self cCode: 'compilerHooks[3](fullGCFlag)'! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp (auto pragmas 12/08) 12/12/1998 17:03'! compilerPreGCHook: fullGCFlag compilerInitialized ifTrue: [self compilerPreGC: fullGCFlag]! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 12/15/1998 13:10'! compilerPreSnapshot ^self cCode: 'compilerHooks[7]()'! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp (auto pragmas 12/08) 12/15/1998 13:10'! compilerPreSnapshotHook compilerInitialized ifTrue: [self compilerPreSnapshot]! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 12/12/1998 17:01'! compilerProcessChange ^self cCode: 'compilerHooks[6]()'! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 11/24/1999 07:09'! compilerProcessChange: oldProc to: newProc ^self cCode: 'compilerHooks[6](oldProc, newProc)'! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp (auto pragmas 12/08) 12/12/1998 17:04'! compilerProcessChangeHook compilerInitialized ifTrue: [self compilerProcessChange]! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 10/22/1999 17:01'! compilerTranslateMethod ^self cCode: 'compilerHooks[1]()'! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp (auto pragmas 12/08) 10/22/1999 17:01'! compilerTranslateMethodHook ^compilerInitialized and: [self compilerTranslateMethod]! ! !Interpreter methodsFor: 'contexts' stamp: 'tpr (auto pragmas 12/08) 3/24/2004 21:00'! context: thisCntx hasSender: aContext "Does thisCntx have aContext in its sender chain?" | s nilOop | thisCntx == aContext ifTrue: [^false]. nilOop := nilObj. s := self fetchPointer: SenderIndex ofObject: thisCntx. [s == nilOop] whileFalse: [s == aContext ifTrue: [^true]. s := self fetchPointer: SenderIndex ofObject: s]. ^false! ! !Interpreter methodsFor: 'bitblt support' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:23'! copyBits "This entry point needs to be implemented for the interpreter proxy. Since BitBlt is now a plugin we need to look up BitBltPlugin:=copyBits and call it. This entire mechanism should eventually go away and be replaced with a dynamic lookup from BitBltPlugin itself but for backward compatibility this stub is provided" | fn | fn := self ioLoadFunction: 'copyBits' From: 'BitBltPlugin'. fn = 0 ifTrue: [^self primitiveFail]. ^self cCode: '((sqInt (*)(void))fn)()'! ! !Interpreter methodsFor: 'bitblt support' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:24'! copyBitsFrom: x0 to: x1 at: y "This entry point needs to be implemented for the interpreter proxy. Since BitBlt is now a plugin we need to look up BitBltPlugin:=copyBitsFrom:to:at: and call it. This entire mechanism should eventually go away and be replaced with a dynamic lookup from BitBltPlugin itself but for backward compatibility this stub is provided" | fn | fn := self ioLoadFunction: 'copyBitsFromtoat' From: 'BitBltPlugin'. fn = 0 ifTrue: [^self primitiveFail]. ^self cCode: '((sqInt (*)(sqInt, sqInt, sqInt))fn)(x0, x1, y)'! ! !Interpreter methodsFor: 'image segment in/out' stamp: 'dtl 5/19/2010 12:52'! copyObj: oop toSegment: segmentWordArray addr: lastSeg stopAt: stopAddr saveOopAt: oopPtr headerAt: hdrPtr "Copy this object into the segment beginning at lastSeg. Install a forwarding pointer, and save oop and header. Fail if out of space. Return the next segmentAddr if successful." "Copy the object..." | extraSize bodySize hdrAddr | self flag: #Dan. "None of the imageSegment stuff has been updated for 64 bits" successFlag ifFalse: [^ lastSeg]. extraSize := self extraHeaderBytes: oop. bodySize := self sizeBitsOf: oop. (self oop: (lastSeg + extraSize + bodySize) isGreaterThanOrEqualTo: stopAddr) ifTrue: [^ self primitiveFail]. self transfer: extraSize + bodySize // self bytesPerWord "wordCount" from: oop - extraSize to: lastSeg + self bytesPerWord. "Clear root and mark bits of all headers copied into the segment" hdrAddr := lastSeg + self bytesPerWord + extraSize. self longAt: hdrAddr put: ((self longAt: hdrAddr) bitAnd: self allButRootBit - self markBit). self forward: oop to: (lastSeg + self bytesPerWord + extraSize - segmentWordArray) savingOopAt: oopPtr andHeaderAt: hdrPtr. "Return new end of segment" ^ lastSeg + extraSize + bodySize! ! !Interpreter methodsFor: 'debug printing'! cr "For testing in Smalltalk, this method should be overridden in a subclass." self printf: '\n'.! ! !Interpreter methodsFor: 'message sending' stamp: 'dtl 5/18/2010 21:42'! createActualMessageTo: aClass "Bundle up the selector, arguments and lookupClass into a Message object. In the process it pops the arguments off the stack, and pushes the message object. This can then be presented as the argument of e.g. #doesNotUnderstand:. ikp 11/20/1999 03:59 -- added hook for external runtime compilers." "remap lookupClass in case GC happens during allocation" | argumentArray message lookupClass | self pushRemappableOop: aClass. argumentArray := self instantiateClass: (self splObj: ClassArray) indexableSize: argumentCount. "remap argumentArray in case GC happens during allocation" self pushRemappableOop: argumentArray. message := self instantiateClass: (self splObj: ClassMessage) indexableSize: 0. argumentArray := self popRemappableOop. lookupClass := self popRemappableOop. self beRootIfOld: argumentArray. compilerInitialized ifTrue: [self compilerCreateActualMessage: message storingArgs: argumentArray] ifFalse: [self transfer: argumentCount from: stackPointer - (argumentCount - 1 * self bytesPerWord) to: argumentArray + self baseHeaderSize. self pop: argumentCount thenPush: message]. argumentCount := 1. self storePointer: MessageSelectorIndex ofObject: message withValue: messageSelector. self storePointer: MessageArgumentsIndex ofObject: message withValue: argumentArray. (self lastPointerOf: message) >= (MessageLookupClassIndex * self bytesPerWord + self baseHeaderSize) ifTrue: ["Only store lookupClass if message has 3 fields (old images don't)" self storePointer: MessageLookupClassIndex ofObject: message withValue: lookupClass]! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 12/12/1998 21:44'! disableCompiler compilerInitialized := false! ! !Interpreter methodsFor: 'message sending' stamp: 'ikp (auto pragmas 12/08) 8/2/2004 18:08'! dispatchFunctionPointer: aFunctionPointer self cCode: '((void (*)(void))aFunctionPointer)()' inSmalltalk: [self error: 'my simulator should simulate me']! ! !Interpreter methodsFor: 'message sending' stamp: 'ikp (auto pragmas 12/08) 8/2/2004 18:18'! dispatchFunctionPointerOn: primIdx in: primTable "Call the primitive at index primIdx in the primitiveTable." ^self dispatchFunctionPointer: (primTable at: primIdx)! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'dtl 5/18/2010 21:42'! displayBitsOf: aForm Left: l Top: t Right: r Bottom: b "Repaint the portion of the Smalltalk screen bounded by the affected rectangle. Used to synchronize the screen after a Bitblt to the Smalltalk Display object." | displayObj dispBits w h dispBitsIndex d left right top bottom surfaceHandle | displayObj := self splObj: TheDisplay. aForm = displayObj ifFalse: [^ nil]. self success: ((self isPointers: displayObj) and: [(self lengthOf: displayObj) >= 4]). successFlag ifTrue: [ dispBits := self fetchPointer: 0 ofObject: displayObj. w := self fetchInteger: 1 ofObject: displayObj. h := self fetchInteger: 2 ofObject: displayObj. d := self fetchInteger: 3 ofObject: displayObj. ]. l < 0 ifTrue:[left := 0] ifFalse: [left := l]. r > w ifTrue: [right := w] ifFalse: [right := r]. t < 0 ifTrue: [top := 0] ifFalse: [top := t]. b > h ifTrue: [bottom := h] ifFalse: [bottom := b]. ((left <= right) and: [top <= bottom]) ifFalse: [^nil]. successFlag ifTrue: [ (self isIntegerObject: dispBits) ifTrue: [ surfaceHandle := self integerValueOf: dispBits. showSurfaceFn = 0 ifTrue: [ showSurfaceFn := self ioLoadFunction: 'ioShowSurface' From: 'SurfacePlugin'. showSurfaceFn = 0 ifTrue: [^self success: false]]. self cCode:'((sqInt (*)(sqInt, sqInt, sqInt, sqInt, sqInt))showSurfaceFn)(surfaceHandle, left, top, right-left, bottom-top)'. ] ifFalse: [ dispBitsIndex := dispBits + self baseHeaderSize. "index in memory byte array" self cCode: 'ioShowDisplay(dispBitsIndex, w, h, d, left, right, top, bottom)' inSmalltalk: [self showDisplayBits: dispBitsIndex w: w h: h d: d left: left right: right top: top bottom: bottom] ]. ].! ! !Interpreter methodsFor: 'arithmetic primitive support' stamp: 'di 11/29/1998 11:22'! doPrimitiveDiv: rcvr by: arg "Rounds negative results towards negative infinity, rather than zero." | result posArg posRcvr integerRcvr integerArg | (self areIntegers: rcvr and: arg) ifTrue: [integerRcvr := self integerValueOf: rcvr. integerArg := self integerValueOf: arg. self success: integerArg ~= 0] ifFalse: [self primitiveFail]. successFlag ifFalse: [^ 1 "fail"]. integerRcvr > 0 ifTrue: [integerArg > 0 ifTrue: [result := integerRcvr // integerArg] ifFalse: ["round negative result toward negative infinity" posArg := 0 - integerArg. result := 0 - ((integerRcvr + (posArg - 1)) // posArg)]] ifFalse: [posRcvr := 0 - integerRcvr. integerArg > 0 ifTrue: ["round negative result toward negative infinity" result := 0 - ((posRcvr + (integerArg - 1)) // integerArg)] ifFalse: [posArg := 0 - integerArg. result := posRcvr // posArg]]. self success: (self isIntegerValue: result). ^ result! ! !Interpreter methodsFor: 'arithmetic primitive support' stamp: 'di 11/29/1998 10:02'! doPrimitiveMod: rcvr by: arg | integerResult integerRcvr integerArg | (self areIntegers: rcvr and: arg) ifTrue: [integerRcvr := self integerValueOf: rcvr. integerArg := self integerValueOf: arg. self success: integerArg ~= 0] ifFalse: [self primitiveFail]. successFlag ifFalse: [^ 1 "fail"]. integerResult := integerRcvr \\ integerArg. "ensure that the result has the same sign as the integerArg" integerArg < 0 ifTrue: [integerResult > 0 ifTrue: [integerResult := integerResult + integerArg]] ifFalse: [integerResult < 0 ifTrue: [integerResult := integerResult + integerArg]]. self success: (self isIntegerValue: integerResult). ^ integerResult ! ! !Interpreter methodsFor: 'send bytecodes' stamp: 'tpr 3/24/2004 18:35'! doubleExtendedDoAnythingBytecode "Replaces the Blue Book double-extended send [132], in which the first byte was wasted on 8 bits of argument count. Here we use 3 bits for the operation sub-type (opType), and the remaining 5 bits for argument count where needed. The last byte give access to 256 instVars or literals. See also secondExtendedSendBytecode" | byte2 byte3 opType top | byte2 := self fetchByte. byte3 := self fetchByte. opType := byte2 >> 5. opType = 0 ifTrue: [messageSelector := self literal: byte3. argumentCount := byte2 bitAnd: 31. ^ self normalSend]. opType = 1 ifTrue: [messageSelector := self literal: byte3. argumentCount := byte2 bitAnd: 31. ^ self superclassSend]. self fetchNextBytecode. opType = 2 ifTrue: [^ self pushReceiverVariable: byte3]. opType = 3 ifTrue: [^ self pushLiteralConstant: byte3]. opType = 4 ifTrue: [^ self pushLiteralVariable: byte3]. opType = 5 ifTrue: [top := self internalStackTop. ^ self storePointer: byte3 ofObject: receiver withValue: top]. opType = 6 ifTrue: [top := self internalStackTop. self internalPop: 1. ^ self storePointer: byte3 ofObject: receiver withValue: top]. opType = 7 ifTrue: [top := self internalStackTop. ^ self storePointer: ValueIndex ofObject: (self literal: byte3) withValue: top]! ! !Interpreter methodsFor: 'initialization' stamp: 'JMM (auto pragmas 12/08) 12/28/2002 22:07'! dummyReferToProxy interpreterProxy := interpreterProxy! ! !Interpreter methodsFor: 'image save/restore' stamp: 'dtl (auto pragmas dtl 2010-09-26) 3/26/2010 02:00'! dumpImage: fileName "Dump the entire image out to the given file. Intended for debugging only." | f dataSize result | f := self cCode: 'sqImageFileOpen(fileName, "wb")'. f = nil ifTrue: [^-1]. dataSize := endOfMemory - self startOfMemory. result := self cCode: 'sqImageFileWrite(pointerForOop(memory), sizeof(unsigned char), dataSize, f)'. self cCode: 'sqImageFileClose(f)'. ^result ! ! !Interpreter methodsFor: 'stack bytecodes' stamp: 'jm 12/10/1998 16:42'! duplicateTopBytecode self fetchNextBytecode. self internalPush: self internalStackTop. ! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 12/12/1998 21:45'! enableCompiler "Calling this before loading the compiler will provoke a nullCompilerHook error" compilerInitialized := true! ! !Interpreter methodsFor: 'message sending' stamp: 'tpr 5/31/2004 17:55'! executeNewMethod "execute a method not found in the mCache - which means that primitiveIndex must be manually set. Used by primitiveClosureValue & primitiveExecuteMethod, where no lookup is previously done" primitiveIndex > 0 ifTrue: [self primitiveResponse. successFlag ifTrue: [^ nil]]. "if not primitive, or primitive failed, activate the method" self activateNewMethod. "check for possible interrupts at each real send" self quickCheckForInterrupts! ! !Interpreter methodsFor: 'message sending' stamp: 'tpr 5/31/2004 17:54'! executeNewMethodFromCache "execute a method found in the mCache - which means that primitiveIndex & primitiveFunctionPointer are already set. Any sender needs to have previously sent findMethodInClass: or equivalent" | nArgs delta | primitiveIndex > 0 ifTrue: [DoBalanceChecks ifTrue: ["check stack balance" nArgs := argumentCount. delta := stackPointer - activeContext]. successFlag := true. self dispatchFunctionPointer: primitiveFunctionPointer. "branch direct to prim function from address stored in mcache" DoBalanceChecks ifTrue: [(self balancedStack: delta afterPrimitive: primitiveIndex withArgs: nArgs) ifFalse: [self printUnbalancedStack: primitiveIndex]]. successFlag ifTrue: [^ nil]]. "if not primitive, or primitive failed, activate the method" self activateNewMethod. "check for possible interrupts at each real send" self quickCheckForInterrupts! ! !Interpreter methodsFor: 'stack bytecodes' stamp: 'jm 12/10/1998 16:46'! extendedPushBytecode | descriptor variableType variableIndex | descriptor := self fetchByte. self fetchNextBytecode. variableType := (descriptor >> 6) bitAnd: 16r3. variableIndex := descriptor bitAnd: 16r3F. variableType=0 ifTrue: [^self pushReceiverVariable: variableIndex]. variableType=1 ifTrue: [^self pushTemporaryVariable: variableIndex]. variableType=2 ifTrue: [^self pushLiteralConstant: variableIndex]. variableType=3 ifTrue: [^self pushLiteralVariable: variableIndex]. ! ! !Interpreter methodsFor: 'stack bytecodes' stamp: 'jm 12/10/1998 16:47'! extendedStoreAndPopBytecode self extendedStoreBytecode. self internalPop: 1. ! ! !Interpreter methodsFor: 'stack bytecodes' stamp: 'tpr (auto pragmas 12/08) 3/24/2004 19:06'! extendedStoreBytecode | descriptor variableType variableIndex association | descriptor := self fetchByte. self fetchNextBytecode. variableType := descriptor >> 6 bitAnd: 3. variableIndex := descriptor bitAnd: 63. variableType = 0 ifTrue: [^ self storePointer: variableIndex ofObject: receiver withValue: self internalStackTop]. variableType = 1 ifTrue: [^ self storePointerUnchecked: variableIndex + TempFrameStart ofObject: localHomeContext withValue: self internalStackTop]. variableType = 2 ifTrue: [self error: 'illegal store']. variableType = 3 ifTrue: [association := self literal: variableIndex. ^ self storePointer: ValueIndex ofObject: association withValue: self internalStackTop]! ! !Interpreter methodsFor: 'utilities' stamp: 'ikp 6/10/2004 11:08'! externalizeIPandSP "Copy the local instruction and stack pointer to global variables for use in primitives and other functions outside the interpret loop." instructionPointer := self oopForPointer: localIP. stackPointer := self oopForPointer: localSP. theHomeContext := localHomeContext. ! ! !Interpreter methodsFor: 'primitive support'! failed ^successFlag not! ! !Interpreter methodsFor: 'utilities' stamp: 'jm (auto pragmas 12/08) 2/15/98 17:11'! fetchArray: fieldIndex ofObject: objectPointer "Fetch the instance variable at the given index of the given object. Return the address of first indexable field of resulting array object, or fail if the instance variable does not contain an indexable bytes or words object." "Note: May be called by translated primitive code." | arrayOop | arrayOop := self fetchPointer: fieldIndex ofObject: objectPointer. ^ self arrayValueOf: arrayOop ! ! !Interpreter methodsFor: 'interpreter shell' stamp: 'ikp 6/10/2004 11:01'! fetchByte "This method uses the preIncrement builtin function which has no Smalltalk equivalent. Thus, it must be overridden in the simulator." ^ self byteAtPointer: localIP preIncrement! ! !Interpreter methodsFor: 'contexts' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/18/2010 21:42'! fetchContextRegisters: activeCntx "Note: internalFetchContextRegisters: should track changes to this method." | tmp | tmp := self fetchPointer: MethodIndex ofObject: activeCntx. (self isIntegerObject: tmp) ifTrue: ["if the MethodIndex field is an integer, activeCntx is a block context" tmp := self fetchPointer: HomeIndex ofObject: activeCntx. (self oop: tmp isLessThan: youngStart) ifTrue: [self beRootIfOld: tmp]] ifFalse: ["otherwise, it is a method context and is its own home context " tmp := activeCntx]. theHomeContext := tmp. receiver := self fetchPointer: ReceiverIndex ofObject: tmp. method := self fetchPointer: MethodIndex ofObject: tmp. "the instruction pointer is a pointer variable equal to method oop + ip + self baseHeaderSize -1 for 0-based addressing of fetchByte -1 because it gets incremented BEFORE fetching currentByte " tmp := self quickFetchInteger: InstructionPointerIndex ofObject: activeCntx. instructionPointer := method + tmp + self baseHeaderSize - 2. "the stack pointer is a pointer variable also..." tmp := self quickFetchInteger: StackPointerIndex ofObject: activeCntx. stackPointer := activeCntx + self baseHeaderSize + (TempFrameStart + tmp - 1 * self bytesPerWord)! ! !Interpreter methodsFor: 'utilities' stamp: '(auto pragmas 12/08) '! fetchFloat: fieldIndex ofObject: objectPointer "Fetch the instance variable at the given index of the given object. Return the C double precision floating point value of that instance variable, or fail if it is not a Float." "Note: May be called by translated primitive code." | floatOop | floatOop := self fetchPointer: fieldIndex ofObject: objectPointer. ^ self floatValueOf: floatOop! ! !Interpreter methodsFor: 'utilities' stamp: 'tpr (auto pragmas 12/08) 3/15/2004 19:52'! fetchInteger: fieldIndex ofObject: objectPointer "Note: May be called by translated primitive code." | intOop | intOop := self fetchPointer: fieldIndex ofObject: objectPointer. ^self checkedIntegerValueOf: intOop! ! !Interpreter methodsFor: 'utilities' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/18/2010 21:42'! fetchIntegerOrTruncFloat: fieldIndex ofObject: objectPointer "Return the integer value of the given field of the given object. If the field contains a Float, truncate it and return its integral part. Fail if the given field does not contain a small integer or Float, or if the truncated Float is out of the range of small integers." "Note: May be called by translated primitive code." | intOrFloat floatVal frac trunc | intOrFloat := self fetchPointer: fieldIndex ofObject: objectPointer. (self isIntegerObject: intOrFloat) ifTrue: [^ self integerValueOf: intOrFloat]. self assertClassOf: intOrFloat is: (self splObj: ClassFloat). successFlag ifTrue: [ self cCode: '' inSmalltalk: [floatVal := Float new: 2]. self fetchFloatAt: intOrFloat + self baseHeaderSize into: floatVal. self cCode: 'frac = modf(floatVal, &trunc)'. "the following range check is for C ints, with range -2^31..2^31-1" self flag: #Dan. "The ranges are INCORRECT if SmallIntegers are wider than 31 bits." self cCode: 'success((-2147483648.0 <= trunc) && (trunc <= 2147483647.0))'.]. successFlag ifTrue: [^ self cCode: '((sqInt) trunc)' inSmalltalk: [floatVal truncated]] ifFalse: [^ 0]. ! ! !Interpreter methodsFor: 'interpreter shell' stamp: 'jm 12/10/1998 16:44'! fetchNextBytecode "This method fetches the next instruction (bytecode). Each bytecode method is responsible for fetching the next bytecode, preferably as early as possible to allow the memory system time to process the request before the next dispatch." currentBytecode := self fetchByte. ! ! !Interpreter methodsFor: 'contexts' stamp: 'tpr (auto pragmas dtl 2010-09-26) 3/24/2004 21:01'! fetchStackPointerOf: aContext "Return the stackPointer of a Context or BlockContext." | sp | sp := self fetchPointer: StackPointerIndex ofObject: aContext. (self isIntegerObject: sp) ifFalse: [^0]. ^self integerValueOf: sp! ! !Interpreter methodsFor: 'debug support'! findClassOfMethod: meth forReceiver: rcvr | currClass classDict classDictSize methodArray i done | currClass := self fetchClassOf: rcvr. done := false. [done] whileFalse: [ classDict := self fetchPointer: MessageDictionaryIndex ofObject: currClass. classDictSize := self fetchWordLengthOf: classDict. methodArray := self fetchPointer: MethodArrayIndex ofObject: classDict. i := 0. [i < (classDictSize - SelectorStart)] whileTrue: [ meth = (self fetchPointer: i ofObject: methodArray) ifTrue: [ ^currClass ]. i := i + 1. ]. currClass := self fetchPointer: SuperclassIndex ofObject: currClass. done := currClass = nilObj. ]. ^self fetchClassOf: rcvr "method not found in superclass chain"! ! !Interpreter methodsFor: 'message sending' stamp: 'tpr (auto pragmas 12/08) 3/24/2004 21:13'! findNewMethodInClass: class "Find the compiled method to be run when the current messageSelector is sent to the given class, setting the values of 'newMethod' and 'primitiveIndex'." | ok | ok := self lookupInMethodCacheSel: messageSelector class: class. ok ifFalse: ["entry was not found in the cache; look it up the hard way " self lookupMethodInClass: class. lkupClass := class. self addNewMethodToCache]! ! !Interpreter methodsFor: 'debug support' stamp: 'ajh 3/16/2003 13:04'! findSelectorOfMethod: meth forReceiver: rcvr | currClass done classDict classDictSize methodArray i | currClass := self fetchClassOf: rcvr. done := false. [done] whileFalse: [ classDict := self fetchPointer: MessageDictionaryIndex ofObject: currClass. classDictSize := self fetchWordLengthOf: classDict. methodArray := self fetchPointer: MethodArrayIndex ofObject: classDict. i := 0. [i <= (classDictSize - SelectorStart)] whileTrue: [ meth = (self fetchPointer: i ofObject: methodArray) ifTrue: [ ^(self fetchPointer: i + SelectorStart ofObject: classDict) ]. i := i + 1. ]. currClass := self fetchPointer: SuperclassIndex ofObject: currClass. done := currClass = nilObj. ]. ^ nilObj "method not found in superclass chain"! ! !Interpreter methodsFor: 'plugin support' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/18/2010 21:42'! firstFixedField: oop ^ self pointerForOop: oop + self baseHeaderSize! ! !Interpreter methodsFor: 'plugin support' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/19/2010 11:05'! firstIndexableField: oop "NOTE: copied in InterpreterSimulator, so please duplicate any changes" | hdr fmt totalLength fixedFields | hdr := self baseHeader: oop. fmt := (hdr >> 8) bitAnd: 16rF. totalLength := self lengthOf: oop baseHeader: hdr format: fmt. fixedFields := self fixedFieldsOf: oop format: fmt length: totalLength. fmt < 8 ifTrue: [fmt = 6 ifTrue: ["32 bit field objects" ^ self pointerForOop: oop + self baseHeaderSize + (fixedFields << 2)]. "full word objects (pointer or bits)" ^ self pointerForOop: oop + self baseHeaderSize + (fixedFields << self shiftForWord)] ifFalse: ["Byte objects" ^ self pointerForOop: oop + self baseHeaderSize + fixedFields]! ! !Interpreter methodsFor: 'object format' stamp: 'ar (auto pragmas dtl 2010-09-26) 3/21/98 02:37'! fixedFieldsOf: oop format: fmt length: wordLength " NOTE: This code supports the backward-compatible extension to 8 bits of instSize. When we revise the image format, it should become... ^ (classFormat >> 2 bitAnd: 16rFF) - 1 " | class classFormat | ((fmt > 4) or: [fmt = 2]) ifTrue: [^ 0]. "indexable fields only" fmt < 2 ifTrue: [^ wordLength]. "fixed fields only (zero or more)" "fmt = 3 or 4: mixture of fixed and indexable fields, so must look at class format word" class := self fetchClassOf: oop. classFormat := self formatOfClass: class. ^ (classFormat >> 11 bitAnd: 16rC0) + (classFormat >> 2 bitAnd: 16r3F) - 1 ! ! !Interpreter methodsFor: 'object format' stamp: 'dtl 9/26/2010 11:32'! floatObjectOf: aFloat | newFloatObj | self flag: #Dan. newFloatObj := self instantiateSmallClass: (self splObj: ClassFloat) sizeInBytes: 8 + self baseHeaderSize. self storeFloatAt: newFloatObj + self baseHeaderSize from: aFloat. ^ newFloatObj. ! ! !Interpreter methodsFor: 'utilities' stamp: 'dtl 9/26/2010 11:32'! floatValueOf: oop "Fetch the instance variable at the given index of the given object. Return the C double precision floating point value of that instance variable, or fail if it is not a Float." "Note: May be called by translated primitive code." | result | self flag: #Dan. "None of the float stuff has been converted for 64 bits" self assertClassOf: oop is: (self splObj: ClassFloat). successFlag ifTrue: [self cCode: '' inSmalltalk: [result := Float new: 2]. self fetchFloatAt: oop + self baseHeaderSize into: result] ifFalse: [result := 0.0]. ^ result! ! !Interpreter methodsFor: 'method lookup cache' stamp: 'dtl 12/13/2010 23:54'! flushAtCache "Flush the at cache. The method cache is flushed on every programming change and garbage collect." 1 to: AtCacheTotalSize do: [ :i | atCache at: i put: 0 ] ! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'tpr 5/12/2005 22:43'! flushExternalPrimitiveOf: methodPtr "methodPtr is a CompiledMethod containing an external primitive. Flush the function address and session ID of the CM" | lit | (self literalCountOf: methodPtr) > 0 ifFalse:[^nil]. "Something's broken" lit := self literal: 0 ofMethod: methodPtr. ((self isArray: lit) and:[(self lengthOf: lit) = 4]) ifFalse:[^nil]. "Something's broken" "ConstZero is a known SmallInt so no root check needed" self storePointerUnchecked: 2 ofObject: lit withValue: ConstZero. self storePointerUnchecked: 3 ofObject: lit withValue: ConstZero. ! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'tpr 3/15/2004 20:46'! flushExternalPrimitiveTable "Flush the external primitive table" 0 to: MaxExternalPrimitiveTableSize-1 do:[:i| externalPrimitiveTable at: i put: 0]. ! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'eem 6/23/2008 16:16'! flushExternalPrimitives "Flush the references to external functions from plugin primitives. This will force a reload of those primitives when accessed next. Note: We must flush the method cache here so that any failed primitives are looked up again." | oop primIdx | oop := self firstObject. [self oop: oop isLessThan: endOfMemory] whileTrue: [(self isFreeObject: oop) ifFalse: [(self isCompiledMethod: oop) ifTrue: ["This is a compiled method" primIdx := self primitiveIndexOf: oop. primIdx = PrimitiveExternalCallIndex ifTrue: ["It's primitiveExternalCall" self flushExternalPrimitiveOf: oop]]]. oop := self objectAfter: oop]. self flushMethodCache. self flushExternalPrimitiveTable! ! !Interpreter methodsFor: 'method lookup cache' stamp: 'dtl 12/13/2010 23:54'! flushMethodCache "Flush the method cache. The method cache is flushed on every programming change and garbage collect." 1 to: MethodCacheSize do: [ :i | methodCache at: i put: 0 ]. self flushAtCache! ! !Interpreter methodsFor: 'method lookup cache' stamp: 'dtl 4/22/2007 22:28'! flushMethodCacheFrom: memStart to: memEnd "Flush entries in the method cache only if the oop address is within the given memory range. This reduces overagressive cache clearing. Note the AtCache is fully flushed, 70% of the time cache entries live in newspace, new objects die young" | probe | probe := 0. 1 to: MethodCacheEntries do: [:i | (methodCache at: probe + MethodCacheSelector) = 0 ifFalse: [(((((self oop: (methodCache at: probe + MethodCacheSelector) isGreaterThanOrEqualTo: memStart) and: [self oop: (methodCache at: probe + MethodCacheSelector) isLessThan: memEnd]) or: [(self oop: (methodCache at: probe + MethodCacheClass) isGreaterThanOrEqualTo: memStart) and: [self oop: (methodCache at: probe + MethodCacheClass) isLessThan: memEnd]]) or: [(self oop: (methodCache at: probe + MethodCacheMethod) isGreaterThanOrEqualTo: memStart) and: [self oop: (methodCache at: probe + MethodCacheMethod) isLessThan: memEnd]]) or: [(self oop: (methodCache at: probe + MethodCacheNative) isGreaterThanOrEqualTo: memStart) and: [self oop: (methodCache at: probe + MethodCacheNative) isLessThan: memEnd]]) ifTrue: [methodCache at: probe + MethodCacheSelector put: 0]]. probe := probe + MethodCacheEntrySize]. 1 to: AtCacheTotalSize do: [:i | atCache at: i put: 0]! ! !Interpreter methodsFor: 'process primitive support' stamp: 'tpr 4/18/2006 13:33'! forceInterruptCheck "force an interrupt check ASAP - setting interruptCheckCounter to a large -ve number is used as a flag to skip messing with the feedback mechanism and nextPollTick resetting makes sure that ioProcess gets called as near immediately as we can manage" interruptCheckCounter := -1000. nextPollTick := 0! ! !Interpreter methodsFor: 'object format'! formatOfClass: classPointer "**should be in-lined**" "Note that, in Smalltalk, the instSpec will be equal to the inst spec part of the base header of an instance (without hdr type) shifted left 1. In this way, apart from the smallInt bit, the bits are just where you want them for the first header word." "Callers expect low 2 bits (header type) to be zero!!" ^ (self fetchPointer: InstanceSpecificationIndex ofObject: classPointer) - 1! ! !Interpreter methodsFor: 'image segment in/out' stamp: 'di 3/24/1999 16:10'! forward: oop to: newOop savingOopAt: oopPtr andHeaderAt: hdrPtr "Make a new entry in the table of saved oops." self longAt: oopPtr put: oop. "Save the oop" self longAt: hdrPtr put: (self longAt: oop). "Save the old header word" "Put a forwarding pointer in the old object, flagged with forbidden header type" self longAt: oop put: newOop + HeaderTypeFree. ! ! !Interpreter methodsFor: 'I/O primitive support' stamp: 'tpr 3/15/2004 10:25'! fullDisplayUpdate "Repaint the entire smalltalk screen, ignoring the affected rectangle. Used in some platform's code when the Smalltalk window is brought to the front or uncovered." | displayObj w h | displayObj := self splObj: TheDisplay. ((self isPointers: displayObj) and: [(self lengthOf: displayObj) >= 4]) ifTrue: [ w := self fetchInteger: 1 ofObject: displayObj. h := self fetchInteger: 2 ofObject: displayObj. self displayBitsOf: displayObj Left: 0 Top: 0 Right: w Bottom: h. self ioForceDisplayUpdate]. ! ! !Interpreter methodsFor: 'method lookup cache' stamp: 'ikp (auto pragmas 12/08) 8/2/2004 17:54'! functionPointerFor: primIdx inClass: theClass "Find an actual function pointer for this primitiveIndex. This is an opportunity to specialise the prim for the relevant class (format for example). Default for now is simply the entry in the base primitiveTable." ^primitiveTable at: primIdx! ! !Interpreter methodsFor: 'interpreter shell'! getCurrentBytecode "currentBytecode will be private to the main dispatch loop in the generated code. This method allows the currentBytecode to be retrieved from global variables." ^ self byteAt: instructionPointer! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'JMM 4/17/2002 12:02'! getFullScreenFlag ^fullScreenFlag! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'JMM 4/17/2002 12:02'! getInterruptCheckCounter ^interruptCheckCounter! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'JMM 4/17/2002 12:02'! getInterruptKeycode ^interruptKeycode! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'JMM 4/17/2002 12:02'! getInterruptPending ^interruptPending! ! !Interpreter methodsFor: 'image save/restore' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:25'! getLongFromFile: aFile swap: swapFlag "Answer the next word read from aFile, byte-swapped according to the swapFlag." | w | w := 0. self cCode: 'sqImageFileRead(&w, sizeof(w), 1, aFile)'. swapFlag ifTrue: [^ self byteSwapped: w] ifFalse: [^ w]. ! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'JMM 4/17/2002 12:03'! getNextWakeupTick ^nextWakeupTick! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'JMM 4/17/2002 12:03'! getSavedWindowSize ^savedWindowSize! ! !Interpreter methodsFor: 'contexts' stamp: 'eem (auto pragmas dtl 2010-09-26) 11/2/2007 15:39'! getStackPointer "For Newsqueak FFI" ^stackPointer! ! !Interpreter methodsFor: 'plugin support' stamp: 'tpr (auto pragmas 12/08) 6/17/2005 17:52'! getThisSessionID "return the global session ID value" ^globalSessionID! ! !Interpreter methodsFor: 'compiled methods' stamp: 'tpr 3/24/2004 21:06'! headerOf: methodPointer ^self fetchPointer: HeaderIndex ofObject: methodPointer! ! !Interpreter methodsFor: 'image save/restore' stamp: 'dtl 5/18/2010 20:55'! imageFormatBackwardCompatibilityVersion "This VM is backwards-compatible with the immediately preceeding pre-closure version, and will allow loading images (or image segments) of that version." self bytesPerWord == 4 ifTrue: [^6502] ifFalse: [^68000]! ! !Interpreter methodsFor: 'image save/restore' stamp: 'dtl 10/3/2010 10:38'! imageFormatInitialVersion "This is the image format version that was saved to in the previous image snapshot. The interpreter checks this value at image load time to determine if it is able to load and run the image file. When the image is next saved, it will be saved using the current imageFormatVersion, which may be different from imageFormatInitialVersion. " ^imageFormatInitialVersion! ! !Interpreter methodsFor: 'image save/restore' stamp: 'eem 2/18/2009 09:51'! imageFormatVersion "Return a magic constant that changes when the image format changes. Since the image reading code uses this to detect byte ordering, one must avoid version numbers that are invariant under byte reversal." "See Interpreter class>>declareCVarsIn: and Interpreter>>pushClosureCopyCopiedValuesBytecode for the initialization of imageFormatVersionNumber" ^imageFormatVersionNumber! ! !Interpreter methodsFor: 'image segment in/out' stamp: 'dtl 5/18/2010 21:43'! imageSegmentVersion | wholeWord | "a more complex version that tells both the word reversal and the endianness of the machine it came from. Low half of word is 6502. Top byte is top byte of #doesNotUnderstand: on this machine. ($d on the Mac or $s on the PC)" wholeWord := self longAt: (self splObj: SelectorDoesNotUnderstand) + self baseHeaderSize. "first data word, 'does' " ^ self imageFormatVersion bitOr: (wholeWord bitAnd: 16rFF000000)! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'ar (auto pragmas 12/08) 11/21/1999 00:11'! includesBehavior: aClass ThatOf: aSuperclass "Return the equivalent of aClass includesBehavior: aSuperclass. Note: written for efficiency and better inlining (only 1 temp)" | theClass | (((theClass := aClass) = aSuperclass) "aClass == aSuperclass" or:[aSuperclass = nilObj]) "every class inherits from nil" ifTrue:[^true]. [(theClass := self superclassOf: theClass) = aSuperclass ifTrue:[^true]. theClass ~= nilObj] whileTrue. ^false! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 11/20/1999 04:53'! initCompilerHooks "Initialize hooks for the 'null compiler'" self cCode: 'compilerHooks[1]= nullCompilerHook'. self cCode: 'compilerHooks[2]= nullCompilerHook'. self cCode: 'compilerHooks[3]= nullCompilerHook'. self cCode: 'compilerHooks[4]= nullCompilerHook'. self cCode: 'compilerHooks[5]= nullCompilerHook'. self cCode: 'compilerHooks[6]= nullCompilerHook'. self cCode: 'compilerHooks[7]= nullCompilerHook'. self cCode: 'compilerHooks[8]= nullCompilerHook'. self cCode: 'compilerHooks[9]= nullCompilerHook'. self cCode: 'compilerHooks[10]= nullCompilerHook'. self cCode: 'compilerHooks[11]= nullCompilerHook'. self cCode: 'compilerHooks[12]= nullCompilerHook'. self cCode: 'compilerHooks[13]= nullCompilerHook'. self cCode: 'compilerHooks[14]= nullCompilerHook'. compilerInitialized := false! ! !Interpreter methodsFor: 'initialization' stamp: 'dtl 5/19/2010 12:52'! initialCleanup "Images written by VMs earlier than 3.6/3.7 will wrongly have the root bit set on the active context. Besides clearing the root bit, we treat this as a marker that these images also lack a cleanup of external primitives (which has been introduced at the same time when the root bit problem was fixed). In this case, we merely flush them from here." ((self longAt: activeContext) bitAnd: self rootBit) = 0 ifTrue:[^nil]. "root bit is clean" "Clean root bit of activeContext" self longAt: activeContext put: ((self longAt: activeContext) bitAnd: self allButRootBit). "Clean external primitives" self flushExternalPrimitives.! ! !Interpreter methodsFor: 'image save/restore' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/19/2010 22:01'! initializeImageFormatVersionIfNeeded "Set the imageFormatVersionNumber to a default value for this word size. Normally this will have been set at image load time, but set it to a reasonable default if this has not been done." imageFormatVersionNumber = 0 ifTrue: [self bytesPerWord == 8 ifFalse: [imageFormatVersionNumber := 6502] ifTrue: [imageFormatVersionNumber := 68000]] ! ! !Interpreter methodsFor: 'initialization' stamp: 'ar 6/8/2006 11:40'! initializeInterpreter: bytesToShift "Initialize Interpreter state before starting execution of a new image." interpreterProxy := self sqGetInterpreterProxy. self dummyReferToProxy. self initializeObjectMemory: bytesToShift. self initCompilerHooks. activeContext := nilObj. theHomeContext := nilObj. method := nilObj. receiver := nilObj. messageSelector := nilObj. newMethod := nilObj. methodClass := nilObj. lkupClass := nilObj. receiverClass := nilObj. newNativeMethod := nilObj. self flushMethodCache. self loadInitialContext. self initialCleanup. interruptCheckCounter := 0. interruptCheckCounterFeedBackReset := 1000. interruptChecksEveryNms := 1. nextPollTick := 0. nextWakeupTick := 0. lastTick := 0. interruptKeycode := 2094. "cmd-. as used for Mac but no other OS" interruptPending := false. semaphoresUseBufferA := true. semaphoresToSignalCountA := 0. semaphoresToSignalCountB := 0. deferDisplayUpdates := false. pendingFinalizationSignals := 0. globalSessionID := 0. [globalSessionID = 0] whileTrue: [globalSessionID := self cCode: 'time(NULL) + ioMSecs()' inSmalltalk: [(Random new next * SmallInteger maxVal) asInteger]]. jmpDepth := 0. jmpMax := MaxJumpBuf. "xxxx: Must match the definition of jmpBuf and suspendedCallbacks" ! ! !Interpreter methodsFor: 'array primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:26'! install: rcvr inAtCache: cache at: atIx string: stringy "Install the oop of this object in the given cache (at or atPut), along with its size, format and fixedSize" | hdr fmt totalLength fixedFields | hdr := self baseHeader: rcvr. fmt := (hdr >> 8) bitAnd: 16rF. (fmt = 3 and: [self isContextHeader: hdr]) ifTrue: ["Contexts must not be put in the atCache, since their size is not constant" ^ self primitiveFail]. totalLength := self lengthOf: rcvr baseHeader: hdr format: fmt. fixedFields := self fixedFieldsOf: rcvr format: fmt length: totalLength. cache at: atIx+AtCacheOop put: rcvr. stringy ifTrue: [cache at: atIx+AtCacheFmt put: fmt + 16] "special flag for strings" ifFalse: [cache at: atIx+AtCacheFmt put: fmt]. cache at: atIx+AtCacheFixedFields put: fixedFields. cache at: atIx+AtCacheSize put: totalLength - fixedFields. ! ! !Interpreter methodsFor: 'return bytecodes' stamp: 'ar (auto pragmas 12/08) 3/6/2001 15:21'! internalAboutToReturn: resultObj through: aContext self internalPush: activeContext. self internalPush: resultObj. self internalPush: aContext. messageSelector := self splObj: SelectorAboutToReturn. argumentCount := 2. ^self normalSend! ! !Interpreter methodsFor: 'message sending' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/19/2010 11:05'! internalActivateNewMethod | methodHeader newContext tempCount argCount2 needsLarge where | methodHeader := self headerOf: newMethod. needsLarge := methodHeader bitAnd: LargeContextBit. (needsLarge = 0 and: [freeContexts ~= NilContext]) ifTrue: [newContext := freeContexts. freeContexts := self fetchPointer: 0 ofObject: newContext] ifFalse: ["Slower call for large contexts or empty free list" self externalizeIPandSP. newContext := self allocateOrRecycleContext: needsLarge. self internalizeIPandSP]. tempCount := (methodHeader >> 19) bitAnd: 16r3F. "Assume: newContext will be recorded as a root if necessary by the call to newActiveContext: below, so we can use unchecked stores." where := newContext + self baseHeaderSize. self longAt: where + (SenderIndex << self shiftForWord) put: activeContext. self longAt: where + (InstructionPointerIndex << self shiftForWord) put: (self integerObjectOf: (((LiteralStart + (self literalCountOfHeader: methodHeader)) * self bytesPerWord) + 1)). self longAt: where + (StackPointerIndex << self shiftForWord) put: (self integerObjectOf: tempCount). self longAt: where + (MethodIndex << self shiftForWord) put: newMethod. self longAt: where + (ClosureIndex << self shiftForWord) put: nilObj. "Copy the receiver and arguments..." argCount2 := argumentCount. 0 to: argCount2 do: [:i | self longAt: where + ((ReceiverIndex+i) << self shiftForWord) put: (self internalStackValue: argCount2-i)]. "clear remaining temps to nil in case it has been recycled" methodHeader := nilObj. "methodHeader here used just as faster (register?) temp" argCount2+1+ReceiverIndex to: tempCount+ReceiverIndex do: [:i | self longAt: where + (i << self shiftForWord) put: methodHeader]. self internalPop: argCount2 + 1. reclaimableContextCount := reclaimableContextCount + 1. self internalNewActiveContext: newContext. ! ! !Interpreter methodsFor: 'return bytecodes' stamp: 'ar (auto pragmas 12/08) 3/6/2001 15:21'! internalCannotReturn: resultObj self internalPush: activeContext. self internalPush: resultObj. messageSelector := self splObj: SelectorCannotReturn. argumentCount := 1. ^ self normalSend! ! !Interpreter methodsFor: 'message sending' stamp: 'tpr (auto pragmas dtl 2010-09-26) 4/22/2004 12:22'! internalExecuteNewMethod | localPrimIndex delta nArgs | localPrimIndex := primitiveIndex. localPrimIndex > 0 ifTrue: [(localPrimIndex > 255 and: [localPrimIndex < 520]) ifTrue: ["Internal return instvars" localPrimIndex >= 264 ifTrue: [^ self internalPop: 1 thenPush: (self fetchPointer: localPrimIndex - 264 ofObject: self internalStackTop)] ifFalse: ["Internal return constants" localPrimIndex = 256 ifTrue: [^ nil]. localPrimIndex = 257 ifTrue: [^ self internalPop: 1 thenPush: trueObj]. localPrimIndex = 258 ifTrue: [^ self internalPop: 1 thenPush: falseObj]. localPrimIndex = 259 ifTrue: [^ self internalPop: 1 thenPush: nilObj]. ^ self internalPop: 1 thenPush: (self integerObjectOf: localPrimIndex - 261)]] ifFalse: [self externalizeIPandSP. "self primitiveResponse. <-replaced with manually inlined code" DoBalanceChecks ifTrue: ["check stack balance" nArgs := argumentCount. delta := stackPointer - activeContext]. successFlag := true. self dispatchFunctionPointer: primitiveFunctionPointer. "branch direct to prim function from address stored in mcache" DoBalanceChecks ifTrue: [(self balancedStack: delta afterPrimitive: localPrimIndex withArgs: nArgs) ifFalse: [self printUnbalancedStack: localPrimIndex]]. self internalizeIPandSP. successFlag ifTrue: [self browserPluginReturnIfNeeded. ^ nil]]]. "if not primitive, or primitive failed, activate the method" self internalActivateNewMethod. "check for possible interrupts at each real send" self internalQuickCheckForInterrupts! ! !Interpreter methodsFor: 'contexts' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/18/2010 21:43'! internalFetchContextRegisters: activeCntx "Inlined into return bytecodes. The only difference between this method and fetchContextRegisters: is that this method sets the local IP and SP." | tmp | tmp := self fetchPointer: MethodIndex ofObject: activeCntx. (self isIntegerObject: tmp) ifTrue: [ "if the MethodIndex field is an integer, activeCntx is a block context" tmp := self fetchPointer: HomeIndex ofObject: activeCntx. (self oop: tmp isLessThan: youngStart) ifTrue: [ self beRootIfOld: tmp ]. ] ifFalse: [ "otherwise, it is a method context and is its own home context" tmp := activeCntx. ]. localHomeContext := tmp. receiver := self fetchPointer: ReceiverIndex ofObject: tmp. method := self fetchPointer: MethodIndex ofObject: tmp. "the instruction pointer is a pointer variable equal to method oop + ip + self baseHeaderSize -1 for 0-based addressing of fetchByte -1 because it gets incremented BEFORE fetching currentByte" tmp := self quickFetchInteger: InstructionPointerIndex ofObject: activeCntx. localIP := self pointerForOop: method + tmp + self baseHeaderSize - 2. "the stack pointer is a pointer variable also..." tmp := self quickFetchInteger: StackPointerIndex ofObject: activeCntx. localSP := self pointerForOop: activeCntx + self baseHeaderSize + ((TempFrameStart + tmp - 1) * self bytesPerWord)! ! !Interpreter methodsFor: 'message sending' stamp: 'ar (auto pragmas 12/08) 7/6/2003 23:55'! internalFindNewMethod "Find the compiled method to be run when the current messageSelector is sent to the class 'lkupClass', setting the values of 'newMethod' and 'primitiveIndex'." | ok | ok := self lookupInMethodCacheSel: messageSelector class: lkupClass. ok ifFalse: [ "entry was not found in the cache; look it up the hard way" self externalizeIPandSP. self lookupMethodInClass: lkupClass. self internalizeIPandSP. self addNewMethodToCache]. ! ! !Interpreter methodsFor: 'object format' stamp: 'John M McIntosh (auto pragmas dtl 2010-09-26) 11/23/2008 00:09'! internalIsImmutable: oop ^false. "^((self baseHeader: oop) bitAnd: ImmutabilityBit) ~= 0"! ! !Interpreter methodsFor: 'object format' stamp: 'John M McIntosh (auto pragmas dtl 2010-09-26) 11/23/2008 00:09'! internalIsMutable: oop ^true "^((self baseHeader: oop) bitAnd: ImmutabilityBit) = 0"! ! !Interpreter methodsFor: 'message sending' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/19/2010 11:05'! internalJustActivateNewMethod "Activate the new method but *do not* copy receiver or argumernts from activeContext." | methodHeader initialIP newContext tempCount needsLarge where | methodHeader := self headerOf: newMethod. needsLarge := methodHeader bitAnd: LargeContextBit. (needsLarge = 0 and: [freeContexts ~= NilContext]) ifTrue: [newContext := freeContexts. freeContexts := self fetchPointer: 0 ofObject: newContext] ifFalse: ["Slower call for large contexts or empty free list" newContext := self allocateOrRecycleContext: needsLarge]. initialIP := ((LiteralStart + (self literalCountOfHeader: methodHeader)) * self bytesPerWord) + 1. tempCount := (methodHeader >> 19) bitAnd: 16r3F. "Assume: newContext will be recorded as a root if necessary by the call to newActiveContext: below, so we can use unchecked stores." where := newContext + self baseHeaderSize. self longAt: where + (SenderIndex << self shiftForWord) put: activeContext. self longAt: where + (InstructionPointerIndex << self shiftForWord) put: (self integerObjectOf: initialIP). self longAt: where + (StackPointerIndex << self shiftForWord) put: (self integerObjectOf: tempCount). self longAt: where + (MethodIndex << self shiftForWord) put: newMethod. "Set the receiver..." self longAt: where + (ReceiverIndex << self shiftForWord) put: receiver. "clear all args and temps to nil in case it has been recycled" needsLarge := nilObj. "needsLarge here used just as faster (register?) temp" ReceiverIndex + 1 to: tempCount + ReceiverIndex do: [:i | self longAt: where + (i << self shiftForWord) put: needsLarge]. reclaimableContextCount := reclaimableContextCount + 1. activeContext := newContext.! ! !Interpreter methodsFor: 'contexts' stamp: 'dtl (auto pragmas 12/08) 4/22/2007 23:27'! internalNewActiveContext: aContext "The only difference between this method and newActiveContext: is that this method uses internal context registers." self internalStoreContextRegisters: activeContext. (self oop: aContext isLessThan: youngStart) ifTrue: [ self beRootIfOld: aContext ]. activeContext := aContext. self internalFetchContextRegisters: aContext.! ! !Interpreter methodsFor: 'contexts' stamp: 'dtl 5/18/2010 20:56'! internalPop: nItems localSP := localSP - (nItems * self bytesPerWord).! ! !Interpreter methodsFor: 'contexts' stamp: 'dtl 5/18/2010 20:57'! internalPop: nItems thenPush: oop self longAtPointer: (localSP := localSP - ((nItems - 1) * self bytesPerWord)) put: oop. ! ! !Interpreter methodsFor: 'control primitives' stamp: 'tpr (auto pragmas dtl 2010-09-26) 5/13/2005 10:50'! internalPrimitiveValue | newContext blockArgumentCount initialIP | self sharedCodeNamed: 'commonPrimitiveValue' inCase: 201. successFlag := true. newContext := self internalStackValue: argumentCount. self assertClassOf: newContext is: (self splObj: ClassBlockContext). blockArgumentCount := self argumentCountOfBlock: newContext. self success: (argumentCount = blockArgumentCount and: [(self fetchPointer: CallerIndex ofObject: newContext) = nilObj]). successFlag ifTrue: ["This code assumes argCount can only = 0 or 1" argumentCount = 1 ifTrue: [self storePointer: TempFrameStart ofObject: newContext withValue: self internalStackTop]. self internalPop: argumentCount + 1. "copy the initialIP value to the ip slot" initialIP := self fetchPointer: InitialIPIndex ofObject: newContext. self storePointerUnchecked: InstructionPointerIndex ofObject: newContext withValue: initialIP. self storeStackPointerValue: argumentCount inContext: newContext. self storePointerUnchecked: CallerIndex ofObject: newContext withValue: activeContext. self internalNewActiveContext: newContext] ifFalse: [messageSelector := self specialSelector: 25 + argumentCount. self normalSend]! ! !Interpreter methodsFor: 'contexts' stamp: 'dtl 5/18/2010 20:57'! internalPush: object self longAtPointer: (localSP := localSP + self bytesPerWord) put: object.! ! !Interpreter methodsFor: 'process primitive support' stamp: 'tpr (auto pragmas dtl 2010-09-26) 2/26/2003 14:05'! internalQuickCheckForInterrupts "Internal version of quickCheckForInterrupts for use within jumps." ((interruptCheckCounter := interruptCheckCounter - 1) <= 0) ifTrue: [ self externalizeIPandSP. self checkForInterrupts. self browserPluginReturnIfNeeded. self internalizeIPandSP]. ! ! !Interpreter methodsFor: 'contexts' stamp: 'ikp 6/10/2004 11:16'! internalStackTop ^ self longAtPointer: localSP! ! !Interpreter methodsFor: 'contexts' stamp: 'dtl 5/18/2010 20:57'! internalStackValue: offset ^ self longAtPointer: localSP - (offset * self bytesPerWord)! ! !Interpreter methodsFor: 'contexts' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/19/2010 11:05'! internalStoreContextRegisters: activeCntx "The only difference between this method and fetchContextRegisters: is that this method stores from the local IP and SP." "InstructionPointer is a pointer variable equal to method oop + ip + self baseHeaderSize -1 for 0-based addressing of fetchByte -1 because it gets incremented BEFORE fetching currentByte" self storePointerUnchecked: InstructionPointerIndex ofObject: activeCntx withValue: (self integerObjectOf: ((self oopForPointer: localIP) + 2 - (method + self baseHeaderSize))). self storePointerUnchecked: StackPointerIndex ofObject: activeCntx withValue: (self integerObjectOf: ((((self oopForPointer: localSP) - (activeCntx + self baseHeaderSize)) >> self shiftForWord) - TempFrameStart + 1)). ! ! !Interpreter methodsFor: 'utilities' stamp: 'ikp 6/10/2004 11:08'! internalizeIPandSP "Copy the local instruction and stack pointer to local variables for rapid access within the interpret loop." localIP := self pointerForOop: instructionPointer. localSP := self pointerForOop: stackPointer. localHomeContext := theHomeContext. ! ! !Interpreter methodsFor: 'interpreter shell' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/19/2010 22:00'! interpret "This is the main interpreter loop. It normally loops forever, fetching and executing bytecodes. When running in the context of a browser plugin VM, however, it must return control to the browser periodically. This should done only when the state of the currently running Squeak thread is safely stored in the object heap. Since this is the case at the moment that a check for interrupts is performed, that is when we return to the browser if it is time to do so. Interrupt checks happen quite frequently." "should not be inlined into any senders" "record entry time when running as a browser plug-in" self browserPluginInitialiseIfNeeded. self initializeImageFormatVersionIfNeeded. self internalizeIPandSP. self fetchNextBytecode. [true] whileTrue: [self dispatchOn: currentBytecode in: BytecodeTable]. localIP := localIP - 1. "undo the pre-increment of IP before returning" self externalizeIPandSP. ! ! !Interpreter methodsFor: 'process primitive support' stamp: 'tpr 3/22/2004 14:20'! interruptCheckForced "was this interrupt check forced by outside code?" ^interruptCheckCounter < -100! ! !Interpreter methodsFor: 'plugin support' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 17:43'! ioFilename: aCharBuffer fromString: aFilenameString ofLength: filenameLength resolveAliases: aBoolean "the vm has to convert aFilenameString via any canonicalization and char-mapping and put the result in aCharBuffer. Note the resolveAliases flag - this is an awful artefact of OSX and Apples demented alias handling. When opening a file, the flag must be true, when closing or renaming it must be false. Sigh." self cCode:'sqGetFilenameFromString(aCharBuffer, aFilenameString, filenameLength, aBoolean)' inSmalltalk:["this doesn't translate well in Smalltalk since we know how long strings are rather than considering them terminated by a 0 char. Do the best we can" aCharBuffer replaceFrom:1 to: filenameLength with: aFilenameString]! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'tpr (auto pragmas dtl 2010-09-26) 12/29/2005 16:26'! is: oop KindOf: className "Support for external primitives." | oopClass | oopClass := self fetchClassOf: oop. [oopClass == nilObj] whileFalse:[ (self classNameOf: oopClass Is: className) ifTrue:[^true]. oopClass := self superclassOf: oopClass]. ^false! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'tpr (auto pragmas dtl 2010-09-26) 12/29/2005 16:26'! is: oop MemberOf: className "Support for external primitives" | oopClass | oopClass := self fetchClassOf: oop. ^(self classNameOf: oopClass Is: className)! ! !Interpreter methodsFor: 'plugin support' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 22:20'! isBigEnder "Answer true (non-zero) if running on a big endian machine." | endianness anInt cString len i | (endianness == -1) ifFalse: [^ endianness]. "answer cached value" len := self cCode: 'sizeof(anInt)' inSmalltalk: [^ (Smalltalk endianness == #little) not]. cString := self cCode: '(char *) &anInt' inSmalltalk: []. i := 0. [i < len] whileTrue: [cString at: i put: i. i := i + 1]. endianness := anInt bitAnd: 255. ^ endianness ! ! !Interpreter methodsFor: 'contexts' stamp: 'eem (auto pragmas 12/08) 5/29/2008 11:53'! isContext: oop ^(self isNonIntegerObject: oop) and: [self isContextHeader: (self baseHeader: oop)]! ! !Interpreter methodsFor: 'contexts' stamp: 'JMM (auto pragmas dtl 2010-09-26) 12/4/2002 13:27'! isContextHeader: aHeader ^ ((aHeader >> 12) bitAnd: 16r1F) = 13 "MethodContext" or: [((aHeader >> 12) bitAnd: 16r1F) = 14 "BlockContext" or: [((aHeader >> 12) bitAnd: 16r1F) = 4]] "PseudoContext"! ! !Interpreter methodsFor: 'process primitive support'! isEmptyList: aLinkedList ^ (self fetchPointer: FirstLinkIndex ofObject: aLinkedList) = nilObj! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'ar 10/7/1998 18:13'! isFloatObject: oop ^(self fetchClassOf: oop) == self classFloat! ! !Interpreter methodsFor: 'compiled methods' stamp: 'ar (auto pragmas 12/08) 3/6/2001 15:04'! isHandlerMarked: aContext "Is this a MethodContext whose meth has a primitive number of 199?" | header meth pIndex | "NB: the use of a primitive number for marking the method is pretty grungy, but it is simple to use for a test sytem, not too expensive and we don't actually have the two spare method header bits we need. We can probably obtain them when the method format is changed. NB 2: actually, the jitter will probably implement the prim to actually mark the volatile frame by changing the return function pointer." header := self baseHeader: aContext. (self isMethodContextHeader: header) ifFalse: [^false]. meth := self fetchPointer: MethodIndex ofObject: aContext. pIndex := self primitiveIndexOf: meth. ^pIndex == 199 ! ! !Interpreter methodsFor: 'object format' stamp: 'ar 10/7/1998 18:13'! isIndexable: oop ^(self formatOf: oop) >= 2! ! !Interpreter methodsFor: 'contexts' stamp: 'di (auto pragmas 12/08) 12/27/1998 23:32'! isMethodContextHeader: aHeader ^ ((aHeader >> 12) bitAnd: 16r1F) = 14! ! !Interpreter methodsFor: 'compiled methods' stamp: 'ar (auto pragmas 12/08) 3/6/2001 15:04'! isUnwindMarked: aContext "Is this a MethodContext whose meth has a primitive number of 198?" | header meth pIndex | "NB: the use of a primitive number for marking the method is pretty grungy, but it is simple to use for a test sytem, not too expensive and we don't actually have the two spare method header bits we need. We can probably obtain them when the method format is changed NB 2: actually, the jitter will probably implement the prim to actually mark the volatile frame by changing the return function pointer." header := self baseHeader: aContext. (self isMethodContextHeader: header) ifFalse: [^false]. meth := self fetchPointer: MethodIndex ofObject: aContext. pIndex := self primitiveIndexOf: meth. ^pIndex == 198 ! ! !Interpreter methodsFor: 'jump bytecodes' stamp: 'ikp 6/10/2004 11:01'! jump: offset localIP := localIP + offset + 1. currentBytecode := self byteAtPointer: localIP. ! ! !Interpreter methodsFor: 'jump bytecodes' stamp: 'tpr 3/24/2004 18:36'! jumplfFalseBy: offset | boolean | boolean := self internalStackTop. boolean = falseObj ifTrue: [self jump: offset] ifFalse: [boolean = trueObj ifFalse: [messageSelector := self splObj: SelectorMustBeBoolean. argumentCount := 0. ^ self normalSend]. self fetchNextBytecode]. self internalPop: 1! ! !Interpreter methodsFor: 'jump bytecodes' stamp: 'tpr 3/24/2004 18:36'! jumplfTrueBy: offset | boolean | boolean := self internalStackTop. boolean = trueObj ifTrue: [self jump: offset] ifFalse: [boolean = falseObj ifFalse: [messageSelector := self splObj: SelectorMustBeBoolean. argumentCount := 0. ^ self normalSend]. self fetchNextBytecode]. self internalPop: 1! ! !Interpreter methodsFor: 'array primitive support' stamp: 'di (auto pragmas dtl 2010-09-26) 11/29/1998 21:24'! lengthOf: oop "Return the number of indexable bytes or words in the given object. Assume the argument is not an integer. For a CompiledMethod, the size of the method header (in bytes) should be subtracted from the result." | header | header := self baseHeader: oop. ^ self lengthOf: oop baseHeader: header format: ((header >> 8) bitAnd: 16rF)! ! !Interpreter methodsFor: 'array primitive support' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/19/2010 12:14'! lengthOf: oop baseHeader: hdr format: fmt "Return the number of indexable bytes or words in the given object. Assume the given oop is not an integer. For a CompiledMethod, the size of the method header (in bytes) should be subtracted from the result of this method." | sz | (hdr bitAnd: TypeMask) = HeaderTypeSizeAndClass ifTrue: [ sz := (self sizeHeader: oop) bitAnd: self longSizeMask ] ifFalse: [ sz := (hdr bitAnd: self sizeMask)]. sz := sz - (hdr bitAnd: self size4Bit). fmt <= 4 ifTrue: [ ^ (sz - self baseHeaderSize) >> self shiftForWord "words"]. fmt < 8 ifTrue: [ ^ (sz - self baseHeaderSize) >> 2 "32-bit longs"] ifFalse: [ ^ (sz - self baseHeaderSize) - (fmt bitAnd: 3) "bytes"]! ! !Interpreter methodsFor: 'compiled methods' stamp: 'tpr 3/24/2004 21:07'! literal: offset ^self literal: offset ofMethod: method! ! !Interpreter methodsFor: 'compiled methods'! literal: offset ofMethod: methodPointer ^ self fetchPointer: offset + LiteralStart ofObject: methodPointer ! ! !Interpreter methodsFor: 'compiled methods'! literalCountOf: methodPointer ^self literalCountOfHeader: (self headerOf: methodPointer)! ! !Interpreter methodsFor: 'compiled methods'! literalCountOfHeader: headerPointer ^ (headerPointer >> 10) bitAnd: 16rFF! ! !Interpreter methodsFor: 'bitblt support' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:26'! loadBitBltFrom: bb "This entry point needs to be implemented for the interpreter proxy. Since BitBlt is now a plugin we need to look up BitBltPlugin:=loadBitBltFrom and call it. This entire mechanism should eventually go away and be replaced with a dynamic lookup from BitBltPlugin itself but for backward compatibility this stub is provided" | fn | fn := self ioLoadFunction: 'loadBitBltFrom' From: 'BitBltPlugin'. fn = 0 ifTrue: [^self primitiveFail]. ^self cCode: '((sqInt (*)(sqInt))fn)(bb)'! ! !Interpreter methodsFor: 'utilities' stamp: 'dtl (auto pragmas dtl 2010-09-26) 9/11/2008 22:44'! loadFloatOrIntFrom: floatOrInt "If floatOrInt is an integer, then convert it to a C double float and return it. If it is a Float, then load its value and return it. Otherwise fail -- ie return with successFlag set to false." (self isIntegerObject: floatOrInt) ifTrue: [^ (self integerValueOf: floatOrInt) asFloat]. (self fetchClassOfNonInt: floatOrInt) = (self splObj: ClassFloat) ifTrue: [^ self floatValueOf: floatOrInt]. successFlag := false! ! !Interpreter methodsFor: 'initialization' stamp: 'dtl 4/22/2007 23:29'! loadInitialContext | sched proc | sched := self fetchPointer: ValueIndex ofObject: (self splObj: SchedulerAssociation). proc := self fetchPointer: ActiveProcessIndex ofObject: sched. activeContext := self fetchPointer: SuspendedContextIndex ofObject: proc. (self oop: activeContext isLessThan: youngStart) ifTrue: [ self beRootIfOld: activeContext ]. self fetchContextRegisters: activeContext. reclaimableContextCount := 0.! ! !Interpreter methodsFor: 'jump bytecodes' stamp: 'tpr 3/24/2004 18:37'! longJumpIfFalse self jumplfFalseBy: ((currentBytecode bitAnd: 3) * 256) + self fetchByte.! ! !Interpreter methodsFor: 'jump bytecodes' stamp: 'tpr 3/24/2004 18:37'! longJumpIfTrue self jumplfTrueBy: ((currentBytecode bitAnd: 3) * 256) + self fetchByte.! ! !Interpreter methodsFor: 'jump bytecodes' stamp: 'tpr 3/24/2004 18:37'! longUnconditionalJump | offset | offset := (((currentBytecode bitAnd: 7) - 4) * 256) + self fetchByte. localIP := localIP + offset. offset < 0 ifTrue: [ "backward jump means we're in a loop; check for possible interrupts" self internalQuickCheckForInterrupts. ]. self fetchNextBytecode ! ! !Interpreter methodsFor: 'method lookup cache' stamp: 'ikp (auto pragmas dtl 2010-09-26) 3/26/2005 13:36'! lookupInMethodCacheSel: selector class: class "This method implements a simple method lookup cache. If an entry for the given selector and class is found in the cache, set the values of 'newMethod' and 'primitiveIndex' and return true. Otherwise, return false." "About the re-probe scheme: The hash is the low bits of the XOR of two large addresses, minus their useless lowest two bits. If a probe doesn't get a hit, the hash is shifted right one bit to compute the next probe, introducing a new randomish bit. The cache is probed CacheProbeMax times before giving up." "WARNING: Since the hash computation is based on the object addresses of the class and selector, we must rehash or flush when compacting storage. We've chosen to flush, since that also saves the trouble of updating the addresses of the objects in the cache." | hash probe | hash := selector bitXor: class. "shift drops two low-order zeros from addresses" probe := hash bitAnd: MethodCacheMask. "first probe" (((methodCache at: probe + MethodCacheSelector) = selector) and: [(methodCache at: probe + MethodCacheClass) = class]) ifTrue: [newMethod := methodCache at: probe + MethodCacheMethod. primitiveIndex := methodCache at: probe + MethodCachePrim. newNativeMethod := methodCache at: probe + MethodCacheNative. primitiveFunctionPointer := self cCoerce: (methodCache at: probe + MethodCachePrimFunction) to: 'void *'. ^ true "found entry in cache; done"]. probe := (hash >> 1) bitAnd: MethodCacheMask. "second probe" (((methodCache at: probe + MethodCacheSelector) = selector) and: [(methodCache at: probe + MethodCacheClass) = class]) ifTrue: [newMethod := methodCache at: probe + MethodCacheMethod. primitiveIndex := methodCache at: probe + MethodCachePrim. newNativeMethod := methodCache at: probe + MethodCacheNative. primitiveFunctionPointer := self cCoerce: (methodCache at: probe + MethodCachePrimFunction) to: 'void *'. ^ true "found entry in cache; done"]. probe := (hash >> 2) bitAnd: MethodCacheMask. (((methodCache at: probe + MethodCacheSelector) = selector) and: [(methodCache at: probe + MethodCacheClass) = class]) ifTrue: [newMethod := methodCache at: probe + MethodCacheMethod. primitiveIndex := methodCache at: probe + MethodCachePrim. newNativeMethod := methodCache at: probe + MethodCacheNative. primitiveFunctionPointer := self cCoerce: (methodCache at: probe + MethodCachePrimFunction) to: 'void *'. ^ true "found entry in cache; done"]. ^ false ! ! !Interpreter methodsFor: 'message sending' stamp: 'ikp (auto pragmas dtl 2010-09-26) 10/24/1999 03:58'! lookupMethodInClass: class | currentClass dictionary found rclass | currentClass := class. [currentClass ~= nilObj] whileTrue: [dictionary := self fetchPointer: MessageDictionaryIndex ofObject: currentClass. dictionary = nilObj ifTrue: ["MethodDict pointer is nil (hopefully due a swapped out stub) -- raise exception #cannotInterpret:." self pushRemappableOop: currentClass. "may cause GC!!" self createActualMessageTo: class. currentClass := self popRemappableOop. messageSelector := self splObj: SelectorCannotInterpret. ^ self lookupMethodInClass: (self superclassOf: currentClass)]. found := self lookupMethodInDictionary: dictionary. found ifTrue: [^ methodClass := currentClass]. currentClass := self superclassOf: currentClass]. "Could not find #doesNotUnderstand: -- unrecoverable error." messageSelector = (self splObj: SelectorDoesNotUnderstand) ifTrue: [self error: 'Recursive not understood error encountered']. "Cound not find a normal message -- raise exception #doesNotUnderstand:" self pushRemappableOop: class. "may cause GC!!" self createActualMessageTo: class. rclass := self popRemappableOop. messageSelector := self splObj: SelectorDoesNotUnderstand. ^ self lookupMethodInClass: rclass! ! !Interpreter methodsFor: 'message sending' stamp: 'tpr (auto pragmas 12/08) 3/24/2004 21:17'! lookupMethodInDictionary: dictionary "This method lookup tolerates integers as Dictionary keys to support execution of images in which Symbols have been compacted out" | length index mask wrapAround nextSelector methodArray | length := self fetchWordLengthOf: dictionary. mask := length - SelectorStart - 1. (self isIntegerObject: messageSelector) ifTrue: [index := (mask bitAnd: (self integerValueOf: messageSelector)) + SelectorStart] ifFalse: [index := (mask bitAnd: (self hashBitsOf: messageSelector)) + SelectorStart]. "It is assumed that there are some nils in this dictionary, and search will stop when one is encountered. However, if there are no nils, then wrapAround will be detected the second time the loop gets to the end of the table." wrapAround := false. [true] whileTrue: [nextSelector := self fetchPointer: index ofObject: dictionary. nextSelector = nilObj ifTrue: [^ false]. nextSelector = messageSelector ifTrue: [methodArray := self fetchPointer: MethodArrayIndex ofObject: dictionary. newMethod := self fetchPointer: index - SelectorStart ofObject: methodArray. "Check if newMethod is a CompiledMethod." (self isCompiledMethod: newMethod) ifTrue: [primitiveIndex := self primitiveIndexOf: newMethod. primitiveIndex > MaxPrimitiveIndex ifTrue: ["If primitiveIndex is out of range, set to zero before putting in cache. This is equiv to primFail, and avoids the need to check on every send." primitiveIndex := 0]] ifFalse: ["indicate that this is no compiled method - use primitiveInvokeObjectAsMethod" primitiveIndex := 248]. ^ true]. index := index + 1. index = length ifTrue: [wrapAround ifTrue: [^ false]. wrapAround := true. index := SelectorStart]]! ! !Interpreter methodsFor: 'alien support' stamp: 'eem (auto pragmas dtl 2010-09-26) 11/16/2007 15:55'! lookupMethodNoMNUEtcInClass: class "Lookup. Answer false on failure father than performing MNU processing etc." | currentClass dictionary | currentClass := class. [currentClass ~= nilObj] whileTrue: [dictionary := self fetchPointer: MessageDictionaryIndex ofObject: currentClass. (dictionary ~= nilObj and: [self lookupMethodInDictionary: dictionary]) ifTrue: [methodClass := currentClass. ^true]. currentClass := self superclassOf: currentClass]. ^false! ! !Interpreter methodsFor: 'utilities' stamp: 'dtl 5/18/2010 20:58'! makePointwithxValue: xValue yValue: yValue "make a Point xValue@yValue. We know both will be integers so no value nor root checking is needed" | pointResult | pointResult := self instantiateSmallClass: (self splObj: ClassPoint) sizeInBytes: 3 * self bytesPerWord. self storePointerUnchecked: XIndex ofObject: pointResult withValue: (self integerObjectOf: xValue). self storePointerUnchecked: YIndex ofObject: pointResult withValue: (self integerObjectOf: yValue). ^ pointResult! ! !Interpreter methodsFor: 'object memory support' stamp: 'ar 1/16/2007 10:48'! mapInterpreterOops "Map all oops in the interpreter's state to their new values during garbage collection or a become: operation." "Assume: All traced variables contain valid oops." | oop | nilObj := self remap: nilObj. falseObj := self remap: falseObj. trueObj := self remap: trueObj. specialObjectsOop := self remap: specialObjectsOop. compilerInitialized ifFalse: [stackPointer := stackPointer - activeContext. "*rel to active" activeContext := self remap: activeContext. stackPointer := stackPointer + activeContext. "*rel to active" theHomeContext := self remap: theHomeContext]. instructionPointer := instructionPointer - method. "*rel to method" method := self remap: method. instructionPointer := instructionPointer + method. "*rel to method" receiver := self remap: receiver. messageSelector := self remap: messageSelector. newMethod := self remap: newMethod. methodClass := self remap: methodClass. lkupClass := self remap: lkupClass. receiverClass := self remap: receiverClass. 1 to: remapBufferCount do: [:i | oop := remapBuffer at: i. (self isIntegerObject: oop) ifFalse: [remapBuffer at: i put: (self remap: oop)]]. "Callback support - trace suspended callback list" 1 to: jmpDepth do:[:i| oop := suspendedCallbacks at: i. (self isIntegerObject: oop) ifFalse:[suspendedCallbacks at: i put: (self remap: oop)]. oop := suspendedMethods at: i. (self isIntegerObject: oop) ifFalse:[suspendedMethods at: i put: (self remap: oop)]. ]. ! ! !Interpreter methodsFor: 'object memory support' stamp: 'ar 1/16/2007 10:47'! markAndTraceInterpreterOops "Mark and trace all oops in the interpreter's state." "Assume: All traced variables contain valid oops." | oop | self compilerMarkHook. self markAndTrace: specialObjectsOop. "also covers nilObj, trueObj, falseObj, and compact classes" compilerInitialized ifTrue: [self markAndTrace: receiver. self markAndTrace: method] ifFalse: [self markAndTrace: activeContext]. self markAndTrace: messageSelector. self markAndTrace: newMethod. self markAndTrace: methodClass. self markAndTrace: lkupClass. self markAndTrace: receiverClass. 1 to: remapBufferCount do: [:i | oop := remapBuffer at: i. (self isIntegerObject: oop) ifFalse: [self markAndTrace: oop]]. "Callback support - trace suspended callback list" 1 to: jmpDepth do:[:i| oop := suspendedCallbacks at: i. (self isIntegerObject: oop) ifFalse:[self markAndTrace: oop]. oop := suspendedMethods at: i. (self isIntegerObject: oop) ifFalse:[self markAndTrace: oop]. ]. ! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'ar 10/7/1998 18:38'! methodArgumentCount ^argumentCount! ! !Interpreter methodsFor: 'compiled methods' stamp: 'tpr 3/24/2004 21:08'! methodClassOf: methodPointer ^ self fetchPointer: ValueIndex ofObject: (self literal: (self literalCountOf: methodPointer) - 1 ofMethod: methodPointer)! ! !Interpreter methodsFor: 'plugin primitive support' stamp: 'ar 10/7/1998 18:39'! methodPrimitiveIndex ^primitiveIndex! ! !Interpreter methodsFor: 'initialization' stamp: 'tpr (auto pragmas 12/08) 3/24/2004 21:22'! moduleUnloaded: aModuleName "The module with the given name was just unloaded. Make sure we have no dangling references." (aModuleName strcmp: 'SurfacePlugin') = 0 ifTrue: ["Surface plugin went away. Should never happen. But then, who knows" showSurfaceFn := 0]! ! !Interpreter methodsFor: 'contexts' stamp: 'dtl 4/22/2007 23:29'! newActiveContext: aContext "Note: internalNewActiveContext: should track changes to this method." self storeContextRegisters: activeContext. (self oop: aContext isLessThan: youngStart) ifTrue: [ self beRootIfOld: aContext ]. activeContext := aContext. self fetchContextRegisters: aContext.! ! !Interpreter methodsFor: 'object format' stamp: 'ar (auto pragmas dtl 2010-09-26) 11/16/2003 01:15'! nonWeakFieldsOf: oop "Return the number of non-weak fields in oop (i.e. the number of fixed fields). Note: The following is copied from fixedFieldsOf:format:length: since we do know the format of the oop (e.g. format = 4) and thus don't need the length." | class classFormat | "No need to inline - we won't call this often" (self isWeakNonInt: oop) ifFalse:[self error:'Called fixedFieldsOfWeak: with a non-weak oop']. "fmt = 3 or 4: mixture of fixed and indexable fields, so must look at class format word" class := self fetchClassOf: oop. classFormat := self formatOfClass: class. ^ (classFormat >> 11 bitAnd: 16rC0) + (classFormat >> 2 bitAnd: 16r3F) - 1 ! ! !Interpreter methodsFor: 'message sending' stamp: 'ar (auto pragmas dtl 2010-09-26) 7/6/2003 22:19'! normalSend "Send a message, starting lookup with the receiver's class." "Assume: messageSelector and argumentCount have been set, and that the receiver and arguments have been pushed onto the stack," "Note: This method is inlined into the interpreter dispatch loop." | rcvr | self sharedCodeNamed: 'normalSend' inCase: 131. rcvr := self internalStackValue: argumentCount. lkupClass := self fetchClassOf: rcvr. receiverClass := lkupClass. self commonSend.! ! !Interpreter methodsFor: 'image save/restore' stamp: 'dtl 10/6/2010 20:24'! normalizeFloatOrderingInImage "Float objects were saved in platform word ordering. Reorder them into the traditional object format." self isBigEnder ifFalse: [ | oop | "Swap words within Float objects, taking them out of native platform ordering" oop := self firstAccessibleObject. [oop = nil] whileFalse: [ | val | (self isFreeObject: oop) ifFalse: [ (self fetchClassOf: oop) = self classFloat ifTrue: [ | floatData | floatData := self cCoerce: (self firstIndexableField: oop) to: 'unsigned int *'. val := floatData at: 0. floatData at: 0 put: (floatData at: 1). floatData at: 1 put: val]. oop := self accessibleObjectAfter: oop]]] ! ! !Interpreter methodsFor: 'compiler support' stamp: 'ikp 12/12/1998 17:08'! nullCompilerHook "This should never be called: either the compiler is uninitialised (in which case the hooks should never be reached) or the compiler initialisation should have replaced all the hook with their external implementations." self error: 'uninitialised compiler hook called'. ^false! ! !Interpreter methodsFor: 'debug support'! okayActiveProcessStack | cntxt | cntxt := activeContext. [cntxt = nilObj] whileFalse: [ self okayFields: cntxt. cntxt := (self fetchPointer: SenderIndex ofObject: cntxt). ].! ! !Interpreter methodsFor: 'debug support' stamp: 'di 2/15/2001 22:33'! okayFields: oop "If this is a pointers object, check that its fields are all okay oops." | i fieldOop c | (oop = nil or: [oop = 0]) ifTrue: [ ^true ]. (self isIntegerObject: oop) ifTrue: [ ^true ]. self okayOop: oop. self oopHasOkayClass: oop. (self isPointers: oop) ifFalse: [ ^true ]. c := self fetchClassOf: oop. (c = (self splObj: ClassMethodContext) or: [c = (self splObj: ClassBlockContext)]) ifTrue: [i := CtxtTempFrameStart + (self fetchStackPointerOf: oop) - 1] ifFalse: [i := (self lengthOf: oop) - 1]. [i >= 0] whileTrue: [ fieldOop := self fetchPointer: i ofObject: oop. (self isIntegerObject: fieldOop) ifFalse: [ self okayOop: fieldOop. self oopHasOkayClass: fieldOop. ]. i := i - 1. ].! ! !Interpreter methodsFor: 'debug support'! okayInterpreterObjects | oopOrZero oop | self okayFields: nilObj. self okayFields: falseObj. self okayFields: trueObj. self okayFields: specialObjectsOop. self okayFields: activeContext. self okayFields: method. self okayFields: receiver. self okayFields: theHomeContext. self okayFields: messageSelector. self okayFields: newMethod. self okayFields: lkupClass. 0 to: MethodCacheEntries - 1 by: MethodCacheEntrySize do: [ :i | oopOrZero := methodCache at: i + MethodCacheSelector. oopOrZero = 0 ifFalse: [ self okayFields: (methodCache at: i + MethodCacheSelector). self okayFields: (methodCache at: i + MethodCacheClass). self okayFields: (methodCache at: i + MethodCacheMethod). ]. ]. 1 to: remapBufferCount do: [ :i | oop := remapBuffer at: i. (self isIntegerObject: oop) ifFalse: [ self okayFields: oop. ]. ]. self okayActiveProcessStack.! ! !Interpreter methodsFor: 'debug support' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/19/2010 12:38'! okayOop: signedOop "Verify that the given oop is legitimate. Check address, header, and size but not class." | sz type fmt unusedBit oop | oop := self cCoerce: signedOop to: 'usqInt'. "address and size checks" (self isIntegerObject: oop) ifTrue: [ ^true ]. (oop < endOfMemory) ifFalse: [ self error: 'oop is not a valid address' ]. ((oop \\ self bytesPerWord) = 0) ifFalse: [ self error: 'oop is not a word-aligned address' ]. sz := self sizeBitsOf: oop. (oop + sz) < endOfMemory ifFalse: [ self error: 'oop size would make it extend beyond the end of memory' ]. "header type checks" type := self headerType: oop. type = HeaderTypeFree ifTrue: [ self error: 'oop is a free chunk, not an object' ]. type = HeaderTypeShort ifTrue: [ (((self baseHeader: oop) >> 12) bitAnd: 16r1F) = 0 ifTrue: [ self error: 'cannot have zero compact class field in a short header' ]. ]. type = HeaderTypeClass ifTrue: [ ((oop >= self bytesPerWord) and: [(self headerType: oop - self bytesPerWord) = type]) ifFalse: [ self error: 'class header word has wrong type' ]. ]. type = HeaderTypeSizeAndClass ifTrue: [ ((oop >= (self bytesPerWord * 2)) and: [(self headerType: oop - (self bytesPerWord * 2)) = type and: [(self headerType: oop - self bytesPerWord) = type]]) ifFalse: [ self error: 'class header word has wrong type' ]. ]. "format check" fmt := self formatOf: oop. ((fmt = 5) | (fmt = 7)) ifTrue: [ self error: 'oop has an unknown format type' ]. "mark and root bit checks" unusedBit := 16r20000000. self bytesPerWord = 8 ifTrue: [unusedBit := unusedBit << 16. unusedBit := unusedBit << 16]. ((self longAt: oop) bitAnd: unusedBit) = 0 ifFalse: [ self error: 'unused header bit 30 is set; should be zero' ]. "xxx ((self longAt: oop) bitAnd: MarkBit) = 0 ifFalse: [ self error: 'mark bit should not be set except during GC' ]. xxx" (((self longAt: oop) bitAnd: self rootBit) = 1 and: [oop >= youngStart]) ifTrue: [ self error: 'root bit is set in a young object' ]. ^true ! ! !Interpreter methodsFor: 'image save/restore' stamp: 'dtl 10/5/2010 22:21'! oldFormatFullScreenFlag: flagsWord "The full screen flags word in the image header file was originally defined as a boolean (low order bit of the word set for true). In more recent usage with StackInterpreter, the remaining bits are allocated for other purposes. This interpreter does not use the new bit definitions, and should clear the bits before saving the image." ^ flagsWord bitAnd: 1! ! !Interpreter methodsFor: 'image segment in/out' stamp: 'dtl 9/26/2010 11:32'! oopHasAcceptableClass: signedOop "Similar to oopHasOkayClass:, except that it only returns true or false." | oopClass formatMask behaviorFormatBits oopFormatBits oop | (self isIntegerObject: signedOop) ifTrue: [^ true]. oop := self cCoerce: signedOop to: 'usqInt'. oop < endOfMemory ifFalse: [^ false]. ((oop \\ self bytesPerWord) = 0) ifFalse: [^ false]. (oop + (self sizeBitsOf: oop)) < endOfMemory ifFalse: [^ false]. oopClass := self cCoerce: (self fetchClassOf: oop) to: 'usqInt'. (self isIntegerObject: oopClass) ifTrue: [^ false]. (oopClass < endOfMemory) ifFalse: [^ false]. ((oopClass \\ self bytesPerWord) = 0) ifFalse: [^ false]. (oopClass + (self sizeBitsOf: oopClass)) < endOfMemory ifFalse: [^ false]. ((self isPointers: oopClass) and: [(self lengthOf: oopClass) >= 3]) ifFalse: [^ false]. (self isBytes: oop) ifTrue: [ formatMask := 16rC00 ] "ignore extra bytes size bits" ifFalse: [ formatMask := 16rF00 ]. behaviorFormatBits := (self formatOfClass: oopClass) bitAnd: formatMask. oopFormatBits := (self baseHeader: oop) bitAnd: formatMask. behaviorFormatBits = oopFormatBits ifFalse: [^ false]. ^ true! ! !Interpreter methodsFor: 'debug support' stamp: 'ikp (auto pragmas dtl 2010-09-26) 3/26/2005 21:06'! oopHasOkayClass: signedOop "Attempt to verify that the given oop has a reasonable behavior. The class must be a valid, non-integer oop and must not be nilObj. It must be a pointers object with three or more fields. Finally, the instance specification field of the behavior must match that of the instance." | oop oopClass formatMask behaviorFormatBits oopFormatBits | oop := self cCoerce: signedOop to: 'usqInt'. self okayOop: oop. oopClass := self cCoerce: (self fetchClassOf: oop) to: 'usqInt'. (self isIntegerObject: oopClass) ifTrue: [ self error: 'a SmallInteger is not a valid class or behavior' ]. self okayOop: oopClass. ((self isPointers: oopClass) and: [(self lengthOf: oopClass) >= 3]) ifFalse: [ self error: 'a class (behavior) must be a pointers object of size >= 3' ]. (self isBytes: oop) ifTrue: [ formatMask := 16rC00 ] "ignore extra bytes size bits" ifFalse: [ formatMask := 16rF00 ]. behaviorFormatBits := (self formatOfClass: oopClass) bitAnd: formatMask. oopFormatBits := (self baseHeader: oop) bitAnd: formatMask. behaviorFormatBits = oopFormatBits ifFalse: [ self error: 'object and its class (behavior) formats differ' ]. ^true! ! !Interpreter methodsFor: 'contexts' stamp: 'di 11/30/1998 12:31'! pop2AndPushIntegerIfOK: integerResult successFlag ifTrue: [(self isIntegerValue: integerResult) ifTrue: [self pop: 2 thenPush: (self integerObjectOf: integerResult)] ifFalse: [successFlag := false]]! ! !Interpreter methodsFor: 'contexts' stamp: 'dtl 5/18/2010 20:59'! pop: nItems "Note: May be called by translated primitive code." stackPointer := stackPointer - (nItems * self bytesPerWord).! ! !Interpreter methodsFor: 'contexts' stamp: 'dtl 5/18/2010 20:59'! pop: nItems thenPush: oop | sp | self longAt: (sp := stackPointer - ((nItems - 1) * self bytesPerWord)) put: oop. stackPointer := sp. ! ! !Interpreter methodsFor: 'contexts' stamp: 'dtl 5/18/2010 21:00'! pop: nItems thenPushInteger: integerVal "lots of places pop a few items off the stack and then push an integer. MAke it convenient" | sp | self longAt: (sp := stackPointer - ((nItems - 1) * self bytesPerWord)) put:(self integerObjectOf: integerVal). stackPointer := sp. ! ! !Interpreter methodsFor: 'stack bytecodes' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/18/2010 21:44'! popFloat "Note: May be called by translated primitive code." | top result | top := self popStack. self assertClassOf: top is: (self splObj: ClassFloat). successFlag ifTrue: [self cCode: '' inSmalltalk: [result := Float new: 2]. self fetchFloatAt: top + self baseHeaderSize into: result]. ^ result! ! !Interpreter methodsFor: 'contexts' stamp: 'tpr 3/15/2004 20:00'! popInteger "returns 0 if the stackTop was not an integer value, plus sets successFlag false" | integerPointer | integerPointer := self popStack. ^self checkedIntegerValueOf: integerPointer! ! !Interpreter methodsFor: 'contexts'! popPos32BitInteger "May set successFlag, and return false if not valid" | top | top := self popStack. ^ self positive32BitValueOf: top! ! !Interpreter methodsFor: 'contexts' stamp: 'dtl 5/18/2010 21:00'! popStack | top | top := self longAt: stackPointer. stackPointer := stackPointer - self bytesPerWord. ^ top! ! !Interpreter methodsFor: 'stack bytecodes' stamp: 'jm 12/10/1998 16:47'! popStackBytecode self fetchNextBytecode. self internalPop: 1. ! ! !Interpreter methodsFor: 'primitive support' stamp: 'dtl 5/18/2010 21:44'! positive32BitIntegerFor: integerValue | newLargeInteger | "Note - integerValue is interpreted as POSITIVE, eg, as the result of Bitmap>at:, or integer>bitAnd:." integerValue >= 0 ifTrue: [(self isIntegerValue: integerValue) ifTrue: [^ self integerObjectOf: integerValue]]. self bytesPerWord = 4 ifTrue: ["Faster instantiateSmallClass: currently only works with integral word size." newLargeInteger := self instantiateSmallClass: (self splObj: ClassLargePositiveInteger) sizeInBytes: self baseHeaderSize + 4] ifFalse: ["Cant use instantiateSmallClass: due to integral word requirement." newLargeInteger := self instantiateClass: (self splObj: ClassLargePositiveInteger) indexableSize: 4]. self storeByte: 3 ofObject: newLargeInteger withValue: ((integerValue >> 24) bitAnd: 16rFF). self storeByte: 2 ofObject: newLargeInteger withValue: ((integerValue >> 16) bitAnd: 16rFF). self storeByte: 1 ofObject: newLargeInteger withValue: ((integerValue >> 8) bitAnd: 16rFF). self storeByte: 0 ofObject: newLargeInteger withValue: (integerValue bitAnd: 16rFF). ^ newLargeInteger! ! !Interpreter methodsFor: 'primitive support'! positive32BitValueOf: oop "Convert the given object into an integer value. The object may be either a positive ST integer or a four-byte LargePositiveInteger." | sz value | (self isIntegerObject: oop) ifTrue: [ value := self integerValueOf: oop. value < 0 ifTrue: [^ self primitiveFail]. ^ value]. self assertClassOf: oop is: (self splObj: ClassLargePositiveInteger). successFlag ifTrue: [ sz := self lengthOf: oop. sz = 4 ifFalse: [^ self primitiveFail]]. successFlag ifTrue: [ ^ (self fetchByte: 0 ofObject: oop) + ((self fetchByte: 1 ofObject: oop) << 8) + ((self fetchByte: 2 ofObject: oop) << 16) + ((self fetchByte: 3 ofObject: oop) << 24) ].! ! !Interpreter methodsFor: 'primitive support' stamp: 'ar (auto pragmas 12/08) 3/21/2008 20:40'! positive64BitIntegerFor: integerValue | newLargeInteger value highWord sz | "Note - integerValue is interpreted as POSITIVE, eg, as the result of Bitmap>at:, or integer>bitAnd:." (self sizeof: integerValue) = 4 ifTrue: [^self positive32BitIntegerFor: integerValue]. highWord := self cCode: 'integerValue >> 32'. "shift is coerced to usqInt otherwise" highWord = 0 ifTrue:[^self positive32BitIntegerFor: integerValue]. sz := 5. (highWord := highWord >> 8) = 0 ifFalse:[sz := sz + 1]. (highWord := highWord >> 8) = 0 ifFalse:[sz := sz + 1]. (highWord := highWord >> 8) = 0 ifFalse:[sz := sz + 1]. newLargeInteger := self instantiateClass: (self splObj: ClassLargePositiveInteger) indexableSize: sz. 0 to: sz-1 do: [:i | value := self cCode: '(integerValue >> (i * 8)) & 255'. self storeByte: i ofObject: newLargeInteger withValue: value]. ^ newLargeInteger ! ! !Interpreter methodsFor: 'primitive support' stamp: 'tpr (auto pragmas 12/08) 3/17/2005 17:47'! positive64BitValueOf: oop "Convert the given object into an integer value. The object may be either a positive ST integer or a eight-byte LargePositiveInteger." | sz szsqLong value | (self isIntegerObject: oop) ifTrue: [ value := self integerValueOf: oop. value < 0 ifTrue: [^ self primitiveFail]. ^ value]. self assertClassOf: oop is: (self splObj: ClassLargePositiveInteger). successFlag ifFalse: [^ self primitiveFail]. szsqLong := self cCode: 'sizeof(sqLong)'. sz := self lengthOf: oop. sz > szsqLong ifTrue: [^ self primitiveFail]. value := 0. 0 to: sz - 1 do: [:i | value := value + ((self cCoerce: (self fetchByte: i ofObject: oop) to: 'sqLong') << (i*8))]. ^value.! ! !Interpreter methodsFor: 'object memory support' stamp: 'JMM 6/9/2007 15:36'! postGCAction "Mark the active and home contexts as roots if old. This allows the interpreter to use storePointerUnchecked to store into them." compilerInitialized ifTrue: [self compilerPostGC] ifFalse: [(self oop: activeContext isLessThan: youngStart) ifTrue: [self beRootIfOld: activeContext]. (self oop: theHomeContext isLessThan: youngStart) ifTrue: [self beRootIfOld: theHomeContext]]. (self oop: (self sizeOfFree: freeBlock) isGreaterThan: shrinkThreshold) ifTrue: ["Attempt to shrink memory after successfully reclaiming lots of memory" self shrinkObjectMemory: (self sizeOfFree: freeBlock) - growHeadroom]. self signalSemaphoreWithIndex: gcSemaphoreIndex. ! ! !Interpreter methodsFor: 'object memory support' stamp: 'tpr 3/24/2004 21:21'! preGCAction: fullGCFlag compilerInitialized ifTrue: [self compilerPreGC: fullGCFlag] ifFalse: [self storeContextRegisters: activeContext].! ! !Interpreter methodsFor: 'primitive support'! primIndex ^ primitiveIndex! ! !Interpreter methodsFor: 'arithmetic integer primitives' stamp: 'di 11/30/1998 10:13'! primitiveAdd self pop2AndPushIntegerIfOK: (self stackIntegerValue: 1) + (self stackIntegerValue: 0)! ! !Interpreter methodsFor: 'arithmetic largeint primitives' stamp: 'ar (auto pragmas 12/08) 3/19/2008 21:37'! primitiveAddLargeIntegers "Primitive arithmetic operations for large integers in 64 bit range" | integerRcvr integerArg result oopResult | integerArg := self signed64BitValueOf: (self stackValue: 0). integerRcvr := self signed64BitValueOf: (self stackValue: 1). successFlag ifFalse:[^nil]. "Compute the preliminary result (which may overflow)" result := integerRcvr + integerArg. "Now check overflow conditions. First is whether rcvr and arg are of the same sign. If they are we need to check for overflow more carefully." (integerRcvr bitXor: integerArg) < 0 ifFalse:[ "Second is whether rcvr and result are of the same sign. If not, we have an overflow." (integerRcvr bitXor: result) < 0 ifTrue:[self primitiveFail]]. successFlag ifFalse:[^nil]. oopResult := self signed64BitIntegerFor: result. successFlag ifTrue:[self pop: 2 thenPush: oopResult]. ! ! !Interpreter methodsFor: 'object access primitives' stamp: 'eem 7/16/2010 19:57'! primitiveAdoptInstance "Primitive. Change the class of the argument to make it an instance of the receiver given that the format of the receiver matches the format of the argument's class. Fail if receiver or argument are SmallIntegers, or the receiver is an instance of a compact class and the argument isn't, or when the argument's class is compact and the receiver isn't, or when the format of the receiver is different from the format of the argument's class, or when the arguments class is fixed and the receiver's size differs from the size that an instance of the argument's class should have." | rcvr arg err | arg := self stackObjectValue: 0. rcvr := self stackObjectValue: 1. err := self changeClassOf: arg to: rcvr. err = 0 ifTrue: ["Flush at cache because rcvr's class has changed." self flushAtCache. self pop: self methodArgumentCount] ifFalse: [self primitiveFail]. ^nil! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:26'! primitiveArctan | rcvr | rcvr := self popFloat. successFlag ifTrue: [self pushFloat: (self cCode: 'atan(rcvr)' inSmalltalk: [rcvr arcTan])] ifFalse: [self unPop: 1]! ! !Interpreter methodsFor: 'object access primitives' stamp: 'brp 9/19/2003 16:08'! primitiveArrayBecome "We must flush the method cache here, to eliminate stale references to mutated classes and/or selectors." | arg rcvr | arg := self stackTop. rcvr := self stackValue: 1. self success: (self become: rcvr with: arg twoWay: true copyHash: true). successFlag ifTrue: [ self pop: 1 ].! ! !Interpreter methodsFor: 'object access primitives' stamp: 'brp 9/26/2003 08:00'! primitiveArrayBecomeOneWay "We must flush the method cache here, to eliminate stale references to mutated classes and/or selectors." | arg rcvr | arg := self stackTop. rcvr := self stackValue: 1. self success: (self become: rcvr with: arg twoWay: false copyHash: true). successFlag ifTrue: [ self pop: 1 ].! ! !Interpreter methodsFor: 'object access primitives' stamp: 'brp 9/26/2003 08:08'! primitiveArrayBecomeOneWayCopyHash "Similar to primitiveArrayBecomeOneWay but accepts a third argument whether to copy the receiver's identity hash over the argument's identity hash." | copyHashFlag arg rcvr | copyHashFlag := self booleanValueOf: (self stackTop). arg := self stackValue: 1. rcvr := self stackValue: 2. self success: (self become: rcvr with: arg twoWay: false copyHash: copyHashFlag). successFlag ifTrue: [ self pop: 2 ].! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'tpr 3/23/2004 17:21'! primitiveAsFloat | arg | arg := self popInteger. successFlag ifTrue: [ self pushFloat: (self cCode: '((double) arg)' inSmalltalk: [arg asFloat]) ] ifFalse: [ self unPop: 1 ].! ! !Interpreter methodsFor: 'object access primitives' stamp: 'tpr 5/13/2005 10:17'! primitiveAsOop | thisReceiver | thisReceiver := self stackTop. self success: (self isIntegerObject: thisReceiver) not. successFlag ifTrue: [self pop:1 thenPushInteger: (self hashBitsOf: thisReceiver)]! ! !Interpreter methodsFor: 'array primitives'! primitiveAt self commonAt: false.! ! !Interpreter methodsFor: 'array and stream primitives' stamp: 'di 12/11/1998 10:15'! primitiveAtEnd | stream index limit | stream := self popStack. successFlag := ((self isPointers: stream) and: [(self lengthOf: stream) >= (StreamReadLimitIndex+1)]). successFlag ifTrue: [ index := self fetchInteger: StreamIndexIndex ofObject: stream. limit := self fetchInteger: StreamReadLimitIndex ofObject: stream]. successFlag ifTrue: [self pushBool: (index >= limit)] ifFalse: [self unPop: 1].! ! !Interpreter methodsFor: 'array primitives'! primitiveAtPut self commonAtPut: false.! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'dtl 5/18/2010 21:44'! primitiveBeCursor "Set the cursor to the given shape. The Mac only supports 16x16 pixel cursors. Cursor offsets are handled by Smalltalk." | cursorObj maskBitsIndex maskObj bitsObj extentX extentY depth offsetObj offsetX offsetY cursorBitsIndex ourCursor | self flag: #Dan. "This is disabled until we convert bitmaps appropriately" self bytesPerWord = 8 ifTrue: [^ self pop: argumentCount]. argumentCount = 0 ifTrue: [ cursorObj := self stackTop. maskBitsIndex := nil]. argumentCount = 1 ifTrue: [ cursorObj := self stackValue: 1. maskObj := self stackTop]. self success: (argumentCount < 2). self success: ((self isPointers: cursorObj) and: [(self lengthOf: cursorObj) >= 5]). successFlag ifTrue: [ bitsObj := self fetchPointer: 0 ofObject: cursorObj. extentX := self fetchInteger: 1 ofObject: cursorObj. extentY := self fetchInteger: 2 ofObject: cursorObj. depth := self fetchInteger: 3 ofObject: cursorObj. offsetObj := self fetchPointer: 4 ofObject: cursorObj]. self success: ((self isPointers: offsetObj) and: [(self lengthOf: offsetObj) >= 2]). successFlag ifTrue: [ offsetX := self fetchInteger: 0 ofObject: offsetObj. offsetY := self fetchInteger: 1 ofObject: offsetObj. (argumentCount = 0 and: [depth = 32]) ifTrue: [ "Support arbitrary-sized 32 bit ARGB forms --bf 3/1/2007 23:51" self success: ((extentX > 0) and: [extentY > 0]). self success: ((offsetX >= (extentX * -1)) and: [offsetX <= 0]). self success: ((offsetY >= (extentY * -1)) and: [offsetY <= 0]). cursorBitsIndex := bitsObj + self baseHeaderSize. self success: ((self isWords: bitsObj) and: [(self lengthOf: bitsObj) = (extentX * extentY)]). self cCode: '' inSmalltalk: [ourCursor := Cursor extent: extentX @ extentY depth: 32 fromArray: ((1 to: extentX * extentY) collect: [:i | self fetchLong32: i-1 ofObject: bitsObj]) offset: offsetX @ offsetY]] ifFalse: [ self success: ((extentX = 16) and: [extentY = 16 and: [depth = 1]]). self success: ((offsetX >= -16) and: [offsetX <= 0]). self success: ((offsetY >= -16) and: [offsetY <= 0]). self success: ((self isWords: bitsObj) and: [(self lengthOf: bitsObj) = 16]). cursorBitsIndex := bitsObj + self baseHeaderSize. self cCode: '' inSmalltalk: [ourCursor := Cursor extent: extentX @ extentY fromArray: ((1 to: 16) collect: [:i | ((self fetchLong32: i-1 ofObject: bitsObj) >> 16) bitAnd: 16rFFFF]) offset: offsetX @ offsetY]]]. argumentCount = 1 ifTrue: [ self success: ((self isPointers: maskObj) and: [(self lengthOf: maskObj) >= 5]). successFlag ifTrue: [ bitsObj := self fetchPointer: 0 ofObject: maskObj. extentX := self fetchInteger: 1 ofObject: maskObj. extentY := self fetchInteger: 2 ofObject: maskObj. depth := self fetchInteger: 3 ofObject: maskObj]. successFlag ifTrue: [ self success: ((extentX = 16) and: [extentY = 16 and: [depth = 1]]). self success: ((self isWords: bitsObj) and: [(self lengthOf: bitsObj) = 16]). maskBitsIndex := bitsObj + self baseHeaderSize]]. successFlag ifTrue: [ argumentCount = 0 ifTrue: [ depth = 32 ifTrue: [(self cCode: 'ioSetCursorARGB(cursorBitsIndex, extentX, extentY, offsetX, offsetY)' inSmalltalk: [ourCursor show. Cursor currentCursor == ourCursor]) ifFalse: [^self success: false]] ifFalse: [self cCode: 'ioSetCursor(cursorBitsIndex, offsetX, offsetY)' inSmalltalk: [ourCursor show]]] ifFalse: [self cCode: 'ioSetCursorWithMask(cursorBitsIndex, maskBitsIndex, offsetX, offsetY)' inSmalltalk: [cursorBitsIndex == maskBitsIndex. "placate compiler" ourCursor show]]. self pop: argumentCount]! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'tpr 3/15/2004 12:13'! primitiveBeDisplay "Record the system Display object in the specialObjectsTable." | rcvr | rcvr := self stackTop. self success: ((self isPointers: rcvr) and: [(self lengthOf: rcvr) >= 4]). successFlag ifTrue: [self storePointer: TheDisplay ofObject: specialObjectsOop withValue: rcvr]! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'tpr 3/15/2004 12:13'! primitiveBeep "make the basic beep noise" self ioBeep.! ! !Interpreter methodsFor: 'arithmetic integer primitives' stamp: 'di 11/29/1998 12:02'! primitiveBitAnd | integerReceiver integerArgument | integerArgument := self popPos32BitInteger. integerReceiver := self popPos32BitInteger. successFlag ifTrue: [self push: (self positive32BitIntegerFor: (integerReceiver bitAnd: integerArgument))] ifFalse: [self unPop: 2]! ! !Interpreter methodsFor: 'arithmetic largeint primitives' stamp: 'ar (auto pragmas 12/08) 3/19/2008 21:37'! primitiveBitAndLargeIntegers "Primitive logical operations for large integers in 64 bit range" | integerRcvr integerArg oopResult | integerArg := self positive64BitValueOf: (self stackValue: 0). integerRcvr := self positive64BitValueOf: (self stackValue: 1). successFlag ifFalse:[^nil]. oopResult := self positive64BitIntegerFor: (integerRcvr bitAnd: integerArg). successFlag ifTrue:[self pop: 2 thenPush: oopResult]. ! ! !Interpreter methodsFor: 'arithmetic integer primitives' stamp: 'di 11/29/1998 12:02'! primitiveBitOr | integerReceiver integerArgument | integerArgument := self popPos32BitInteger. integerReceiver := self popPos32BitInteger. successFlag ifTrue: [self push: (self positive32BitIntegerFor: (integerReceiver bitOr: integerArgument))] ifFalse: [self unPop: 2]! ! !Interpreter methodsFor: 'arithmetic largeint primitives' stamp: 'ar (auto pragmas 12/08) 3/19/2008 21:37'! primitiveBitOrLargeIntegers "Primitive logical operations for large integers in 64 bit range" | integerRcvr integerArg oopResult | integerArg := self positive64BitValueOf: (self stackValue: 0). integerRcvr := self positive64BitValueOf: (self stackValue: 1). successFlag ifFalse:[^nil]. oopResult := self positive64BitIntegerFor: (integerRcvr bitOr: integerArg). successFlag ifTrue:[self pop: 2 thenPush: oopResult]. ! ! !Interpreter methodsFor: 'arithmetic integer primitives' stamp: 'di 11/29/1998 12:04'! primitiveBitShift | integerReceiver integerArgument shifted | integerArgument := self popInteger. integerReceiver := self popPos32BitInteger. successFlag ifTrue: [ integerArgument >= 0 ifTrue: [ "Left shift -- must fail if we lose bits beyond 32" self success: integerArgument <= 31. shifted := integerReceiver << integerArgument. self success: (shifted >> integerArgument) = integerReceiver. ] ifFalse: [ "Right shift -- OK to lose bits" self success: integerArgument >= -31. shifted := integerReceiver bitShift: integerArgument. ]. ]. successFlag ifTrue: [self push: (self positive32BitIntegerFor: shifted)] ifFalse: [self unPop: 2]! ! !Interpreter methodsFor: 'arithmetic largeint primitives' stamp: 'ar (auto pragmas 12/08) 3/21/2008 20:41'! primitiveBitShiftLargeIntegers "Primitive logical operations for large integers in 64 bit range" | shifted integerArg integerRcvr oopResult | integerArg := self stackIntegerValue: 0. integerRcvr := self signed64BitValueOf: (self stackValue: 1). successFlag ifTrue: [ integerArg >= 0 ifTrue: [ "Left shift -- must fail if we lose bits beyond 64" self success: integerArg < 64. shifted := integerRcvr << integerArg. self success: (self cCode: 'shifted >> integerArg') = integerRcvr. ] ifFalse: [ "Right shift -- OK to lose bits" self success: integerArg > -64. shifted := self cCode: 'integerRcvr >> (0 - integerArg)'. "right shift coerces to usqInt" ]. ]. successFlag ifFalse:[^nil]. oopResult := self signed64BitIntegerFor: shifted. successFlag ifTrue:[self pop: 2 thenPush: oopResult]. ! ! !Interpreter methodsFor: 'arithmetic integer primitives' stamp: 'di 11/30/1998 13:18'! primitiveBitXor | integerReceiver integerArgument | integerArgument := self popPos32BitInteger. integerReceiver := self popPos32BitInteger. successFlag ifTrue: [self push: (self positive32BitIntegerFor: (integerReceiver bitXor: integerArgument))] ifFalse: [self unPop: 2]! ! !Interpreter methodsFor: 'arithmetic largeint primitives' stamp: 'ar (auto pragmas 12/08) 3/19/2008 21:38'! primitiveBitXorLargeIntegers "Primitive logical operations for large integers in 64 bit range" | integerRcvr integerArg oopResult | integerArg := self positive64BitValueOf: (self stackValue: 0). integerRcvr := self positive64BitValueOf: (self stackValue: 1). successFlag ifFalse:[^nil]. oopResult := self positive64BitIntegerFor: (integerRcvr bitXor: integerArg). successFlag ifTrue:[self pop: 2 thenPush: oopResult]. ! ! !Interpreter methodsFor: 'control primitives' stamp: 'dtl 5/18/2010 21:44'! primitiveBlockCopy | context methodContext contextSize newContext initialIP | context := self stackValue: 1. (self isIntegerObject: (self fetchPointer: MethodIndex ofObject: context)) ifTrue: ["context is a block; get the context of its enclosing method" methodContext := self fetchPointer: HomeIndex ofObject: context] ifFalse: [methodContext := context]. contextSize := self sizeBitsOf: methodContext. "in bytes, including header" context := nil. "context is no longer needed and is not preserved across allocation" "remap methodContext in case GC happens during allocation" self pushRemappableOop: methodContext. newContext := self instantiateContext: (self splObj: ClassBlockContext) sizeInBytes: contextSize. methodContext := self popRemappableOop. initialIP := self integerObjectOf: (instructionPointer+1+3) - (method + self baseHeaderSize). "Was instructionPointer + 3, but now it's greater by 1 due to preIncrement" "Assume: have just allocated a new context; it must be young. Thus, can use uncheck stores. See the comment in fetchContextRegisters." self storePointerUnchecked: InitialIPIndex ofObject: newContext withValue: initialIP. self storePointerUnchecked: InstructionPointerIndex ofObject: newContext withValue: initialIP. self storeStackPointerValue: 0 inContext: newContext. self storePointerUnchecked: BlockArgumentCountIndex ofObject: newContext withValue: (self stackValue: 0). self storePointerUnchecked: HomeIndex ofObject: newContext withValue: methodContext. self storePointerUnchecked: SenderIndex ofObject: newContext withValue: nilObj. self pop: 2 thenPush: newContext.! ! !Interpreter methodsFor: 'memory space primitives' stamp: 'dtl 11/2/2010 09:35'! primitiveBytesLeft "Reports bytes available at this moment. For more meaningful results, calls to this primitive should be preceeded by a full or incremental garbage collection." | aBool | self methodArgumentCount = 0 ifTrue: ["old behavior - just return the size of the free block" ^self pop: 1 thenPush: (self positive64BitIntegerFor: (self sizeOfFree: freeBlock))]. self methodArgumentCount = 1 ifTrue: ["new behaviour -including or excluding swap space depending on aBool" aBool := self booleanValueOf: self stackTop. successFlag ifFalse: [^ nil]. ^self pop: 2 thenPush: (self positive64BitIntegerFor: (self bytesLeft: aBool))]. ^ self primitiveFail! ! !Interpreter methodsFor: 'message sending' stamp: 'ikp (auto pragmas 12/08) 6/10/2004 14:10'! primitiveCalloutToFFI "Perform a function call to a foreign function. Only invoked from method containing explicit external call spec. Due to this we use the pluggable prim mechanism explicitly here (the first literal of any FFI spec'ed method is an ExternalFunction and not an array as used in the pluggable primitive mechanism)." | function moduleName functionName | function = 0 ifTrue: [ function := self ioLoadExternalFunction: (self oopForPointer: functionName) OfLength: 16 FromModule: (self oopForPointer: moduleName) OfLength: 14. function == 0 ifTrue: [^self primitiveFail]]. ^self cCode: '((sqInt (*)(void))function)()'. ! ! !Interpreter methodsFor: 'object access primitives' stamp: 'yo 4/3/2006 16:47'! primitiveChangeClass "Primitive. Change the class of the receiver into the class of the argument given that the format of the receiver matches the format of the argument's class. Fail if receiver or argument are SmallIntegers, or the receiver is an instance of a compact class and the argument isn't, or when the argument's class is compact and the receiver isn't, or when the format of the receiver is different from the format of the argument's class, or when the arguments class is fixed and the receiver's size differs from the size that an instance of the argument's class should have." | arg rcvr argClass | self methodArgumentCount = 1 ifFalse: [self primitiveFail. ^ nil]. arg := self stackObjectValue: 0. rcvr := self stackObjectValue: 1. argClass := self fetchClassOf: arg. self changeClassOf: rcvr to: argClass. successFlag ifTrue: [ self pop: 1 ]. ^ nil. ! ! !Interpreter methodsFor: 'object access primitives' stamp: 'yo (auto pragmas dtl 2010-09-26) 4/3/2006 16:47'! primitiveChangeClassWithClass "Primitive. Change the class of the receiver into the class of the argument given that the format of the receiver matches the format of the argument's class. Fail if receiver or argument are SmallIntegers, or the receiver is an instance of a compact class and the argument isn't, or when the argument's class is compact and the receiver isn't, or when the format of the receiver is different from the format of the argument's class, or when the arguments class is fixed and the receiver's size differs from the size that an instance of the argument's class should have." | rcvr argClass | self methodArgumentCount = 1 ifFalse: [self primitiveFail. ^ nil]. argClass := self stackObjectValue: 0. rcvr := self stackObjectValue: 1. self changeClassOf: rcvr to: argClass. successFlag ifTrue: [ self pop: 1 ]. ^ nil. ! ! !Interpreter methodsFor: 'object access primitives' stamp: 'ls 8/17/2000 15:52'! primitiveClass | instance | instance := self stackTop. self pop: argumentCount+1 thenPush: (self fetchClassOf: instance)! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'dtl 5/18/2010 21:44'! primitiveClipboardText "When called with a single string argument, post the string to the clipboard. When called with zero arguments, return a string containing the current clipboard contents." | s sz | argumentCount = 1 ifTrue: [s := self stackTop. (self isBytes: s) ifFalse: [^ self primitiveFail]. successFlag ifTrue: [sz := self stSizeOf: s. self clipboardWrite: sz From: s + self baseHeaderSize At: 0. self pop: 1]] ifFalse: [sz := self clipboardSize. (self sufficientSpaceToAllocate: sz) ifFalse:[^self primitiveFail]. s := self instantiateClass: (self splObj: ClassString) indexableSize: sz. self clipboardRead: sz Into: s + self baseHeaderSize At: 0. self pop: 1 thenPush: s]! ! !Interpreter methodsFor: 'object access primitives' stamp: 'tpr 4/25/2005 19:41'! primitiveClone "Return a shallow copy of the receiver." | newCopy | newCopy := self clone: (self stackTop). newCopy = 0 ifTrue:["not enough memory most likely" ^self primitiveFail]. self pop: 1 thenPush: newCopy.! ! !Interpreter methodsFor: 'control primitives' stamp: 'dtl 5/18/2010 21:44'! primitiveClosureCopyWithCopiedValues | newClosure copiedValues numCopiedValues numArgs | numArgs := self stackIntegerValue: 1. copiedValues := self stackTop. self success: (self fetchClassOf: copiedValues) = (self splObj: ClassArray). successFlag ifFalse: [^self primitiveFail]. numCopiedValues := self fetchWordLengthOf: copiedValues. newClosure := self closureNumArgs: numArgs "greater by 1 due to preIncrement of localIP" instructionPointer: instructionPointer + 2 - (method + self baseHeaderSize) numCopiedValues: numCopiedValues. "Assume: have just allocated a new closure; it must be young. Thus, can use unchecked stores." self storePointerUnchecked: ClosureOuterContextIndex ofObject: newClosure withValue: (self stackValue: 2). numCopiedValues > 0 ifTrue: ["Allocation may have done a GC and copiedValues may have moved." copiedValues := self stackTop. 0 to: numCopiedValues - 1 do: [:i| "Assume: have just allocated a new BlockClosure; it must be young. Thus, can use unchecked stores." self storePointerUnchecked: i + ClosureFirstCopiedValueIndex ofObject: newClosure withValue: (self fetchPointer: i ofObject: copiedValues)]]. self pop: 3 thenPush: newClosure! ! !Interpreter methodsFor: 'control primitives' stamp: 'eem 9/23/2010 21:00'! primitiveClosureValue | blockClosure blockArgumentCount closureMethod outerContext | blockClosure := self stackValue: argumentCount. blockArgumentCount := self argumentCountOfClosure: blockClosure. argumentCount = blockArgumentCount ifFalse: [^self primitiveFail]. "Somewhat paranoiac checks we need while debugging that we may be able to discard in a robust system." outerContext := self fetchPointer: ClosureOuterContextIndex ofObject: blockClosure. (self isContext: outerContext) ifFalse: [^self primitiveFail]. closureMethod := self fetchPointer: MethodIndex ofObject: outerContext. "Check if the closure's method is actually a CompiledMethod." (self isOopCompiledMethod: closureMethod) ifFalse: [^self primitiveFail]. self activateNewClosureMethod: blockClosure. self quickCheckForInterrupts! ! !Interpreter methodsFor: 'control primitives' stamp: 'eem 9/23/2010 21:00'! primitiveClosureValueNoContextSwitch "An exact clone of primitiveClosureValue except that this version will not check for interrupts on stack overflow." | blockClosure blockArgumentCount closureMethod outerContext | blockClosure := self stackValue: argumentCount. blockArgumentCount := self argumentCountOfClosure: blockClosure. argumentCount = blockArgumentCount ifFalse: [^self primitiveFail]. "Somewhat paranoiac checks we need while debugging that we may be able to discard in a robust system." outerContext := self fetchPointer: ClosureOuterContextIndex ofObject: blockClosure. (self isContext: outerContext) ifFalse: [^self primitiveFail]. closureMethod := self fetchPointer: MethodIndex ofObject: outerContext. "Check if the closure's method is actually a CompiledMethod." (self isOopCompiledMethod: closureMethod) ifFalse: [^self primitiveFail]. self activateNewClosureMethod: blockClosure! ! !Interpreter methodsFor: 'control primitives' stamp: 'eem 9/23/2010 21:00'! primitiveClosureValueWithArgs | argumentArray arraySize cntxSize blockClosure blockArgumentCount closureMethod index outerContext | argumentArray := self stackTop. (self isArray: argumentArray) ifFalse: [^self primitiveFail]. "Check for enough space in thisContext to push all args" arraySize := self fetchWordLengthOf: argumentArray. cntxSize := self fetchWordLengthOf: activeContext. (self stackPointerIndex + arraySize) < cntxSize ifFalse: [^self primitiveFail]. blockClosure := self stackValue: argumentCount. blockArgumentCount := self argumentCountOfClosure: blockClosure. arraySize = blockArgumentCount ifFalse: [^self primitiveFail]. "Somewhat paranoiac checks we need while debugging that we may be able to discard in a robust system." outerContext := self fetchPointer: ClosureOuterContextIndex ofObject: blockClosure. (self isContext: outerContext) ifFalse: [^self primitiveFail]. closureMethod := self fetchPointer: MethodIndex ofObject: outerContext. "Check if the closure's method is actually a CompiledMethod." (self isOopCompiledMethod: closureMethod) ifFalse: [^self primitiveFail]. self popStack. "Copy the arguments to the stack, and activate" index := 1. [index <= arraySize] whileTrue: [self push: (self fetchPointer: index - 1 ofObject: argumentArray). index := index + 1]. argumentCount := arraySize. self activateNewClosureMethod: blockClosure. self quickCheckForInterrupts! ! !Interpreter methodsFor: 'array primitives' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/18/2010 21:45'! primitiveConstantFill "Fill the receiver, which must be an indexable bytes or words objects, with the given integer value." | fillValue rcvr rcvrIsBytes end i | fillValue := self positive32BitValueOf: self stackTop. rcvr := self stackValue: 1. self success: (self isWordsOrBytes: rcvr). rcvrIsBytes := self isBytes: rcvr. rcvrIsBytes ifTrue: [self success: (fillValue >= 0 and: [fillValue <= 255])]. successFlag ifTrue: [end := rcvr + (self sizeBitsOf: rcvr). i := rcvr + self baseHeaderSize. rcvrIsBytes ifTrue: [[i < end] whileTrue: [self byteAt: i put: fillValue. i := i + 1]] ifFalse: [[i < end] whileTrue: [self long32At: i put: fillValue. i := i + 4]]. self pop: 1]! ! !Interpreter methodsFor: 'object access primitives' stamp: 'tpr 3/23/2004 17:40'! primitiveCopyObject "Primitive. Copy the state of the receiver from the argument. Fail if receiver and argument are of a different class. Fail if the receiver or argument are non-pointer objects. Fail if receiver and argument have different lengths (for indexable objects). " | rcvr arg length | self methodArgumentCount = 1 ifFalse:[^self primitiveFail]. arg := self stackObjectValue: 0. rcvr := self stackObjectValue: 1. self failed ifTrue:[^nil]. (self isPointers: rcvr) ifFalse:[^self primitiveFail]. (self fetchClassOf: rcvr) = (self fetchClassOf: arg) ifFalse:[^self primitiveFail]. length := self lengthOf: rcvr. length = (self lengthOf: arg) ifFalse:[^self primitiveFail]. "Now copy the elements" 0 to: length-1 do:[:i| self storePointer: i ofObject: rcvr withValue: (self fetchPointer: i ofObject: arg)]. "Note: The above could be faster for young receivers but I don't think it'll matter" self pop: 1. "pop arg; answer receiver" ! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'tpr 3/15/2004 12:16'! primitiveDeferDisplayUpdates "Set or clear the flag that controls whether modifications of the Display object are propagated to the underlying platform's screen." | flag | flag := self stackTop. flag = trueObj ifTrue: [deferDisplayUpdates := true] ifFalse: [flag = falseObj ifTrue: [deferDisplayUpdates := false] ifFalse: [self primitiveFail]]. successFlag ifTrue: [self pop: 1]! ! !Interpreter methodsFor: 'system control primitives' stamp: 'tpr (auto pragmas 12/08) 5/9/2005 18:58'! primitiveDisablePowerManager "Pass in a non-negative value to disable the architectures powermanager if any, zero to enable. This is a named (not numbered) primitive in the null module (ie the VM)" | integer | integer := self stackIntegerValue: 0. successFlag ifTrue: [ self ioDisablePowerManager: integer. self pop: 1]. "integer; leave rcvr on stack" ! ! !Interpreter methodsFor: 'arithmetic integer primitives' stamp: 'tpr 3/15/2004 20:24'! primitiveDiv | quotient | quotient := self doPrimitiveDiv: (self stackValue: 1) by: (self stackTop). self pop2AndPushIntegerIfOK: quotient! ! !Interpreter methodsFor: 'arithmetic largeint primitives' stamp: 'ar (auto pragmas 12/08) 3/20/2008 22:52'! primitiveDivLargeIntegers "Primitive arithmetic operations for large integers in 64 bit range" | integerRcvr integerArg result posArg posRcvr oopResult | integerArg := self signed64BitValueOf: (self stackValue: 0). integerRcvr := self signed64BitValueOf: (self stackValue: 1). integerArg = 0 ifTrue:[self primitiveFail]. successFlag ifFalse:[^nil]. integerRcvr > 0 ifTrue: [integerArg > 0 ifTrue: [result := integerRcvr // integerArg] ifFalse: ["round negative result toward negative infinity" posArg := 0 - integerArg. posRcvr := integerRcvr + (posArg - 1). "can overflow!!" posRcvr < 0 ifTrue:[self primitiveFail]. result := 0 - (posRcvr // posArg)]] ifFalse: [posRcvr := 0 - integerRcvr. integerArg > 0 ifTrue: ["round negative result toward negative infinity" posRcvr := posRcvr + (integerArg - 1). "can overflow!!" posRcvr < 0 ifTrue:[self primitiveFail]. result := 0 - (posRcvr // integerArg)] ifFalse: [posArg := 0 - integerArg. result := posRcvr // posArg]]. successFlag ifTrue:[oopResult := self signed64BitIntegerFor: result]. successFlag ifTrue:[self pop: 2 thenPush: oopResult]. ! ! !Interpreter methodsFor: 'arithmetic integer primitives' stamp: 'di 11/30/1998 10:25'! primitiveDivide | integerReceiver integerArgument | integerReceiver := self stackIntegerValue: 1. integerArgument := self stackIntegerValue: 0. (integerArgument ~= 0 and: [integerReceiver \\ integerArgument = 0]) ifTrue: [self pop2AndPushIntegerIfOK: integerReceiver // integerArgument] ifFalse: [self primitiveFail]! ! !Interpreter methodsFor: 'arithmetic largeint primitives' stamp: 'ar (auto pragmas 12/08) 3/19/2008 21:38'! primitiveDivideLargeIntegers "Primitive arithmetic operations for large integers in 64 bit range" | integerRcvr integerArg result oopResult | integerArg := self signed64BitValueOf: (self stackValue: 0). integerRcvr := self signed64BitValueOf: (self stackValue: 1). (integerArg ~= 0 and:[integerRcvr \\ integerArg = 0]) ifFalse:[self primitiveFail]. successFlag ifFalse:[^nil]. result := integerRcvr // integerArg. oopResult := self signed64BitIntegerFor: result. successFlag ifTrue:[self pop: 2 thenPush: oopResult]. ! ! !Interpreter methodsFor: 'control primitives' stamp: 'tpr 3/23/2004 17:55'! primitiveDoPrimitiveWithArgs | argumentArray arraySize index cntxSize primIdx | argumentArray := self stackTop. arraySize := self fetchWordLengthOf: argumentArray. cntxSize := self fetchWordLengthOf: activeContext. self success: self stackPointerIndex + arraySize < cntxSize. (self isArray: argumentArray) ifFalse: [^ self primitiveFail]. primIdx := self stackIntegerValue: 1. successFlag ifFalse: [^ self primitiveFail]. "invalid args" "Pop primIndex and argArray, then push args in place..." self pop: 2. primitiveIndex := primIdx. argumentCount := arraySize. index := 1. [index <= argumentCount] whileTrue: [self push: (self fetchPointer: index - 1 ofObject: argumentArray). index := index + 1]. "Run the primitive (sets successFlag)" self pushRemappableOop: argumentArray. "prim might alloc/gc" lkupClass := nilObj. self primitiveResponse. argumentArray := self popRemappableOop. successFlag ifFalse: ["If primitive failed, then restore state for failure code" self pop: arraySize. self pushInteger: primIdx. self push: argumentArray. argumentCount := 2]! ! !Interpreter methodsFor: 'arithmetic integer primitives' stamp: 'di 11/27/1998 15:43'! primitiveEqual | integerReceiver integerArgument result | integerArgument := self popStack. integerReceiver := self popStack. result := self compare31or32Bits: integerReceiver equal: integerArgument. self checkBooleanResult: result! ! !Interpreter methodsFor: 'arithmetic largeint primitives' stamp: 'ar (auto pragmas 12/08) 3/19/2008 21:38'! primitiveEqualLargeIntegers "Primitive comparison operations for large integers in 64 bit range" | integerRcvr integerArg | integerArg := self signed64BitValueOf: (self stackValue: 0). integerRcvr := self signed64BitValueOf: (self stackValue: 1). successFlag ifTrue:[ self pop: 2. self pushBool: integerRcvr = integerArg ]. ! ! !Interpreter methodsFor: 'object access primitives' stamp: 'tpr 3/23/2004 17:41'! primitiveEquivalent "is the receiver the same object as the argument?" | thisObject otherObject | otherObject := self popStack. thisObject := self popStack. self pushBool: thisObject = otherObject! ! !Interpreter methodsFor: 'control primitives' stamp: 'tpr 11/2/2004 18:04'! primitiveExecuteMethod "receiver, args, then method are on top of stack. Execute method against receiver and args" newMethod := self popStack. primitiveIndex := self primitiveIndexOf: newMethod. self success: argumentCount - 1 = (self argumentCountOf: newMethod). successFlag ifTrue: [argumentCount := argumentCount - 1. self executeNewMethod] ifFalse: [self unPop: 1]! ! !Interpreter methodsFor: 'control primitives' stamp: 'dtl 11/23/2010 10:59'! primitiveExecuteMethodArgsArray "receiver, argsArray, then method are on top of stack. Execute method against receiver and args" | methodArgument argCnt argumentArray | methodArgument := self popStack. argumentArray := self popStack. ((self isOopCompiledMethod: methodArgument) and: [self isArray: argumentArray]) ifFalse: [self unPop: 2. ^self primitiveFail]. argCnt := self argumentCountOf: methodArgument. argCnt = (self fetchWordLengthOf: argumentArray) ifFalse: [self unPop: 2. ^self primitiveFail]. self transfer: argCnt from: argumentArray + self baseHeaderSize to: stackPointer + self bytesPerWord. self unPop: argCnt. newMethod := methodArgument. primitiveIndex := self primitiveIndexOf: newMethod. argumentCount := argCnt. self executeNewMethod. "Recursive xeq affects successFlag" successFlag := true! ! !Interpreter methodsFor: 'system control primitives'! primitiveExitToDebugger self error: 'Exit to debugger at user request'.! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:27'! primitiveExp "Computes E raised to the receiver power." | rcvr | rcvr := self popFloat. successFlag ifTrue: [self pushFloat: (self cCode: 'exp(rcvr)' inSmalltalk: [rcvr exp])] ifFalse: [self unPop: 1]! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:28'! primitiveExponent "Exponent part of this float." | rcvr frac pwr | rcvr := self popFloat. successFlag ifTrue: [ "rcvr = frac * 2^pwr, where frac is in [0.5..1.0)" self cCode: 'frac = frexp(rcvr, &pwr)' inSmalltalk: [pwr := rcvr exponent]. self pushInteger: pwr - 1] ifFalse: [self unPop: 1].! ! !Interpreter methodsFor: 'plugin primitives' stamp: 'dtl 12/14/2010 08:13'! primitiveExternalCall "Call an external primitive. The external primitive methods contain as first literal an array consisting of: * The module name (String | Symbol) * The function name (String | Symbol) * The session ID (SmallInteger) [OBSOLETE] * The function index (Integer) in the externalPrimitiveTable For fast failures the primitive index of any method where the external prim is not found is rewritten in the method cache with zero. This allows for ultra fast responses as long as the method stays in the cache. The fast failure response relies on lkupClass being properly set. This is done in #addToMethodCacheSel:class:method:primIndex: to compensate for execution of methods that are looked up in a superclass (such as in primitivePerformAt). With the latest modifications (e.g., actually flushing the function addresses from the VM), the session ID is obsolete. But for backward compatibility it is still kept around. Also, a failed lookup is reported specially. If a method has been looked up and not been found, the function address is stored as -1 (e.g., the SmallInteger -1 to distinguish from 16rFFFFFFFF which may be returned from the lookup). It is absolutely okay to remove the rewrite if we run into any problems later on. It has an approximate speed difference of 30% per failed primitive call which may be noticable but if, for any reasons, we run into problems (like with J3) we can always remove the rewrite. " | lit addr moduleName functionName moduleLength functionLength index | "Fetch the first literal of the method" self success: (self literalCountOf: newMethod) > 0. "@@: Could this be omitted for speed?!!" successFlag ifFalse: [^ nil]. lit := self literal: 0 ofMethod: newMethod. "Check if it's an array of length 4" self success: ((self isArray: lit) and: [(self lengthOf: lit) = 4]). successFlag ifFalse: [^ nil]. "Look at the function index in case it has been loaded before" index := self fetchPointer: 3 ofObject: lit. index := self checkedIntegerValueOf: index. successFlag ifFalse: [^ nil]. "Check if we have already looked up the function and failed." index < 0 ifTrue: ["Function address was not found in this session, Rewrite the mcache entry with a zero primitive index." self rewriteMethodCacheSel: messageSelector class: lkupClass primIndex: 0. ^ self success: false]. "Try to call the function directly" (index > 0 and: [index <= MaxExternalPrimitiveTableSize]) ifTrue: [addr := externalPrimitiveTable at: index - 1. addr ~= 0 ifTrue: [self rewriteMethodCacheSel: messageSelector class: lkupClass primIndex: (1000 + index) primFunction: addr. self callExternalPrimitive: addr. ^ nil]. "if we get here, then an index to the external prim was kept on the ST side although the underlying prim table was already flushed" ^ self primitiveFail]. "Clean up session id and external primitive index" self storePointerUnchecked: 2 ofObject: lit withValue: ConstZero. self storePointerUnchecked: 3 ofObject: lit withValue: ConstZero. "The function has not been loaded yet. Fetch module and function name." moduleName := self fetchPointer: 0 ofObject: lit. moduleName = nilObj ifTrue: [moduleLength := 0] ifFalse: [self success: (self isBytes: moduleName). moduleLength := self lengthOf: moduleName. self cCode: '' inSmalltalk: [ (#('FloatArrayPlugin' 'Matrix2x3Plugin') includes: (self stringOf: moduleName)) ifTrue: [moduleLength := 0 "Cause all of these to fail"]]]. functionName := self fetchPointer: 1 ofObject: lit. self success: (self isBytes: functionName). functionLength := self lengthOf: functionName. successFlag ifFalse: [^ nil]. addr := self ioLoadExternalFunction: functionName + self baseHeaderSize OfLength: functionLength FromModule: moduleName + self baseHeaderSize OfLength: moduleLength. addr = 0 ifTrue: [index := -1] ifFalse: ["add the function to the external primitive table" index := self addToExternalPrimitiveTable: addr]. self success: index >= 0. "Store the index (or -1 if failure) back in the literal" self storePointerUnchecked: 3 ofObject: lit withValue: (self integerObjectOf: index). "If the function has been successfully loaded process it" (successFlag and: [addr ~= 0]) ifTrue: [self rewriteMethodCacheSel: messageSelector class: lkupClass primIndex: (1000 + index) primFunction: addr. self callExternalPrimitive: addr] ifFalse: ["Otherwise rewrite the primitive index" self rewriteMethodCacheSel: messageSelector class: lkupClass primIndex: 0]! ! !Interpreter methodsFor: 'primitive support'! primitiveFail successFlag := false.! ! !Interpreter methodsFor: 'image segment in/out' stamp: 'dtl 5/18/2010 21:45'! primitiveFailAfterCleanup: outPointerArray "If the storeSegment primitive fails, it must clean up first." | i lastAddr | "Store nils throughout the outPointer array." lastAddr := outPointerArray + (self lastPointerOf: outPointerArray). i := outPointerArray + self baseHeaderSize. [i <= lastAddr] whileTrue: [self longAt: i put: nilObj. i := i + self bytesPerWord]. DoAssertionChecks ifTrue: [self verifyCleanHeaders]. self primitiveFail! ! !Interpreter methodsFor: 'primitive support' stamp: 'John M McIntosh 11/23/2008 22:15'! primitiveFailFor: reasonCode "Set specific primitive failure." primFailCode := reasonCode. self primitiveFail.! ! !Interpreter methodsFor: 'process primitives' stamp: 'ar 3/6/2001 14:57'! primitiveFindHandlerContext "Primitive. Search up the context stack for the next method context marked for exception handling starting at the receiver. Return nil if none found" | thisCntx nilOop | thisCntx := self popStack. nilOop := nilObj. [(self isHandlerMarked: thisCntx) ifTrue:[ self push: thisCntx. ^nil]. thisCntx := self fetchPointer: SenderIndex ofObject: thisCntx. thisCntx = nilOop] whileFalse. ^self push: nilObj! ! !Interpreter methodsFor: 'process primitives' stamp: 'ar 7/8/2003 11:33'! primitiveFindNextUnwindContext "Primitive. Search up the context stack for the next method context marked for unwind handling from the receiver up to but not including the argument. Return nil if none found." | thisCntx nilOop aContext unwindMarked | aContext := self popStack. thisCntx := self fetchPointer: SenderIndex ofObject: self popStack. nilOop := nilObj. [(thisCntx = aContext) or: [thisCntx = nilOop]] whileFalse: [ unwindMarked := self isUnwindMarked: thisCntx. unwindMarked ifTrue:[ self push: thisCntx. ^nil]. thisCntx := self fetchPointer: SenderIndex ofObject: thisCntx]. ^self push: nilOop! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'di 11/27/1998 11:45'! primitiveFloatAdd ^ self primitiveFloatAdd: (self stackValue: 1) toArg: self stackTop! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:29'! primitiveFloatAdd: rcvrOop toArg: argOop | rcvr arg | rcvr := self loadFloatOrIntFrom: rcvrOop. arg := self loadFloatOrIntFrom: argOop. successFlag ifTrue: [ self pop: 2. self pushFloat: rcvr + arg].! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'di 11/27/1998 11:45'! primitiveFloatDivide ^ self primitiveFloatDivide: (self stackValue: 1) byArg: self stackTop! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:29'! primitiveFloatDivide: rcvrOop byArg: argOop | rcvr arg | rcvr := self loadFloatOrIntFrom: rcvrOop. arg := self loadFloatOrIntFrom: argOop. successFlag ifTrue: [ self success: arg ~= 0.0. successFlag ifTrue: [ self pop: 2. self pushFloat: (self cCode: 'rcvr / arg' inSmalltalk: [rcvr / arg])]].! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'acg 8/30/2002 17:30'! primitiveFloatEqual | aBool | aBool := self primitiveFloatEqual: (self stackValue: 1) toArg: self stackTop. successFlag ifTrue: [self pop: 2. self pushBool: aBool]. ! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:29'! primitiveFloatEqual: rcvrOop toArg: argOop | rcvr arg | rcvr := self loadFloatOrIntFrom: rcvrOop. arg := self loadFloatOrIntFrom: argOop. successFlag ifTrue: [^ rcvr = arg]! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:29'! primitiveFloatGreater: rcvrOop thanArg: argOop | rcvr arg | rcvr := self loadFloatOrIntFrom: rcvrOop. arg := self loadFloatOrIntFrom: argOop. successFlag ifTrue: [^ rcvr > arg]. ! ! !Interpreter methodsFor: 'float primitives' stamp: 'nice 1/4/2009 21:24'! primitiveFloatGreaterOrEqual | aBool | aBool := self primitiveFloatGreaterOrEqual: (self stackValue: 1) toArg: self stackTop. successFlag ifTrue: [self pop: 2. self pushBool: aBool].! ! !Interpreter methodsFor: 'float primitives' stamp: 'nice (auto pragmas dtl 2010-09-26) 1/4/2009 21:22'! primitiveFloatGreaterOrEqual: rcvrOop toArg: argOop | rcvr arg | rcvr := self loadFloatOrIntFrom: rcvrOop. arg := self loadFloatOrIntFrom: argOop. successFlag ifTrue: [^ rcvr >= arg]. ! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'acg 8/30/2002 17:31'! primitiveFloatGreaterThan | aBool | aBool := self primitiveFloatGreater: (self stackValue: 1) thanArg: self stackTop. successFlag ifTrue: [self pop: 2. self pushBool: aBool]. ! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:29'! primitiveFloatLess: rcvrOop thanArg: argOop | rcvr arg | rcvr := self loadFloatOrIntFrom: rcvrOop. arg := self loadFloatOrIntFrom: argOop. successFlag ifTrue: [^ rcvr < arg]. ! ! !Interpreter methodsFor: 'float primitives' stamp: 'nice 1/4/2009 21:24'! primitiveFloatLessOrEqual | aBool | aBool := self primitiveFloatLessOrEqual: (self stackValue: 1) toArg: self stackTop. successFlag ifTrue: [self pop: 2. self pushBool: aBool].! ! !Interpreter methodsFor: 'float primitives' stamp: 'nice (auto pragmas dtl 2010-09-26) 1/4/2009 21:23'! primitiveFloatLessOrEqual: rcvrOop toArg: argOop | rcvr arg | rcvr := self loadFloatOrIntFrom: rcvrOop. arg := self loadFloatOrIntFrom: argOop. successFlag ifTrue: [^ rcvr <= arg]. ! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'acg 8/30/2002 17:31'! primitiveFloatLessThan | aBool | aBool := self primitiveFloatLess: (self stackValue: 1) thanArg: self stackTop. successFlag ifTrue: [self pop: 2. self pushBool: aBool]. ! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'di 11/27/1998 11:46'! primitiveFloatMultiply ^ self primitiveFloatMultiply: (self stackValue: 1) byArg: self stackTop! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:29'! primitiveFloatMultiply: rcvrOop byArg: argOop | rcvr arg | rcvr := self loadFloatOrIntFrom: rcvrOop. arg := self loadFloatOrIntFrom: argOop. successFlag ifTrue: [ self pop: 2. self pushFloat: rcvr * arg].! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'acg 8/30/2002 17:31'! primitiveFloatNotEqual | aBool | aBool := self primitiveFloatEqual: (self stackValue: 1) toArg: self stackTop. successFlag ifTrue: [self pop: 2. self pushBool: aBool not]. ! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'di 11/27/1998 11:46'! primitiveFloatSubtract ^ self primitiveFloatSubtract: (self stackValue: 1) fromArg: self stackTop! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:30'! primitiveFloatSubtract: rcvrOop fromArg: argOop | rcvr arg | rcvr := self loadFloatOrIntFrom: rcvrOop. arg := self loadFloatOrIntFrom: argOop. successFlag ifTrue: [ self pop: 2. self pushFloat: rcvr - arg].! ! !Interpreter methodsFor: 'system control primitives' stamp: 'md 2/12/2001 16:41'! primitiveFlushCache "Clear the method lookup cache. This must be done after every programming change." self flushMethodCache. self compilerFlushCacheHook: nil. "Flush the dynamic compiler's inline caches." ! ! !Interpreter methodsFor: 'system control primitives' stamp: 'ikp 1/4/1999 11:31'! primitiveFlushCacheByMethod "The receiver is a compiledMethod. Clear all entries in the method lookup cache that refer to this method, presumably because it has been redefined, overridden or removed." | probe oldMethod | oldMethod := self stackTop. probe := 0. 1 to: MethodCacheEntries do: [:i | (methodCache at: probe + MethodCacheMethod) = oldMethod ifTrue: [methodCache at: probe + MethodCacheSelector put: 0]. probe := probe + MethodCacheEntrySize]. self compilerFlushCacheHook: oldMethod. "Flush the dynamic compiler's inline caches."! ! !Interpreter methodsFor: 'system control primitives' stamp: 'jm 12/14/1998 14:32'! primitiveFlushCacheSelective "The receiver is a message selector. Clear all entries in the method lookup cache with this selector, presumably because an associated method has been redefined." | selector probe | selector := self stackTop. probe := 0. 1 to: MethodCacheEntries do: [:i | (methodCache at: probe + MethodCacheSelector) = selector ifTrue: [methodCache at: probe + MethodCacheSelector put: 0]. probe := probe + MethodCacheEntrySize]! ! !Interpreter methodsFor: 'plugin primitives' stamp: 'ar 3/26/2000 16:03'! primitiveFlushExternalPrimitives "Primitive. Flush all the existing external primitives in the image thus forcing a reload on next invokation." ^self flushExternalPrimitives! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'jm 5/17/1998 07:06'! primitiveForceDisplayUpdate "On some platforms, this primitive forces enqueued display updates to be processed immediately. On others, it does nothing." self ioForceDisplayUpdate. ! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'JMM (auto pragmas 12/08) 1/27/2005 13:21'! primitiveForceTenure "Set force tenure flag to true, this forces a tenure operation on the next incremental GC" forceTenureFlag := 1! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/18/2010 21:01'! primitiveFormPrint "On platforms that support it, this primitive prints the receiver, assumed to be a Form, to the default printer." | landscapeFlag vScale hScale rcvr bitsArray w h depth pixelsPerWord wordsPerLine bitsArraySize ok | landscapeFlag := self booleanValueOf: self stackTop. vScale := self floatValueOf: (self stackValue: 1). hScale := self floatValueOf: (self stackValue: 2). rcvr := self stackValue: 3. (rcvr isIntegerObject: rcvr) ifTrue: [self success: false]. successFlag ifTrue: [ ((self isPointers: rcvr) and: [(self lengthOf: rcvr) >= 4]) ifFalse: [self success: false]]. successFlag ifTrue: [ bitsArray := self fetchPointer: 0 ofObject: rcvr. w := self fetchInteger: 1 ofObject: rcvr. h := self fetchInteger: 2 ofObject: rcvr. depth := self fetchInteger: 3 ofObject: rcvr. (w > 0 and: [h > 0]) ifFalse: [self success: false]. pixelsPerWord := 32 // depth. wordsPerLine := (w + (pixelsPerWord - 1)) // pixelsPerWord. ((rcvr isIntegerObject: rcvr) not and: [self isWordsOrBytes: bitsArray]) ifTrue: [ bitsArraySize := self byteLengthOf: bitsArray. self success: (bitsArraySize = (wordsPerLine * h * 4))] ifFalse: [self success: false]]. successFlag ifTrue: [ self bytesPerWord = 8 ifTrue: [ok := self cCode: 'ioFormPrint(bitsArray + 8, w, h, depth, hScale, vScale, landscapeFlag)'] ifFalse: [ok := self cCode: 'ioFormPrint(bitsArray + 4, w, h, depth, hScale, vScale, landscapeFlag)']. self success: ok]. successFlag ifTrue: [ self pop: 3]. "pop hScale, vScale, and landscapeFlag; leave rcvr on stack" ! ! !Interpreter methodsFor: 'arithmetic float primitives' stamp: 'tpr (auto pragmas 12/08) 12/29/2005 16:30'! primitiveFractionalPart | rcvr frac trunc | rcvr := self popFloat. successFlag ifTrue: [self cCode: 'frac = modf(rcvr, &trunc)' inSmalltalk: [frac := rcvr fractionPart]. self pushFloat: frac] ifFalse: [self unPop: 1]! ! !Interpreter methodsFor: 'memory space primitives' stamp: 'dtl 11/2/2010 09:30'! primitiveFullGC "Do a full garbage collection and return the number of bytes available (including swap space if dynamic memory management is supported)." self pop: 1. self incrementalGC. "maximimize space for forwarding table" self fullGC. self push: (self positive64BitIntegerFor: (self bytesLeft: true)) ! ! !Interpreter methodsFor: 'system control primitives' stamp: 'dtl 5/18/2010 21:45'! primitiveGetAttribute "Fetch the system attribute with the given integer ID. The result is a string, which will be empty if the attribute is not defined." | attr sz s | attr := self stackIntegerValue: 0. successFlag ifTrue: [sz := self attributeSize: attr]. successFlag ifTrue: [s := self instantiateClass: (self splObj: ClassString) indexableSize: sz. self getAttribute: attr Into: s + self baseHeaderSize Length: sz. self pop: 2 thenPush: s]! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'John M McIntosh (auto pragmas dtl 2010-09-26) 7/8/2010 12:01'! primitiveGetNextEvent "Primitive. Return the next input event from the VM event queue." | evtBuf arg value eventTypeIs | self cCode:'' inSmalltalk:[evtBuf := CArrayAccessor on: (IntegerArray new: 8)]. arg := self stackTop. ((self isArray: arg) and:[(self slotSizeOf: arg) = 8]) ifFalse:[^self primitiveFail]. self ioGetNextEvent: (self cCoerce: evtBuf to: 'sqInputEvent*'). successFlag ifFalse:[^nil]. "Event type" eventTypeIs := evtBuf at: 0. self storeInteger: 0 ofObject: arg withValue: (evtBuf at: 0). successFlag ifFalse:[^nil]. "Event is Complex, assume evtBuf is populated correctly and return" eventTypeIs = 6 ifTrue: [1 to: 7 do: [:i | value := evtBuf at: i. self storePointer: i ofObject: arg withValue: value]] ifFalse: [ "Event time stamp" self storeInteger: 1 ofObject: arg withValue: ((evtBuf at: 1) bitAnd: MillisecondClockMask). successFlag ifFalse:[^nil]. "Event arguments" 2 to: 7 do:[:i| value := evtBuf at: i. (self isIntegerValue: value) ifTrue:[self storeInteger: i ofObject: arg withValue: value] ifFalse:["Need to remap because allocation may cause GC" self pushRemappableOop: arg. value := self positive32BitIntegerFor: value. arg := self popRemappableOop. self storePointer: i ofObject: arg withValue: value]]]. successFlag ifFalse:[^nil]. self pop: 1.! ! !Interpreter methodsFor: 'arithmetic integer primitives' stamp: 'di 11/27/1998 15:43'! primitiveGreaterOrEqual | integerReceiver integerArgument | integerArgument := self popInteger. integerReceiver := self popInteger. self checkBooleanResult: integerReceiver >= integerArgument! ! !Interpreter methodsFor: 'arithmetic largeint primitives' stamp: 'ar (auto pragmas 12/08) 3/19/2008 21:38'! primitiveGreaterOrEqualLargeIntegers "Primitive comparison operations for large integers in 64 bit range" | integerRcvr integerArg | integerArg := self signed64BitValueOf: (self stackValue: 0). integerRcvr := self signed64BitValueOf: (self stackValue: 1). successFlag ifTrue:[ self pop: 2. self pushBool: integerRcvr >= integerArg ]. ! ! !Interpreter methodsFor: 'arithmetic integer primitives' stamp: 'di 11/27/1998 15:43'! primitiveGreaterThan | integerReceiver integerArgument | integerArgument := self popInteger. integerReceiver := self popInteger. self checkBooleanResult: integerReceiver > integerArgument! ! !Interpreter methodsFor: 'arithmetic largeint primitives' stamp: 'ar (auto pragmas 12/08) 3/19/2008 21:38'! primitiveGreaterThanLargeIntegers "Primitive comparison operations for large integers in 64 bit range" | integerRcvr integerArg | integerArg := self signed64BitValueOf: (self stackValue: 0). integerRcvr := self signed64BitValueOf: (self stackValue: 1). successFlag ifTrue:[ self pop: 2. self pushBool: integerRcvr > integerArg ]. ! ! !Interpreter methodsFor: 'other primitives' stamp: 'dtl (auto pragmas dtl 2010-09-26) 4/10/2010 12:32'! primitiveImageFormatVersion "Answer an integer identifying the type of image. The image version number may identify the format of the image (e.g. 32 or 64-bit word size) or specific requirements of the image (e.g. block closure support required). This is a named (not numbered) primitive in the null module (ie the VM)" self pop: 1 thenPush: (self positive32BitIntegerFor: self imageFormatVersion) ! ! !Interpreter methodsFor: 'other primitives' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/18/2010 21:45'! primitiveImageName "When called with a single string argument, record the string as the current image file name. When called with zero arguments, return a string containing the current image file name." | s sz sCRIfn okToRename | argumentCount = 1 ifTrue: [ "If the security plugin can be loaded, use it to check for rename permission. If not, assume it's ok" sCRIfn := self ioLoadFunction: 'secCanRenameImage' From: 'SecurityPlugin'. sCRIfn ~= 0 ifTrue:[okToRename := self cCode:' ((sqInt (*)(void))sCRIfn)()'. okToRename ifFalse:[^self primitiveFail]]. s := self stackTop. self assertClassOf: s is: (self splObj: ClassString). successFlag ifTrue: [ sz := self stSizeOf: s. self imageNamePut: (s + self baseHeaderSize) Length: sz. self pop: 1. "pop s, leave rcvr on stack" ]. ] ifFalse: [ sz := self imageNameSize. s := self instantiateClass: (self splObj: ClassString) indexableSize: sz. self imageNameGet: (s + self baseHeaderSize) Length: sz. self pop: 1. "rcvr" self push: s. ]. ! ! !Interpreter methodsFor: 'memory space primitives' stamp: 'dtl 11/2/2010 09:31'! primitiveIncrementalGC "Do a quick, incremental garbage collection and return the number of bytes immediately available. (Note: more space may be made available by doing a full garbage collection." self pop: 1. self incrementalGC. self push: (self positive64BitIntegerFor: (self bytesLeft: false)) ! ! !Interpreter methodsFor: 'compiled methods' stamp: 'ls 6/22/2000 14:35'! primitiveIndexOf: methodPointer "Note: We now have 10 bits of primitive index, but they are in two places for temporary backward compatibility. The time to unpack is negligible, since the reconstituted full index is stored in the method cache." | primBits | primBits := ((self headerOf: methodPointer) >> 1) bitAnd: 16r100001FF. ^ (primBits bitAnd: 16r1FF) + (primBits >> 19) ! ! !Interpreter methodsFor: 'compiled methods' stamp: 'eem 11/25/2008 13:54'! primitiveIndexOfMethodHeader: methodHeader "Note: We now have 10 bits of primitive index, but they are in two places for temporary backward compatibility. The time to unpack is negligible, since the derived primitive function pointer is stored in the method cache." | primBits | primBits := (methodHeader >> 1). ^(primBits bitAnd: 16r1FF) + ((primBits >> 19) bitAnd: 16r200)! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'tpr 3/29/2006 12:20'! primitiveInputSemaphore "Register the input semaphore. The argument is an index into the ExternalObjectsArray part of the specialObjectsArray and must have been allocated via 'Smalltalk registerExternalObject: the Semaphore' " | arg | arg := self stackTop. (self isIntegerObject: arg) ifTrue: ["If arg is integer, then condsider it as an index into the external objects array and install it as the new event semaphore" self ioSetInputSemaphore: (self integerValueOf: arg). successFlag ifTrue: [self pop: 1]. ^ nil]! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'tpr 5/13/2005 10:17'! primitiveInputWord "Return an integer indicating the reason for the most recent input interrupt." self pop: 1 thenPushInteger: 0. "noop for now"! ! !Interpreter methodsFor: 'object access primitives' stamp: 'tpr 3/23/2004 17:42'! primitiveInstVarAt | index rcvr hdr fmt totalLength fixedFields value | index := self stackIntegerValue: 0. rcvr := self stackValue: 1. successFlag ifTrue: [hdr := self baseHeader: rcvr. fmt := hdr >> 8 bitAnd: 15. totalLength := self lengthOf: rcvr baseHeader: hdr format: fmt. fixedFields := self fixedFieldsOf: rcvr format: fmt length: totalLength. (index >= 1 and: [index <= fixedFields]) ifFalse: [successFlag := false]]. successFlag ifTrue: [value := self subscript: rcvr with: index format: fmt]. successFlag ifTrue: [self pop: argumentCount + 1 thenPush: value]! ! !Interpreter methodsFor: 'object access primitives' stamp: 'tpr 3/23/2004 17:43'! primitiveInstVarAtPut | newValue index rcvr hdr fmt totalLength fixedFields | newValue := self stackTop. index := self stackIntegerValue: 1. rcvr := self stackValue: 2. successFlag ifTrue: [hdr := self baseHeader: rcvr. fmt := hdr >> 8 bitAnd: 15. totalLength := self lengthOf: rcvr baseHeader: hdr format: fmt. fixedFields := self fixedFieldsOf: rcvr format: fmt length: totalLength. (index >= 1 and: [index <= fixedFields]) ifFalse: [successFlag := false]]. successFlag ifTrue: [self subscript: rcvr with: index storing: newValue format: fmt]. successFlag ifTrue: [self pop: argumentCount + 1 thenPush: newValue]! ! !Interpreter methodsFor: 'quick primitives' stamp: 'dtl 4/22/2007 23:35'! primitiveInstVarsPutFromStack "Note: this primitive has been decommissioned. It is only here for short-term compatibility with an internal 2.3beta-d image that used this. It did not save much time and it complicated several things. Plus Jitter will do it right anyway." | rcvr offsetBits | rcvr := self stackValue: argumentCount. "Mark dirty so stores below can be unchecked" (self oop: rcvr isLessThan: youngStart) ifTrue: [ self beRootIfOld: rcvr ]. 0 to: argumentCount-1 do: [:i | (i bitAnd: 3) = 0 ifTrue: [offsetBits := self positive32BitValueOf: (self literal: i//4 ofMethod: newMethod)]. self storePointerUnchecked: (offsetBits bitAnd: 16rFF) ofObject: rcvr withValue: (self stackValue: i). offsetBits := offsetBits >> 8]. self pop: argumentCount! ! !Interpreter methodsFor: 'array primitives' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/18/2010 21:45'! primitiveIntegerAt "Return the 32bit signed integer contents of a words receiver" | index rcvr sz addr value intValue | index := self stackIntegerValue: 0. rcvr := self stackValue: 1. (self isIntegerObject: rcvr) ifTrue: [^self success: false]. (self isWords: rcvr) ifFalse: [^self success: false]. sz := self lengthOf: rcvr. "number of fields" self success: ((index >= 1) and: [index <= sz]). successFlag ifTrue: [ addr := rcvr + self baseHeaderSize - 4 "for zero indexing" + (index * 4). value := self intAt: addr. self pop: 2. "pop rcvr, index" "push element value" (self isIntegerValue: value) ifTrue: [self pushInteger: value] ifFalse: [ intValue := value. "32 bit int may have been stored in 32 or 64 bit sqInt" self push: (self signed32BitIntegerFor: intValue)]. "intValue may be sign extended to 64 bit sqInt" ].! ! !Interpreter methodsFor: 'array primitives' stamp: 'dtl 5/18/2010 21:45'! primitiveIntegerAtPut "Return the 32bit signed integer contents of a words receiver" | index rcvr sz addr value valueOop | valueOop := self stackValue: 0. index := self stackIntegerValue: 1. rcvr := self stackValue: 2. (self isIntegerObject: rcvr) ifTrue:[^self success: false]. (self isWords: rcvr) ifFalse:[^self success: false]. sz := self lengthOf: rcvr. "number of fields" ((index >= 1) and: [index <= sz]) ifFalse:[^self success: false]. (self isIntegerObject: valueOop) ifTrue:[value := self integerValueOf: valueOop] ifFalse:[value := self signed32BitValueOf: valueOop]. successFlag ifTrue:[ addr := rcvr + self baseHeaderSize - 4 "for zero indexing" + (index * 4). value := self intAt: addr put: value. self pop: 3 thenPush: valueOop. "pop all; return value" ]. ! ! !Interpreter methodsFor: 'other primitives' stamp: 'dtl (auto pragmas dtl 2010-09-26) 4/9/2010 00:44'! primitiveInterpreterSourceVersion "Answer a string corresponding to the version of the interpreter source. This represents the version level of the Smalltalk source code (interpreter and various plugins) that is translated to C by a CCodeGenerator, as distinct from the external platform source code, typically written in C and managed separately for each platform. This is a named (not numbered) primitive in the null module (ie the VM)" | len versionString p cString | cString := InterpreterSourceVersion. len := self cCode: 'strlen(cString)' inSmalltalk: [0]. versionString := interpreterProxy instantiateClass: interpreterProxy classString indexableSize: len. p := interpreterProxy arrayValueOf: versionString. self cCode: 'strncpy(p, cString, len)'. self pop: 1 thenPush: versionString ! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'tpr 3/15/2004 12:37'! primitiveInterruptSemaphore "Register the user interrupt semaphore. If the argument is not a Semaphore, unregister the current interrupt semaphore. " | arg | arg := self popStack. (self fetchClassOf: arg) = (self splObj: ClassSemaphore) ifTrue: [self storePointer: TheInterruptSemaphore ofObject: specialObjectsOop withValue: arg] ifFalse: [self storePointer: TheInterruptSemaphore ofObject: specialObjectsOop withValue: nilObj]! ! !Interpreter methodsFor: 'control primitives' stamp: 'dtl 5/18/2010 21:45'! primitiveInvokeObjectAsMethod "Primitive. 'Invoke' an object like a function, sending the special message run: originalSelector with: arguments in: aReceiver. " | runSelector runReceiver runArgs newReceiver lookupClass | runArgs := self instantiateClass: (self splObj: ClassArray) indexableSize: argumentCount. self beRootIfOld: runArgs. "do we really need this?" self transfer: argumentCount from: stackPointer - ((argumentCount - 1) * self bytesPerWord) to: runArgs + self baseHeaderSize. runSelector := messageSelector. runReceiver := self stackValue: argumentCount. self pop: argumentCount+1. "stack is clean here" newReceiver := newMethod. messageSelector := self splObj: SelectorRunWithIn. argumentCount := 3. self push: newReceiver. self push: runSelector. self push: runArgs. self push: runReceiver. lookupClass := self fetchClassOf: newReceiver. self findNewMethodInClass: lookupClass. self executeNewMethodFromCache. "Recursive xeq affects successFlag" successFlag := true. ! ! !Interpreter methodsFor: 'memory space primitives' stamp: 'dtl (auto pragmas dtl 2010-09-26) 5/19/2010 12:38'! primitiveIsRoot "Primitive. Answer whether the argument to the primitive is a root for young space" | oop | oop := self stackObjectValue: 0. successFlag ifTrue:[ self pop: argumentCount + 1. self pushBool: ((self baseHeader: oop) bitAnd: self rootBit). ].! ! !Interpreter methodsFor: 'memory space primitives' stamp: 'dtl (auto pragmas 12/08) 4/22/2007 22:51'! primitiveIsYoung "Primitive. Answer whether the argument to the primitive resides in young space." | oop | oop := self stackObjectValue: 0. successFlag ifTrue:[ self pop: argumentCount + 1. self pushBool: (self oop: oop isGreaterThanOrEqualTo: youngStart). ].! ! !Interpreter methodsFor: 'I/O primitives' stamp: 'tpr 3/15/2004 12:38'! primitiveKbdNext "Obsolete on virtually all platforms; old style input polling code. Return the next keycode and remove it from the input buffer. The low byte is the 8-bit ISO character. The next four bits are the Smalltalk modifier bits