Skip to content

Commit

Permalink
release 1.2.1
Browse files Browse the repository at this point in the history
  • Loading branch information
codefrau committed May 28, 2024
1 parent e31ac8e commit 02547f2
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 25 deletions.
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ <h2>About</h2>
<a name="news">
<h2>News</h2>
</a>
<p><b>May 2024</b>Release 1.2.1 adds virtual cmd button, fixes touch events
<p><b>March 2024</b> Release 1.2.0 adds FFI and MIDI plugins, JIT for Sista bytecodes, JPEG write prim, fixes keyboard input, copy/paste, scroll wheel, highdpi, allows ES6 in source</p>
<p><b>November 2023</b> Release 1.1.2 with more fixes (thanks to Agustin Martinez for narrowing down the problem).</p>
<p><b>November 2023</b> Expanded the <a href="https://squeak.js.org/docs/jit.md.html">High-performance JIT Mockups</a>.</p>
Expand Down
118 changes: 93 additions & 25 deletions squeak.js
Original file line number Diff line number Diff line change
Expand Up @@ -1409,7 +1409,11 @@
Objects are tenured to old space during a full GC.
New objects are only referenced by other objects' pointers, and thus can be garbage-collected
at any time by the Javascript GC.
A partial GC links new objects to support enumeration of new space.
A partial GC creates a linked list of new objects reachable from old space. We call this
list "young space". It is not stored, but only created by primitives like nextObject,
nextInstance, or become to support enumeration of new space.
To efficiently find potential young space roots, any write to an instance variable sets
the "dirty" flag of the object, allowing to skip clean objects.

Weak references are finalized by a full GC. A partial GC only finalizes young weak references.

Expand Down Expand Up @@ -1808,10 +1812,9 @@
// sorting them by id, and then linking them into old space.
this.vm.addMessage("fullGC: " + reason);
var start = Date.now();
var previousNew = this.newSpaceCount;
var previousYoung = this.youngSpaceCount;
var previousNew = this.newSpaceCount; // includes young and newly allocated
var previousOld = this.oldSpaceCount;
var newObjects = this.markReachableObjects();
var newObjects = this.markReachableObjects(); // technically these are young objects
this.removeUnmarkedOldObjects();
this.appendToOldObjects(newObjects);
this.finalizeWeakReferences();
Expand All @@ -1821,11 +1824,20 @@
this.hasNewInstances = {};
this.gcCount++;
this.gcMilliseconds += Date.now() - start;
var delta = previousOld - this.oldSpaceCount;
console.log("Full GC (" + reason + "): " + (Date.now() - start) + " ms, " +
"surviving objects: " + this.oldSpaceCount + " (" + this.oldSpaceBytes + " bytes), " +
"tenured " + newObjects.length + " (total " + (delta > 0 ? "+" : "") + delta + "), " +
"gc'ed " + previousYoung + " young and " + (previousNew - previousYoung) + " new objects");
var delta = previousOld - this.oldSpaceCount; // absolute change
var survivingNew = newObjects.length;
var survivingOld = this.oldSpaceCount - survivingNew;
var gcedNew = previousNew - survivingNew;
var gcedOld = previousOld - survivingOld;
console.log("Full GC (" + reason + "): " + (Date.now() - start) + " ms;" +
" before: " + previousOld.toLocaleString() + " old objects;" +
" allocated " + previousNew.toLocaleString() + " new;" +
" surviving " + survivingOld.toLocaleString() + " old;" +
" tenuring " + survivingNew.toLocaleString() + " new;" +
" gc'ed " + gcedOld.toLocaleString() + " old and " + gcedNew.toLocaleString() + " new;" +
" total now: " + this.oldSpaceCount.toLocaleString() + " (" + (delta > 0 ? "+" : "") + delta.toLocaleString() + ", "
+ this.oldSpaceBytes.toLocaleString() + " bytes)"
);

return newObjects.length > 0 ? newObjects[0] : null;
},
Expand All @@ -1836,7 +1848,7 @@
},
markReachableObjects: function() {
// FullGC: Visit all reachable objects and mark them.
// Return surviving new objects
// Return surviving new objects (young objects to be tenured).
// Contexts are handled specially: they have garbage beyond the stack pointer
// which must not be traced, and is cleared out here
// In weak objects, only the inst vars are traced
Expand Down Expand Up @@ -1986,8 +1998,8 @@
this.pgcCount++;
this.pgcMilliseconds += Date.now() - start;
console.log("Partial GC (" + reason+ "): " + (Date.now() - start) + " ms, " +
"found " + this.youngRootsCount + " roots in " + this.oldSpaceCount + " old, " +
"kept " + this.youngSpaceCount + " young (" + (previous - this.youngSpaceCount) + " gc'ed)");
"found " + this.youngRootsCount.toLocaleString() + " roots in " + this.oldSpaceCount.toLocaleString() + " old, " +
"kept " + this.youngSpaceCount.toLocaleString() + " young (" + (previous - this.youngSpaceCount).toLocaleString() + " gc'ed)");
return young[0];
},
youngRoots: function() {
Expand Down Expand Up @@ -6711,8 +6723,16 @@
return this.popNandPushIfOK(argCount+1, this.makeLargeIfNeeded(bytes));
},
primitivePartialGC: function(argCount) {
this.vm.image.partialGC("primitive");
var bytes = this.vm.image.bytesLeft();
var young = this.vm.image.partialGC("primitive");
var youngSpaceBytes = 0;
while (young) {
youngSpaceBytes += young.totalBytes();
young = young.nextObject;
}
console.log(" old space: " + this.vm.image.oldSpaceBytes.toLocaleString() + " bytes, " +
"young space: " + youngSpaceBytes.toLocaleString() + " bytes, " +
"total: " + (this.vm.image.oldSpaceBytes + youngSpaceBytes).toLocaleString() + " bytes");
var bytes = this.vm.image.bytesLeft() - youngSpaceBytes;
return this.popNandPushIfOK(argCount+1, this.makeLargeIfNeeded(bytes));
},
primitiveMakePoint: function(argCount, checkNumbers) {
Expand Down Expand Up @@ -56181,7 +56201,8 @@
function recordModifiers(evt, display) {
var shiftPressed = evt.shiftKey,
ctrlPressed = evt.ctrlKey && !evt.altKey,
cmdPressed = display.isMac ? evt.metaKey : evt.altKey && !evt.ctrlKey,
cmdPressed = (display.isMac ? evt.metaKey : evt.altKey && !evt.ctrlKey)
|| display.cmdButtonTouched,
modifiers =
(shiftPressed ? Squeak.Keyboard_Shift : 0) +
(ctrlPressed ? Squeak.Keyboard_Ctrl : 0) +
Expand All @@ -56190,9 +56211,15 @@
return modifiers;
}

var canUseMouseOffset = navigator.userAgent.match("AppleWebKit/");
var canUseMouseOffset = null;

function updateMousePos(evt, canvas, display) {
if (canUseMouseOffset === null) {
// Per https://caniuse.com/mdn-api_mouseevent_offsetx, essentially all *current*
// browsers support `offsetX`/`offsetY`, but it does little harm to fall back to the
// older `layerX`/`layerY` for now.
canUseMouseOffset = 'offsetX' in evt;
}
var evtX = canUseMouseOffset ? evt.offsetX : evt.layerX,
evtY = canUseMouseOffset ? evt.offsetY : evt.layerY;
if (display.cursorCanvas) {
Expand Down Expand Up @@ -56373,6 +56400,7 @@
mouseY: 0,
buttons: 0,
keys: [],
cmdButtonTouched: null, // touchscreen button pressed (touch ID)
eventQueue: null, // only used if image uses event primitives
clipboardString: '',
clipboardStringChanged: false,
Expand Down Expand Up @@ -56523,10 +56551,18 @@
function touchToMouse(evt) {
if (evt.touches.length) {
// average all touch positions
// but ignore the cmd button touch
touch.x = touch.y = 0;
let n = 0;
for (var i = 0; i < evt.touches.length; i++) {
touch.x += evt.touches[i].pageX / evt.touches.length;
touch.y += evt.touches[i].pageY / evt.touches.length;
if (evt.touches[i].identifier === display.cmdButtonTouched) continue;
touch.x += evt.touches[i].pageX;
touch.y += evt.touches[i].pageY;
n++;
}
if (n > 0) {
touch.x /= n;
touch.y /= n;
}
}
return {
Expand Down Expand Up @@ -56632,12 +56668,14 @@
// * if fingers moved significantly within 200ms of 2nd down, start zooming
// * if touch ended within this time, generate click (down+up)
// * otherwise, start mousing with 2nd button
// * also, ignore finger on cmd button
// When mousing, always generate a move event before down event so that
// mouseover eventhandlers in image work better
canvas.ontouchstart = function(evt) {
evt.preventDefault();
var e = touchToMouse(evt);
for (var i = 0; i < evt.changedTouches.length; i++) {
if (evt.changedTouches[i].identifier === display.cmdButtonTouched) continue;
switch (touch.state) {
case 'idle':
touch.state = 'got1stFinger';
Expand Down Expand Up @@ -56682,34 +56720,35 @@
break;
case 'mousing':
recordMouseEvent('mousemove', e, canvas, display, options);
return;
break;
case 'got2ndFinger':
if (evt.touches.length > 1)
touch.dist = dist(evt.touches[0], evt.touches[1]);
return;
break;
case 'zooming':
zoomMove(evt);
return;
break;
}
};
canvas.ontouchend = function(evt) {
evt.preventDefault();
checkFullscreen();
var e = touchToMouse(evt);
for (var i = 0; i < evt.changedTouches.length; i++) {
if (evt.changedTouches[i].identifier === display.cmdButtonTouched) continue;
switch (touch.state) {
case 'mousing':
if (evt.touches.length > 0) break;
touch.state = 'idle';
recordMouseEvent('mouseup', e, canvas, display, options);
return;
break;
case 'got1stFinger':
touch.state = 'idle';
touch.button = e.button = 0;
recordMouseEvent('mousemove', e, canvas, display, options);
recordMouseEvent('mousedown', e, canvas, display, options);
recordMouseEvent('mouseup', e, canvas, display, options);
return;
break;
case 'got2ndFinger':
touch.state = 'mousing';
touch.button = e.button = 2;
Expand All @@ -56720,7 +56759,7 @@
if (evt.touches.length > 0) break;
touch.state = 'idle';
zoomEnd();
return;
break;
}
}
};
Expand Down Expand Up @@ -56752,8 +56791,9 @@
input.style.opacity = "0";
input.style.pointerEvents = "none";
canvas.parentElement.appendChild(input);
// touch-keyboard button
// touch-keyboard buttons
if ('ontouchstart' in document) {
// button to show on-screen keyboard
var keyboardButton = document.createElement('div');
keyboardButton.innerHTML = '<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="50px" height="50px" viewBox="0 0 150 150" version="1.1" xmlns="http://www.w3.org/2000/svg"><g id="Page-1" stroke="none" fill="#000000"><rect x="33" y="105" width="10" height="10" rx="1"></rect><rect x="26" y="60" width="10" height="10" rx="1"></rect><rect x="41" y="60" width="10" height="10" rx="1"></rect><rect x="56" y="60" width="10" height="10" rx="1"></rect><rect x="71" y="60" width="10" height="10" rx="1"></rect><rect x="86" y="60" width="10" height="10" rx="1"></rect><rect x="101" y="60" width="10" height="10" rx="1"></rect><rect x="116" y="60" width="10" height="10" rx="1"></rect><rect x="108" y="105" width="10" height="10" rx="1"></rect><rect x="33" y="75" width="10" height="10" rx="1"></rect><rect x="48" y="75" width="10" height="10" rx="1"></rect><rect x="63" y="75" width="10" height="10" rx="1"></rect><rect x="78" y="75" width="10" height="10" rx="1"></rect><rect x="93" y="75" width="10" height="10" rx="1"></rect><rect x="108" y="75" width="10" height="10" rx="1"></rect><rect x="41" y="90" width="10" height="10" rx="1"></rect><rect x="26" y="90" width="10" height="10" rx="1"></rect><rect x="56" y="90" width="10" height="10" rx="1"></rect><rect x="71" y="90" width="10" height="10" rx="1"></rect><rect x="86" y="90" width="10" height="10" rx="1"></rect><rect x="101" y="90" width="10" height="10" rx="1"></rect><rect x="116" y="90" width="10" height="10" rx="1"></rect><rect x="48" y="105" width="55" height="10" rx="1"></rect><path d="M20.0056004,51 C18.3456532,51 17.0000001,52.3496496 17.0000001,54.0038284 L17.0000001,85.6824519 L17,120.003453 C17.0000001,121.6584 18.3455253,123 20.0056004,123 L131.9944,123 C133.654347,123 135,121.657592 135,119.997916 L135,54.0020839 C135,52.3440787 133.654475,51 131.9944,51 L20.0056004,51 Z" fill="none" stroke="#000000" stroke-width="2"></path><path d="M52.0410156,36.6054687 L75.5449219,21.6503905 L102.666016,36.6054687" id="Line" stroke="#000000" stroke-width="3" stroke-linecap="round" fill="none"></path></g></svg>';
keyboardButton.setAttribute('style', 'position:fixed;right:0;bottom:0;background-color:rgba(128,128,128,0.5);border-radius:5px');
Expand All @@ -56764,6 +56804,34 @@
evt.preventDefault();
};
keyboardButton.ontouchstart = keyboardButton.onmousedown;
// modifier button for CMD key
var cmdButton = document.createElement('div');
cmdButton.innerHTML = '⌘';
cmdButton.setAttribute('style', 'position:fixed;left:0;background-color:rgba(128,128,128,0.5);width:50px;height:50px;font-size:30px;text-align:center;vertical-align:middle;line-height:50px;border-radius:5px');
if (window.visualViewport) {
// fix position of button when virtual keyboard is shown
const vv = window.visualViewport;
const fixPosition = () => cmdButton.style.top = `${vv.height}px`;
vv.addEventListener('resize', fixPosition);
cmdButton.style.transform = `translateY(-100%)`;
fixPosition();
} else {
cmdButton.style.bottom = '0';
}
canvas.parentElement.appendChild(cmdButton);
cmdButton.ontouchstart = function(evt) {
display.cmdButtonTouched = evt.changedTouches[0].identifier;
cmdButton.style.backgroundColor = 'rgba(255,255,255,0.5)';
evt.preventDefault();
evt.stopPropagation();
};
cmdButton.ontouchend = function(evt) {
display.cmdButtonTouched = null;
cmdButton.style.backgroundColor = 'rgba(128,128,128,0.5)';
evt.preventDefault();
evt.stopPropagation();
};
cmdButton.ontouchcancel = cmdButton.ontouchend;
} else {
// keep focus on input field
input.onblur = function() { input.focus(); };
Expand Down

0 comments on commit 02547f2

Please sign in to comment.