* Cache Block Inputs & Procedure Definitions
* @mzgoddard requested changes on this pull request
* Move all caching into a single reusable field _cache.
* Invalidate 'all' caches on any change.
* Use 'typeof' instead of hasOwnProperty.
* Take caching out of Block and use lookup instead.
Before: `_removeThread` stops a thread and immediately removes it from
the runtime's thread array. If this happens while iterating over the
thread array, such as in the case of clone deletion, some elements of
the array can be missed.
After: `_removeThread` has been renamed to `_stopThread`. It still stops
the thread immediately but it no longer removes the thread from the
runtime's thread array. Instead, `_stopThread` marks the thread for
later removal. Such threads are removed at the top of the next `_step`.
return false from isActiveThread if thread's status is done even when
its contained in the runtime threads list. As it is done, the thread
will not be run until either its replaced by a new copy of the thread
or the thread is removed from the list and another is added at a later
time.
As part of reusing the block utility object, asynchronous say block
functions cannot use the utility in a promise or timeout asynchronous
handle. Store the needed target reference so utility is not needed
later.
blockUtility as an object literal inside execute creates 11 objects,
one for the object, and 10 for the function closures. As a separate
object and allocated once, setting its sequencer and thread members,
block functions can share the same util object. Extract blockUtility to
cut down on allocations.
`handleReport` inside `src/engine/execute.js`'s `execute` method needs
to allocate a closure to be able to refer to the higher scoped
variables. `execute` is called frequently that this has a noticable
impact on memory allocation and later collection. Extract handleReport
and add arguments to prevent the allocation.
Testing with implicitly casted `value` and `value.then` is deoptimizing
isPromise, which deoptimizes execute. In this case deoptimizing means
that the JavaScript VM cannot compile the functions into a form that
can be run faster.
Remove indexOf tests for thread existence in doneThreads. Maintain a
list of null and thread objects mirroring the index position of threads
that are done in runtime.threads. Filter out null values after
filtering out done threads from runtime.threads.
This has a small side effect that threads that normally became DONE and
were added to doneThreads before being removed or restarted will not be
in doneThreads in this version. Restarted threads (_restartThread) do
not appear in this version but new copies will be in Runtime
this.threads supporting glow and monitor updates. Removed threads
(_removeThread) do not appear in this version if they are removed after
they were seen as DONE by the prior version. Threads removed before
they are seen as DONE do not appear in doneThreads in the prior or this
version.
Threads that are removed before normally becoming DONE do not appear in
doneThreads in either case. Threads that are restarted before the loop
checks if the thread is done do not appear in doneThreads in either
case.
- Accumulate extension info while deserializing JSON
- Install extensions (if any) before installing target(s)
- Merged 'install' steps of the "add sprite" and "load project" paths
Since we will only have builtin extensions for a while, the
more-complicated, watchdog-based extension duplication prevention has
been replaced with one that treats the extension URL as equivalent to
the extension ID. This is true only for built-in extensions, so once we
start supporting third-party extensions we will likely need to bring
back the watchdog (commit e4381b4693) and
the more-complex duplication prevention (commit
670e51d335).
The code here should be treated as a last resort: ideally the GUI should
check if a particular extension is loaded (maybe by calling the
Extension Manager's new `isExtensionLoaded` method) and avoid calling
`loadExtensionURL` if it is.
If an extension attempts to register with the same ID as another
extension which has already registered, the new registration is refused.
If the extension is in a worker and no other extension is successfully
registered by that worker, the watchdog system will terminate the
"empty" worker.
If an extension worker does not complete initialization in a reasonable
amount of time (currently 15 seconds) then the worker will be
terminated. A complete initialization includes registering an extension.
* Playground: use UMD to load storage as global
It appears that `expose-loader` is not compatible with WebPack's UMD
exporter, so the VM playground broke when I converted `scratch-storage`
to use UMD. This change causes the playground to load `scratch-storage`
as an independent script and relies on its UMD loader to expose it as a
global. Bonus points: we get better source mapping this way.
* Playground: tell eslint about global ScratchStorage
Due to a typo (I believe) we were overwriting a horizontal hat block's
fields list when collecting hat block inputs. Now we collect inputs into
a temporary object in this case.
Dynamic menus are not yet supported for extension menus, though they are
part of the extension spec. This change provides more thorough feedback
if an extension tries to register an unsupported dynamic menu.
- Remove WeDo 2 extension from the runtime's default block packages list
- The WeDo 2.0 extension now calls its own `connect` method on startup
I also renamed `EXTENSION_NAME` to `EXTENSION_ID` for consistency with
the rest of the extension system.
This prevents generation of invalid XML due to characters like '<' or
'>' in fields' default values. Unfortunately the value comes back in its
escaped form, so there's still more work to be done.
WeDo2 and Pen blocks have been converted to internal extensions, and can
now be loaded by giving `loadExtensionURL` the string 'pen' or 'wedo2'
instead of an actual URL.