1 // Copyright 2015 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/api-natives.h"
6
7 #include "src/api-inl.h"
8 #include "src/isolate-inl.h"
9 #include "src/lookup.h"
10 #include "src/messages.h"
11 #include "src/objects/api-callbacks.h"
12 #include "src/objects/hash-table-inl.h"
13 #include "src/objects/templates.h"
14
15 namespace v8 {
16 namespace internal {
17
18
19 namespace {
20
21 class InvokeScope {
22 public:
InvokeScope(Isolate * isolate)23 explicit InvokeScope(Isolate* isolate)
24 : isolate_(isolate), save_context_(isolate) {}
~InvokeScope()25 ~InvokeScope() {
26 bool has_exception = isolate_->has_pending_exception();
27 if (has_exception) {
28 isolate_->ReportPendingMessages();
29 } else {
30 isolate_->clear_pending_message();
31 }
32 }
33
34 private:
35 Isolate* isolate_;
36 SaveContext save_context_;
37 };
38
39 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
40 Handle<ObjectTemplateInfo> data,
41 Handle<JSReceiver> new_target,
42 bool is_hidden_prototype,
43 bool is_prototype);
44
45 MaybeHandle<JSFunction> InstantiateFunction(
46 Isolate* isolate, Handle<FunctionTemplateInfo> data,
47 MaybeHandle<Name> maybe_name = MaybeHandle<Name>());
48
Instantiate(Isolate * isolate,Handle<Object> data,MaybeHandle<Name> maybe_name=MaybeHandle<Name> ())49 MaybeHandle<Object> Instantiate(
50 Isolate* isolate, Handle<Object> data,
51 MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
52 if (data->IsFunctionTemplateInfo()) {
53 return InstantiateFunction(
54 isolate, Handle<FunctionTemplateInfo>::cast(data), maybe_name);
55 } else if (data->IsObjectTemplateInfo()) {
56 return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
57 Handle<JSReceiver>(), false, false);
58 } else {
59 return data;
60 }
61 }
62
DefineAccessorProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes,bool force_instantiate)63 MaybeHandle<Object> DefineAccessorProperty(
64 Isolate* isolate, Handle<JSObject> object, Handle<Name> name,
65 Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes,
66 bool force_instantiate) {
67 DCHECK(!getter->IsFunctionTemplateInfo() ||
68 !FunctionTemplateInfo::cast(*getter)->do_not_cache());
69 DCHECK(!setter->IsFunctionTemplateInfo() ||
70 !FunctionTemplateInfo::cast(*setter)->do_not_cache());
71 if (force_instantiate) {
72 if (getter->IsFunctionTemplateInfo()) {
73 ASSIGN_RETURN_ON_EXCEPTION(
74 isolate, getter,
75 InstantiateFunction(isolate,
76 Handle<FunctionTemplateInfo>::cast(getter)),
77 Object);
78 }
79 if (setter->IsFunctionTemplateInfo()) {
80 ASSIGN_RETURN_ON_EXCEPTION(
81 isolate, setter,
82 InstantiateFunction(isolate,
83 Handle<FunctionTemplateInfo>::cast(setter)),
84 Object);
85 }
86 }
87 RETURN_ON_EXCEPTION(isolate, JSObject::DefineAccessor(object, name, getter,
88 setter, attributes),
89 Object);
90 return object;
91 }
92
93
DefineDataProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> prop_data,PropertyAttributes attributes)94 MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
95 Handle<JSObject> object,
96 Handle<Name> name,
97 Handle<Object> prop_data,
98 PropertyAttributes attributes) {
99 Handle<Object> value;
100 ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
101 Instantiate(isolate, prop_data, name), Object);
102
103 LookupIterator it = LookupIterator::PropertyOrElement(
104 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
105
106 #ifdef DEBUG
107 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
108 DCHECK(maybe.IsJust());
109 if (it.IsFound()) {
110 THROW_NEW_ERROR(
111 isolate,
112 NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
113 Object);
114 }
115 #endif
116
117 MAYBE_RETURN_NULL(
118 Object::AddDataProperty(&it, value, attributes, kThrowOnError,
119 Object::CERTAINLY_NOT_STORE_FROM_KEYED));
120 return value;
121 }
122
123
DisableAccessChecks(Isolate * isolate,Handle<JSObject> object)124 void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
125 Handle<Map> old_map(object->map(), isolate);
126 // Copy map so it won't interfere constructor's initial map.
127 Handle<Map> new_map = Map::Copy(isolate, old_map, "DisableAccessChecks");
128 new_map->set_is_access_check_needed(false);
129 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
130 }
131
132
EnableAccessChecks(Isolate * isolate,Handle<JSObject> object)133 void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
134 Handle<Map> old_map(object->map(), isolate);
135 // Copy map so it won't interfere constructor's initial map.
136 Handle<Map> new_map = Map::Copy(isolate, old_map, "EnableAccessChecks");
137 new_map->set_is_access_check_needed(true);
138 new_map->set_may_have_interesting_symbols(true);
139 JSObject::MigrateToMap(object, new_map);
140 }
141
142
143 class AccessCheckDisableScope {
144 public:
AccessCheckDisableScope(Isolate * isolate,Handle<JSObject> obj)145 AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
146 : isolate_(isolate),
147 disabled_(obj->map()->is_access_check_needed()),
148 obj_(obj) {
149 if (disabled_) {
150 DisableAccessChecks(isolate_, obj_);
151 }
152 }
~AccessCheckDisableScope()153 ~AccessCheckDisableScope() {
154 if (disabled_) {
155 EnableAccessChecks(isolate_, obj_);
156 }
157 }
158
159 private:
160 Isolate* isolate_;
161 const bool disabled_;
162 Handle<JSObject> obj_;
163 };
164
165
GetIntrinsic(Isolate * isolate,v8::Intrinsic intrinsic)166 Object* GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
167 Handle<Context> native_context = isolate->native_context();
168 DCHECK(!native_context.is_null());
169 switch (intrinsic) {
170 #define GET_INTRINSIC_VALUE(name, iname) \
171 case v8::k##name: \
172 return native_context->iname();
173 V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
174 #undef GET_INTRINSIC_VALUE
175 }
176 return nullptr;
177 }
178
179
180 template <typename TemplateInfoT>
ConfigureInstance(Isolate * isolate,Handle<JSObject> obj,Handle<TemplateInfoT> data,bool is_hidden_prototype)181 MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
182 Handle<TemplateInfoT> data,
183 bool is_hidden_prototype) {
184 HandleScope scope(isolate);
185 // Disable access checks while instantiating the object.
186 AccessCheckDisableScope access_check_scope(isolate, obj);
187
188 // Walk the inheritance chain and copy all accessors to current object.
189 int max_number_of_properties = 0;
190 TemplateInfoT* info = *data;
191 while (info != nullptr) {
192 Object* props = info->property_accessors();
193 if (!props->IsUndefined(isolate)) {
194 max_number_of_properties += TemplateList::cast(props)->length();
195 }
196 info = info->GetParent(isolate);
197 }
198
199 if (max_number_of_properties > 0) {
200 int valid_descriptors = 0;
201 // Use a temporary FixedArray to accumulate unique accessors.
202 Handle<FixedArray> array =
203 isolate->factory()->NewFixedArray(max_number_of_properties);
204
205 for (Handle<TemplateInfoT> temp(*data, isolate); *temp != nullptr;
206 temp = handle(temp->GetParent(isolate), isolate)) {
207 // Accumulate accessors.
208 Object* maybe_properties = temp->property_accessors();
209 if (!maybe_properties->IsUndefined(isolate)) {
210 valid_descriptors = AccessorInfo::AppendUnique(
211 isolate, handle(maybe_properties, isolate), array,
212 valid_descriptors);
213 }
214 }
215
216 // Install accumulated accessors.
217 for (int i = 0; i < valid_descriptors; i++) {
218 Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)), isolate);
219 Handle<Name> name(Name::cast(accessor->name()), isolate);
220 JSObject::SetAccessor(obj, name, accessor,
221 accessor->initial_property_attributes())
222 .Assert();
223 }
224 }
225
226 Object* maybe_property_list = data->property_list();
227 if (maybe_property_list->IsUndefined(isolate)) return obj;
228 Handle<TemplateList> properties(TemplateList::cast(maybe_property_list),
229 isolate);
230 if (properties->length() == 0) return obj;
231
232 int i = 0;
233 for (int c = 0; c < data->number_of_properties(); c++) {
234 auto name = handle(Name::cast(properties->get(i++)), isolate);
235 Object* bit = properties->get(i++);
236 if (bit->IsSmi()) {
237 PropertyDetails details(Smi::cast(bit));
238 PropertyAttributes attributes = details.attributes();
239 PropertyKind kind = details.kind();
240
241 if (kind == kData) {
242 auto prop_data = handle(properties->get(i++), isolate);
243 RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
244 prop_data, attributes),
245 JSObject);
246 } else {
247 auto getter = handle(properties->get(i++), isolate);
248 auto setter = handle(properties->get(i++), isolate);
249 RETURN_ON_EXCEPTION(
250 isolate, DefineAccessorProperty(isolate, obj, name, getter, setter,
251 attributes, is_hidden_prototype),
252 JSObject);
253 }
254 } else {
255 // Intrinsic data property --- Get appropriate value from the current
256 // context.
257 PropertyDetails details(Smi::cast(properties->get(i++)));
258 PropertyAttributes attributes = details.attributes();
259 DCHECK_EQ(kData, details.kind());
260
261 v8::Intrinsic intrinsic =
262 static_cast<v8::Intrinsic>(Smi::ToInt(properties->get(i++)));
263 auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
264
265 RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
266 prop_data, attributes),
267 JSObject);
268 }
269 }
270 return obj;
271 }
272
273 // Whether or not to cache every instance: when we materialize a getter or
274 // setter from an lazy AccessorPair, we rely on this cache to be able to always
275 // return the same getter or setter. However, objects will be cloned anyways,
276 // so it's not observable if we didn't cache an instance. Furthermore, a badly
277 // behaved embedder might create an unlimited number of objects, so we limit
278 // the cache for those cases.
279 enum class CachingMode { kLimited, kUnlimited };
280
ProbeInstantiationsCache(Isolate * isolate,int serial_number,CachingMode caching_mode)281 MaybeHandle<JSObject> ProbeInstantiationsCache(Isolate* isolate,
282 int serial_number,
283 CachingMode caching_mode) {
284 DCHECK_LE(1, serial_number);
285 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
286 Handle<FixedArray> fast_cache =
287 isolate->fast_template_instantiations_cache();
288 return fast_cache->GetValue<JSObject>(isolate, serial_number - 1);
289 } else if (caching_mode == CachingMode::kUnlimited ||
290 (serial_number <=
291 TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
292 Handle<SimpleNumberDictionary> slow_cache =
293 isolate->slow_template_instantiations_cache();
294 int entry = slow_cache->FindEntry(isolate, serial_number);
295 if (entry == SimpleNumberDictionary::kNotFound) {
296 return MaybeHandle<JSObject>();
297 }
298 return handle(JSObject::cast(slow_cache->ValueAt(entry)), isolate);
299 } else {
300 return MaybeHandle<JSObject>();
301 }
302 }
303
CacheTemplateInstantiation(Isolate * isolate,int serial_number,CachingMode caching_mode,Handle<JSObject> object)304 void CacheTemplateInstantiation(Isolate* isolate, int serial_number,
305 CachingMode caching_mode,
306 Handle<JSObject> object) {
307 DCHECK_LE(1, serial_number);
308 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
309 Handle<FixedArray> fast_cache =
310 isolate->fast_template_instantiations_cache();
311 Handle<FixedArray> new_cache =
312 FixedArray::SetAndGrow(isolate, fast_cache, serial_number - 1, object);
313 if (*new_cache != *fast_cache) {
314 isolate->native_context()->set_fast_template_instantiations_cache(
315 *new_cache);
316 }
317 } else if (caching_mode == CachingMode::kUnlimited ||
318 (serial_number <=
319 TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
320 Handle<SimpleNumberDictionary> cache =
321 isolate->slow_template_instantiations_cache();
322 auto new_cache =
323 SimpleNumberDictionary::Set(isolate, cache, serial_number, object);
324 if (*new_cache != *cache) {
325 isolate->native_context()->set_slow_template_instantiations_cache(
326 *new_cache);
327 }
328 }
329 }
330
UncacheTemplateInstantiation(Isolate * isolate,int serial_number,CachingMode caching_mode)331 void UncacheTemplateInstantiation(Isolate* isolate, int serial_number,
332 CachingMode caching_mode) {
333 DCHECK_LE(1, serial_number);
334 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
335 Handle<FixedArray> fast_cache =
336 isolate->fast_template_instantiations_cache();
337 DCHECK(!fast_cache->get(serial_number - 1)->IsUndefined(isolate));
338 fast_cache->set_undefined(serial_number - 1);
339 } else if (caching_mode == CachingMode::kUnlimited ||
340 (serial_number <=
341 TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
342 Handle<SimpleNumberDictionary> cache =
343 isolate->slow_template_instantiations_cache();
344 int entry = cache->FindEntry(isolate, serial_number);
345 DCHECK_NE(SimpleNumberDictionary::kNotFound, entry);
346 cache = SimpleNumberDictionary::DeleteEntry(isolate, cache, entry);
347 isolate->native_context()->set_slow_template_instantiations_cache(*cache);
348 }
349 }
350
IsSimpleInstantiation(Isolate * isolate,ObjectTemplateInfo * info,JSReceiver * new_target)351 bool IsSimpleInstantiation(Isolate* isolate, ObjectTemplateInfo* info,
352 JSReceiver* new_target) {
353 DisallowHeapAllocation no_gc;
354
355 if (!new_target->IsJSFunction()) return false;
356 JSFunction* fun = JSFunction::cast(new_target);
357 if (fun->shared()->function_data() != info->constructor()) return false;
358 if (info->immutable_proto()) return false;
359 return fun->context()->native_context() == isolate->raw_native_context();
360 }
361
InstantiateObject(Isolate * isolate,Handle<ObjectTemplateInfo> info,Handle<JSReceiver> new_target,bool is_hidden_prototype,bool is_prototype)362 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
363 Handle<ObjectTemplateInfo> info,
364 Handle<JSReceiver> new_target,
365 bool is_hidden_prototype,
366 bool is_prototype) {
367 Handle<JSFunction> constructor;
368 int serial_number = Smi::ToInt(info->serial_number());
369 if (!new_target.is_null()) {
370 if (IsSimpleInstantiation(isolate, *info, *new_target)) {
371 constructor = Handle<JSFunction>::cast(new_target);
372 } else {
373 // Disable caching for subclass instantiation.
374 serial_number = 0;
375 }
376 }
377 // Fast path.
378 Handle<JSObject> result;
379 if (serial_number) {
380 if (ProbeInstantiationsCache(isolate, serial_number, CachingMode::kLimited)
381 .ToHandle(&result)) {
382 return isolate->factory()->CopyJSObject(result);
383 }
384 }
385
386 if (constructor.is_null()) {
387 Object* maybe_constructor_info = info->constructor();
388 if (maybe_constructor_info->IsUndefined(isolate)) {
389 constructor = isolate->object_function();
390 } else {
391 // Enter a new scope. Recursion could otherwise create a lot of handles.
392 HandleScope scope(isolate);
393 Handle<FunctionTemplateInfo> cons_templ(
394 FunctionTemplateInfo::cast(maybe_constructor_info), isolate);
395 Handle<JSFunction> tmp_constructor;
396 ASSIGN_RETURN_ON_EXCEPTION(isolate, tmp_constructor,
397 InstantiateFunction(isolate, cons_templ),
398 JSObject);
399 constructor = scope.CloseAndEscape(tmp_constructor);
400 }
401
402 if (new_target.is_null()) new_target = constructor;
403 }
404
405 Handle<JSObject> object;
406 ASSIGN_RETURN_ON_EXCEPTION(isolate, object,
407 JSObject::New(constructor, new_target), JSObject);
408
409 if (is_prototype) JSObject::OptimizeAsPrototype(object);
410
411 ASSIGN_RETURN_ON_EXCEPTION(
412 isolate, result,
413 ConfigureInstance(isolate, object, info, is_hidden_prototype), JSObject);
414 if (info->immutable_proto()) {
415 JSObject::SetImmutableProto(object);
416 }
417 if (!is_prototype) {
418 // Keep prototypes in slow-mode. Let them be lazily turned fast later on.
419 // TODO(dcarney): is this necessary?
420 JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
421 // Don't cache prototypes.
422 if (serial_number) {
423 CacheTemplateInstantiation(isolate, serial_number, CachingMode::kLimited,
424 result);
425 result = isolate->factory()->CopyJSObject(result);
426 }
427 }
428
429 return result;
430 }
431
432 namespace {
GetInstancePrototype(Isolate * isolate,Object * function_template)433 MaybeHandle<Object> GetInstancePrototype(Isolate* isolate,
434 Object* function_template) {
435 // Enter a new scope. Recursion could otherwise create a lot of handles.
436 HandleScope scope(isolate);
437 Handle<JSFunction> parent_instance;
438 ASSIGN_RETURN_ON_EXCEPTION(
439 isolate, parent_instance,
440 InstantiateFunction(
441 isolate,
442 handle(FunctionTemplateInfo::cast(function_template), isolate)),
443 JSFunction);
444 Handle<Object> instance_prototype;
445 // TODO(cbruni): decide what to do here.
446 ASSIGN_RETURN_ON_EXCEPTION(
447 isolate, instance_prototype,
448 JSObject::GetProperty(isolate, parent_instance,
449 isolate->factory()->prototype_string()),
450 JSFunction);
451 return scope.CloseAndEscape(instance_prototype);
452 }
453 } // namespace
454
InstantiateFunction(Isolate * isolate,Handle<FunctionTemplateInfo> data,MaybeHandle<Name> maybe_name)455 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
456 Handle<FunctionTemplateInfo> data,
457 MaybeHandle<Name> maybe_name) {
458 int serial_number = Smi::ToInt(data->serial_number());
459 if (serial_number) {
460 Handle<JSObject> result;
461 if (ProbeInstantiationsCache(isolate, serial_number,
462 CachingMode::kUnlimited)
463 .ToHandle(&result)) {
464 return Handle<JSFunction>::cast(result);
465 }
466 }
467 Handle<Object> prototype;
468 if (!data->remove_prototype()) {
469 Object* prototype_templ = data->prototype_template();
470 if (prototype_templ->IsUndefined(isolate)) {
471 Object* protoype_provider_templ = data->prototype_provider_template();
472 if (protoype_provider_templ->IsUndefined(isolate)) {
473 prototype = isolate->factory()->NewJSObject(isolate->object_function());
474 } else {
475 ASSIGN_RETURN_ON_EXCEPTION(
476 isolate, prototype,
477 GetInstancePrototype(isolate, protoype_provider_templ), JSFunction);
478 }
479 } else {
480 ASSIGN_RETURN_ON_EXCEPTION(
481 isolate, prototype,
482 InstantiateObject(
483 isolate,
484 handle(ObjectTemplateInfo::cast(prototype_templ), isolate),
485 Handle<JSReceiver>(), data->hidden_prototype(), true),
486 JSFunction);
487 }
488 Object* parent = data->parent_template();
489 if (!parent->IsUndefined(isolate)) {
490 Handle<Object> parent_prototype;
491 ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype,
492 GetInstancePrototype(isolate, parent),
493 JSFunction);
494 JSObject::ForceSetPrototype(Handle<JSObject>::cast(prototype),
495 parent_prototype);
496 }
497 }
498 Handle<JSFunction> function = ApiNatives::CreateApiFunction(
499 isolate, data, prototype, ApiNatives::JavaScriptObjectType, maybe_name);
500 if (serial_number) {
501 // Cache the function.
502 CacheTemplateInstantiation(isolate, serial_number, CachingMode::kUnlimited,
503 function);
504 }
505 MaybeHandle<JSObject> result =
506 ConfigureInstance(isolate, function, data, data->hidden_prototype());
507 if (result.is_null()) {
508 // Uncache on error.
509 if (serial_number) {
510 UncacheTemplateInstantiation(isolate, serial_number,
511 CachingMode::kUnlimited);
512 }
513 return MaybeHandle<JSFunction>();
514 }
515 return function;
516 }
517
518
AddPropertyToPropertyList(Isolate * isolate,Handle<TemplateInfo> templ,int length,Handle<Object> * data)519 void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
520 int length, Handle<Object>* data) {
521 Object* maybe_list = templ->property_list();
522 Handle<TemplateList> list;
523 if (maybe_list->IsUndefined(isolate)) {
524 list = TemplateList::New(isolate, length);
525 } else {
526 list = handle(TemplateList::cast(maybe_list), isolate);
527 }
528 templ->set_number_of_properties(templ->number_of_properties() + 1);
529 for (int i = 0; i < length; i++) {
530 Handle<Object> value =
531 data[i].is_null()
532 ? Handle<Object>::cast(isolate->factory()->undefined_value())
533 : data[i];
534 list = TemplateList::Add(isolate, list, value);
535 }
536 templ->set_property_list(*list);
537 }
538
539 } // namespace
540
InstantiateFunction(Handle<FunctionTemplateInfo> data,MaybeHandle<Name> maybe_name)541 MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
542 Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
543 Isolate* isolate = data->GetIsolate();
544 InvokeScope invoke_scope(isolate);
545 return ::v8::internal::InstantiateFunction(isolate, data, maybe_name);
546 }
547
InstantiateObject(Isolate * isolate,Handle<ObjectTemplateInfo> data,Handle<JSReceiver> new_target)548 MaybeHandle<JSObject> ApiNatives::InstantiateObject(
549 Isolate* isolate, Handle<ObjectTemplateInfo> data,
550 Handle<JSReceiver> new_target) {
551 InvokeScope invoke_scope(isolate);
552 return ::v8::internal::InstantiateObject(isolate, data, new_target, false,
553 false);
554 }
555
InstantiateRemoteObject(Handle<ObjectTemplateInfo> data)556 MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
557 Handle<ObjectTemplateInfo> data) {
558 Isolate* isolate = data->GetIsolate();
559 InvokeScope invoke_scope(isolate);
560
561 Handle<FunctionTemplateInfo> constructor(
562 FunctionTemplateInfo::cast(data->constructor()), isolate);
563 Handle<Map> object_map = isolate->factory()->NewMap(
564 JS_SPECIAL_API_OBJECT_TYPE,
565 JSObject::kHeaderSize + data->embedder_field_count() * kPointerSize,
566 TERMINAL_FAST_ELEMENTS_KIND);
567 object_map->SetConstructor(*constructor);
568 object_map->set_is_access_check_needed(true);
569 object_map->set_may_have_interesting_symbols(true);
570
571 Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(object_map);
572 JSObject::ForceSetPrototype(object, isolate->factory()->null_value());
573
574 return object;
575 }
576
AddDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)577 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
578 Handle<Name> name, Handle<Object> value,
579 PropertyAttributes attributes) {
580 PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
581 auto details_handle = handle(details.AsSmi(), isolate);
582 Handle<Object> data[] = {name, details_handle, value};
583 AddPropertyToPropertyList(isolate, info, arraysize(data), data);
584 }
585
586
AddDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,v8::Intrinsic intrinsic,PropertyAttributes attributes)587 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
588 Handle<Name> name, v8::Intrinsic intrinsic,
589 PropertyAttributes attributes) {
590 auto value = handle(Smi::FromInt(intrinsic), isolate);
591 auto intrinsic_marker = isolate->factory()->true_value();
592 PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
593 auto details_handle = handle(details.AsSmi(), isolate);
594 Handle<Object> data[] = {name, intrinsic_marker, details_handle, value};
595 AddPropertyToPropertyList(isolate, info, arraysize(data), data);
596 }
597
598
AddAccessorProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,Handle<FunctionTemplateInfo> getter,Handle<FunctionTemplateInfo> setter,PropertyAttributes attributes)599 void ApiNatives::AddAccessorProperty(Isolate* isolate,
600 Handle<TemplateInfo> info,
601 Handle<Name> name,
602 Handle<FunctionTemplateInfo> getter,
603 Handle<FunctionTemplateInfo> setter,
604 PropertyAttributes attributes) {
605 PropertyDetails details(kAccessor, attributes, PropertyCellType::kNoCell);
606 auto details_handle = handle(details.AsSmi(), isolate);
607 Handle<Object> data[] = {name, details_handle, getter, setter};
608 AddPropertyToPropertyList(isolate, info, arraysize(data), data);
609 }
610
611
AddNativeDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<AccessorInfo> property)612 void ApiNatives::AddNativeDataProperty(Isolate* isolate,
613 Handle<TemplateInfo> info,
614 Handle<AccessorInfo> property) {
615 Object* maybe_list = info->property_accessors();
616 Handle<TemplateList> list;
617 if (maybe_list->IsUndefined(isolate)) {
618 list = TemplateList::New(isolate, 1);
619 } else {
620 list = handle(TemplateList::cast(maybe_list), isolate);
621 }
622 list = TemplateList::Add(isolate, list, property);
623 info->set_property_accessors(*list);
624 }
625
CreateApiFunction(Isolate * isolate,Handle<FunctionTemplateInfo> obj,Handle<Object> prototype,ApiInstanceType instance_type,MaybeHandle<Name> maybe_name)626 Handle<JSFunction> ApiNatives::CreateApiFunction(
627 Isolate* isolate, Handle<FunctionTemplateInfo> obj,
628 Handle<Object> prototype, ApiInstanceType instance_type,
629 MaybeHandle<Name> maybe_name) {
630 Handle<SharedFunctionInfo> shared =
631 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj,
632 maybe_name);
633 // To simplify things, API functions always have shared name.
634 DCHECK(shared->HasSharedName());
635
636 Handle<JSFunction> result =
637 isolate->factory()->NewFunctionFromSharedFunctionInfo(
638 shared, isolate->native_context());
639
640 if (obj->remove_prototype()) {
641 DCHECK(prototype.is_null());
642 DCHECK(result->shared()->IsApiFunction());
643 DCHECK(!result->IsConstructor());
644 DCHECK(!result->has_prototype_slot());
645 return result;
646 }
647
648 // Down from here is only valid for API functions that can be used as a
649 // constructor (don't set the "remove prototype" flag).
650 DCHECK(result->has_prototype_slot());
651
652 if (obj->read_only_prototype()) {
653 result->set_map(*isolate->sloppy_function_with_readonly_prototype_map());
654 }
655
656 if (prototype->IsTheHole(isolate)) {
657 prototype = isolate->factory()->NewFunctionPrototype(result);
658 } else if (obj->prototype_provider_template()->IsUndefined(isolate)) {
659 JSObject::AddProperty(isolate, Handle<JSObject>::cast(prototype),
660 isolate->factory()->constructor_string(), result,
661 DONT_ENUM);
662 }
663
664 int embedder_field_count = 0;
665 bool immutable_proto = false;
666 if (!obj->instance_template()->IsUndefined(isolate)) {
667 Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
668 ObjectTemplateInfo::cast(obj->instance_template()), isolate);
669 embedder_field_count = instance_template->embedder_field_count();
670 immutable_proto = instance_template->immutable_proto();
671 }
672
673 // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing
674 // JSObject::GetHeaderSize.
675 int instance_size = kPointerSize * embedder_field_count;
676 InstanceType type;
677 switch (instance_type) {
678 case JavaScriptObjectType:
679 if (!obj->needs_access_check() &&
680 obj->named_property_handler()->IsUndefined(isolate) &&
681 obj->indexed_property_handler()->IsUndefined(isolate)) {
682 type = JS_API_OBJECT_TYPE;
683 } else {
684 type = JS_SPECIAL_API_OBJECT_TYPE;
685 }
686 instance_size += JSObject::kHeaderSize;
687 break;
688 case GlobalObjectType:
689 type = JS_GLOBAL_OBJECT_TYPE;
690 instance_size += JSGlobalObject::kSize;
691 break;
692 case GlobalProxyType:
693 type = JS_GLOBAL_PROXY_TYPE;
694 instance_size += JSGlobalProxy::kSize;
695 break;
696 default:
697 UNREACHABLE();
698 break;
699 }
700
701 Handle<Map> map = isolate->factory()->NewMap(type, instance_size,
702 TERMINAL_FAST_ELEMENTS_KIND);
703 JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype));
704
705 // Mark as undetectable if needed.
706 if (obj->undetectable()) {
707 // We only allow callable undetectable receivers here, since this whole
708 // undetectable business is only to support document.all, which is both
709 // undetectable and callable. If we ever see the need to have an object
710 // that is undetectable but not callable, we need to update the types.h
711 // to allow encoding this.
712 CHECK(!obj->instance_call_handler()->IsUndefined(isolate));
713 map->set_is_undetectable(true);
714 }
715
716 // Mark as needs_access_check if needed.
717 if (obj->needs_access_check()) {
718 map->set_is_access_check_needed(true);
719 map->set_may_have_interesting_symbols(true);
720 }
721
722 // Set interceptor information in the map.
723 if (!obj->named_property_handler()->IsUndefined(isolate)) {
724 map->set_has_named_interceptor(true);
725 map->set_may_have_interesting_symbols(true);
726 }
727 if (!obj->indexed_property_handler()->IsUndefined(isolate)) {
728 map->set_has_indexed_interceptor(true);
729 }
730
731 // Mark instance as callable in the map.
732 if (!obj->instance_call_handler()->IsUndefined(isolate)) {
733 map->set_is_callable(true);
734 }
735
736 if (immutable_proto) map->set_is_immutable_proto(true);
737
738 return result;
739 }
740
741 } // namespace internal
742 } // namespace v8
743