Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/api-natives.cc b/src/api-natives.cc
new file mode 100644
index 0000000..bc71e3e
--- /dev/null
+++ b/src/api-natives.cc
@@ -0,0 +1,625 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/api-natives.h"
+
+#include "src/api.h"
+#include "src/isolate-inl.h"
+#include "src/lookup.h"
+#include "src/messages.h"
+
+namespace v8 {
+namespace internal {
+
+
+namespace {
+
+MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
+ Handle<ObjectTemplateInfo> data);
+
+
+MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
+ Handle<FunctionTemplateInfo> data,
+ Handle<Name> name = Handle<Name>());
+
+
+MaybeHandle<Object> Instantiate(Isolate* isolate, Handle<Object> data,
+ Handle<Name> name = Handle<Name>()) {
+ if (data->IsFunctionTemplateInfo()) {
+ return InstantiateFunction(isolate,
+ Handle<FunctionTemplateInfo>::cast(data), name);
+ } else if (data->IsObjectTemplateInfo()) {
+ return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data));
+ } else {
+ return data;
+ }
+}
+
+
+MaybeHandle<Object> DefineAccessorProperty(Isolate* isolate,
+ Handle<JSObject> object,
+ Handle<Name> name,
+ Handle<Object> getter,
+ Handle<Object> setter,
+ PropertyAttributes attributes) {
+ if (!getter->IsUndefined()) {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, getter,
+ InstantiateFunction(isolate,
+ Handle<FunctionTemplateInfo>::cast(getter)),
+ Object);
+ }
+ if (!setter->IsUndefined()) {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, setter,
+ InstantiateFunction(isolate,
+ Handle<FunctionTemplateInfo>::cast(setter)),
+ Object);
+ }
+ RETURN_ON_EXCEPTION(isolate, JSObject::DefineAccessor(object, name, getter,
+ setter, attributes),
+ Object);
+ return object;
+}
+
+
+MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
+ Handle<JSObject> object,
+ Handle<Name> name,
+ Handle<Object> prop_data,
+ PropertyAttributes attributes) {
+ Handle<Object> value;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
+ Instantiate(isolate, prop_data, name), Object);
+
+ LookupIterator it = LookupIterator::PropertyOrElement(
+ isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
+
+#ifdef DEBUG
+ Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+ DCHECK(maybe.IsJust());
+ if (it.IsFound()) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
+ Object);
+ }
+#endif
+
+ MAYBE_RETURN_NULL(
+ Object::AddDataProperty(&it, value, attributes, Object::THROW_ON_ERROR,
+ Object::CERTAINLY_NOT_STORE_FROM_KEYED));
+ return value;
+}
+
+
+void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
+ Handle<Map> old_map(object->map());
+ // Copy map so it won't interfere constructor's initial map.
+ Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks");
+ new_map->set_is_access_check_needed(false);
+ JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
+}
+
+
+void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
+ Handle<Map> old_map(object->map());
+ // Copy map so it won't interfere constructor's initial map.
+ Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks");
+ new_map->set_is_access_check_needed(true);
+ JSObject::MigrateToMap(object, new_map);
+}
+
+
+class AccessCheckDisableScope {
+ public:
+ AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
+ : isolate_(isolate),
+ disabled_(obj->map()->is_access_check_needed()),
+ obj_(obj) {
+ if (disabled_) {
+ DisableAccessChecks(isolate_, obj_);
+ }
+ }
+ ~AccessCheckDisableScope() {
+ if (disabled_) {
+ EnableAccessChecks(isolate_, obj_);
+ }
+ }
+
+ private:
+ Isolate* isolate_;
+ const bool disabled_;
+ Handle<JSObject> obj_;
+};
+
+
+Object* GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
+ Handle<Context> native_context = isolate->native_context();
+ DCHECK(!native_context.is_null());
+ switch (intrinsic) {
+#define GET_INTRINSIC_VALUE(name, iname) \
+ case v8::k##name: \
+ return native_context->iname();
+ V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
+#undef GET_INTRINSIC_VALUE
+ }
+ return nullptr;
+}
+
+
+MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
+ Handle<TemplateInfo> data) {
+ auto property_list = handle(data->property_list(), isolate);
+ if (property_list->IsUndefined()) return obj;
+ // TODO(dcarney): just use a FixedArray here.
+ NeanderArray properties(property_list);
+ if (properties.length() == 0) return obj;
+ HandleScope scope(isolate);
+ // Disable access checks while instantiating the object.
+ AccessCheckDisableScope access_check_scope(isolate, obj);
+
+ int i = 0;
+ for (int c = 0; c < data->number_of_properties(); c++) {
+ auto name = handle(Name::cast(properties.get(i++)), isolate);
+ auto bit = handle(properties.get(i++), isolate);
+ if (bit->IsSmi()) {
+ PropertyDetails details(Smi::cast(*bit));
+ PropertyAttributes attributes = details.attributes();
+ PropertyKind kind = details.kind();
+
+ if (kind == kData) {
+ auto prop_data = handle(properties.get(i++), isolate);
+
+ RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
+ prop_data, attributes),
+ JSObject);
+ } else {
+ auto getter = handle(properties.get(i++), isolate);
+ auto setter = handle(properties.get(i++), isolate);
+ RETURN_ON_EXCEPTION(isolate,
+ DefineAccessorProperty(isolate, obj, name, getter,
+ setter, attributes),
+ JSObject);
+ }
+ } else {
+ // Intrinsic data property --- Get appropriate value from the current
+ // context.
+ PropertyDetails details(Smi::cast(properties.get(i++)));
+ PropertyAttributes attributes = details.attributes();
+ DCHECK_EQ(kData, details.kind());
+
+ v8::Intrinsic intrinsic =
+ static_cast<v8::Intrinsic>(Smi::cast(properties.get(i++))->value());
+ auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
+
+ RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
+ prop_data, attributes),
+ JSObject);
+ }
+ }
+ return obj;
+}
+
+
+MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
+ Handle<ObjectTemplateInfo> data) {
+ // Enter a new scope. Recursion could otherwise create a lot of handles.
+ HandleScope scope(isolate);
+ // Fast path.
+ Handle<JSObject> result;
+ auto info = Handle<ObjectTemplateInfo>::cast(data);
+ auto constructor = handle(info->constructor(), isolate);
+ Handle<JSFunction> cons;
+ if (constructor->IsUndefined()) {
+ cons = isolate->object_function();
+ } else {
+ auto cons_templ = Handle<FunctionTemplateInfo>::cast(constructor);
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, cons, InstantiateFunction(isolate, cons_templ), JSFunction);
+ }
+ auto object = isolate->factory()->NewJSObject(cons);
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, result, ConfigureInstance(isolate, object, info), JSFunction);
+ // TODO(dcarney): is this necessary?
+ JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
+ return scope.CloseAndEscape(result);
+}
+
+
+void CacheFunction(Isolate* isolate, Handle<Smi> serial_number,
+ Handle<JSFunction> function) {
+ auto cache = isolate->function_cache();
+ auto new_cache = ObjectHashTable::Put(cache, serial_number, function);
+ isolate->native_context()->set_function_cache(*new_cache);
+}
+
+
+void UncacheFunction(Isolate* isolate, Handle<Smi> serial_number) {
+ auto cache = isolate->function_cache();
+ bool was_present = false;
+ auto new_cache = ObjectHashTable::Remove(cache, serial_number, &was_present);
+ DCHECK(was_present);
+ isolate->native_context()->set_function_cache(*new_cache);
+}
+
+
+MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
+ Handle<FunctionTemplateInfo> data,
+ Handle<Name> name) {
+ auto serial_number = handle(Smi::cast(data->serial_number()), isolate);
+ // Probe cache.
+ if (!data->do_not_cache()) {
+ auto cache = isolate->function_cache();
+ Object* element = cache->Lookup(serial_number);
+ if (element->IsJSFunction()) {
+ return handle(JSFunction::cast(element), isolate);
+ }
+ }
+ // Enter a new scope. Recursion could otherwise create a lot of handles.
+ HandleScope scope(isolate);
+ Handle<JSObject> prototype;
+ if (!data->remove_prototype()) {
+ auto prototype_templ = handle(data->prototype_template(), isolate);
+ if (prototype_templ->IsUndefined()) {
+ prototype = isolate->factory()->NewJSObject(isolate->object_function());
+ } else {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, prototype,
+ InstantiateObject(isolate,
+ Handle<ObjectTemplateInfo>::cast(prototype_templ)),
+ JSFunction);
+ }
+ auto parent = handle(data->parent_template(), isolate);
+ if (!parent->IsUndefined()) {
+ Handle<JSFunction> parent_instance;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, parent_instance,
+ InstantiateFunction(isolate,
+ Handle<FunctionTemplateInfo>::cast(parent)),
+ JSFunction);
+ // TODO(dcarney): decide what to do here.
+ Handle<Object> parent_prototype;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, parent_prototype,
+ JSObject::GetProperty(parent_instance,
+ isolate->factory()->prototype_string()),
+ JSFunction);
+ MAYBE_RETURN(JSObject::SetPrototype(prototype, parent_prototype, false,
+ Object::THROW_ON_ERROR),
+ MaybeHandle<JSFunction>());
+ }
+ }
+ auto function = ApiNatives::CreateApiFunction(
+ isolate, data, prototype, ApiNatives::JavaScriptObjectType);
+ if (!name.is_null() && name->IsString()) {
+ function->shared()->set_name(*name);
+ }
+ if (!data->do_not_cache()) {
+ // Cache the function.
+ CacheFunction(isolate, serial_number, function);
+ }
+ auto result = ConfigureInstance(isolate, function, data);
+ if (result.is_null()) {
+ // Uncache on error.
+ if (!data->do_not_cache()) {
+ UncacheFunction(isolate, serial_number);
+ }
+ return MaybeHandle<JSFunction>();
+ }
+ return scope.CloseAndEscape(function);
+}
+
+
+class InvokeScope {
+ public:
+ explicit InvokeScope(Isolate* isolate)
+ : isolate_(isolate), save_context_(isolate) {}
+ ~InvokeScope() {
+ bool has_exception = isolate_->has_pending_exception();
+ if (has_exception) {
+ isolate_->ReportPendingMessages();
+ } else {
+ isolate_->clear_pending_message();
+ }
+ }
+
+ private:
+ Isolate* isolate_;
+ SaveContext save_context_;
+};
+
+
+void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
+ int length, Handle<Object>* data) {
+ auto list = handle(templ->property_list(), isolate);
+ if (list->IsUndefined()) {
+ list = NeanderArray(isolate).value();
+ templ->set_property_list(*list);
+ }
+ templ->set_number_of_properties(templ->number_of_properties() + 1);
+ NeanderArray array(list);
+ for (int i = 0; i < length; i++) {
+ Handle<Object> value =
+ data[i].is_null()
+ ? Handle<Object>::cast(isolate->factory()->undefined_value())
+ : data[i];
+ array.add(isolate, value);
+ }
+}
+
+} // namespace
+
+
+MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
+ Handle<FunctionTemplateInfo> data) {
+ Isolate* isolate = data->GetIsolate();
+ InvokeScope invoke_scope(isolate);
+ return ::v8::internal::InstantiateFunction(isolate, data);
+}
+
+
+MaybeHandle<JSObject> ApiNatives::InstantiateObject(
+ Handle<ObjectTemplateInfo> data) {
+ Isolate* isolate = data->GetIsolate();
+ InvokeScope invoke_scope(isolate);
+ return ::v8::internal::InstantiateObject(isolate, data);
+}
+
+
+MaybeHandle<FunctionTemplateInfo> ApiNatives::ConfigureInstance(
+ Isolate* isolate, Handle<FunctionTemplateInfo> desc,
+ Handle<JSObject> instance) {
+ // Configure the instance by adding the properties specified by the
+ // instance template.
+ if (desc->instance_template()->IsUndefined()) return desc;
+ InvokeScope invoke_scope(isolate);
+ Handle<ObjectTemplateInfo> instance_template(
+ ObjectTemplateInfo::cast(desc->instance_template()), isolate);
+ RETURN_ON_EXCEPTION(isolate, ::v8::internal::ConfigureInstance(
+ isolate, instance, instance_template),
+ FunctionTemplateInfo);
+ return desc;
+}
+
+
+void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
+ Handle<Name> name, Handle<Object> value,
+ PropertyAttributes attributes) {
+ const int kSize = 3;
+ PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
+ auto details_handle = handle(details.AsSmi(), isolate);
+ Handle<Object> data[kSize] = {name, details_handle, value};
+ AddPropertyToPropertyList(isolate, info, kSize, data);
+}
+
+
+void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
+ Handle<Name> name, v8::Intrinsic intrinsic,
+ PropertyAttributes attributes) {
+ const int kSize = 4;
+ auto value = handle(Smi::FromInt(intrinsic), isolate);
+ auto intrinsic_marker = isolate->factory()->true_value();
+ PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
+ auto details_handle = handle(details.AsSmi(), isolate);
+ Handle<Object> data[kSize] = {name, intrinsic_marker, details_handle, value};
+ AddPropertyToPropertyList(isolate, info, kSize, data);
+}
+
+
+void ApiNatives::AddAccessorProperty(Isolate* isolate,
+ Handle<TemplateInfo> info,
+ Handle<Name> name,
+ Handle<FunctionTemplateInfo> getter,
+ Handle<FunctionTemplateInfo> setter,
+ PropertyAttributes attributes) {
+ const int kSize = 4;
+ PropertyDetails details(attributes, ACCESSOR, 0, PropertyCellType::kNoCell);
+ auto details_handle = handle(details.AsSmi(), isolate);
+ Handle<Object> data[kSize] = {name, details_handle, getter, setter};
+ AddPropertyToPropertyList(isolate, info, kSize, data);
+}
+
+
+void ApiNatives::AddNativeDataProperty(Isolate* isolate,
+ Handle<TemplateInfo> info,
+ Handle<AccessorInfo> property) {
+ auto list = handle(info->property_accessors(), isolate);
+ if (list->IsUndefined()) {
+ list = NeanderArray(isolate).value();
+ info->set_property_accessors(*list);
+ }
+ NeanderArray array(list);
+ array.add(isolate, property);
+}
+
+
+Handle<JSFunction> ApiNatives::CreateApiFunction(
+ Isolate* isolate, Handle<FunctionTemplateInfo> obj,
+ Handle<Object> prototype, ApiInstanceType instance_type) {
+ Handle<Code> code;
+ if (obj->call_code()->IsCallHandlerInfo() &&
+ CallHandlerInfo::cast(obj->call_code())->fast_handler()->IsCode()) {
+ code = isolate->builtins()->HandleFastApiCall();
+ } else {
+ code = isolate->builtins()->HandleApiCall();
+ }
+ Handle<Code> construct_stub =
+ prototype.is_null() ? isolate->builtins()->ConstructedNonConstructable()
+ : isolate->builtins()->JSConstructStubApi();
+
+ obj->set_instantiated(true);
+ Handle<JSFunction> result;
+ if (obj->remove_prototype()) {
+ result = isolate->factory()->NewFunctionWithoutPrototype(
+ isolate->factory()->empty_string(), code);
+ } else {
+ int internal_field_count = 0;
+ if (!obj->instance_template()->IsUndefined()) {
+ Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
+ ObjectTemplateInfo::cast(obj->instance_template()));
+ internal_field_count =
+ Smi::cast(instance_template->internal_field_count())->value();
+ }
+
+ // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing
+ // JSObject::GetHeaderSize.
+ int instance_size = kPointerSize * internal_field_count;
+ InstanceType type;
+ switch (instance_type) {
+ case JavaScriptObjectType:
+ type = JS_OBJECT_TYPE;
+ instance_size += JSObject::kHeaderSize;
+ break;
+ case GlobalObjectType:
+ type = JS_GLOBAL_OBJECT_TYPE;
+ instance_size += JSGlobalObject::kSize;
+ break;
+ case GlobalProxyType:
+ type = JS_GLOBAL_PROXY_TYPE;
+ instance_size += JSGlobalProxy::kSize;
+ break;
+ default:
+ UNREACHABLE();
+ type = JS_OBJECT_TYPE; // Keep the compiler happy.
+ break;
+ }
+
+ result = isolate->factory()->NewFunction(
+ isolate->factory()->empty_string(), code, prototype, type,
+ instance_size, obj->read_only_prototype(), true);
+ }
+
+ result->shared()->set_length(obj->length());
+ Handle<Object> class_name(obj->class_name(), isolate);
+ if (class_name->IsString()) {
+ result->shared()->set_instance_class_name(*class_name);
+ result->shared()->set_name(*class_name);
+ }
+ result->shared()->set_function_data(*obj);
+ result->shared()->set_construct_stub(*construct_stub);
+ result->shared()->DontAdaptArguments();
+
+ if (obj->remove_prototype()) {
+ DCHECK(result->shared()->IsApiFunction());
+ DCHECK(!result->has_initial_map());
+ DCHECK(!result->has_prototype());
+ return result;
+ }
+
+#ifdef DEBUG
+ LookupIterator it(handle(JSObject::cast(result->prototype())),
+ isolate->factory()->constructor_string(),
+ LookupIterator::OWN_SKIP_INTERCEPTOR);
+ MaybeHandle<Object> maybe_prop = Object::GetProperty(&it);
+ DCHECK(it.IsFound());
+ DCHECK(maybe_prop.ToHandleChecked().is_identical_to(result));
+#endif
+
+ // Down from here is only valid for API functions that can be used as a
+ // constructor (don't set the "remove prototype" flag).
+
+ Handle<Map> map(result->initial_map());
+
+ // Mark as undetectable if needed.
+ if (obj->undetectable()) {
+ map->set_is_undetectable();
+ }
+
+ // Mark as hidden for the __proto__ accessor if needed.
+ if (obj->hidden_prototype()) {
+ map->set_is_hidden_prototype();
+ }
+
+ // Mark as needs_access_check if needed.
+ if (obj->needs_access_check()) {
+ map->set_is_access_check_needed(true);
+ }
+
+ // Set interceptor information in the map.
+ if (!obj->named_property_handler()->IsUndefined()) {
+ map->set_has_named_interceptor();
+ }
+ if (!obj->indexed_property_handler()->IsUndefined()) {
+ map->set_has_indexed_interceptor();
+ }
+
+ // Mark instance as callable in the map.
+ if (!obj->instance_call_handler()->IsUndefined()) {
+ map->set_is_callable();
+ map->set_is_constructor();
+ }
+
+ // Recursively copy parent instance templates' accessors,
+ // 'data' may be modified.
+ int max_number_of_additional_properties = 0;
+ int max_number_of_static_properties = 0;
+ FunctionTemplateInfo* info = *obj;
+ while (true) {
+ if (!info->instance_template()->IsUndefined()) {
+ Object* props = ObjectTemplateInfo::cast(info->instance_template())
+ ->property_accessors();
+ if (!props->IsUndefined()) {
+ Handle<Object> props_handle(props, isolate);
+ NeanderArray props_array(props_handle);
+ max_number_of_additional_properties += props_array.length();
+ }
+ }
+ if (!info->property_accessors()->IsUndefined()) {
+ Object* props = info->property_accessors();
+ if (!props->IsUndefined()) {
+ Handle<Object> props_handle(props, isolate);
+ NeanderArray props_array(props_handle);
+ max_number_of_static_properties += props_array.length();
+ }
+ }
+ Object* parent = info->parent_template();
+ if (parent->IsUndefined()) break;
+ info = FunctionTemplateInfo::cast(parent);
+ }
+
+ Map::EnsureDescriptorSlack(map, max_number_of_additional_properties);
+
+ // Use a temporary FixedArray to acculumate static accessors
+ int valid_descriptors = 0;
+ Handle<FixedArray> array;
+ if (max_number_of_static_properties > 0) {
+ array = isolate->factory()->NewFixedArray(max_number_of_static_properties);
+ }
+
+ while (true) {
+ // Install instance descriptors
+ if (!obj->instance_template()->IsUndefined()) {
+ Handle<ObjectTemplateInfo> instance = Handle<ObjectTemplateInfo>(
+ ObjectTemplateInfo::cast(obj->instance_template()), isolate);
+ Handle<Object> props =
+ Handle<Object>(instance->property_accessors(), isolate);
+ if (!props->IsUndefined()) {
+ Map::AppendCallbackDescriptors(map, props);
+ }
+ }
+ // Accumulate static accessors
+ if (!obj->property_accessors()->IsUndefined()) {
+ Handle<Object> props = Handle<Object>(obj->property_accessors(), isolate);
+ valid_descriptors =
+ AccessorInfo::AppendUnique(props, array, valid_descriptors);
+ }
+ // Climb parent chain
+ Handle<Object> parent = Handle<Object>(obj->parent_template(), isolate);
+ if (parent->IsUndefined()) break;
+ obj = Handle<FunctionTemplateInfo>::cast(parent);
+ }
+
+ // Install accumulated static accessors
+ for (int i = 0; i < valid_descriptors; i++) {
+ Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)));
+ JSObject::SetAccessor(result, accessor).Assert();
+ }
+
+ DCHECK(result->shared()->IsApiFunction());
+ return result;
+}
+
+} // namespace internal
+} // namespace v8