| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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, | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 19 |                                         Handle<ObjectTemplateInfo> data, | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 20 |                                         Handle<JSReceiver> new_target, | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 21 |                                         bool is_hidden_prototype); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 22 |  | 
 | 23 | MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate, | 
 | 24 |                                             Handle<FunctionTemplateInfo> data, | 
 | 25 |                                             Handle<Name> name = Handle<Name>()); | 
 | 26 |  | 
 | 27 |  | 
 | 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()) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 34 |     return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data), | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 35 |                              Handle<JSReceiver>(), false); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 36 |   } else { | 
 | 37 |     return data; | 
 | 38 |   } | 
 | 39 | } | 
 | 40 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 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 |     } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 64 |   } | 
 | 65 |   RETURN_ON_EXCEPTION(isolate, JSObject::DefineAccessor(object, name, getter, | 
 | 66 |                                                         setter, attributes), | 
 | 67 |                       Object); | 
 | 68 |   return object; | 
 | 69 | } | 
 | 70 |  | 
 | 71 |  | 
 | 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 |  | 
 | 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 |  | 
 | 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: | 
 | 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 |   } | 
 | 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 |  | 
 | 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 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 156 | // Returns parent function template or null. | 
 | 157 | FunctionTemplateInfo* GetParent(FunctionTemplateInfo* data) { | 
 | 158 |   Object* parent = data->parent_template(); | 
 | 159 |   return parent->IsUndefined() ? nullptr : FunctionTemplateInfo::cast(parent); | 
 | 160 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 161 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 162 | // Starting from given object template's constructor walk up the inheritance | 
 | 163 | // chain till a function template that has an instance template is found. | 
 | 164 | ObjectTemplateInfo* GetParent(ObjectTemplateInfo* data) { | 
 | 165 |   Object* maybe_ctor = data->constructor(); | 
 | 166 |   if (maybe_ctor->IsUndefined()) return nullptr; | 
 | 167 |   FunctionTemplateInfo* ctor = FunctionTemplateInfo::cast(maybe_ctor); | 
 | 168 |   while (true) { | 
 | 169 |     ctor = GetParent(ctor); | 
 | 170 |     if (ctor == nullptr) return nullptr; | 
 | 171 |     Object* maybe_obj = ctor->instance_template(); | 
 | 172 |     if (!maybe_obj->IsUndefined()) return ObjectTemplateInfo::cast(maybe_obj); | 
 | 173 |   } | 
 | 174 | } | 
 | 175 |  | 
 | 176 | template <typename TemplateInfoT> | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 177 | MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj, | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 178 |                                         Handle<TemplateInfoT> data, | 
 | 179 |                                         bool is_hidden_prototype) { | 
 | 180 |   HandleScope scope(isolate); | 
 | 181 |   // Disable access checks while instantiating the object. | 
 | 182 |   AccessCheckDisableScope access_check_scope(isolate, obj); | 
 | 183 |  | 
 | 184 |   // Walk the inheritance chain and copy all accessors to current object. | 
 | 185 |   int max_number_of_properties = 0; | 
 | 186 |   TemplateInfoT* info = *data; | 
 | 187 |   while (info != nullptr) { | 
 | 188 |     if (!info->property_accessors()->IsUndefined()) { | 
 | 189 |       Object* props = info->property_accessors(); | 
 | 190 |       if (!props->IsUndefined()) { | 
 | 191 |         Handle<Object> props_handle(props, isolate); | 
 | 192 |         NeanderArray props_array(props_handle); | 
 | 193 |         max_number_of_properties += props_array.length(); | 
 | 194 |       } | 
 | 195 |     } | 
 | 196 |     info = GetParent(info); | 
 | 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 |     info = *data; | 
 | 206 |     while (info != nullptr) { | 
 | 207 |       // Accumulate accessors. | 
 | 208 |       if (!info->property_accessors()->IsUndefined()) { | 
 | 209 |         Handle<Object> props(info->property_accessors(), isolate); | 
 | 210 |         valid_descriptors = | 
 | 211 |             AccessorInfo::AppendUnique(props, array, valid_descriptors); | 
 | 212 |       } | 
 | 213 |       info = GetParent(info); | 
 | 214 |     } | 
 | 215 |  | 
 | 216 |     // Install accumulated accessors. | 
 | 217 |     for (int i = 0; i < valid_descriptors; i++) { | 
 | 218 |       Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i))); | 
 | 219 |       JSObject::SetAccessor(obj, accessor).Assert(); | 
 | 220 |     } | 
 | 221 |   } | 
 | 222 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 223 |   auto property_list = handle(data->property_list(), isolate); | 
 | 224 |   if (property_list->IsUndefined()) return obj; | 
 | 225 |   // TODO(dcarney): just use a FixedArray here. | 
 | 226 |   NeanderArray properties(property_list); | 
 | 227 |   if (properties.length() == 0) return obj; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 228 |  | 
 | 229 |   int i = 0; | 
 | 230 |   for (int c = 0; c < data->number_of_properties(); c++) { | 
 | 231 |     auto name = handle(Name::cast(properties.get(i++)), isolate); | 
 | 232 |     auto bit = handle(properties.get(i++), isolate); | 
 | 233 |     if (bit->IsSmi()) { | 
 | 234 |       PropertyDetails details(Smi::cast(*bit)); | 
 | 235 |       PropertyAttributes attributes = details.attributes(); | 
 | 236 |       PropertyKind kind = details.kind(); | 
 | 237 |  | 
 | 238 |       if (kind == kData) { | 
 | 239 |         auto prop_data = handle(properties.get(i++), isolate); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 240 |         RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name, | 
 | 241 |                                                         prop_data, attributes), | 
 | 242 |                             JSObject); | 
 | 243 |       } else { | 
 | 244 |         auto getter = handle(properties.get(i++), isolate); | 
 | 245 |         auto setter = handle(properties.get(i++), isolate); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 246 |         RETURN_ON_EXCEPTION( | 
 | 247 |             isolate, DefineAccessorProperty(isolate, obj, name, getter, setter, | 
 | 248 |                                             attributes, is_hidden_prototype), | 
 | 249 |             JSObject); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 250 |       } | 
 | 251 |     } else { | 
 | 252 |       // Intrinsic data property --- Get appropriate value from the current | 
 | 253 |       // context. | 
 | 254 |       PropertyDetails details(Smi::cast(properties.get(i++))); | 
 | 255 |       PropertyAttributes attributes = details.attributes(); | 
 | 256 |       DCHECK_EQ(kData, details.kind()); | 
 | 257 |  | 
 | 258 |       v8::Intrinsic intrinsic = | 
 | 259 |           static_cast<v8::Intrinsic>(Smi::cast(properties.get(i++))->value()); | 
 | 260 |       auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate); | 
 | 261 |  | 
 | 262 |       RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name, | 
 | 263 |                                                       prop_data, attributes), | 
 | 264 |                           JSObject); | 
 | 265 |     } | 
 | 266 |   } | 
 | 267 |   return obj; | 
 | 268 | } | 
 | 269 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 270 | void CacheTemplateInstantiation(Isolate* isolate, uint32_t serial_number, | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 271 |                                 Handle<JSObject> object) { | 
 | 272 |   auto cache = isolate->template_instantiations_cache(); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 273 |   auto new_cache = | 
 | 274 |       UnseededNumberDictionary::AtNumberPut(cache, serial_number, object); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 275 |   isolate->native_context()->set_template_instantiations_cache(*new_cache); | 
 | 276 | } | 
 | 277 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 278 | void UncacheTemplateInstantiation(Isolate* isolate, uint32_t serial_number) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 279 |   auto cache = isolate->template_instantiations_cache(); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 280 |   int entry = cache->FindEntry(serial_number); | 
 | 281 |   DCHECK(entry != UnseededNumberDictionary::kNotFound); | 
 | 282 |   Handle<Object> result = | 
 | 283 |       UnseededNumberDictionary::DeleteProperty(cache, entry); | 
 | 284 |   USE(result); | 
 | 285 |   DCHECK(result->IsTrue()); | 
 | 286 |   auto new_cache = UnseededNumberDictionary::Shrink(cache, entry); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 287 |   isolate->native_context()->set_template_instantiations_cache(*new_cache); | 
 | 288 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 289 |  | 
 | 290 | MaybeHandle<JSObject> InstantiateObject(Isolate* isolate, | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 291 |                                         Handle<ObjectTemplateInfo> info, | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 292 |                                         Handle<JSReceiver> new_target, | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 293 |                                         bool is_hidden_prototype) { | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 294 |   Handle<JSFunction> constructor; | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 295 |   uint32_t serial_number = | 
 | 296 |       static_cast<uint32_t>(Smi::cast(info->serial_number())->value()); | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 297 |   if (!new_target.is_null()) { | 
 | 298 |     if (new_target->IsJSFunction() && | 
 | 299 |         JSFunction::cast(*new_target)->shared()->function_data() == | 
 | 300 |             info->constructor() && | 
 | 301 |         JSFunction::cast(*new_target)->context()->native_context() == | 
 | 302 |             isolate->context()->native_context()) { | 
 | 303 |       constructor = Handle<JSFunction>::cast(new_target); | 
 | 304 |     } else { | 
 | 305 |       // Disable caching for subclass instantiation. | 
 | 306 |       serial_number = 0; | 
 | 307 |     } | 
 | 308 |   } | 
 | 309 |   // Fast path. | 
 | 310 |   Handle<JSObject> result; | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 311 |   if (serial_number) { | 
 | 312 |     // Probe cache. | 
 | 313 |     auto cache = isolate->template_instantiations_cache(); | 
 | 314 |     int entry = cache->FindEntry(serial_number); | 
 | 315 |     if (entry != UnseededNumberDictionary::kNotFound) { | 
 | 316 |       Object* boilerplate = cache->ValueAt(entry); | 
 | 317 |       result = handle(JSObject::cast(boilerplate), isolate); | 
 | 318 |       return isolate->factory()->CopyJSObject(result); | 
 | 319 |     } | 
 | 320 |   } | 
 | 321 |   // Enter a new scope.  Recursion could otherwise create a lot of handles. | 
 | 322 |   HandleScope scope(isolate); | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 323 |  | 
 | 324 |   if (constructor.is_null()) { | 
 | 325 |     Handle<Object> cons(info->constructor(), isolate); | 
 | 326 |     if (cons->IsUndefined()) { | 
 | 327 |       constructor = isolate->object_function(); | 
 | 328 |     } else { | 
 | 329 |       auto cons_templ = Handle<FunctionTemplateInfo>::cast(cons); | 
 | 330 |       ASSIGN_RETURN_ON_EXCEPTION(isolate, constructor, | 
 | 331 |                                  InstantiateFunction(isolate, cons_templ), | 
 | 332 |                                  JSObject); | 
 | 333 |     } | 
 | 334 |  | 
 | 335 |     if (new_target.is_null()) new_target = constructor; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 336 |   } | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 337 |  | 
 | 338 |   Handle<JSObject> object; | 
 | 339 |   ASSIGN_RETURN_ON_EXCEPTION(isolate, object, | 
 | 340 |                              JSObject::New(constructor, new_target), JSObject); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 341 |   ASSIGN_RETURN_ON_EXCEPTION( | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 342 |       isolate, result, | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 343 |       ConfigureInstance(isolate, object, info, is_hidden_prototype), JSObject); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 344 |   // TODO(dcarney): is this necessary? | 
 | 345 |   JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject"); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 346 |  | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 347 |   if (serial_number) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 348 |     CacheTemplateInstantiation(isolate, serial_number, result); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 349 |     result = isolate->factory()->CopyJSObject(result); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 350 |   } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 351 |   return scope.CloseAndEscape(result); | 
 | 352 | } | 
 | 353 |  | 
 | 354 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 355 | MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate, | 
 | 356 |                                             Handle<FunctionTemplateInfo> data, | 
 | 357 |                                             Handle<Name> name) { | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 358 |   uint32_t serial_number = | 
 | 359 |       static_cast<uint32_t>(Smi::cast(data->serial_number())->value()); | 
 | 360 |   if (serial_number) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 361 |     // Probe cache. | 
 | 362 |     auto cache = isolate->template_instantiations_cache(); | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 363 |     int entry = cache->FindEntry(serial_number); | 
 | 364 |     if (entry != UnseededNumberDictionary::kNotFound) { | 
 | 365 |       Object* element = cache->ValueAt(entry); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 366 |       return handle(JSFunction::cast(element), isolate); | 
 | 367 |     } | 
 | 368 |   } | 
 | 369 |   // Enter a new scope.  Recursion could otherwise create a lot of handles. | 
 | 370 |   HandleScope scope(isolate); | 
 | 371 |   Handle<JSObject> prototype; | 
 | 372 |   if (!data->remove_prototype()) { | 
 | 373 |     auto prototype_templ = handle(data->prototype_template(), isolate); | 
 | 374 |     if (prototype_templ->IsUndefined()) { | 
 | 375 |       prototype = isolate->factory()->NewJSObject(isolate->object_function()); | 
 | 376 |     } else { | 
 | 377 |       ASSIGN_RETURN_ON_EXCEPTION( | 
 | 378 |           isolate, prototype, | 
 | 379 |           InstantiateObject(isolate, | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 380 |                             Handle<ObjectTemplateInfo>::cast(prototype_templ), | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 381 |                             Handle<JSReceiver>(), data->hidden_prototype()), | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 382 |           JSFunction); | 
 | 383 |     } | 
 | 384 |     auto parent = handle(data->parent_template(), isolate); | 
 | 385 |     if (!parent->IsUndefined()) { | 
 | 386 |       Handle<JSFunction> parent_instance; | 
 | 387 |       ASSIGN_RETURN_ON_EXCEPTION( | 
 | 388 |           isolate, parent_instance, | 
 | 389 |           InstantiateFunction(isolate, | 
 | 390 |                               Handle<FunctionTemplateInfo>::cast(parent)), | 
 | 391 |           JSFunction); | 
 | 392 |       // TODO(dcarney): decide what to do here. | 
 | 393 |       Handle<Object> parent_prototype; | 
 | 394 |       ASSIGN_RETURN_ON_EXCEPTION( | 
 | 395 |           isolate, parent_prototype, | 
 | 396 |           JSObject::GetProperty(parent_instance, | 
 | 397 |                                 isolate->factory()->prototype_string()), | 
 | 398 |           JSFunction); | 
 | 399 |       MAYBE_RETURN(JSObject::SetPrototype(prototype, parent_prototype, false, | 
 | 400 |                                           Object::THROW_ON_ERROR), | 
 | 401 |                    MaybeHandle<JSFunction>()); | 
 | 402 |     } | 
 | 403 |   } | 
 | 404 |   auto function = ApiNatives::CreateApiFunction( | 
 | 405 |       isolate, data, prototype, ApiNatives::JavaScriptObjectType); | 
 | 406 |   if (!name.is_null() && name->IsString()) { | 
 | 407 |     function->shared()->set_name(*name); | 
 | 408 |   } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 409 |   if (serial_number) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 410 |     // Cache the function. | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 411 |     CacheTemplateInstantiation(isolate, serial_number, function); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 412 |   } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 413 |   auto result = | 
 | 414 |       ConfigureInstance(isolate, function, data, data->hidden_prototype()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 415 |   if (result.is_null()) { | 
 | 416 |     // Uncache on error. | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 417 |     if (serial_number) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 418 |       UncacheTemplateInstantiation(isolate, serial_number); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 419 |     } | 
 | 420 |     return MaybeHandle<JSFunction>(); | 
 | 421 |   } | 
 | 422 |   return scope.CloseAndEscape(function); | 
 | 423 | } | 
 | 424 |  | 
 | 425 |  | 
 | 426 | class InvokeScope { | 
 | 427 |  public: | 
 | 428 |   explicit InvokeScope(Isolate* isolate) | 
 | 429 |       : isolate_(isolate), save_context_(isolate) {} | 
 | 430 |   ~InvokeScope() { | 
 | 431 |     bool has_exception = isolate_->has_pending_exception(); | 
 | 432 |     if (has_exception) { | 
 | 433 |       isolate_->ReportPendingMessages(); | 
 | 434 |     } else { | 
 | 435 |       isolate_->clear_pending_message(); | 
 | 436 |     } | 
 | 437 |   } | 
 | 438 |  | 
 | 439 |  private: | 
 | 440 |   Isolate* isolate_; | 
 | 441 |   SaveContext save_context_; | 
 | 442 | }; | 
 | 443 |  | 
 | 444 |  | 
 | 445 | void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ, | 
 | 446 |                                int length, Handle<Object>* data) { | 
 | 447 |   auto list = handle(templ->property_list(), isolate); | 
 | 448 |   if (list->IsUndefined()) { | 
 | 449 |     list = NeanderArray(isolate).value(); | 
 | 450 |     templ->set_property_list(*list); | 
 | 451 |   } | 
 | 452 |   templ->set_number_of_properties(templ->number_of_properties() + 1); | 
 | 453 |   NeanderArray array(list); | 
 | 454 |   for (int i = 0; i < length; i++) { | 
 | 455 |     Handle<Object> value = | 
 | 456 |         data[i].is_null() | 
 | 457 |             ? Handle<Object>::cast(isolate->factory()->undefined_value()) | 
 | 458 |             : data[i]; | 
 | 459 |     array.add(isolate, value); | 
 | 460 |   } | 
 | 461 | } | 
 | 462 |  | 
 | 463 | }  // namespace | 
 | 464 |  | 
 | 465 |  | 
 | 466 | MaybeHandle<JSFunction> ApiNatives::InstantiateFunction( | 
 | 467 |     Handle<FunctionTemplateInfo> data) { | 
 | 468 |   Isolate* isolate = data->GetIsolate(); | 
 | 469 |   InvokeScope invoke_scope(isolate); | 
 | 470 |   return ::v8::internal::InstantiateFunction(isolate, data); | 
 | 471 | } | 
 | 472 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 473 | MaybeHandle<JSObject> ApiNatives::InstantiateObject( | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 474 |     Handle<ObjectTemplateInfo> data, Handle<JSReceiver> new_target) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 475 |   Isolate* isolate = data->GetIsolate(); | 
 | 476 |   InvokeScope invoke_scope(isolate); | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 477 |   return ::v8::internal::InstantiateObject(isolate, data, new_target, false); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 478 | } | 
 | 479 |  | 
 | 480 |  | 
 | 481 | void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info, | 
 | 482 |                                  Handle<Name> name, Handle<Object> value, | 
 | 483 |                                  PropertyAttributes attributes) { | 
 | 484 |   const int kSize = 3; | 
 | 485 |   PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); | 
 | 486 |   auto details_handle = handle(details.AsSmi(), isolate); | 
 | 487 |   Handle<Object> data[kSize] = {name, details_handle, value}; | 
 | 488 |   AddPropertyToPropertyList(isolate, info, kSize, data); | 
 | 489 | } | 
 | 490 |  | 
 | 491 |  | 
 | 492 | void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info, | 
 | 493 |                                  Handle<Name> name, v8::Intrinsic intrinsic, | 
 | 494 |                                  PropertyAttributes attributes) { | 
 | 495 |   const int kSize = 4; | 
 | 496 |   auto value = handle(Smi::FromInt(intrinsic), isolate); | 
 | 497 |   auto intrinsic_marker = isolate->factory()->true_value(); | 
 | 498 |   PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); | 
 | 499 |   auto details_handle = handle(details.AsSmi(), isolate); | 
 | 500 |   Handle<Object> data[kSize] = {name, intrinsic_marker, details_handle, value}; | 
 | 501 |   AddPropertyToPropertyList(isolate, info, kSize, data); | 
 | 502 | } | 
 | 503 |  | 
 | 504 |  | 
 | 505 | void ApiNatives::AddAccessorProperty(Isolate* isolate, | 
 | 506 |                                      Handle<TemplateInfo> info, | 
 | 507 |                                      Handle<Name> name, | 
 | 508 |                                      Handle<FunctionTemplateInfo> getter, | 
 | 509 |                                      Handle<FunctionTemplateInfo> setter, | 
 | 510 |                                      PropertyAttributes attributes) { | 
 | 511 |   const int kSize = 4; | 
 | 512 |   PropertyDetails details(attributes, ACCESSOR, 0, PropertyCellType::kNoCell); | 
 | 513 |   auto details_handle = handle(details.AsSmi(), isolate); | 
 | 514 |   Handle<Object> data[kSize] = {name, details_handle, getter, setter}; | 
 | 515 |   AddPropertyToPropertyList(isolate, info, kSize, data); | 
 | 516 | } | 
 | 517 |  | 
 | 518 |  | 
 | 519 | void ApiNatives::AddNativeDataProperty(Isolate* isolate, | 
 | 520 |                                        Handle<TemplateInfo> info, | 
 | 521 |                                        Handle<AccessorInfo> property) { | 
 | 522 |   auto list = handle(info->property_accessors(), isolate); | 
 | 523 |   if (list->IsUndefined()) { | 
 | 524 |     list = NeanderArray(isolate).value(); | 
 | 525 |     info->set_property_accessors(*list); | 
 | 526 |   } | 
 | 527 |   NeanderArray array(list); | 
 | 528 |   array.add(isolate, property); | 
 | 529 | } | 
 | 530 |  | 
 | 531 |  | 
 | 532 | Handle<JSFunction> ApiNatives::CreateApiFunction( | 
 | 533 |     Isolate* isolate, Handle<FunctionTemplateInfo> obj, | 
 | 534 |     Handle<Object> prototype, ApiInstanceType instance_type) { | 
 | 535 |   Handle<Code> code; | 
 | 536 |   if (obj->call_code()->IsCallHandlerInfo() && | 
 | 537 |       CallHandlerInfo::cast(obj->call_code())->fast_handler()->IsCode()) { | 
 | 538 |     code = isolate->builtins()->HandleFastApiCall(); | 
 | 539 |   } else { | 
 | 540 |     code = isolate->builtins()->HandleApiCall(); | 
 | 541 |   } | 
 | 542 |   Handle<Code> construct_stub = | 
 | 543 |       prototype.is_null() ? isolate->builtins()->ConstructedNonConstructable() | 
 | 544 |                           : isolate->builtins()->JSConstructStubApi(); | 
 | 545 |  | 
 | 546 |   obj->set_instantiated(true); | 
 | 547 |   Handle<JSFunction> result; | 
 | 548 |   if (obj->remove_prototype()) { | 
 | 549 |     result = isolate->factory()->NewFunctionWithoutPrototype( | 
 | 550 |         isolate->factory()->empty_string(), code); | 
 | 551 |   } else { | 
 | 552 |     int internal_field_count = 0; | 
 | 553 |     if (!obj->instance_template()->IsUndefined()) { | 
 | 554 |       Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>( | 
 | 555 |           ObjectTemplateInfo::cast(obj->instance_template())); | 
 | 556 |       internal_field_count = | 
 | 557 |           Smi::cast(instance_template->internal_field_count())->value(); | 
 | 558 |     } | 
 | 559 |  | 
 | 560 |     // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing | 
 | 561 |     // JSObject::GetHeaderSize. | 
 | 562 |     int instance_size = kPointerSize * internal_field_count; | 
 | 563 |     InstanceType type; | 
 | 564 |     switch (instance_type) { | 
 | 565 |       case JavaScriptObjectType: | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 566 |         if (!obj->needs_access_check() && | 
 | 567 |             obj->named_property_handler()->IsUndefined() && | 
 | 568 |             obj->indexed_property_handler()->IsUndefined()) { | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 569 |           type = JS_API_OBJECT_TYPE; | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 570 |         } else { | 
 | 571 |           type = JS_SPECIAL_API_OBJECT_TYPE; | 
 | 572 |         } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 573 |         instance_size += JSObject::kHeaderSize; | 
 | 574 |         break; | 
 | 575 |       case GlobalObjectType: | 
 | 576 |         type = JS_GLOBAL_OBJECT_TYPE; | 
 | 577 |         instance_size += JSGlobalObject::kSize; | 
 | 578 |         break; | 
 | 579 |       case GlobalProxyType: | 
 | 580 |         type = JS_GLOBAL_PROXY_TYPE; | 
 | 581 |         instance_size += JSGlobalProxy::kSize; | 
 | 582 |         break; | 
 | 583 |       default: | 
 | 584 |         UNREACHABLE(); | 
 | 585 |         type = JS_OBJECT_TYPE;  // Keep the compiler happy. | 
 | 586 |         break; | 
 | 587 |     } | 
 | 588 |  | 
 | 589 |     result = isolate->factory()->NewFunction( | 
 | 590 |         isolate->factory()->empty_string(), code, prototype, type, | 
 | 591 |         instance_size, obj->read_only_prototype(), true); | 
 | 592 |   } | 
 | 593 |  | 
 | 594 |   result->shared()->set_length(obj->length()); | 
 | 595 |   Handle<Object> class_name(obj->class_name(), isolate); | 
 | 596 |   if (class_name->IsString()) { | 
 | 597 |     result->shared()->set_instance_class_name(*class_name); | 
 | 598 |     result->shared()->set_name(*class_name); | 
 | 599 |   } | 
| Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 600 |   result->shared()->set_api_func_data(*obj); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 601 |   result->shared()->set_construct_stub(*construct_stub); | 
 | 602 |   result->shared()->DontAdaptArguments(); | 
 | 603 |  | 
 | 604 |   if (obj->remove_prototype()) { | 
 | 605 |     DCHECK(result->shared()->IsApiFunction()); | 
 | 606 |     DCHECK(!result->has_initial_map()); | 
 | 607 |     DCHECK(!result->has_prototype()); | 
 | 608 |     return result; | 
 | 609 |   } | 
 | 610 |  | 
 | 611 | #ifdef DEBUG | 
 | 612 |   LookupIterator it(handle(JSObject::cast(result->prototype())), | 
 | 613 |                     isolate->factory()->constructor_string(), | 
 | 614 |                     LookupIterator::OWN_SKIP_INTERCEPTOR); | 
 | 615 |   MaybeHandle<Object> maybe_prop = Object::GetProperty(&it); | 
 | 616 |   DCHECK(it.IsFound()); | 
 | 617 |   DCHECK(maybe_prop.ToHandleChecked().is_identical_to(result)); | 
 | 618 | #endif | 
 | 619 |  | 
 | 620 |   // Down from here is only valid for API functions that can be used as a | 
 | 621 |   // constructor (don't set the "remove prototype" flag). | 
 | 622 |  | 
 | 623 |   Handle<Map> map(result->initial_map()); | 
 | 624 |  | 
 | 625 |   // Mark as undetectable if needed. | 
 | 626 |   if (obj->undetectable()) { | 
 | 627 |     map->set_is_undetectable(); | 
 | 628 |   } | 
 | 629 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 630 |   // Mark as needs_access_check if needed. | 
 | 631 |   if (obj->needs_access_check()) { | 
 | 632 |     map->set_is_access_check_needed(true); | 
 | 633 |   } | 
 | 634 |  | 
 | 635 |   // Set interceptor information in the map. | 
 | 636 |   if (!obj->named_property_handler()->IsUndefined()) { | 
 | 637 |     map->set_has_named_interceptor(); | 
 | 638 |   } | 
 | 639 |   if (!obj->indexed_property_handler()->IsUndefined()) { | 
 | 640 |     map->set_has_indexed_interceptor(); | 
 | 641 |   } | 
 | 642 |  | 
 | 643 |   // Mark instance as callable in the map. | 
 | 644 |   if (!obj->instance_call_handler()->IsUndefined()) { | 
 | 645 |     map->set_is_callable(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 646 |     map->set_is_constructor(true); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 647 |   } | 
 | 648 |  | 
 | 649 |   DCHECK(result->shared()->IsApiFunction()); | 
 | 650 |   return result; | 
 | 651 | } | 
 | 652 |  | 
 | 653 | }  // namespace internal | 
 | 654 | }  // namespace v8 |