Implement realm object and support realms for built-ins and JS functions (#4354)

- Type for realm objects is introduced (ecma_global_object_t)
- Realm reference is added to built-in objects and ECMAScript functions
- Resolving built-ins, global environments, and scopes require realm object
- Unnecessary global object accesses are removed from the code

Missing: external functions and static snapshot functions have no realm reference

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2020-12-08 14:36:36 +01:00
committed by GitHub
parent 7cb9f808f7
commit df92c86ecf
32 changed files with 1128 additions and 188 deletions
+4
View File
@@ -9,6 +9,7 @@ f | Function |
addX | Function |
z | undefined | undefined
c | undefined | undefined
createRealm | Function |
resourceName | Function |
print | Function |
gc | Function |
@@ -21,6 +22,7 @@ f | Function |
addX | Function |
z | undefined | undefined
c | undefined | undefined
createRealm | Function |
resourceName | Function |
print | Function |
gc | Function |
@@ -48,6 +50,7 @@ f | Function |
addX | Function |
z | Number | 5
c | Number | 4
createRealm | Function |
resourceName | Function |
print | Function |
gc | Function |
@@ -68,6 +71,7 @@ f | Function |
addX | Function |
z | Number | 5
c | Number | 4
createRealm | Function |
resourceName | Function |
print | Function |
gc | Function |
+95
View File
@@ -0,0 +1,95 @@
// Copyright JS Foundation and other contributors, http://js.foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
var realm = createRealm()
var ev = realm.eval
assert(realm.Math != Math)
assert(typeof realm.Math === "object")
assert(realm.Object != Object)
assert(typeof realm.Object === "function")
assert(realm.eval != eval)
assert(typeof realm.eval === "function")
// Share our 'assert' function with the realm
realm.assert = assert
// Test1: var1 and var2 must be different properties
realm.var1 = 3.5
assert(realm.var2 === undefined)
var var1 = "X"
var var2 = "Y"
ev("assert(var1 === 3.5); \
try { realm; assert(false) } catch (e) { assert(e instanceof ReferenceError) } \
assert(this === globalThis); \
var var2 = this")
assert(realm.var2 === realm)
assert(var1 === "X")
assert(var2 === "Y")
// Test2: constructing any objects (including errors) must use the realm
assert (realm.RangeError != RangeError)
assert (realm.RangeError.prototype != RangeError.prototype)
realm.RangeError.prototype.myProperty = "XY"
assert(RangeError.prototype.myProperty === undefined)
try {
var NumberToString = realm.Number.prototype.toString;
NumberToString.call(0, 0)
assert(false)
} catch (e) {
assert(e instanceof realm.RangeError)
assert(!(e instanceof RangeError))
assert(e.myProperty === "XY")
}
assert (realm.SyntaxError != SyntaxError)
assert (realm.SyntaxError.prototype != SyntaxError.prototype)
realm.SyntaxError.prototype.myProperty = "AB"
assert(SyntaxError.prototype.myProperty === undefined)
try {
ev("5 +")
assert(false)
} catch (e) {
assert(e instanceof realm.SyntaxError)
assert(!(e instanceof SyntaxError))
assert(e.myProperty === "AB")
}
// Test3: only the realm corresponding to the function matters
realm.Boolean.prototype.valueOf.a = Function.prototype.apply
Boolean.prototype.valueOf.a = realm.Function.prototype.apply
try {
realm.Boolean.prototype.valueOf.a()
} catch (e) {
assert(e instanceof realm.TypeError)
assert(!(e instanceof TypeError))
}
try {
Boolean.prototype.valueOf.a()
} catch (e) {
assert(e instanceof TypeError)
assert(!(e instanceof realm.TypeError))
}
+48
View File
@@ -0,0 +1,48 @@
// Copyright JS Foundation and other contributors, http://js.foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Test1: realm cannot be gc-ed until it is referenced
function f1() {
var ev = createRealm().eval
gc()
try {
ev("5 +")
} catch (e) {
assert(e instanceof ev("this").SyntaxError)
assert(!(e instanceof SyntaxError))
}
}
f1()
// Test2: built-ins cannot be gc-ed until the realm exists
function f2() {
var realm = createRealm()
var str = new realm.String("A");
// Assign a property to String.prototype
Object.getPrototypeOf(str).myProperty = "XY"
str = null
// No reference to String.prototype
gc()
str = new realm.String("A")
assert(Object.getPrototypeOf(str).myProperty === "XY")
assert(realm.String.prototype.myProperty === "XY")
}
f2()
+198
View File
@@ -0,0 +1,198 @@
// Copyright JS Foundation and other contributors, http://js.foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Test1: reading global values from other realms
var a = 4.5
function f1()
{
var realm = createRealm()
var f = realm.eval("function g() { return a } g")
realm.a = -6.25
assert(f() === -6.25)
assert(a === 4.5)
assert(realm.g === f)
realm.eval("var v1 = 6; eval('var v2 = 7.5')")
assert(realm.v1 === 6)
assert(realm.v2 === 7.5)
var e = realm.eval
eval("e('var v3 = -5.25'); var v3 = 1.5; e('v3++')")
assert(realm.v3 === -4.25)
assert(v3 === 1.5)
}
f1()
// Test2: recursive calls
var b = "S"
function f2()
{
function f(fun) {
return fun() + b;
}
var realm = createRealm()
realm.eval("function h() { return b }")
var g = realm.Function("fun", "return fun(h) + b")
realm.b = "X"
assert(g(f) === "XSX")
assert(b === "S")
}
f2()
// Test3: built-in functions
function f3()
{
var realm = createRealm()
realm.f = function () { return eval("/a/") }
var res = realm.eval("[f(), /a/, f(), /b/]")
assert(Object.getPrototypeOf(res[0]) === RegExp.prototype)
assert(Object.getPrototypeOf(res[1]) === realm.RegExp.prototype)
assert(Object.getPrototypeOf(res[2]) === RegExp.prototype)
assert(Object.getPrototypeOf(res[3]) === realm.RegExp.prototype)
realm.g = function () { return non_existent }
try {
realm.eval("g()")
assert(false)
} catch (e) {
assert(e instanceof ReferenceError)
assert(!(e instanceof realm.ReferenceError))
}
try {
realm.eval("non_existent")
assert(false)
} catch (e) {
assert(e instanceof realm.ReferenceError)
assert(!(e instanceof ReferenceError))
}
}
f3()
// Test4: generator functions
function f4()
{
function f() {
return b;
}
var realm = createRealm()
function check_gen_result(result, value, done)
{
assert(Object.getPrototypeOf(result) === realm.Object.prototype)
assert(result.value === value)
assert(result.done === done)
}
realm.eval("var a = 'P', b = 'Q'")
var gen = realm.eval("function* gen(f) { yield f() + a; yield f() + b; return a + b + f() }")
var it = realm.gen(f)
check_gen_result(it.next(), "SP", false)
check_gen_result(it.next(), "SQ", false)
check_gen_result(it.next(), "PQS", true)
}
f4()
// Test5: async functions
var successCount = 0
function f5()
{
function f() {
return b;
}
var r, p = new Promise(function(resolve, reject) { r = resolve })
var realm = createRealm()
realm.assert = assert
realm.eval("async function asy(p, f) { assert(f() === 'S'); assert(await p === 4.5); return f() + b }")
realm.b = "X"
realm.asy(p, f).then(function(v) {
assert(v === "SX")
successCount++
}, function() {
assert(false)
})
r(4.5)
}
f5()
// Test6: async generator functions
function f6()
{
function f() {
return b;
}
var r, p = new Promise(function(resolve, reject) { r = resolve })
var realm = createRealm()
function check_fulfilled(p, value, done)
{
assert(p instanceof realm.Promise)
p.then(function(v) {
assert(v.value === value)
assert(v.done === done)
successCount++
}, function() {
assert(false)
})
}
realm.assert = assert
realm.eval("async function *asygen(p, f) { assert(f() === 'S'); assert(await p === -1.5); yield f() + a; return f() + b }")
realm.a = "X"
realm.b = "Y"
var gen = realm.asygen(p, f)
check_fulfilled(gen.next(), "SX", false)
check_fulfilled(gen.next(), "SY", true)
r(-1.5)
}
f6()
function __checkAsync() {
assert(successCount === 3)
}
+1 -1
View File
@@ -51,4 +51,4 @@ try {
/* Check properties of a */
assert(Object.keys(a) == "one,two");
/* Check properties of global object */
assert(Object.keys(this) == "assert,gc,print,resourceName,a,fail,fail_two");
assert(Object.keys(this) == "assert,gc,print,resourceName,createRealm,a,fail,fail_two");