@swf2es/runtime 0.1.15 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avm2/cache-fill.d.ts +4 -1
- package/dist/avm2/cache-fill.d.ts.map +1 -1
- package/dist/avm2/cache-fill.js +5 -6
- package/dist/avm2/cache-fill.js.map +1 -1
- package/dist/avm2/descriptors.d.ts +6 -1
- package/dist/avm2/descriptors.d.ts.map +1 -1
- package/dist/avm2/descriptors.js.map +1 -1
- package/dist/avm2/errors.d.ts +14 -0
- package/dist/avm2/errors.d.ts.map +1 -1
- package/dist/avm2/errors.js +17 -0
- package/dist/avm2/errors.js.map +1 -1
- package/dist/avm2/index.d.ts +1 -0
- package/dist/avm2/index.d.ts.map +1 -1
- package/dist/avm2/index.js +1 -0
- package/dist/avm2/index.js.map +1 -1
- package/dist/avm2/names.d.ts +11 -0
- package/dist/avm2/names.d.ts.map +1 -1
- package/dist/avm2/names.js +12 -0
- package/dist/avm2/names.js.map +1 -1
- package/dist/avm2/natives/proxy.d.ts.map +1 -1
- package/dist/avm2/natives/proxy.js +9 -4
- package/dist/avm2/natives/proxy.js.map +1 -1
- package/dist/avm2/options.d.ts +5 -0
- package/dist/avm2/options.d.ts.map +1 -1
- package/dist/avm2/options.js.map +1 -1
- package/dist/avm2/property-cache.d.ts +17 -13
- package/dist/avm2/property-cache.d.ts.map +1 -1
- package/dist/avm2/property-cache.js +50 -10
- package/dist/avm2/property-cache.js.map +1 -1
- package/dist/avm2/runtime.d.ts +62 -0
- package/dist/avm2/runtime.d.ts.map +1 -1
- package/dist/avm2/runtime.js +245 -25
- package/dist/avm2/runtime.js.map +1 -1
- package/dist/avm2/traits.d.ts +7 -0
- package/dist/avm2/traits.d.ts.map +1 -1
- package/dist/avm2/traits.js +6 -0
- package/dist/avm2/traits.js.map +1 -1
- package/package.json +2 -2
- package/src/avm2/cache-fill.ts +5 -7
- package/src/avm2/descriptors.ts +6 -2
- package/src/avm2/errors.ts +18 -0
- package/src/avm2/index.ts +1 -0
- package/src/avm2/names.ts +13 -0
- package/src/avm2/natives/proxy.ts +20 -4
- package/src/avm2/options.ts +5 -0
- package/src/avm2/property-cache.ts +57 -11
- package/src/avm2/runtime.ts +280 -26
- package/src/avm2/traits.ts +7 -1
package/dist/avm2/runtime.js
CHANGED
|
@@ -21,18 +21,18 @@ import { NAMED } from "./dictionary-keys.js";
|
|
|
21
21
|
import { compileUnit, Domain, definitionNames, findScript } from "./domain.js";
|
|
22
22
|
import { isViewRangeError, SharedMemoryView } from "./domain-memory.js";
|
|
23
23
|
import { continues, dictionaryAt, elementsAt, enumerated, INT_ATOM_LIMIT, nextIndex, ownNames, pairIndex, pairOf, walkless, } from "./enumeration.js";
|
|
24
|
-
import { AsError, describe, errorMessage, stackOf } from "./errors.js";
|
|
24
|
+
import { AsError, describe, detailOf, errorMessage, stackOf, UnsupportedError } from "./errors.js";
|
|
25
25
|
import { FloatValue, floatValue } from "./float.js";
|
|
26
26
|
import { hookedBinding } from "./hooks.js";
|
|
27
27
|
import { installMethod, nativeFactory, noBodyFactory, unverifiedFactory, verifyErrorFactory, } from "./method-factories.js";
|
|
28
28
|
import { Modules } from "./modules.js";
|
|
29
|
-
import { arrayIndex, CONSTANT_Multiname, CONSTANT_MultinameA, CONSTANT_MultinameL, CONSTANT_MultinameLA, CONSTANT_Qname, CONSTANT_RTQname, CONSTANT_RTQnameA, CONSTANT_RTQnameL, CONSTANT_RTQnameLA, Multiname, Namespace, NS_Private, NS_Public, namespace, prefixedNamespace, prefixOf, publicNs, publicQname, qname, TypeName, } from "./names.js";
|
|
29
|
+
import { arrayIndex, CONSTANT_Multiname, CONSTANT_MultinameA, CONSTANT_MultinameL, CONSTANT_MultinameLA, CONSTANT_Qname, CONSTANT_RTQname, CONSTANT_RTQnameA, CONSTANT_RTQnameL, CONSTANT_RTQnameLA, MADE_Number, MADE_Value, Multiname, Namespace, NS_Private, NS_Public, namespace, prefixedNamespace, prefixOf, publicNs, publicQname, qname, TypeName, } from "./names.js";
|
|
30
30
|
import { FloatVector, setFloatElement } from "./natives/float-vector.js";
|
|
31
31
|
import { storeDouble, storeInt, storeObject, } from "./natives/vector-elements.js";
|
|
32
32
|
import { escapeAttributeValue, escapeElementValue } from "./natives/xml/escape.js";
|
|
33
33
|
import { numberToString, stringToNumber } from "./number-strings.js";
|
|
34
34
|
import { defaultPrint, memoryFiles, } from "./options.js";
|
|
35
|
-
import { cached, epoch, IC_Call, IC_Const, IC_Dynamic, IC_Get, IC_GetSet, IC_Method, IC_Set, IC_Slot, invalidate, NO_CACHE,
|
|
35
|
+
import { cached, epoch, IC_Call, IC_Const, IC_Dynamic, IC_Get, IC_GetSet, IC_Method, IC_Set, IC_Slot, invalidate, NO_CACHE, ScopeFinds, UNFILLED, } from "./property-cache.js";
|
|
36
36
|
import { BIND_Const, BIND_Get, BIND_GetSet, BIND_Method, BIND_Set, BIND_Var, boundKey, ClassRef, methodKey, slotKey, Traits, untypedSetKey, VectorRef, } from "./traits.js";
|
|
37
37
|
export { NOT_FOUND } from "./descriptors.js";
|
|
38
38
|
/**
|
|
@@ -54,6 +54,16 @@ class ScopePack {
|
|
|
54
54
|
this.w = w;
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
+
/** Whether a chain or a pack, `scopes` with bits `w`, has a with scope, in a pack in it too. */
|
|
58
|
+
function hasWith(scopes, w) {
|
|
59
|
+
for (let i = 0; i < scopes.length; i++) {
|
|
60
|
+
const o = scopes[i];
|
|
61
|
+
if (o instanceof ScopePack ? hasWith(o.scopes, o.w) : (w >> i) & 1) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
57
67
|
/** The value of `o`'s dynamic property `name`, or NOT_FOUND. */
|
|
58
68
|
function dynamicValue(o, name) {
|
|
59
69
|
const d = o.$d;
|
|
@@ -67,6 +77,7 @@ export class Runtime {
|
|
|
67
77
|
classHooks;
|
|
68
78
|
print;
|
|
69
79
|
debugger;
|
|
80
|
+
onUnsupported;
|
|
70
81
|
compileAbc;
|
|
71
82
|
files;
|
|
72
83
|
/** See RuntimeOptions.workers and worker. */
|
|
@@ -147,7 +158,7 @@ export class Runtime {
|
|
|
147
158
|
/** Special traits: an activation's or a catch scope's, by descriptor. */
|
|
148
159
|
scopeTraits = new WeakMap();
|
|
149
160
|
specialized = new Map();
|
|
150
|
-
empty = Object.assign([], { w: 0 });
|
|
161
|
+
empty = Object.assign([], { w: 0, found: undefined });
|
|
151
162
|
/**
|
|
152
163
|
* `natives` are the natives by name, or a provider that makes them for
|
|
153
164
|
* this runtime, so that a natives module can close over its runtime (as a
|
|
@@ -158,6 +169,7 @@ export class Runtime {
|
|
|
158
169
|
this.classHooks = classHooks;
|
|
159
170
|
this.print = options.print ?? defaultPrint;
|
|
160
171
|
this.debugger = options.debugger ?? false;
|
|
172
|
+
this.onUnsupported = options.onUnsupported;
|
|
161
173
|
this.compileAbc = options.compileAbc ?? null;
|
|
162
174
|
this.files = options.files ?? memoryFiles();
|
|
163
175
|
this.workerHost = options.workers ?? null;
|
|
@@ -289,6 +301,7 @@ export class Runtime {
|
|
|
289
301
|
// Its string only once a lookup needs it: a Dictionary does not.
|
|
290
302
|
const keyed = Multiname.keyed(kind, namespaces, versions, part, mn.attribute, this.keyName);
|
|
291
303
|
keyed.domain = mn.domain;
|
|
304
|
+
keyed.made = MADE_Value;
|
|
292
305
|
return keyed;
|
|
293
306
|
}
|
|
294
307
|
else {
|
|
@@ -297,6 +310,37 @@ export class Runtime {
|
|
|
297
310
|
}
|
|
298
311
|
const named = new Multiname(kind, namespaces, versions, name, mn.attribute);
|
|
299
312
|
named.domain = mn.domain;
|
|
313
|
+
// A number here is one no element access made: a Proxy tells it by its string.
|
|
314
|
+
if (mn.runtimeName && typeof last !== "number") {
|
|
315
|
+
named.made = MADE_Value;
|
|
316
|
+
}
|
|
317
|
+
return named;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* The name runtimeName makes of `mn`, a MultinameL, and a string the
|
|
321
|
+
* code itself holds, `obj["name"]`: a module makes it once as it loads
|
|
322
|
+
* and keeps it as it keeps `mn`, so it has a cache as a module's own
|
|
323
|
+
* names have, however many such names the module has and however long
|
|
324
|
+
* the string is.
|
|
325
|
+
*/
|
|
326
|
+
literalName(mn, name) {
|
|
327
|
+
const named = new Multiname(mn.kind, mn.namespaces, mn.versions, name, mn.attribute);
|
|
328
|
+
named.domain = mn.domain;
|
|
329
|
+
named.made = MADE_Value;
|
|
330
|
+
named.cache = UNFILLED;
|
|
331
|
+
return named;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* The name number `i` makes of `mn` in an element's read or write, which
|
|
335
|
+
* avmplus' JIT hands an object as a number (getpropertylate_i and _d), a
|
|
336
|
+
* Proxy as its string: where the name has no public namespace, it is a
|
|
337
|
+
* name as any other.
|
|
338
|
+
*/
|
|
339
|
+
indexName(mn, i) {
|
|
340
|
+
const named = this.runtimeName(mn, i);
|
|
341
|
+
if (mn.kind === CONSTANT_MultinameL && mn.elementName) {
|
|
342
|
+
named.made = MADE_Number;
|
|
343
|
+
}
|
|
300
344
|
return named;
|
|
301
345
|
}
|
|
302
346
|
stringNames = new WeakMap();
|
|
@@ -318,6 +362,7 @@ export class Runtime {
|
|
|
318
362
|
}
|
|
319
363
|
const named = new Multiname(base.kind, base.namespaces, base.versions, name, base.attribute);
|
|
320
364
|
named.domain = base.domain;
|
|
365
|
+
named.made = MADE_Value;
|
|
321
366
|
if (!cache) {
|
|
322
367
|
cache = { names: new Map(), misses: 0 };
|
|
323
368
|
this.stringNames.set(base, cache);
|
|
@@ -417,6 +462,7 @@ export class Runtime {
|
|
|
417
462
|
const traits = new Traits("global", this.objectTraits);
|
|
418
463
|
traits.dynamic = true;
|
|
419
464
|
traits.isGlobal = true;
|
|
465
|
+
traits.abc = script.abc;
|
|
420
466
|
traits.describe(script.desc.traits);
|
|
421
467
|
const g = traits.instance();
|
|
422
468
|
// As the script's initializer, its methods run in an empty scope chain,
|
|
@@ -490,6 +536,7 @@ export class Runtime {
|
|
|
490
536
|
scope(outer, locals, withs) {
|
|
491
537
|
const chain = outer.concat(locals);
|
|
492
538
|
chain.w = outer.w | (withs << outer.length);
|
|
539
|
+
chain.found = undefined;
|
|
493
540
|
return chain;
|
|
494
541
|
}
|
|
495
542
|
/**
|
|
@@ -504,6 +551,7 @@ export class Runtime {
|
|
|
504
551
|
const packed = chain.slice(0, at);
|
|
505
552
|
packed.push(new ScopePack(chain.slice(at), chain.w >>> at));
|
|
506
553
|
packed.w = (chain.w & ((1 << at) - 1)) | (1 << at);
|
|
554
|
+
packed.found = undefined;
|
|
507
555
|
return packed;
|
|
508
556
|
}
|
|
509
557
|
/**
|
|
@@ -532,6 +580,40 @@ export class Runtime {
|
|
|
532
580
|
return locals[i];
|
|
533
581
|
}
|
|
534
582
|
}
|
|
583
|
+
const found = this.outerScopeOf(outer, mn);
|
|
584
|
+
if (found !== null) {
|
|
585
|
+
return found;
|
|
586
|
+
}
|
|
587
|
+
return this.global(mn, outer.length ? outer[0] : locals[0], strict);
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* The innermost object of a captured chain that has `mn`, or null: kept
|
|
591
|
+
* on a chain without a with scope (ScopeFinds), as a function whose
|
|
592
|
+
* chain the compiler could not type, such as one made where chains of
|
|
593
|
+
* different lengths meet, looks its names up each time it runs.
|
|
594
|
+
*/
|
|
595
|
+
outerScopeOf(outer, mn) {
|
|
596
|
+
let finds = outer.found;
|
|
597
|
+
if (finds === undefined) {
|
|
598
|
+
finds = hasWith(outer, outer.w) ? null : new ScopeFinds();
|
|
599
|
+
outer.found = finds;
|
|
600
|
+
}
|
|
601
|
+
// A name made at run time is a new one each time: keeping it would only grow the map.
|
|
602
|
+
if (finds === null || mn.cache === NO_CACHE) {
|
|
603
|
+
return this.searchOuter(outer, mn);
|
|
604
|
+
}
|
|
605
|
+
if (finds.epoch !== epoch()) {
|
|
606
|
+
finds.clear();
|
|
607
|
+
finds.epoch = epoch();
|
|
608
|
+
}
|
|
609
|
+
let o = finds.get(mn);
|
|
610
|
+
if (o === undefined) {
|
|
611
|
+
o = this.searchOuter(outer, mn);
|
|
612
|
+
finds.set(mn, o);
|
|
613
|
+
}
|
|
614
|
+
return o;
|
|
615
|
+
}
|
|
616
|
+
searchOuter(outer, mn) {
|
|
535
617
|
for (let i = outer.length - 1; i >= 0; i--) {
|
|
536
618
|
const o = outer[i];
|
|
537
619
|
if (o instanceof ScopePack) {
|
|
@@ -544,7 +626,7 @@ export class Runtime {
|
|
|
544
626
|
return o;
|
|
545
627
|
}
|
|
546
628
|
}
|
|
547
|
-
return
|
|
629
|
+
return null;
|
|
548
630
|
}
|
|
549
631
|
findPropertyStrict(mn, outer, locals, withs) {
|
|
550
632
|
return this.findProperty(mn, outer, locals, withs, true);
|
|
@@ -669,15 +751,22 @@ export class Runtime {
|
|
|
669
751
|
traitsOf(v) {
|
|
670
752
|
switch (typeof v) {
|
|
671
753
|
case "object":
|
|
672
|
-
case "function":
|
|
754
|
+
case "function": {
|
|
673
755
|
if (v === null) {
|
|
674
756
|
throw this.error("TypeError", 1009);
|
|
675
757
|
}
|
|
758
|
+
// An object's own first: instanceof walks the whole prototype
|
|
759
|
+
// chain of an object, and a class's is as deep as its bases.
|
|
760
|
+
const traits = v.$traits;
|
|
761
|
+
if (traits !== undefined) {
|
|
762
|
+
return traits;
|
|
763
|
+
}
|
|
676
764
|
return v instanceof FloatValue
|
|
677
765
|
? this.builtinTraits("float")
|
|
678
766
|
: v instanceof Namespace
|
|
679
767
|
? this.builtinTraits("Namespace")
|
|
680
|
-
:
|
|
768
|
+
: traits;
|
|
769
|
+
}
|
|
681
770
|
// As avmplus' toVTable: every number is a Number at run time, int or
|
|
682
771
|
// not; int's and uint's traits only bind early, from static types.
|
|
683
772
|
case "number":
|
|
@@ -698,12 +787,17 @@ export class Runtime {
|
|
|
698
787
|
receiverTraits(v) {
|
|
699
788
|
switch (typeof v) {
|
|
700
789
|
case "object":
|
|
701
|
-
case "function":
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
790
|
+
case "function": {
|
|
791
|
+
if (v === null) {
|
|
792
|
+
return undefined;
|
|
793
|
+
}
|
|
794
|
+
// A float and a Namespace have none of their own (see traitsOf).
|
|
795
|
+
const traits = v.$traits;
|
|
796
|
+
if (traits !== undefined) {
|
|
797
|
+
return traits;
|
|
798
|
+
}
|
|
799
|
+
return v instanceof FloatValue ? this.builtinTraits("float") : undefined;
|
|
800
|
+
}
|
|
707
801
|
case "string":
|
|
708
802
|
return this.stringTraits;
|
|
709
803
|
case "number":
|
|
@@ -877,7 +971,7 @@ export class Runtime {
|
|
|
877
971
|
}
|
|
878
972
|
}
|
|
879
973
|
}
|
|
880
|
-
return this.getProperty(o, this.
|
|
974
|
+
return this.getProperty(o, this.indexName(mn, i));
|
|
881
975
|
}
|
|
882
976
|
/** obj[i] = v for a number i, as avmplus' setUintProperty. */
|
|
883
977
|
setIndexed(o, mn, i, v) {
|
|
@@ -889,12 +983,93 @@ export class Runtime {
|
|
|
889
983
|
traits.setIndex(o, i, v, this);
|
|
890
984
|
return;
|
|
891
985
|
}
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
986
|
+
const a = o.$a;
|
|
987
|
+
if (a !== undefined) {
|
|
988
|
+
if (a !== SEALED_ELEMENTS && i !== 0xffffffff) {
|
|
989
|
+
a[i] = v;
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
else if (traits?.dynamic && traits.properties === null && !traits.refusesNames) {
|
|
994
|
+
// As ScriptObject::setUintProperty: an object with no elements of its own keeps the
|
|
995
|
+
// number among its dynamic properties, with no binding asked for.
|
|
996
|
+
const d = o.$d;
|
|
997
|
+
if (d) {
|
|
998
|
+
d.set(`${i}`, v);
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
895
1001
|
}
|
|
896
1002
|
}
|
|
897
|
-
this.setProperty(o, this.
|
|
1003
|
+
this.setProperty(o, this.indexName(mn, i), v);
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* obj[k] for a key whose type the compiler does not know, by a name with
|
|
1007
|
+
* no namespace from the stack, as avmplus' getprop_index and
|
|
1008
|
+
* getpropertyHelper: a number is an index (getIndexed), an object a
|
|
1009
|
+
* Dictionary has as a key is read by itself, and anything else, a QName
|
|
1010
|
+
* and a Dictionary's absent key among them, is looked up by the name it
|
|
1011
|
+
* makes.
|
|
1012
|
+
*/
|
|
1013
|
+
getKeyed(o, mn, k) {
|
|
1014
|
+
let r;
|
|
1015
|
+
if (typeof k === "number") {
|
|
1016
|
+
r = this.getIndexed(o, mn, k);
|
|
1017
|
+
return r;
|
|
1018
|
+
}
|
|
1019
|
+
if (typeof k === "object" && k !== null) {
|
|
1020
|
+
const keys = o?.$keys;
|
|
1021
|
+
if (keys !== undefined) {
|
|
1022
|
+
if (!mn.elementName) {
|
|
1023
|
+
r = this.getProperty(o, this.runtimeName(mn, this.unkeyed(k)));
|
|
1024
|
+
return r;
|
|
1025
|
+
}
|
|
1026
|
+
// What is there was put there by a name with the object as its key, which a QName's is not.
|
|
1027
|
+
const v = keys.get(k);
|
|
1028
|
+
if (v !== undefined) {
|
|
1029
|
+
return v;
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
r = this.getProperty(o, this.runtimeName(mn, k));
|
|
1034
|
+
return r;
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* An object given as the key of a Dictionary by a name with no public
|
|
1038
|
+
* namespace, as the name is made of it: avmplus' JIT asks a Dictionary
|
|
1039
|
+
* for an object only through getprop_index and setprop_index, which such
|
|
1040
|
+
* a name does not reach, so the object is its string, as on any other
|
|
1041
|
+
* receiver (initMultinameLate); a QName names what it names. Its
|
|
1042
|
+
* interpreter asks the Dictionary by any name, as a name made without
|
|
1043
|
+
* this does: the compiler leaves script and class initializers to that.
|
|
1044
|
+
*/
|
|
1045
|
+
unkeyed(k) {
|
|
1046
|
+
return k.$traits !== undefined && k.$local === undefined ? this.toString(k) : k;
|
|
1047
|
+
}
|
|
1048
|
+
/** obj[k] = v for a key whose type the compiler does not know, as avmplus' setprop_index and setpropertyHelper. */
|
|
1049
|
+
setKeyed(o, mn, k, v) {
|
|
1050
|
+
if (typeof k === "number") {
|
|
1051
|
+
this.setIndexed(o, mn, k, v);
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
if (typeof k === "object" && k !== null) {
|
|
1055
|
+
const keys = o?.$keys;
|
|
1056
|
+
if (keys !== undefined) {
|
|
1057
|
+
if (!mn.elementName) {
|
|
1058
|
+
this.setProperty(o, this.runtimeName(mn, this.unkeyed(k)), v);
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
if (keys.replace(k, v)) {
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
// A new key: an object of traits, which a float and a Namespace are not, and no QName,
|
|
1065
|
+
// which names what it names. Those are added, or not, by the name they make.
|
|
1066
|
+
if (k.$traits !== undefined && k.$local === undefined) {
|
|
1067
|
+
keys.add(k, v);
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
this.setProperty(o, this.runtimeName(mn, k), v);
|
|
898
1073
|
}
|
|
899
1074
|
/**
|
|
900
1075
|
* Element i of Vector o set to x, already converted, as
|
|
@@ -1093,9 +1268,7 @@ export class Runtime {
|
|
|
1093
1268
|
/** fillCache (cache-fill.ts), for a name that caches on traits a cache knows `o` by. */
|
|
1094
1269
|
fill(o, traits, b, mn) {
|
|
1095
1270
|
const head = mn.cache;
|
|
1096
|
-
if (head === NO_CACHE ||
|
|
1097
|
-
(head.replaced === REPLACEMENTS && head.epoch === epoch()) ||
|
|
1098
|
-
this.receiverTraits(o) !== traits) {
|
|
1271
|
+
if (head === NO_CACHE || this.receiverTraits(o) !== traits) {
|
|
1099
1272
|
return;
|
|
1100
1273
|
}
|
|
1101
1274
|
fillCache(head, o, traits, b, mn);
|
|
@@ -1124,6 +1297,8 @@ export class Runtime {
|
|
|
1124
1297
|
f.$length = method.$length ?? method.length;
|
|
1125
1298
|
f.$id = method.$id ?? 0;
|
|
1126
1299
|
f.$closure = true;
|
|
1300
|
+
// Whose method it is, for moduleOf.
|
|
1301
|
+
f.$of = traits;
|
|
1127
1302
|
if (typeof o === "object") {
|
|
1128
1303
|
byMethod.set(method, f);
|
|
1129
1304
|
}
|
|
@@ -1388,8 +1563,7 @@ export class Runtime {
|
|
|
1388
1563
|
// A namespace is the runtime's own object: its prototype is its class's.
|
|
1389
1564
|
if (typeof o === "object" &&
|
|
1390
1565
|
o !== null &&
|
|
1391
|
-
!(o instanceof Namespace)
|
|
1392
|
-
!(o instanceof FloatValue)) {
|
|
1566
|
+
(o.$traits !== undefined || !(o instanceof Namespace || o instanceof FloatValue))) {
|
|
1393
1567
|
return o.$p;
|
|
1394
1568
|
}
|
|
1395
1569
|
return this.traitsOf(o).proto.$p;
|
|
@@ -1809,6 +1983,19 @@ export class Runtime {
|
|
|
1809
1983
|
this.functionObjects.set(method, f);
|
|
1810
1984
|
return f;
|
|
1811
1985
|
}
|
|
1986
|
+
/**
|
|
1987
|
+
* The module a function's code is from, as avmplus has a method's code
|
|
1988
|
+
* context: a function's by the global object its scope begins with, a
|
|
1989
|
+
* bound method's by its receiver's class; null for a native, a class's
|
|
1990
|
+
* own method, or anything but a function.
|
|
1991
|
+
*/
|
|
1992
|
+
moduleOf(f) {
|
|
1993
|
+
const o = f;
|
|
1994
|
+
if (o?.$of) {
|
|
1995
|
+
return o.$of.abc;
|
|
1996
|
+
}
|
|
1997
|
+
return o?.$global ? this.traitsOf(o.$global).abc : null;
|
|
1998
|
+
}
|
|
1812
1999
|
/** A Function object calling `f`, with `global` as its receiver when it has none. */
|
|
1813
2000
|
newFunctionObject(f, global) {
|
|
1814
2001
|
const o = this.functionTraits.instance();
|
|
@@ -2543,12 +2730,21 @@ export class Runtime {
|
|
|
2543
2730
|
catch {
|
|
2544
2731
|
return new AsError(`${name}: ${message}`);
|
|
2545
2732
|
}
|
|
2546
|
-
|
|
2733
|
+
const made = this.constructClass(cls, [message, id]);
|
|
2734
|
+
// What the number stands for, kept beside the message for a host's report (detailOf).
|
|
2735
|
+
if (!this.debugger) {
|
|
2736
|
+
Object.defineProperty(made, "$detail", { value: errorMessage(true, id, args) });
|
|
2737
|
+
}
|
|
2738
|
+
return made;
|
|
2547
2739
|
}
|
|
2548
2740
|
/** See stackOf in errors.ts. */
|
|
2549
2741
|
stackOf(error) {
|
|
2550
2742
|
return stackOf(error);
|
|
2551
2743
|
}
|
|
2744
|
+
/** See detailOf in errors.ts. */
|
|
2745
|
+
detailOf(error) {
|
|
2746
|
+
return detailOf(error);
|
|
2747
|
+
}
|
|
2552
2748
|
/** See errorMessage in errors.ts. */
|
|
2553
2749
|
errorMessage(id, args = []) {
|
|
2554
2750
|
return errorMessage(this.debugger, id, args);
|
|
@@ -2573,11 +2769,35 @@ export class Runtime {
|
|
|
2573
2769
|
if (isViewRangeError(e)) {
|
|
2574
2770
|
return this.error("RangeError", 1506);
|
|
2575
2771
|
}
|
|
2772
|
+
if (e instanceof UnsupportedError) {
|
|
2773
|
+
return this.unsupportedCaught(e);
|
|
2774
|
+
}
|
|
2576
2775
|
if (e instanceof Error && !(e instanceof AsError)) {
|
|
2577
2776
|
throw e;
|
|
2578
2777
|
}
|
|
2579
2778
|
return e;
|
|
2580
2779
|
}
|
|
2780
|
+
/** What a catch was told of already (unsupportedCaught). */
|
|
2781
|
+
unsupportedTold = new Set();
|
|
2782
|
+
/**
|
|
2783
|
+
* What is not supported as the AS3 error a catch gets: an
|
|
2784
|
+
* IllegalOperationError with its message, or an Error where the player's
|
|
2785
|
+
* classes are not loaded; said once to the host, as the code may say nothing.
|
|
2786
|
+
*/
|
|
2787
|
+
unsupportedCaught(e) {
|
|
2788
|
+
if (!this.unsupportedTold.has(e.message)) {
|
|
2789
|
+
this.unsupportedTold.add(e.message);
|
|
2790
|
+
this.onUnsupported?.(e.message);
|
|
2791
|
+
}
|
|
2792
|
+
let cls;
|
|
2793
|
+
try {
|
|
2794
|
+
cls = this.resolve(this.cls(namespace(NS_Public, "flash.errors"), "IllegalOperationError"));
|
|
2795
|
+
}
|
|
2796
|
+
catch {
|
|
2797
|
+
cls = this.builtinClass("Error");
|
|
2798
|
+
}
|
|
2799
|
+
return this.constructClass(cls, [e.message, 0]);
|
|
2800
|
+
}
|
|
2581
2801
|
catches(e, type) {
|
|
2582
2802
|
return this.isInstanceOf(e, this.traitsOfType(type));
|
|
2583
2803
|
}
|
|
@@ -2585,7 +2805,7 @@ export class Runtime {
|
|
|
2585
2805
|
return new Error("swf2es: a dispatcher reached no block");
|
|
2586
2806
|
}
|
|
2587
2807
|
unsupported(what) {
|
|
2588
|
-
return new
|
|
2808
|
+
return new UnsupportedError(`swf2es: ${what} is not supported yet`);
|
|
2589
2809
|
}
|
|
2590
2810
|
// Class aliases and the classes AMF makes (amf-classes.ts).
|
|
2591
2811
|
registerClassAlias(name, cls) {
|