blob: 0969726915e4033bc9dfa6592b397f959d9d8649 [file] [log] [blame]
// Copyright 2019 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/builtins/builtins-object-gen.h'
namespace runtime {
extern transitioning runtime ObjectIsExtensible(
implicit context: Context)(JSAny): JSAny;
extern transitioning runtime JSReceiverPreventExtensionsThrow(
implicit context: Context)(JSReceiver): JSAny;
extern transitioning runtime JSReceiverPreventExtensionsDontThrow(
implicit context: Context)(JSReceiver): JSAny;
extern transitioning runtime JSReceiverGetPrototypeOf(
implicit context: Context)(JSReceiver): JSAny;
extern transitioning runtime JSReceiverSetPrototypeOfThrow(
implicit context: Context)(JSReceiver, JSAny): JSAny;
extern transitioning runtime JSReceiverSetPrototypeOfDontThrow(
implicit context: Context)(JSReceiver, JSAny): JSAny;
extern transitioning runtime ObjectCreate(
implicit context: Context)(JSAny, JSAny): JSAny;
} // namespace runtime
namespace object {
transitioning macro ObjectIsExtensibleImpl(
implicit context: Context)(object: JSAny): JSAny {
const objectJSReceiver = Cast<JSReceiver>(object) otherwise return False;
const objectJSProxy = Cast<JSProxy>(objectJSReceiver)
otherwise return runtime::ObjectIsExtensible(objectJSReceiver);
return proxy::ProxyIsExtensible(objectJSProxy);
}
transitioning macro ObjectPreventExtensionsThrow(
implicit context: Context)(object: JSAny): JSAny {
const objectJSReceiver = Cast<JSReceiver>(object) otherwise return object;
const objectJSProxy = Cast<JSProxy>(objectJSReceiver)
otherwise return runtime::JSReceiverPreventExtensionsThrow(objectJSReceiver);
proxy::ProxyPreventExtensions(objectJSProxy, True);
return objectJSReceiver;
}
transitioning macro ObjectPreventExtensionsDontThrow(
implicit context: Context)(object: JSAny): JSAny {
const objectJSReceiver = Cast<JSReceiver>(object) otherwise return False;
const objectJSProxy = Cast<JSProxy>(objectJSReceiver)
otherwise return runtime::JSReceiverPreventExtensionsDontThrow(
objectJSReceiver);
return proxy::ProxyPreventExtensions(objectJSProxy, False);
}
transitioning macro ObjectGetPrototypeOfImpl(
implicit context: Context)(object: JSAny): JSAny {
const objectJSReceiver: JSReceiver = ToObject_Inline(context, object);
return object::JSReceiverGetPrototypeOf(objectJSReceiver);
}
transitioning macro JSReceiverGetPrototypeOf(
implicit context: Context)(object: JSReceiver): JSAny {
const objectJSProxy = Cast<JSProxy>(object)
otherwise return runtime::JSReceiverGetPrototypeOf(object);
return proxy::ProxyGetPrototypeOf(objectJSProxy);
}
transitioning macro ObjectSetPrototypeOfThrow(
implicit context: Context)(object: JSAny, proto: JSReceiver|Null): JSAny {
const objectJSReceiver = Cast<JSReceiver>(object) otherwise return object;
const objectJSProxy = Cast<JSProxy>(objectJSReceiver)
otherwise return runtime::JSReceiverSetPrototypeOfThrow(
objectJSReceiver, proto);
proxy::ProxySetPrototypeOf(objectJSProxy, proto, True);
return objectJSReceiver;
}
transitioning macro ObjectSetPrototypeOfDontThrow(
implicit context: Context)(object: JSAny, proto: JSReceiver|Null): JSAny {
const objectJSReceiver = Cast<JSReceiver>(object) otherwise return False;
const objectJSProxy = Cast<JSProxy>(objectJSReceiver)
otherwise return runtime::JSReceiverSetPrototypeOfDontThrow(
objectJSReceiver, proto);
return proxy::ProxySetPrototypeOf(objectJSProxy, proto, False);
}
transitioning builtin CreateObjectWithoutProperties(
implicit context: Context)(prototype: JSAny): JSAny {
try {
let map: Map;
let properties: NameDictionary|SwissNameDictionary|EmptyFixedArray;
typeswitch (prototype) {
case (Null): {
map = *NativeContextSlot(
ContextSlot::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP);
@if(V8_ENABLE_SWISS_NAME_DICTIONARY) {
properties =
AllocateSwissNameDictionary(kSwissNameDictionaryInitialCapacity);
}
@ifnot(V8_ENABLE_SWISS_NAME_DICTIONARY) {
properties = AllocateNameDictionary(kNameDictionaryInitialCapacity);
}
}
case (prototype: JSReceiver): {
properties = kEmptyFixedArray;
const objectFunction =
*NativeContextSlot(ContextSlot::OBJECT_FUNCTION_INDEX);
map = UnsafeCast<Map>(objectFunction.prototype_or_initial_map);
if (prototype != map.prototype) {
const prototypeInfo = prototype.map.PrototypeInfo() otherwise Runtime;
typeswitch (prototypeInfo.derived_maps) {
case (Undefined): {
goto Runtime;
}
case (derived_maps: WeakArrayList): {
const theMap = MaybeObjectToStrong(derived_maps.objects[0])
otherwise Runtime;
map = UnsafeCast<Map>(theMap);
}
}
}
}
case (JSAny): {
goto Runtime;
}
}
return AllocateJSObjectFromMap(map, properties);
} label Runtime deferred {
return runtime::ObjectCreate(prototype, Undefined);
}
}
// ES6 section 19.1.2.11 Object.isExtensible ( O )
transitioning javascript builtin ObjectIsExtensible(
js-implicit context: NativeContext)(object: JSAny): JSAny {
return object::ObjectIsExtensibleImpl(object);
}
// ES6 section 19.1.2.18 Object.preventExtensions ( O )
transitioning javascript builtin ObjectPreventExtensions(
js-implicit context: NativeContext)(object: JSAny): JSAny {
return object::ObjectPreventExtensionsThrow(object);
}
// ES6 section 19.1.2.9 Object.getPrototypeOf ( O )
transitioning javascript builtin ObjectGetPrototypeOf(
js-implicit context: NativeContext)(object: JSAny): JSAny {
return object::ObjectGetPrototypeOfImpl(object);
}
// ES6 section 19.1.2.21 Object.setPrototypeOf ( O, proto )
transitioning javascript builtin ObjectSetPrototypeOf(
js-implicit context: NativeContext)(object: JSAny, proto: JSAny): JSAny {
// 1. Set O to ? RequireObjectCoercible(O).
RequireObjectCoercible(object, 'Object.setPrototypeOf');
// 2. If Type(proto) is neither Object nor Null, throw a TypeError
// exception.
// 3. If Type(O) is not Object, return O.
// 4. Let status be ? O.[[SetPrototypeOf]](proto).
// 5. If status is false, throw a TypeError exception.
// 6. Return O.
typeswitch (proto) {
case (proto: JSReceiver|Null): {
return object::ObjectSetPrototypeOfThrow(object, proto);
}
case (JSAny): {
ThrowTypeError(MessageTemplate::kProtoObjectOrNull, proto);
}
}
}
// ES #sec-object.prototype.tostring
transitioning javascript builtin ObjectPrototypeToString(
js-implicit context: Context, receiver: JSAny)(): String {
return ObjectToString(context, receiver);
}
// ES #sec-object.prototype.valueof
transitioning javascript builtin ObjectPrototypeValueOf(
js-implicit context: Context, receiver: JSAny)(): JSReceiver {
// 1. Return ? ToObject(this value).
return ToObject_Inline(context, receiver);
}
// ES #sec-object.prototype.tolocalestring
transitioning javascript builtin ObjectPrototypeToLocaleString(
js-implicit context: Context, receiver: JSAny)(): JSAny {
// 1. Let O be the this value.
// 2. Return ? Invoke(O, "toString").
if (receiver == Null || receiver == Undefined) deferred {
ThrowTypeError(
MessageTemplate::kCalledOnNullOrUndefined,
'Object.prototype.toLocaleString');
}
const method = GetProperty(receiver, 'toString');
return Call(context, method, receiver);
}
// JSDataPropertyDescriptor constants
const kJSDataPropertyDescriptorWritableOffset: constexpr int31
generates 'JSDataPropertyDescriptor::kWritableOffset';
const kJSDataPropertyDescriptorEnumerableOffset: constexpr int31
generates 'JSDataPropertyDescriptor::kEnumerableOffset';
const kJSDataPropertyDescriptorConfigurableOffset: constexpr int31
generates 'JSDataPropertyDescriptor::kConfigurableOffset';
const kJSDataPropertyDescriptorValueOffset: constexpr int31
generates 'JSDataPropertyDescriptor::kValueOffset';
// JSAccessorPropertyDescriptor constants
const kJSAccessorPropertyDescriptorEnumerableOffset: constexpr int31
generates 'JSAccessorPropertyDescriptor::kEnumerableOffset';
const kJSAccessorPropertyDescriptorConfigurableOffset: constexpr int31
generates 'JSAccessorPropertyDescriptor::kConfigurableOffset';
const kJSAccessorPropertyDescriptorGetOffset: constexpr int31
generates 'JSAccessorPropertyDescriptor::kGetOffset';
const kJSAccessorPropertyDescriptorSetOffset: constexpr int31
generates 'JSAccessorPropertyDescriptor::kSetOffset';
// ToPropertyDescriptor (https://tc39.es/ecma262/#sec-topropertydescriptor)
transitioning macro ToPropertyDescriptor(
implicit context: Context)(object: JSReceiver): PropertyDescriptorObject {
const result: PropertyDescriptorObject = AllocatePropertyDescriptorObject();
if (object.map == *NativeContextSlot<Map>(
context, ContextSlot::DATA_PROPERTY_DESCRIPTOR_MAP_INDEX)) {
const writable = UnsafeCast<JSAny>(
LoadObjectField(object, kJSDataPropertyDescriptorWritableOffset));
result.flags.has_writable = true;
result.flags.is_writable = ToBoolean(writable);
const enumerable = UnsafeCast<JSAny>(
LoadObjectField(object, kJSDataPropertyDescriptorEnumerableOffset));
result.flags.has_enumerable = true;
result.flags.is_enumerable = ToBoolean(enumerable);
const configurable = UnsafeCast<JSAny>(
LoadObjectField(object, kJSDataPropertyDescriptorConfigurableOffset));
result.flags.has_configurable = true;
result.flags.is_configurable = ToBoolean(configurable);
result.flags.has_value = true;
result.value = UnsafeCast<JSAny>(
LoadObjectField(object, kJSDataPropertyDescriptorValueOffset));
} else if (
object.map == *NativeContextSlot<Map>(
context, ContextSlot::ACCESSOR_PROPERTY_DESCRIPTOR_MAP_INDEX)) {
const enumerable = UnsafeCast<JSAny>(
LoadObjectField(object, kJSAccessorPropertyDescriptorEnumerableOffset));
result.flags.has_enumerable = true;
result.flags.is_enumerable = ToBoolean(enumerable);
const configurable = UnsafeCast<JSAny>(LoadObjectField(
object, kJSAccessorPropertyDescriptorConfigurableOffset));
result.flags.has_configurable = true;
result.flags.is_configurable = ToBoolean(configurable);
result.flags.has_get = true;
result.get = UnsafeCast<JSAny>(
LoadObjectField(object, kJSAccessorPropertyDescriptorGetOffset));
result.flags.has_set = true;
result.set = UnsafeCast<JSAny>(
LoadObjectField(object, kJSAccessorPropertyDescriptorSetOffset));
} else {
const hasEnumerable = HasProperty(object, 'enumerable');
if (hasEnumerable == True) {
const enumerable = ToBoolean(GetProperty(object, 'enumerable'));
result.flags.has_enumerable = true;
result.flags.is_enumerable = enumerable;
}
const hasConfigurable = HasProperty(object, 'configurable');
if (hasConfigurable == True) {
const configurable = ToBoolean(GetProperty(object, 'configurable'));
result.flags.has_configurable = true;
result.flags.is_configurable = configurable;
}
const hasValue = HasProperty(object, 'value');
if (hasValue == True) {
const value = GetProperty(object, 'value');
result.flags.has_value = true;
result.value = value;
}
const hasWritable = HasProperty(object, 'writable');
if (hasWritable == True) {
const writable = ToBoolean(GetProperty(object, 'writable'));
result.flags.has_writable = true;
result.flags.is_writable = writable;
}
const hasGet = HasProperty(object, 'get');
if (hasGet == True) {
let getter = GetProperty(object, 'get');
if (!Is<Undefined>(getter) && !Is<FunctionTemplateInfo>(getter)) {
getter = Cast<Callable>(getter) otherwise ThrowTypeError(
MessageTemplate::kObjectGetterCallable, getter);
}
result.flags.has_get = true;
result.get = getter;
}
const hasSet = HasProperty(object, 'set');
if (hasSet == True) {
let setter = GetProperty(object, 'set');
if (!Is<Undefined>(setter) && !Is<FunctionTemplateInfo>(setter)) {
setter = Cast<Callable>(setter) otherwise ThrowTypeError(
MessageTemplate::kObjectSetterCallable, setter);
}
result.flags.has_set = true;
result.set = setter;
}
}
return result;
}
@export
transitioning macro ToPropertyDescriptor(
implicit context: Context)(object: JSAny): PropertyDescriptorObject
|Undefined {
typeswitch (object) {
case (Undefined): {
return Undefined;
}
case (receiver: JSReceiver): {
return ToPropertyDescriptor(receiver);
}
case (JSAny): {
ThrowTypeError(MessageTemplate::kPropertyDescObject, object);
}
}
}
extern transitioning macro ObjectBuiltinsAssembler::FromPropertyDescriptor(
Context, JSAny): JSAny;
@export
transitioning macro FromPropertyDescriptor(
implicit context: Context)(object: JSAny): JSAny {
return FromPropertyDescriptor(context, object);
}
} // namespace object