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