Commit bd67bb53 authored by Gus Caplan's avatar Gus Caplan Committed by Commit Bot

[torque] port FinalizationGroup methods to torque

Bug: v8:9891
Change-Id: Ief289a9990ac545aa479f564094e3bbde4144aae
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2293709
Commit-Queue: Gus Caplan <snek@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarShu-yu Guo <syg@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69145}
parent ce9cfb6e
......@@ -331,6 +331,9 @@ extern enum MessageTemplate {
kWasmTrapNullDereference,
kWasmTrapIllegalCast,
kWasmTrapArrayOutOfBounds,
kWeakRefsRegisterTargetAndHoldingsMustNotBeSame,
kWeakRefsRegisterTargetMustBeObject,
kWeakRefsUnregisterTokenMustBeObject,
kWeakRefsWeakRefConstructorTargetMustBeObject,
...
}
......@@ -1166,6 +1169,9 @@ macro GetFastAliasedArgumentsMap(implicit context: Context)(): Map {
LoadNativeContext(context)
.elements[NativeContextSlot::FAST_ALIASED_ARGUMENTS_MAP_INDEX]);
}
macro GetWeakCellMap(implicit context: Context)(): Map {
return %GetClassMapConstant<WeakCell>();
}
// Call(Context, Target, Receiver, ...Args)
// TODO(joshualitt): Assuming the context parameter is for throwing when Target
......
......@@ -919,7 +919,6 @@ namespace internal {
CPP(Trace) \
\
/* Weak refs */ \
CPP(FinalizationRegistryRegister) \
CPP(FinalizationRegistryUnregister) \
\
/* Async modules */ \
......
......@@ -9,54 +9,6 @@
namespace v8 {
namespace internal {
BUILTIN(FinalizationRegistryRegister) {
HandleScope scope(isolate);
const char* method_name = "FinalizationRegistry.prototype.register";
// 1. Let finalizationGroup be the this value.
//
// 2. If Type(finalizationGroup) is not Object, throw a TypeError
// exception.
//
// 4. If finalizationGroup does not have a [[Cells]] internal slot,
// throw a TypeError exception.
CHECK_RECEIVER(JSFinalizationRegistry, finalization_registry, method_name);
Handle<Object> target = args.atOrUndefined(isolate, 1);
// 3. If Type(target) is not Object, throw a TypeError exception.
if (!target->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewTypeError(MessageTemplate::kWeakRefsRegisterTargetMustBeObject));
}
Handle<Object> holdings = args.atOrUndefined(isolate, 2);
if (target->SameValue(*holdings)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewTypeError(
MessageTemplate::kWeakRefsRegisterTargetAndHoldingsMustNotBeSame));
}
Handle<Object> unregister_token = args.atOrUndefined(isolate, 3);
// 5. If Type(unregisterToken) is not Object,
// a. If unregisterToken is not undefined, throw a TypeError exception.
if (!unregister_token->IsJSReceiver() && !unregister_token->IsUndefined()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewTypeError(MessageTemplate::kWeakRefsUnregisterTokenMustBeObject,
unregister_token));
}
// TODO(marja): Realms.
JSFinalizationRegistry::Register(finalization_registry,
Handle<JSReceiver>::cast(target), holdings,
unregister_token, isolate);
return ReadOnlyRoots(isolate).undefined_value();
}
BUILTIN(FinalizationRegistryUnregister) {
HandleScope scope(isolate);
const char* method_name = "FinalizationRegistry.prototype.unregister";
......
......@@ -6,6 +6,8 @@ namespace runtime {
extern runtime
ShrinkFinalizationRegistryUnregisterTokenMap(
Context, JSFinalizationRegistry): void;
extern runtime JSFinalizationRegistryRegisterWeakCellWithUnregisterToken(
implicit context: Context)(JSFinalizationRegistry, WeakCell): void;
}
namespace weakref {
......@@ -52,6 +54,19 @@ PopClearedCell(finalizationRegistry: JSFinalizationRegistry): WeakCell|
}
}
transitioning macro PushCell(
finalizationRegistry: JSFinalizationRegistry, cell: WeakCell) {
cell.next = finalizationRegistry.active_cells;
typeswitch (finalizationRegistry.active_cells) {
case (Undefined): {
}
case (oldHead: WeakCell): {
oldHead.prev = cell;
}
}
finalizationRegistry.active_cells = cell;
}
transitioning macro
FinalizationRegistryCleanupLoop(implicit context: Context)(
finalizationRegistry: JSFinalizationRegistry, callback: Callable) {
......@@ -110,6 +125,70 @@ FinalizationRegistryConstructor(
return finalizationRegistry;
}
transitioning javascript builtin
FinalizationRegistryRegister(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
// 1. Let finalizationRegistry be the this value.
// 2. Perform ? RequireInternalSlot(finalizationRegistry, [[Cells]]).
const finalizationRegistry = Cast<JSFinalizationRegistry>(receiver) otherwise
ThrowTypeError(
MessageTemplate::kIncompatibleMethodReceiver,
'FinalizationRegistry.prototype.register', receiver);
// 3. If Type(target) is not Object, throw a TypeError exception.
const target = Cast<JSReceiver>(arguments[0]) otherwise ThrowTypeError(
MessageTemplate::kWeakRefsRegisterTargetMustBeObject);
const heldValue = arguments[1];
// 4. If SameValue(target, heldValue), throw a TypeError exception.
if (target == heldValue) {
ThrowTypeError(
MessageTemplate::kWeakRefsRegisterTargetAndHoldingsMustNotBeSame);
}
const unregisterToken = arguments[2];
// 5. If Type(unregisterToken) is not Object,
// a. If unregisterToken is not undefined, throw a TypeError exception.
// b. Set unregisterToken to empty.
let hasUnregisterToken: bool = false;
typeswitch (unregisterToken) {
case (Undefined): {
}
case (JSReceiver): {
hasUnregisterToken = true;
}
case (JSAny): deferred {
ThrowTypeError(
MessageTemplate::kWeakRefsUnregisterTokenMustBeObject,
unregisterToken);
}
}
// 6. Let cell be the Record { [[WeakRefTarget]] : target, [[HeldValue]]:
// heldValue, [[UnregisterToken]]: unregisterToken }.
// Allocate the WeakCell object in the old space, because 1) WeakCell weakness
// handling is only implemented in the old space 2) they're supposedly
// long-living. TODO(marja, gsathya): Support WeakCells in Scavenger.
const cell = new (Pretenured) WeakCell{
map: GetWeakCellMap(),
finalization_registry: finalizationRegistry,
target: target,
unregister_token: unregisterToken,
holdings: heldValue,
prev: Undefined,
next: Undefined,
key_list_prev: Undefined,
key_list_next: Undefined
};
// 7. Append cell to finalizationRegistry.[[Cells]].
PushCell(finalizationRegistry, cell);
if (hasUnregisterToken) {
// If an unregister token is provided, a runtime call is needed to
// do some OrderedHashTable operations and register the mapping.
// See v8:10705.
runtime::JSFinalizationRegistryRegisterWeakCellWithUnregisterToken(
finalizationRegistry, cell);
}
// 8. Return undefined.
return Undefined;
}
transitioning javascript builtin
FinalizationRegistryPrototypeCleanupSome(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
......
......@@ -2009,17 +2009,6 @@ Handle<JSObject> Factory::NewFunctionPrototype(Handle<JSFunction> function) {
return prototype;
}
Handle<WeakCell> Factory::NewWeakCell() {
// Allocate the WeakCell object in the old space, because 1) WeakCell weakness
// handling is only implemented in the old space 2) they're supposedly
// long-living. TODO(marja, gsathya): Support WeakCells in Scavenger.
Handle<WeakCell> result(
WeakCell::cast(AllocateRawWithImmortalMap(
WeakCell::kSize, AllocationType::kOld, *weak_cell_map())),
isolate());
return result;
}
Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
Handle<SharedFunctionInfo> info, Handle<Context> context,
AllocationType allocation) {
......
......@@ -419,8 +419,6 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function);
Handle<WeakCell> NewWeakCell();
// Returns a deep copy of the JavaScript object.
// Properties and elements are copied too.
Handle<JSObject> CopyJSObject(Handle<JSObject> object);
......
......@@ -170,7 +170,6 @@ enum ContextLookupFlags {
V(JS_MODULE_NAMESPACE_MAP, Map, js_module_namespace_map) \
V(JS_SET_FUN_INDEX, JSFunction, js_set_fun) \
V(JS_SET_MAP_INDEX, Map, js_set_map) \
V(WEAK_CELL_MAP_INDEX, Map, weak_cell_map) \
V(JS_WEAK_MAP_FUN_INDEX, JSFunction, js_weak_map_fun) \
V(JS_WEAK_SET_FUN_INDEX, JSFunction, js_weak_set_fun) \
V(JS_WEAK_REF_FUNCTION_INDEX, JSFunction, js_weak_ref_fun) \
......
......@@ -256,6 +256,7 @@ TYPED_ARRAYS(TYPED_ARRAY_IS_TYPE_FUNCTION_DECL)
V(_, CachedTemplateObjectMap, cached_template_object_map, \
CachedTemplateObject) \
V(_, CellMap, cell_map, Cell) \
V(_, WeakCellMap, weak_cell_map, WeakCell) \
V(_, CodeMap, code_map, Code) \
V(_, CoverageInfoMap, coverage_info_map, CoverageInfo) \
V(_, DebugInfoMap, debug_info_map, DebugInfo) \
......
......@@ -35,51 +35,31 @@ CAST_ACCESSOR(JSFinalizationRegistry)
BIT_FIELD_ACCESSORS(JSFinalizationRegistry, flags, scheduled_for_cleanup,
JSFinalizationRegistry::ScheduledForCleanupBit)
void JSFinalizationRegistry::Register(
void JSFinalizationRegistry::RegisterWeakCellWithUnregisterToken(
Handle<JSFinalizationRegistry> finalization_registry,
Handle<JSReceiver> target, Handle<Object> holdings,
Handle<Object> unregister_token, Isolate* isolate) {
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell();
weak_cell->set_finalization_registry(*finalization_registry);
weak_cell->set_target(*target);
weak_cell->set_holdings(*holdings);
weak_cell->set_prev(ReadOnlyRoots(isolate).undefined_value());
weak_cell->set_next(ReadOnlyRoots(isolate).undefined_value());
weak_cell->set_unregister_token(*unregister_token);
weak_cell->set_key_list_prev(ReadOnlyRoots(isolate).undefined_value());
weak_cell->set_key_list_next(ReadOnlyRoots(isolate).undefined_value());
// Add to active_cells.
weak_cell->set_next(finalization_registry->active_cells());
if (finalization_registry->active_cells().IsWeakCell()) {
WeakCell::cast(finalization_registry->active_cells()).set_prev(*weak_cell);
Handle<WeakCell> weak_cell, Isolate* isolate) {
Handle<SimpleNumberDictionary> key_map;
if (finalization_registry->key_map().IsUndefined(isolate)) {
key_map = SimpleNumberDictionary::New(isolate, 1);
} else {
key_map =
handle(SimpleNumberDictionary::cast(finalization_registry->key_map()),
isolate);
}
finalization_registry->set_active_cells(*weak_cell);
if (!unregister_token->IsUndefined(isolate)) {
Handle<SimpleNumberDictionary> key_map;
if (finalization_registry->key_map().IsUndefined(isolate)) {
key_map = SimpleNumberDictionary::New(isolate, 1);
} else {
key_map =
handle(SimpleNumberDictionary::cast(finalization_registry->key_map()),
isolate);
}
// Unregister tokens are held weakly as objects are often their own
// unregister token. To avoid using an ephemeron map, the map for token
// lookup is keyed on the token's identity hash instead of the token itself.
uint32_t key = unregister_token->GetOrCreateHash(isolate).value();
InternalIndex entry = key_map->FindEntry(isolate, key);
if (entry.is_found()) {
Object value = key_map->ValueAt(entry);
WeakCell existing_weak_cell = WeakCell::cast(value);
existing_weak_cell.set_key_list_prev(*weak_cell);
weak_cell->set_key_list_next(existing_weak_cell);
}
key_map = SimpleNumberDictionary::Set(isolate, key_map, key, weak_cell);
finalization_registry->set_key_map(*key_map);
// Unregister tokens are held weakly as objects are often their own
// unregister token. To avoid using an ephemeron map, the map for token
// lookup is keyed on the token's identity hash instead of the token itself.
uint32_t key = weak_cell->unregister_token().GetOrCreateHash(isolate).value();
InternalIndex entry = key_map->FindEntry(isolate, key);
if (entry.is_found()) {
Object value = key_map->ValueAt(entry);
WeakCell existing_weak_cell = WeakCell::cast(value);
existing_weak_cell.set_key_list_prev(*weak_cell);
weak_cell->set_key_list_next(existing_weak_cell);
}
key_map = SimpleNumberDictionary::Set(isolate, key_map, key, weak_cell);
finalization_registry->set_key_map(*key_map);
}
bool JSFinalizationRegistry::Unregister(
......
......@@ -40,10 +40,9 @@ class JSFinalizationRegistry : public JSObject {
class BodyDescriptor;
inline static void Register(
inline static void RegisterWeakCellWithUnregisterToken(
Handle<JSFinalizationRegistry> finalization_registry,
Handle<JSReceiver> target, Handle<Object> holdings, Handle<Object> key,
Isolate* isolate);
Handle<WeakCell> weak_cell, Isolate* isolate);
inline static bool Unregister(
Handle<JSFinalizationRegistry> finalization_registry,
Handle<JSReceiver> unregister_token, Isolate* isolate);
......
......@@ -26,6 +26,19 @@ RUNTIME_FUNCTION(Runtime_ShrinkFinalizationRegistryUnregisterTokenMap) {
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(
Runtime_JSFinalizationRegistryRegisterWeakCellWithUnregisterToken) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFinalizationRegistry, finalization_registry, 0);
CONVERT_ARG_HANDLE_CHECKED(WeakCell, weak_cell, 1);
JSFinalizationRegistry::RegisterWeakCellWithUnregisterToken(
finalization_registry, weak_cell, isolate);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_JSWeakRefAddToKeptObjects) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......
......@@ -582,8 +582,9 @@ namespace internal {
F(WasmDebugBreak, 0, 1) \
F(WasmAllocateRtt, 2, 1)
#define FOR_EACH_INTRINSIC_WEAKREF(F, I) \
F(JSWeakRefAddToKeptObjects, 1, 1) \
#define FOR_EACH_INTRINSIC_WEAKREF(F, I) \
F(JSFinalizationRegistryRegisterWeakCellWithUnregisterToken, 4, 1) \
F(JSWeakRefAddToKeptObjects, 1, 1) \
F(ShrinkFinalizationRegistryUnregisterTokenMap, 1, 1)
#define FOR_EACH_INTRINSIC_RETURN_PAIR_IMPL(F, I) \
......
......@@ -68,10 +68,17 @@ Handle<JSObject> CreateKey(const char* key_prop_value, Isolate* isolate) {
Handle<WeakCell> FinalizationRegistryRegister(
Handle<JSFinalizationRegistry> finalization_registry,
Handle<JSObject> target, Handle<Object> holdings, Handle<Object> key,
Isolate* isolate) {
JSFinalizationRegistry::Register(finalization_registry, target, holdings, key,
isolate);
Handle<JSObject> target, Handle<Object> held_value,
Handle<Object> unregister_token, Isolate* isolate) {
Factory* factory = isolate->factory();
Handle<JSFunction> regfunc = Handle<JSFunction>::cast(
Object::GetProperty(isolate, finalization_registry,
factory->NewStringFromStaticChars("register"))
.ToHandleChecked());
Handle<Object> args[] = {target, held_value, unregister_token};
Execution::Call(isolate, regfunc, finalization_registry, arraysize(args),
args)
.ToHandleChecked();
CHECK(finalization_registry->active_cells().IsWeakCell());
Handle<WeakCell> weak_cell =
handle(WeakCell::cast(finalization_registry->active_cells()), isolate);
......
......@@ -445,27 +445,27 @@ KNOWN_OBJECTS = {
("old_space", 0x02a69): "StringSplitCache",
("old_space", 0x02e71): "RegExpMultipleCache",
("old_space", 0x03279): "BuiltinsConstantsTable",
("old_space", 0x03621): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x03649): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x03671): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x03699): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x036c1): "AsyncGeneratorYieldResolveSharedFun",
("old_space", 0x036e9): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x03711): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x03739): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x03761): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x03789): "PromiseAllResolveElementSharedFun",
("old_space", 0x037b1): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x037d9): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x03801): "PromiseAnyRejectElementSharedFun",
("old_space", 0x03829): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x03851): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x03879): "PromiseCatchFinallySharedFun",
("old_space", 0x038a1): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x038c9): "PromiseThenFinallySharedFun",
("old_space", 0x038f1): "PromiseThrowerFinallySharedFun",
("old_space", 0x03919): "PromiseValueThunkFinallySharedFun",
("old_space", 0x03941): "ProxyRevokeSharedFun",
("old_space", 0x03625): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x0364d): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x03675): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x0369d): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x036c5): "AsyncGeneratorYieldResolveSharedFun",
("old_space", 0x036ed): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x03715): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x0373d): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x03765): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x0378d): "PromiseAllResolveElementSharedFun",
("old_space", 0x037b5): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x037dd): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x03805): "PromiseAnyRejectElementSharedFun",
("old_space", 0x0382d): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x03855): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x0387d): "PromiseCatchFinallySharedFun",
("old_space", 0x038a5): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x038cd): "PromiseThenFinallySharedFun",
("old_space", 0x038f5): "PromiseThrowerFinallySharedFun",
("old_space", 0x0391d): "PromiseValueThunkFinallySharedFun",
("old_space", 0x03945): "ProxyRevokeSharedFun",
}
# Lower 32 bits of first page addresses for various heap spaces.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment