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:
@@ -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 |
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user