Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 #include "src/isolate-inl.h" | |
| 7 | |
| 8 namespace v8 { | |
| 9 namespace internal { | |
| 10 | |
| 11 namespace { | |
| 12 | |
| 13 // Transform getter or setter into something DefineAccessor can handle. | |
| 14 Handle<Object> InstantiateAccessorComponent(Isolate* isolate, | |
| 15 Handle<Object> component) { | |
| 16 if (component->IsUndefined()) return isolate->factory()->undefined_value(); | |
| 17 Handle<FunctionTemplateInfo> info = | |
| 18 Handle<FunctionTemplateInfo>::cast(component); | |
| 19 // TODO(dcarney): instantiate directly. | |
| 20 return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction()); | |
| 21 } | |
| 22 | |
| 23 | |
| 24 Object* DefineApiAccessorProperty(Isolate* isolate, Handle<JSObject> object, | |
| 25 Handle<Name> name, Handle<Object> getter, | |
| 26 Handle<Object> setter, Smi* attribute) { | |
| 27 DCHECK(PropertyDetails::AttributesField::is_valid( | |
| 28 static_cast<PropertyAttributes>(attribute->value()))); | |
| 29 RETURN_FAILURE_ON_EXCEPTION( | |
| 30 isolate, JSObject::DefineAccessor( | |
| 31 object, name, InstantiateAccessorComponent(isolate, getter), | |
| 32 InstantiateAccessorComponent(isolate, setter), | |
| 33 static_cast<PropertyAttributes>(attribute->value()))); | |
| 34 return *object; | |
| 35 } | |
| 36 | |
| 37 | |
| 38 Object* AddPropertyForTemplate(Isolate* isolate, Handle<JSObject> object, | |
| 39 Handle<Object> key, Handle<Object> value, | |
| 40 Smi* unchecked_attributes) { | |
| 41 DCHECK((unchecked_attributes->value() & | |
| 42 ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); | |
| 43 // Compute attributes. | |
| 44 PropertyAttributes attributes = | |
| 45 static_cast<PropertyAttributes>(unchecked_attributes->value()); | |
| 46 | |
| 47 #ifdef DEBUG | |
| 48 bool duplicate; | |
| 49 if (key->IsName()) { | |
| 50 LookupIterator it(object, Handle<Name>::cast(key), | |
| 51 LookupIterator::OWN_SKIP_INTERCEPTOR); | |
| 52 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); | |
| 53 DCHECK(maybe.has_value); | |
| 54 duplicate = it.IsFound(); | |
| 55 } else { | |
| 56 uint32_t index = 0; | |
| 57 key->ToArrayIndex(&index); | |
| 58 Maybe<bool> maybe = JSReceiver::HasOwnElement(object, index); | |
| 59 if (!maybe.has_value) return isolate->heap()->exception(); | |
| 60 duplicate = maybe.value; | |
| 61 } | |
| 62 if (duplicate) { | |
| 63 Handle<Object> args[1] = {key}; | |
| 64 THROW_NEW_ERROR_RETURN_FAILURE( | |
| 65 isolate, | |
| 66 NewTypeError("duplicate_template_property", HandleVector(args, 1))); | |
| 67 } | |
| 68 #endif | |
| 69 | |
| 70 Handle<Object> result; | |
| 71 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 72 isolate, result, | |
| 73 Runtime::DefineObjectProperty(object, key, value, attributes)); | |
| 74 return *result; | |
| 75 } | |
| 76 | |
| 77 | |
| 78 void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) { | |
| 79 Handle<Map> old_map(object->map()); | |
| 80 // Copy map so it won't interfere constructor's initial map. | |
| 81 Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks"); | |
| 82 new_map->set_is_access_check_needed(false); | |
| 83 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map); | |
| 84 } | |
| 85 | |
| 86 | |
| 87 void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) { | |
| 88 Handle<Map> old_map(object->map()); | |
| 89 // Copy map so it won't interfere constructor's initial map. | |
| 90 Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks"); | |
| 91 new_map->set_is_access_check_needed(true); | |
| 92 JSObject::MigrateToMap(object, new_map); | |
| 93 } | |
| 94 | |
| 95 | |
| 96 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate, | |
| 97 Handle<ObjectTemplateInfo> data); | |
| 98 | |
| 99 | |
| 100 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate, | |
| 101 Handle<FunctionTemplateInfo> data, | |
| 102 Handle<Name> name = Handle<Name>()); | |
| 103 | |
| 104 | |
| 105 MaybeHandle<Object> Instantiate(Isolate* isolate, Handle<Object> data, | |
| 106 Handle<Name> name = Handle<Name>()) { | |
| 107 if (data->IsFunctionTemplateInfo()) { | |
| 108 return InstantiateFunction(isolate, | |
| 109 Handle<FunctionTemplateInfo>::cast(data), name); | |
| 110 } else if (data->IsObjectTemplateInfo()) { | |
| 111 return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data)); | |
| 112 } else { | |
| 113 // TODO(dcarney): CHECK data is JSObject or Primitive. | |
| 114 return data; | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 | |
| 119 MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj, | |
| 120 Handle<TemplateInfo> data) { | |
| 121 auto property_list = handle(data->property_list(), isolate); | |
| 122 if (property_list->IsUndefined()) return obj; | |
| 123 // TODO(dcarney): just use a FixedArray here. | |
| 124 NeanderArray properties(property_list); | |
| 125 if (properties.length() == 0) return obj; | |
| 126 HandleScope scope(isolate); | |
| 127 // // Disable access checks while instantiating the object. | |
| 128 bool requires_access_checks = obj->map()->is_access_check_needed(); | |
| 129 if (requires_access_checks) { | |
| 130 DisableAccessChecks(isolate, obj); | |
| 131 } | |
| 132 // TODO(dcarney): put iteration in own function so exception checking is more | |
| 133 // standard. | |
|
Toon Verwaest
2015/02/04 12:04:04
Would indeed be nice if you'd just move the Disabl
| |
| 134 MaybeHandle<JSObject> result = obj; | |
| 135 for (int i = 0; i < properties.length();) { | |
| 136 int length = Smi::cast(properties.get(i))->value(); | |
| 137 if (length == 3) { | |
| 138 auto name = handle(Name::cast(properties.get(i + 1)), isolate); | |
| 139 auto prop_data = handle(properties.get(i + 2), isolate); | |
| 140 auto attributes = Smi::cast(properties.get(i + 3)); | |
| 141 auto instantiate_result = Instantiate(isolate, prop_data, name); | |
| 142 Handle<Object> value; | |
| 143 if (!instantiate_result.ToHandle(&value)) { | |
| 144 result = MaybeHandle<JSObject>(); | |
| 145 break; | |
| 146 } | |
| 147 auto add_result = | |
| 148 AddPropertyForTemplate(isolate, obj, name, value, attributes); | |
|
Toon Verwaest
2015/02/04 12:04:04
Can you change this to return a MaybeHandle<> rath
| |
| 149 if (add_result->IsException()) { | |
| 150 result = MaybeHandle<JSObject>(); | |
| 151 break; | |
| 152 } | |
| 153 } else { | |
| 154 DCHECK(length == 4 || length == 5); | |
| 155 // TODO(verwaest): The 5th value used to be access_control. Remove once | |
| 156 // the bindings are updated. | |
| 157 auto name = handle(Name::cast(properties.get(i + 1)), isolate); | |
| 158 auto getter = handle(properties.get(i + 2), isolate); | |
| 159 auto setter = handle(properties.get(i + 3), isolate); | |
| 160 auto attributes = Smi::cast(properties.get(i + 4)); | |
| 161 auto define_result = DefineApiAccessorProperty(isolate, obj, name, getter, | |
| 162 setter, attributes); | |
|
Toon Verwaest
2015/02/04 12:04:04
Same here
| |
| 163 if (define_result->IsException()) { | |
| 164 result = MaybeHandle<JSObject>(); | |
| 165 break; | |
| 166 } | |
| 167 } | |
| 168 i += length + 1; | |
| 169 } | |
| 170 if (requires_access_checks) { | |
| 171 EnableAccessChecks(isolate, obj); | |
| 172 } | |
| 173 // TODO(dcarney): return a Object* here? | |
| 174 return result; | |
| 175 } | |
| 176 | |
| 177 | |
| 178 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate, | |
| 179 Handle<ObjectTemplateInfo> data) { | |
| 180 // Enter a new scope. Recursion could otherwise create a lot of handles. | |
| 181 HandleScope scope(isolate); | |
| 182 // Fast path. | |
| 183 Handle<JSObject> result; | |
| 184 auto info = Handle<ObjectTemplateInfo>::cast(data); | |
| 185 auto constructor = handle(info->constructor(), isolate); | |
| 186 Handle<JSFunction> cons; | |
| 187 if (constructor->IsUndefined()) { | |
| 188 cons = isolate->object_function(); | |
| 189 } else { | |
| 190 auto cons_templ = Handle<FunctionTemplateInfo>::cast(constructor); | |
| 191 ASSIGN_RETURN_ON_EXCEPTION( | |
| 192 isolate, cons, InstantiateFunction(isolate, cons_templ), JSFunction); | |
| 193 } | |
| 194 auto object = isolate->factory()->NewJSObject(cons); | |
| 195 ASSIGN_RETURN_ON_EXCEPTION( | |
| 196 isolate, result, ConfigureInstance(isolate, object, info), JSFunction); | |
| 197 // TODO(dcarney): is this necessary? | |
| 198 JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject"); | |
| 199 return scope.CloseAndEscape(result); | |
| 200 } | |
| 201 | |
| 202 | |
| 203 void InstallInCache(Isolate* isolate, int serial_number, | |
| 204 Handle<JSFunction> function) { | |
| 205 Handle<FixedArray> cache(isolate->native_context()->function_cache()); | |
|
Toon Verwaest
2015/02/04 12:04:04
auto cache = isolate->function_cache();
| |
| 206 if (isolate->native_context()->function_cache()->length() <= serial_number) { | |
|
Toon Verwaest
2015/02/04 12:04:04
cache->length()
| |
| 207 int new_size; | |
| 208 if (isolate->next_serial_number() < 50) { | |
| 209 new_size = 100; | |
| 210 } else { | |
| 211 new_size = 3 * isolate->next_serial_number() / 2; | |
| 212 } | |
| 213 cache = FixedArray::CopySize(cache, new_size); | |
| 214 isolate->native_context()->set_function_cache(*cache); | |
| 215 } | |
| 216 cache->set(serial_number, *function); | |
| 217 } | |
| 218 | |
| 219 | |
| 220 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate, | |
| 221 Handle<FunctionTemplateInfo> data, | |
| 222 Handle<Name> name) { | |
| 223 int serial_number = Smi::cast(data->serial_number())->value(); | |
| 224 // Probe cache. | |
| 225 if (!data->do_not_cache()) { | |
| 226 Handle<FixedArray> cache(isolate->native_context()->function_cache()); | |
|
Toon Verwaest
2015/02/04 12:04:04
auto cache = isolate->function_cache()
| |
| 227 // Fast case: see if the function has already been instantiated | |
| 228 if (serial_number < cache->length()) { | |
| 229 Handle<Object> element = FixedArray::get(cache, serial_number); | |
| 230 if (element->IsJSFunction()) { | |
| 231 return Handle<JSFunction>::cast(element); | |
| 232 } | |
| 233 } | |
| 234 } | |
| 235 // Enter a new scope. Recursion could otherwise create a lot of handles. | |
| 236 HandleScope scope(isolate); | |
| 237 Handle<JSObject> prototype; | |
| 238 if (!data->remove_prototype()) { | |
| 239 auto prototype_templ = handle(data->prototype_template(), isolate); | |
| 240 if (prototype_templ->IsUndefined()) { | |
| 241 prototype = isolate->factory()->NewJSObject(isolate->object_function()); | |
| 242 } else { | |
| 243 ASSIGN_RETURN_ON_EXCEPTION( | |
| 244 isolate, prototype, | |
| 245 InstantiateObject(isolate, | |
| 246 Handle<ObjectTemplateInfo>::cast(prototype_templ)), | |
| 247 JSFunction); | |
| 248 } | |
| 249 auto parent = handle(data->parent_template(), isolate); | |
| 250 if (!parent->IsUndefined()) { | |
| 251 Handle<JSFunction> parent_instance; | |
| 252 ASSIGN_RETURN_ON_EXCEPTION( | |
| 253 isolate, parent_instance, | |
| 254 InstantiateFunction(isolate, | |
| 255 Handle<FunctionTemplateInfo>::cast(parent)), | |
| 256 JSFunction); | |
| 257 // TODO(dcarney): decide what to do here. | |
| 258 Handle<Object> parent_prototype; | |
| 259 ASSIGN_RETURN_ON_EXCEPTION( | |
| 260 isolate, parent_prototype, | |
| 261 JSObject::GetProperty(parent_instance, | |
| 262 isolate->factory()->prototype_string()), | |
| 263 JSFunction); | |
| 264 RETURN_ON_EXCEPTION( | |
| 265 isolate, JSObject::SetPrototype(prototype, parent_prototype, false), | |
| 266 JSFunction); | |
| 267 } | |
| 268 } | |
| 269 auto function = ApiNatives::CreateApiFunction( | |
| 270 isolate, data, prototype, ApiNatives::JavaScriptObjectType); | |
| 271 if (!name.is_null() && name->IsString()) { | |
| 272 function->shared()->set_name(*name); | |
| 273 } | |
| 274 if (!data->do_not_cache()) { | |
| 275 // Cache the function to limit recursion. | |
| 276 InstallInCache(isolate, serial_number, function); | |
| 277 } | |
| 278 auto result = ConfigureInstance(isolate, function, data); | |
| 279 if (result.is_null()) { | |
| 280 // uncache on error. | |
| 281 if (!data->do_not_cache()) { | |
| 282 Handle<FixedArray> cache(isolate->native_context()->function_cache()); | |
| 283 cache->set(serial_number, isolate->heap()->undefined_value()); | |
| 284 } | |
| 285 return MaybeHandle<JSFunction>(); | |
| 286 } | |
| 287 return scope.CloseAndEscape(function); | |
| 288 } | |
| 289 | |
| 290 | |
| 291 class InvokeScope { | |
| 292 public: | |
| 293 explicit InvokeScope(Isolate* isolate) | |
| 294 : isolate_(isolate), save_context_(isolate) {} | |
| 295 ~InvokeScope() { | |
| 296 bool has_exception = isolate_->has_pending_exception(); | |
| 297 if (has_exception) { | |
| 298 isolate_->ReportPendingMessages(); | |
| 299 } else { | |
| 300 isolate_->clear_pending_message(); | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 private: | |
| 305 Isolate* isolate_; | |
| 306 SaveContext save_context_; | |
| 307 }; | |
| 308 | |
| 309 } // namespace | |
| 310 | |
| 311 | |
| 312 MaybeHandle<JSFunction> ApiNatives::InstantiateFunction( | |
| 313 Handle<FunctionTemplateInfo> data) { | |
| 314 Isolate* isolate = data->GetIsolate(); | |
| 315 InvokeScope invoke_scope(isolate); | |
| 316 return ::v8::internal::InstantiateFunction(isolate, data); | |
| 317 } | |
| 318 | |
| 319 | |
| 320 MaybeHandle<JSObject> ApiNatives::InstantiateObject( | |
| 321 Handle<ObjectTemplateInfo> data) { | |
| 322 Isolate* isolate = data->GetIsolate(); | |
| 323 InvokeScope invoke_scope(isolate); | |
| 324 return ::v8::internal::InstantiateObject(isolate, data); | |
| 325 } | |
| 326 | |
| 327 | |
| 328 MaybeHandle<FunctionTemplateInfo> ApiNatives::ConfigureInstance( | |
| 329 Isolate* isolate, Handle<FunctionTemplateInfo> desc, | |
| 330 Handle<JSObject> instance) { | |
| 331 // Configure the instance by adding the properties specified by the | |
| 332 // instance template. | |
| 333 if (desc->instance_template()->IsUndefined()) return desc; | |
| 334 InvokeScope invoke_scope(isolate); | |
| 335 Handle<ObjectTemplateInfo> instance_template( | |
| 336 ObjectTemplateInfo::cast(desc->instance_template()), isolate); | |
| 337 RETURN_ON_EXCEPTION(isolate, ::v8::internal::ConfigureInstance( | |
| 338 isolate, instance, instance_template), | |
| 339 FunctionTemplateInfo); | |
| 340 return desc; | |
| 341 } | |
| 342 | |
| 343 | |
| 344 Handle<JSFunction> ApiNatives::CreateApiFunction( | |
| 345 Isolate* isolate, Handle<FunctionTemplateInfo> obj, | |
| 346 Handle<Object> prototype, ApiInstanceType instance_type) { | |
| 347 Handle<Code> code = isolate->builtins()->HandleApiCall(); | |
| 348 Handle<Code> construct_stub = isolate->builtins()->JSConstructStubApi(); | |
| 349 | |
| 350 obj->set_instantiated(true); | |
| 351 Handle<JSFunction> result; | |
| 352 if (obj->remove_prototype()) { | |
| 353 result = isolate->factory()->NewFunctionWithoutPrototype( | |
| 354 isolate->factory()->empty_string(), code); | |
| 355 } else { | |
| 356 int internal_field_count = 0; | |
| 357 if (!obj->instance_template()->IsUndefined()) { | |
| 358 Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>( | |
| 359 ObjectTemplateInfo::cast(obj->instance_template())); | |
| 360 internal_field_count = | |
| 361 Smi::cast(instance_template->internal_field_count())->value(); | |
| 362 } | |
| 363 | |
| 364 // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing | |
| 365 // JSObject::GetHeaderSize. | |
| 366 int instance_size = kPointerSize * internal_field_count; | |
| 367 InstanceType type; | |
| 368 switch (instance_type) { | |
| 369 case JavaScriptObjectType: | |
| 370 type = JS_OBJECT_TYPE; | |
| 371 instance_size += JSObject::kHeaderSize; | |
| 372 break; | |
| 373 case GlobalObjectType: | |
| 374 type = JS_GLOBAL_OBJECT_TYPE; | |
| 375 instance_size += JSGlobalObject::kSize; | |
| 376 break; | |
| 377 case GlobalProxyType: | |
| 378 type = JS_GLOBAL_PROXY_TYPE; | |
| 379 instance_size += JSGlobalProxy::kSize; | |
| 380 break; | |
| 381 default: | |
| 382 UNREACHABLE(); | |
| 383 type = JS_OBJECT_TYPE; // Keep the compiler happy. | |
| 384 break; | |
| 385 } | |
| 386 | |
| 387 result = isolate->factory()->NewFunction( | |
| 388 isolate->factory()->empty_string(), code, prototype, type, | |
| 389 instance_size, obj->read_only_prototype(), true); | |
| 390 } | |
| 391 | |
| 392 result->shared()->set_length(obj->length()); | |
| 393 Handle<Object> class_name(obj->class_name(), isolate); | |
| 394 if (class_name->IsString()) { | |
| 395 result->shared()->set_instance_class_name(*class_name); | |
| 396 result->shared()->set_name(*class_name); | |
| 397 } | |
| 398 result->shared()->set_function_data(*obj); | |
| 399 result->shared()->set_construct_stub(*construct_stub); | |
| 400 result->shared()->DontAdaptArguments(); | |
| 401 | |
| 402 if (obj->remove_prototype()) { | |
| 403 DCHECK(result->shared()->IsApiFunction()); | |
| 404 DCHECK(!result->has_initial_map()); | |
| 405 DCHECK(!result->has_prototype()); | |
| 406 return result; | |
| 407 } | |
| 408 | |
| 409 #ifdef DEBUG | |
| 410 LookupIterator it(handle(JSObject::cast(result->prototype())), | |
| 411 isolate->factory()->constructor_string(), | |
| 412 LookupIterator::OWN_SKIP_INTERCEPTOR); | |
| 413 MaybeHandle<Object> maybe_prop = Object::GetProperty(&it); | |
| 414 DCHECK(it.IsFound()); | |
| 415 DCHECK(maybe_prop.ToHandleChecked().is_identical_to(result)); | |
| 416 #endif | |
| 417 | |
| 418 // Down from here is only valid for API functions that can be used as a | |
| 419 // constructor (don't set the "remove prototype" flag). | |
| 420 | |
| 421 Handle<Map> map(result->initial_map()); | |
| 422 | |
| 423 // Mark as undetectable if needed. | |
| 424 if (obj->undetectable()) { | |
| 425 map->set_is_undetectable(); | |
| 426 } | |
| 427 | |
| 428 // Mark as hidden for the __proto__ accessor if needed. | |
| 429 if (obj->hidden_prototype()) { | |
| 430 map->set_is_hidden_prototype(); | |
| 431 } | |
| 432 | |
| 433 // Mark as needs_access_check if needed. | |
| 434 if (obj->needs_access_check()) { | |
| 435 map->set_is_access_check_needed(true); | |
| 436 } | |
| 437 | |
| 438 // Set interceptor information in the map. | |
| 439 if (!obj->named_property_handler()->IsUndefined()) { | |
| 440 map->set_has_named_interceptor(); | |
| 441 } | |
| 442 if (!obj->indexed_property_handler()->IsUndefined()) { | |
| 443 map->set_has_indexed_interceptor(); | |
| 444 } | |
| 445 | |
| 446 // Set instance call-as-function information in the map. | |
| 447 if (!obj->instance_call_handler()->IsUndefined()) { | |
| 448 map->set_has_instance_call_handler(); | |
| 449 } | |
| 450 | |
| 451 // Recursively copy parent instance templates' accessors, | |
| 452 // 'data' may be modified. | |
| 453 int max_number_of_additional_properties = 0; | |
| 454 int max_number_of_static_properties = 0; | |
| 455 FunctionTemplateInfo* info = *obj; | |
| 456 while (true) { | |
| 457 if (!info->instance_template()->IsUndefined()) { | |
| 458 Object* props = ObjectTemplateInfo::cast(info->instance_template()) | |
| 459 ->property_accessors(); | |
| 460 if (!props->IsUndefined()) { | |
| 461 Handle<Object> props_handle(props, isolate); | |
| 462 NeanderArray props_array(props_handle); | |
| 463 max_number_of_additional_properties += props_array.length(); | |
| 464 } | |
| 465 } | |
| 466 if (!info->property_accessors()->IsUndefined()) { | |
| 467 Object* props = info->property_accessors(); | |
| 468 if (!props->IsUndefined()) { | |
| 469 Handle<Object> props_handle(props, isolate); | |
| 470 NeanderArray props_array(props_handle); | |
| 471 max_number_of_static_properties += props_array.length(); | |
| 472 } | |
| 473 } | |
| 474 Object* parent = info->parent_template(); | |
| 475 if (parent->IsUndefined()) break; | |
| 476 info = FunctionTemplateInfo::cast(parent); | |
| 477 } | |
| 478 | |
| 479 Map::EnsureDescriptorSlack(map, max_number_of_additional_properties); | |
| 480 | |
| 481 // Use a temporary FixedArray to acculumate static accessors | |
| 482 int valid_descriptors = 0; | |
| 483 Handle<FixedArray> array; | |
| 484 if (max_number_of_static_properties > 0) { | |
| 485 array = isolate->factory()->NewFixedArray(max_number_of_static_properties); | |
| 486 } | |
| 487 | |
| 488 while (true) { | |
| 489 // Install instance descriptors | |
| 490 if (!obj->instance_template()->IsUndefined()) { | |
| 491 Handle<ObjectTemplateInfo> instance = Handle<ObjectTemplateInfo>( | |
| 492 ObjectTemplateInfo::cast(obj->instance_template()), isolate); | |
| 493 Handle<Object> props = | |
| 494 Handle<Object>(instance->property_accessors(), isolate); | |
| 495 if (!props->IsUndefined()) { | |
| 496 Map::AppendCallbackDescriptors(map, props); | |
| 497 } | |
| 498 } | |
| 499 // Accumulate static accessors | |
| 500 if (!obj->property_accessors()->IsUndefined()) { | |
| 501 Handle<Object> props = Handle<Object>(obj->property_accessors(), isolate); | |
| 502 valid_descriptors = | |
| 503 AccessorInfo::AppendUnique(props, array, valid_descriptors); | |
| 504 } | |
| 505 // Climb parent chain | |
| 506 Handle<Object> parent = Handle<Object>(obj->parent_template(), isolate); | |
| 507 if (parent->IsUndefined()) break; | |
| 508 obj = Handle<FunctionTemplateInfo>::cast(parent); | |
| 509 } | |
| 510 | |
| 511 // Install accumulated static accessors | |
| 512 for (int i = 0; i < valid_descriptors; i++) { | |
| 513 Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i))); | |
| 514 JSObject::SetAccessor(result, accessor).Assert(); | |
| 515 } | |
| 516 | |
| 517 DCHECK(result->shared()->IsApiFunction()); | |
| 518 return result; | |
| 519 } | |
| 520 | |
| 521 } // namespace internal | |
| 522 } // namespace v8 | |
| OLD | NEW |