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 1548 : BUILTIN(WeakFactoryConstructor) {
13 : HandleScope scope(isolate);
14 387 : Handle<JSFunction> target = args.target();
15 1161 : 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 378 : Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
22 : Handle<Object> cleanup = args.atOrUndefined(isolate, 1);
23 :
24 756 : if (!cleanup->IsCallable()) {
25 72 : THROW_NEW_ERROR_RETURN_FAILURE(
26 : isolate, NewTypeError(MessageTemplate::kWeakRefsCleanupMustBeCallable));
27 : }
28 :
29 : Handle<JSObject> result;
30 684 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
31 : isolate, result,
32 : JSObject::New(target, new_target, Handle<AllocationSite>::null()));
33 :
34 342 : Handle<JSWeakFactory> weak_factory = Handle<JSWeakFactory>::cast(result);
35 684 : weak_factory->set_native_context(*isolate->native_context());
36 342 : weak_factory->set_cleanup(*cleanup);
37 : weak_factory->set_flags(
38 : JSWeakFactory::ScheduledForCleanupField::encode(false));
39 342 : return *weak_factory;
40 : }
41 :
42 1800 : BUILTIN(WeakFactoryMakeCell) {
43 : HandleScope scope(isolate);
44 : const char* method_name = "WeakFactory.prototype.makeCell";
45 :
46 927 : CHECK_RECEIVER(JSWeakFactory, weak_factory, method_name);
47 :
48 : Handle<Object> target = args.atOrUndefined(isolate, 1);
49 882 : if (!target->IsJSReceiver()) {
50 126 : THROW_NEW_ERROR_RETURN_FAILURE(
51 : isolate,
52 : NewTypeError(MessageTemplate::kWeakRefsMakeCellTargetMustBeObject));
53 : }
54 378 : Handle<JSReceiver> target_receiver = Handle<JSReceiver>::cast(target);
55 : Handle<Object> holdings = args.atOrUndefined(isolate, 2);
56 378 : if (target->SameValue(*holdings)) {
57 18 : THROW_NEW_ERROR_RETURN_FAILURE(
58 : isolate,
59 : NewTypeError(
60 : MessageTemplate::kWeakRefsMakeCellTargetAndHoldingsMustNotBeSame));
61 : }
62 :
63 : // TODO(marja): Realms.
64 :
65 1107 : Handle<Map> weak_cell_map(isolate->native_context()->js_weak_cell_map(),
66 369 : isolate);
67 :
68 : // Allocate the JSWeakCell object in the old space, because 1) JSWeakCell
69 : // weakness handling is only implemented in the old space 2) they're
70 : // supposedly long-living. TODO(marja): Support JSWeakCells in Scavenger.
71 : Handle<JSWeakCell> weak_cell =
72 : Handle<JSWeakCell>::cast(isolate->factory()->NewJSObjectFromMap(
73 369 : weak_cell_map, TENURED, Handle<AllocationSite>::null()));
74 738 : weak_cell->set_target(*target_receiver);
75 369 : weak_cell->set_holdings(*holdings);
76 369 : weak_factory->AddWeakCell(*weak_cell);
77 369 : return *weak_cell;
78 : }
79 :
80 216 : BUILTIN(WeakFactoryCleanupSome) {
81 : HandleScope scope(isolate);
82 : const char* method_name = "WeakFactory.prototype.cleanupSome";
83 :
84 135 : CHECK_RECEIVER(JSWeakFactory, weak_factory, method_name);
85 :
86 : // Don't do set_scheduled_for_cleanup(false); we still have the microtask
87 : // scheduled and don't want to schedule another one in case the user never
88 : // executes microtasks.
89 45 : JSWeakFactory::Cleanup(weak_factory, isolate);
90 45 : return ReadOnlyRoots(isolate).undefined_value();
91 : }
92 :
93 1332 : BUILTIN(WeakFactoryCleanupIteratorNext) {
94 : HandleScope scope(isolate);
95 666 : CHECK_RECEIVER(JSWeakFactoryCleanupIterator, iterator, "next");
96 :
97 666 : Handle<JSWeakFactory> weak_factory(iterator->factory(), isolate);
98 333 : if (!weak_factory->NeedsCleanup()) {
99 : return *isolate->factory()->NewJSIteratorResult(
100 288 : handle(ReadOnlyRoots(isolate).undefined_value(), isolate), true);
101 : }
102 : Handle<JSWeakCell> weak_cell_object =
103 378 : handle(weak_factory->PopClearedCell(isolate), isolate);
104 :
105 378 : return *isolate->factory()->NewJSIteratorResult(weak_cell_object, false);
106 : }
107 :
108 612 : BUILTIN(WeakCellHoldingsGetter) {
109 : HandleScope scope(isolate);
110 333 : CHECK_RECEIVER(JSWeakCell, weak_cell, "get WeakCell.holdings");
111 144 : return weak_cell->holdings();
112 : }
113 :
114 468 : BUILTIN(WeakCellClear) {
115 : HandleScope scope(isolate);
116 261 : CHECK_RECEIVER(JSWeakCell, weak_cell, "WeakCell.prototype.clear");
117 108 : weak_cell->Clear(isolate);
118 108 : return ReadOnlyRoots(isolate).undefined_value();
119 : }
120 :
121 612 : BUILTIN(WeakRefConstructor) {
122 : HandleScope scope(isolate);
123 153 : Handle<JSFunction> target = args.target();
124 459 : if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
125 27 : THROW_NEW_ERROR_RETURN_FAILURE(
126 : isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
127 : handle(target->shared()->Name(), isolate)));
128 : }
129 : // [[Construct]]
130 144 : Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
131 : Handle<Object> target_object = args.atOrUndefined(isolate, 1);
132 288 : if (!target_object->IsJSReceiver()) {
133 126 : THROW_NEW_ERROR_RETURN_FAILURE(
134 : isolate,
135 : NewTypeError(
136 : MessageTemplate::kWeakRefsWeakRefConstructorTargetMustBeObject));
137 : }
138 : isolate->heap()->AddKeepDuringJobTarget(
139 81 : Handle<JSReceiver>::cast(target_object));
140 :
141 : // TODO(marja): Realms.
142 :
143 : Handle<JSObject> result;
144 162 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
145 : isolate, result,
146 : JSObject::New(target, new_target, Handle<AllocationSite>::null()));
147 :
148 81 : Handle<JSWeakRef> weak_ref = Handle<JSWeakRef>::cast(result);
149 81 : weak_ref->set_target(*target_object);
150 81 : return *weak_ref;
151 : }
152 :
153 684 : BUILTIN(WeakRefDeref) {
154 : HandleScope scope(isolate);
155 396 : CHECK_RECEIVER(JSWeakRef, weak_ref, "WeakRef.prototype.deref");
156 306 : if (weak_ref->target()->IsJSReceiver()) {
157 : Handle<JSReceiver> target =
158 198 : handle(JSReceiver::cast(weak_ref->target()), isolate);
159 : // AddKeepDuringJobTarget might allocate and cause a GC, but it won't clear
160 : // weak_ref since we hold a Handle to its target.
161 99 : isolate->heap()->AddKeepDuringJobTarget(target);
162 : } else {
163 : DCHECK(weak_ref->target()->IsUndefined(isolate));
164 : }
165 153 : return weak_ref->target();
166 : }
167 :
168 : } // namespace internal
169 183867 : } // namespace v8
|