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