Line data Source code
1 : // Copyright 2018 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/builtins/builtins-utils-inl.h"
6 : #include "src/counters.h"
7 : #include "src/objects/js-weak-refs-inl.h"
8 :
9 : namespace v8 {
10 : namespace internal {
11 :
12 1770 : BUILTIN(FinalizationGroupConstructor) {
13 : HandleScope scope(isolate);
14 : Handle<JSFunction> target = args.target();
15 354 : if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
16 27 : THROW_NEW_ERROR_RETURN_FAILURE(
17 : isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
18 : handle(target->shared()->Name(), isolate)));
19 : }
20 : // [[Construct]]
21 345 : Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
22 : Handle<Object> cleanup = args.atOrUndefined(isolate, 1);
23 :
24 345 : if (!cleanup->IsCallable()) {
25 92 : THROW_NEW_ERROR_RETURN_FAILURE(
26 : isolate, NewTypeError(MessageTemplate::kWeakRefsCleanupMustBeCallable));
27 : }
28 :
29 : Handle<JSObject> result;
30 598 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
31 : isolate, result,
32 : JSObject::New(target, new_target, Handle<AllocationSite>::null()));
33 :
34 : Handle<JSFinalizationGroup> finalization_group =
35 : Handle<JSFinalizationGroup>::cast(result);
36 598 : finalization_group->set_native_context(*isolate->native_context());
37 299 : finalization_group->set_cleanup(*cleanup);
38 : finalization_group->set_flags(
39 : JSFinalizationGroup::ScheduledForCleanupField::encode(false));
40 :
41 : DCHECK(finalization_group->active_cells()->IsUndefined(isolate));
42 : DCHECK(finalization_group->cleared_cells()->IsUndefined(isolate));
43 : DCHECK(finalization_group->key_map()->IsUndefined(isolate));
44 299 : return *finalization_group;
45 : }
46 :
47 2035 : BUILTIN(FinalizationGroupRegister) {
48 : HandleScope scope(isolate);
49 : const char* method_name = "FinalizationGroup.prototype.register";
50 :
51 434 : CHECK_RECEIVER(JSFinalizationGroup, finalization_group, method_name);
52 :
53 : Handle<Object> target = args.atOrUndefined(isolate, 1);
54 398 : if (!target->IsJSReceiver()) {
55 118 : THROW_NEW_ERROR_RETURN_FAILURE(
56 : isolate,
57 : NewTypeError(MessageTemplate::kWeakRefsRegisterTargetMustBeObject));
58 : }
59 : Handle<Object> holdings = args.atOrUndefined(isolate, 2);
60 339 : if (target->SameValue(*holdings)) {
61 28 : THROW_NEW_ERROR_RETURN_FAILURE(
62 : isolate,
63 : NewTypeError(
64 : MessageTemplate::kWeakRefsRegisterTargetAndHoldingsMustNotBeSame));
65 : }
66 :
67 325 : Handle<Object> key = args.atOrUndefined(isolate, 3);
68 : // TODO(marja, gsathya): Restrictions on "key" (e.g., does it need to be an
69 : // object).
70 :
71 : // TODO(marja): Realms.
72 :
73 : JSFinalizationGroup::Register(finalization_group,
74 : Handle<JSReceiver>::cast(target), holdings, key,
75 325 : isolate);
76 325 : return ReadOnlyRoots(isolate).undefined_value();
77 : }
78 :
79 540 : BUILTIN(FinalizationGroupUnregister) {
80 : HandleScope scope(isolate);
81 : const char* method_name = "FinalizationGroup.prototype.unregister";
82 :
83 108 : CHECK_RECEIVER(JSFinalizationGroup, finalization_group, method_name);
84 :
85 108 : Handle<Object> key = args.atOrUndefined(isolate, 1);
86 108 : JSFinalizationGroup::Unregister(finalization_group, key, isolate);
87 108 : return ReadOnlyRoots(isolate).undefined_value();
88 : }
89 :
90 270 : BUILTIN(FinalizationGroupCleanupSome) {
91 : HandleScope scope(isolate);
92 : const char* method_name = "FinalizationGroup.prototype.cleanupSome";
93 :
94 81 : CHECK_RECEIVER(JSFinalizationGroup, finalization_group, method_name);
95 :
96 : // TODO(marja, gsathya): Add missing "cleanup" callback.
97 :
98 : // Don't do set_scheduled_for_cleanup(false); we still have the microtask
99 : // scheduled and don't want to schedule another one in case the user never
100 : // executes microtasks.
101 45 : JSFinalizationGroup::Cleanup(finalization_group, isolate);
102 45 : return ReadOnlyRoots(isolate).undefined_value();
103 : }
104 :
105 1845 : BUILTIN(FinalizationGroupCleanupIteratorNext) {
106 : HandleScope scope(isolate);
107 369 : CHECK_RECEIVER(JSFinalizationGroupCleanupIterator, iterator, "next");
108 :
109 : Handle<JSFinalizationGroup> finalization_group(iterator->finalization_group(),
110 : isolate);
111 369 : if (!finalization_group->NeedsCleanup()) {
112 324 : return *isolate->factory()->NewJSIteratorResult(
113 324 : handle(ReadOnlyRoots(isolate).undefined_value(), isolate), true);
114 : }
115 : Handle<Object> holdings = handle(
116 : JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate),
117 414 : isolate);
118 :
119 414 : return *isolate->factory()->NewJSIteratorResult(holdings, false);
120 : }
121 :
122 720 : BUILTIN(WeakRefConstructor) {
123 : HandleScope scope(isolate);
124 : Handle<JSFunction> target = args.target();
125 144 : if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
126 27 : THROW_NEW_ERROR_RETURN_FAILURE(
127 : isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
128 : handle(target->shared()->Name(), isolate)));
129 : }
130 : // [[Construct]]
131 135 : Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
132 : Handle<Object> target_object = args.atOrUndefined(isolate, 1);
133 135 : if (!target_object->IsJSReceiver()) {
134 126 : THROW_NEW_ERROR_RETURN_FAILURE(
135 : isolate,
136 : NewTypeError(
137 : MessageTemplate::kWeakRefsWeakRefConstructorTargetMustBeObject));
138 : }
139 : Handle<JSReceiver> target_receiver =
140 : handle(JSReceiver::cast(*target_object), isolate);
141 72 : isolate->heap()->AddKeepDuringJobTarget(target_receiver);
142 :
143 : // TODO(marja): Realms.
144 :
145 : Handle<JSObject> result;
146 144 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
147 : isolate, result,
148 : JSObject::New(target, new_target, Handle<AllocationSite>::null()));
149 :
150 : Handle<JSWeakRef> weak_ref = Handle<JSWeakRef>::cast(result);
151 144 : weak_ref->set_target(*target_receiver);
152 72 : return *weak_ref;
153 : }
154 :
155 720 : BUILTIN(WeakRefDeref) {
156 : HandleScope scope(isolate);
157 144 : CHECK_RECEIVER(JSWeakRef, weak_ref, "WeakRef.prototype.deref");
158 144 : if (weak_ref->target()->IsJSReceiver()) {
159 : Handle<JSReceiver> target =
160 90 : handle(JSReceiver::cast(weak_ref->target()), isolate);
161 : // AddKeepDuringJobTarget might allocate and cause a GC, but it won't clear
162 : // weak_ref since we hold a Handle to its target.
163 90 : isolate->heap()->AddKeepDuringJobTarget(target);
164 : } else {
165 : DCHECK(weak_ref->target()->IsUndefined(isolate));
166 : }
167 144 : return weak_ref->target();
168 : }
169 :
170 : } // namespace internal
171 122036 : } // namespace v8
|