| Index: src/runtime/runtime.cc
|
| diff --git a/src/runtime/runtime.cc b/src/runtime/runtime.cc
|
| index 974d1a6e7aa7d85009184cd9b3dc7001f07a4719..dbb51ec926f7e1b29b66d7e275216c4149f172c7 100644
|
| --- a/src/runtime/runtime.cc
|
| +++ b/src/runtime/runtime.cc
|
| @@ -8,30 +8,19 @@
|
| #include "src/v8.h"
|
|
|
| #include "src/accessors.h"
|
| -#include "src/allocation-site-scopes.h"
|
| #include "src/api.h"
|
| #include "src/arguments.h"
|
| #include "src/bailout-reason.h"
|
| #include "src/base/cpu.h"
|
| #include "src/base/platform/platform.h"
|
| #include "src/bootstrapper.h"
|
| -#include "src/codegen.h"
|
| -#include "src/compilation-cache.h"
|
| -#include "src/compiler.h"
|
| #include "src/conversions.h"
|
| -#include "src/deoptimizer.h"
|
| -#include "src/execution.h"
|
| -#include "src/full-codegen.h"
|
| #include "src/global-handles.h"
|
| #include "src/isolate-inl.h"
|
| -#include "src/parser.h"
|
| #include "src/prototype.h"
|
| #include "src/runtime/runtime.h"
|
| #include "src/runtime/runtime-utils.h"
|
| -#include "src/scopeinfo.h"
|
| -#include "src/smart-pointers.h"
|
| #include "src/utils.h"
|
| -#include "src/v8threads.h"
|
|
|
|
|
| namespace v8 {
|
| @@ -60,165 +49,6 @@ INLINE_FUNCTION_LIST(I)
|
| #undef P
|
|
|
|
|
| -static Handle<Map> ComputeObjectLiteralMap(
|
| - Handle<Context> context, Handle<FixedArray> constant_properties,
|
| - bool* is_result_from_cache) {
|
| - Isolate* isolate = context->GetIsolate();
|
| - int properties_length = constant_properties->length();
|
| - int number_of_properties = properties_length / 2;
|
| - // Check that there are only internal strings and array indices among keys.
|
| - int number_of_string_keys = 0;
|
| - for (int p = 0; p != properties_length; p += 2) {
|
| - Object* key = constant_properties->get(p);
|
| - uint32_t element_index = 0;
|
| - if (key->IsInternalizedString()) {
|
| - number_of_string_keys++;
|
| - } else if (key->ToArrayIndex(&element_index)) {
|
| - // An index key does not require space in the property backing store.
|
| - number_of_properties--;
|
| - } else {
|
| - // Bail out as a non-internalized-string non-index key makes caching
|
| - // impossible.
|
| - // DCHECK to make sure that the if condition after the loop is false.
|
| - DCHECK(number_of_string_keys != number_of_properties);
|
| - break;
|
| - }
|
| - }
|
| - // If we only have internalized strings and array indices among keys then we
|
| - // can use the map cache in the native context.
|
| - const int kMaxKeys = 10;
|
| - if ((number_of_string_keys == number_of_properties) &&
|
| - (number_of_string_keys < kMaxKeys)) {
|
| - // Create the fixed array with the key.
|
| - Handle<FixedArray> keys =
|
| - isolate->factory()->NewFixedArray(number_of_string_keys);
|
| - if (number_of_string_keys > 0) {
|
| - int index = 0;
|
| - for (int p = 0; p < properties_length; p += 2) {
|
| - Object* key = constant_properties->get(p);
|
| - if (key->IsInternalizedString()) {
|
| - keys->set(index++, key);
|
| - }
|
| - }
|
| - DCHECK(index == number_of_string_keys);
|
| - }
|
| - *is_result_from_cache = true;
|
| - return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
|
| - }
|
| - *is_result_from_cache = false;
|
| - return Map::Create(isolate, number_of_properties);
|
| -}
|
| -
|
| -
|
| -MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate(
|
| - Isolate* isolate, Handle<FixedArray> literals,
|
| - Handle<FixedArray> constant_properties);
|
| -
|
| -
|
| -MUST_USE_RESULT static MaybeHandle<Object> CreateObjectLiteralBoilerplate(
|
| - Isolate* isolate, Handle<FixedArray> literals,
|
| - Handle<FixedArray> constant_properties, bool should_have_fast_elements,
|
| - bool has_function_literal) {
|
| - // Get the native context from the literals array. This is the
|
| - // context in which the function was created and we use the object
|
| - // function from this context to create the object literal. We do
|
| - // not use the object function from the current native context
|
| - // because this might be the object function from another context
|
| - // which we should not have access to.
|
| - Handle<Context> context =
|
| - Handle<Context>(JSFunction::NativeContextFromLiterals(*literals));
|
| -
|
| - // In case we have function literals, we want the object to be in
|
| - // slow properties mode for now. We don't go in the map cache because
|
| - // maps with constant functions can't be shared if the functions are
|
| - // not the same (which is the common case).
|
| - bool is_result_from_cache = false;
|
| - Handle<Map> map = has_function_literal
|
| - ? Handle<Map>(context->object_function()->initial_map())
|
| - : ComputeObjectLiteralMap(context, constant_properties,
|
| - &is_result_from_cache);
|
| -
|
| - PretenureFlag pretenure_flag =
|
| - isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
|
| -
|
| - Handle<JSObject> boilerplate =
|
| - isolate->factory()->NewJSObjectFromMap(map, pretenure_flag);
|
| -
|
| - // Normalize the elements of the boilerplate to save space if needed.
|
| - if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
|
| -
|
| - // Add the constant properties to the boilerplate.
|
| - int length = constant_properties->length();
|
| - bool should_transform =
|
| - !is_result_from_cache && boilerplate->HasFastProperties();
|
| - bool should_normalize = should_transform || has_function_literal;
|
| - if (should_normalize) {
|
| - // TODO(verwaest): We might not want to ever normalize here.
|
| - JSObject::NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES,
|
| - length / 2);
|
| - }
|
| - // TODO(verwaest): Support tracking representations in the boilerplate.
|
| - for (int index = 0; index < length; index += 2) {
|
| - Handle<Object> key(constant_properties->get(index + 0), isolate);
|
| - Handle<Object> value(constant_properties->get(index + 1), isolate);
|
| - if (value->IsFixedArray()) {
|
| - // The value contains the constant_properties of a
|
| - // simple object or array literal.
|
| - Handle<FixedArray> array = Handle<FixedArray>::cast(value);
|
| - ASSIGN_RETURN_ON_EXCEPTION(
|
| - isolate, value, CreateLiteralBoilerplate(isolate, literals, array),
|
| - Object);
|
| - }
|
| - MaybeHandle<Object> maybe_result;
|
| - uint32_t element_index = 0;
|
| - if (key->IsInternalizedString()) {
|
| - if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
|
| - // Array index as string (uint32).
|
| - if (value->IsUninitialized()) value = handle(Smi::FromInt(0), isolate);
|
| - maybe_result =
|
| - JSObject::SetOwnElement(boilerplate, element_index, value, SLOPPY);
|
| - } else {
|
| - Handle<String> name(String::cast(*key));
|
| - DCHECK(!name->AsArrayIndex(&element_index));
|
| - maybe_result = JSObject::SetOwnPropertyIgnoreAttributes(
|
| - boilerplate, name, value, NONE);
|
| - }
|
| - } else if (key->ToArrayIndex(&element_index)) {
|
| - // Array index (uint32).
|
| - if (value->IsUninitialized()) value = handle(Smi::FromInt(0), isolate);
|
| - maybe_result =
|
| - JSObject::SetOwnElement(boilerplate, element_index, value, SLOPPY);
|
| - } else {
|
| - // Non-uint32 number.
|
| - DCHECK(key->IsNumber());
|
| - double num = key->Number();
|
| - char arr[100];
|
| - Vector<char> buffer(arr, arraysize(arr));
|
| - const char* str = DoubleToCString(num, buffer);
|
| - Handle<String> name = isolate->factory()->NewStringFromAsciiChecked(str);
|
| - maybe_result = JSObject::SetOwnPropertyIgnoreAttributes(boilerplate, name,
|
| - value, NONE);
|
| - }
|
| - // If setting the property on the boilerplate throws an
|
| - // exception, the exception is converted to an empty handle in
|
| - // the handle based operations. In that case, we need to
|
| - // convert back to an exception.
|
| - RETURN_ON_EXCEPTION(isolate, maybe_result, Object);
|
| - }
|
| -
|
| - // Transform to fast properties if necessary. For object literals with
|
| - // containing function literals we defer this operation until after all
|
| - // computed properties have been assigned so that we can generate
|
| - // constant function properties.
|
| - if (should_transform && !has_function_literal) {
|
| - JSObject::MigrateSlowToFast(boilerplate,
|
| - boilerplate->map()->unused_property_fields());
|
| - }
|
| -
|
| - return boilerplate;
|
| -}
|
| -
|
| -
|
| MUST_USE_RESULT static MaybeHandle<Object> TransitionElements(
|
| Handle<Object> object, ElementsKind to_kind, Isolate* isolate) {
|
| HandleScope scope(isolate);
|
| @@ -237,401 +67,6 @@ MUST_USE_RESULT static MaybeHandle<Object> TransitionElements(
|
| }
|
|
|
|
|
| -MaybeHandle<Object> Runtime::CreateArrayLiteralBoilerplate(
|
| - Isolate* isolate, Handle<FixedArray> literals,
|
| - Handle<FixedArray> elements) {
|
| - // Create the JSArray.
|
| - Handle<JSFunction> constructor(
|
| - JSFunction::NativeContextFromLiterals(*literals)->array_function());
|
| -
|
| - PretenureFlag pretenure_flag =
|
| - isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
|
| -
|
| - Handle<JSArray> object = Handle<JSArray>::cast(
|
| - isolate->factory()->NewJSObject(constructor, pretenure_flag));
|
| -
|
| - ElementsKind constant_elements_kind =
|
| - static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
|
| - Handle<FixedArrayBase> constant_elements_values(
|
| - FixedArrayBase::cast(elements->get(1)));
|
| -
|
| - {
|
| - DisallowHeapAllocation no_gc;
|
| - DCHECK(IsFastElementsKind(constant_elements_kind));
|
| - Context* native_context = isolate->context()->native_context();
|
| - Object* maps_array = native_context->js_array_maps();
|
| - DCHECK(!maps_array->IsUndefined());
|
| - Object* map = FixedArray::cast(maps_array)->get(constant_elements_kind);
|
| - object->set_map(Map::cast(map));
|
| - }
|
| -
|
| - Handle<FixedArrayBase> copied_elements_values;
|
| - if (IsFastDoubleElementsKind(constant_elements_kind)) {
|
| - copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
|
| - Handle<FixedDoubleArray>::cast(constant_elements_values));
|
| - } else {
|
| - DCHECK(IsFastSmiOrObjectElementsKind(constant_elements_kind));
|
| - const bool is_cow = (constant_elements_values->map() ==
|
| - isolate->heap()->fixed_cow_array_map());
|
| - if (is_cow) {
|
| - copied_elements_values = constant_elements_values;
|
| -#if DEBUG
|
| - Handle<FixedArray> fixed_array_values =
|
| - Handle<FixedArray>::cast(copied_elements_values);
|
| - for (int i = 0; i < fixed_array_values->length(); i++) {
|
| - DCHECK(!fixed_array_values->get(i)->IsFixedArray());
|
| - }
|
| -#endif
|
| - } else {
|
| - Handle<FixedArray> fixed_array_values =
|
| - Handle<FixedArray>::cast(constant_elements_values);
|
| - Handle<FixedArray> fixed_array_values_copy =
|
| - isolate->factory()->CopyFixedArray(fixed_array_values);
|
| - copied_elements_values = fixed_array_values_copy;
|
| - for (int i = 0; i < fixed_array_values->length(); i++) {
|
| - if (fixed_array_values->get(i)->IsFixedArray()) {
|
| - // The value contains the constant_properties of a
|
| - // simple object or array literal.
|
| - Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_ON_EXCEPTION(
|
| - isolate, result, CreateLiteralBoilerplate(isolate, literals, fa),
|
| - Object);
|
| - fixed_array_values_copy->set(i, *result);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - object->set_elements(*copied_elements_values);
|
| - object->set_length(Smi::FromInt(copied_elements_values->length()));
|
| -
|
| - JSObject::ValidateElements(object);
|
| - return object;
|
| -}
|
| -
|
| -
|
| -MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate(
|
| - Isolate* isolate, Handle<FixedArray> literals, Handle<FixedArray> array) {
|
| - Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
|
| - const bool kHasNoFunctionLiteral = false;
|
| - switch (CompileTimeValue::GetLiteralType(array)) {
|
| - case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
|
| - return CreateObjectLiteralBoilerplate(isolate, literals, elements, true,
|
| - kHasNoFunctionLiteral);
|
| - case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
|
| - return CreateObjectLiteralBoilerplate(isolate, literals, elements, false,
|
| - kHasNoFunctionLiteral);
|
| - case CompileTimeValue::ARRAY_LITERAL:
|
| - return Runtime::CreateArrayLiteralBoilerplate(isolate, literals,
|
| - elements);
|
| - default:
|
| - UNREACHABLE();
|
| - return MaybeHandle<Object>();
|
| - }
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 4);
|
| - CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
|
| - CONVERT_SMI_ARG_CHECKED(literals_index, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
|
| - CONVERT_SMI_ARG_CHECKED(flags, 3);
|
| - bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
|
| - bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
|
| -
|
| - RUNTIME_ASSERT(literals_index >= 0 && literals_index < literals->length());
|
| -
|
| - // Check if boilerplate exists. If not, create it first.
|
| - Handle<Object> literal_site(literals->get(literals_index), isolate);
|
| - Handle<AllocationSite> site;
|
| - Handle<JSObject> boilerplate;
|
| - if (*literal_site == isolate->heap()->undefined_value()) {
|
| - Handle<Object> raw_boilerplate;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, raw_boilerplate,
|
| - CreateObjectLiteralBoilerplate(isolate, literals, constant_properties,
|
| - should_have_fast_elements,
|
| - has_function_literal));
|
| - boilerplate = Handle<JSObject>::cast(raw_boilerplate);
|
| -
|
| - AllocationSiteCreationContext creation_context(isolate);
|
| - site = creation_context.EnterNewScope();
|
| - RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, JSObject::DeepWalk(boilerplate, &creation_context));
|
| - creation_context.ExitScope(site, boilerplate);
|
| -
|
| - // Update the functions literal and return the boilerplate.
|
| - literals->set(literals_index, *site);
|
| - } else {
|
| - site = Handle<AllocationSite>::cast(literal_site);
|
| - boilerplate =
|
| - Handle<JSObject>(JSObject::cast(site->transition_info()), isolate);
|
| - }
|
| -
|
| - AllocationSiteUsageContext usage_context(isolate, site, true);
|
| - usage_context.EnterNewScope();
|
| - MaybeHandle<Object> maybe_copy =
|
| - JSObject::DeepCopy(boilerplate, &usage_context);
|
| - usage_context.ExitScope(site, boilerplate);
|
| - Handle<Object> copy;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, copy, maybe_copy);
|
| - return *copy;
|
| -}
|
| -
|
| -
|
| -MUST_USE_RESULT static MaybeHandle<AllocationSite> GetLiteralAllocationSite(
|
| - Isolate* isolate, Handle<FixedArray> literals, int literals_index,
|
| - Handle<FixedArray> elements) {
|
| - // Check if boilerplate exists. If not, create it first.
|
| - Handle<Object> literal_site(literals->get(literals_index), isolate);
|
| - Handle<AllocationSite> site;
|
| - if (*literal_site == isolate->heap()->undefined_value()) {
|
| - DCHECK(*elements != isolate->heap()->empty_fixed_array());
|
| - Handle<Object> boilerplate;
|
| - ASSIGN_RETURN_ON_EXCEPTION(
|
| - isolate, boilerplate,
|
| - Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements),
|
| - AllocationSite);
|
| -
|
| - AllocationSiteCreationContext creation_context(isolate);
|
| - site = creation_context.EnterNewScope();
|
| - if (JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate),
|
| - &creation_context).is_null()) {
|
| - return Handle<AllocationSite>::null();
|
| - }
|
| - creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate));
|
| -
|
| - literals->set(literals_index, *site);
|
| - } else {
|
| - site = Handle<AllocationSite>::cast(literal_site);
|
| - }
|
| -
|
| - return site;
|
| -}
|
| -
|
| -
|
| -static MaybeHandle<JSObject> CreateArrayLiteralImpl(Isolate* isolate,
|
| - Handle<FixedArray> literals,
|
| - int literals_index,
|
| - Handle<FixedArray> elements,
|
| - int flags) {
|
| - RUNTIME_ASSERT_HANDLIFIED(
|
| - literals_index >= 0 && literals_index < literals->length(), JSObject);
|
| - Handle<AllocationSite> site;
|
| - ASSIGN_RETURN_ON_EXCEPTION(
|
| - isolate, site,
|
| - GetLiteralAllocationSite(isolate, literals, literals_index, elements),
|
| - JSObject);
|
| -
|
| - bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0;
|
| - Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
|
| - AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
|
| - usage_context.EnterNewScope();
|
| - JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements) == 0
|
| - ? JSObject::kNoHints
|
| - : JSObject::kObjectIsShallow;
|
| - MaybeHandle<JSObject> copy =
|
| - JSObject::DeepCopy(boilerplate, &usage_context, hints);
|
| - usage_context.ExitScope(site, boilerplate);
|
| - return copy;
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_CreateArrayLiteral) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 4);
|
| - CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
|
| - CONVERT_SMI_ARG_CHECKED(literals_index, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
|
| - CONVERT_SMI_ARG_CHECKED(flags, 3);
|
| -
|
| - Handle<JSObject> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result, CreateArrayLiteralImpl(isolate, literals, literals_index,
|
| - elements, flags));
|
| - return *result;
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_CreateArrayLiteralStubBailout) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 3);
|
| - CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
|
| - CONVERT_SMI_ARG_CHECKED(literals_index, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
|
| -
|
| - Handle<JSObject> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result,
|
| - CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
|
| - ArrayLiteral::kShallowElements));
|
| - return *result;
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_CreateSymbol) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
|
| - RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
|
| - Handle<Symbol> symbol = isolate->factory()->NewSymbol();
|
| - if (name->IsString()) symbol->set_name(*name);
|
| - return *symbol;
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_CreatePrivateSymbol) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
|
| - RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
|
| - Handle<Symbol> symbol = isolate->factory()->NewPrivateSymbol();
|
| - if (name->IsString()) symbol->set_name(*name);
|
| - return *symbol;
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_CreatePrivateOwnSymbol) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
|
| - RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
|
| - Handle<Symbol> symbol = isolate->factory()->NewPrivateOwnSymbol();
|
| - if (name->IsString()) symbol->set_name(*name);
|
| - return *symbol;
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_CreateGlobalPrivateOwnSymbol) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
|
| - Handle<JSObject> registry = isolate->GetSymbolRegistry();
|
| - Handle<String> part = isolate->factory()->private_intern_string();
|
| - Handle<Object> privates;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, privates, Object::GetPropertyOrElement(registry, part));
|
| - Handle<Object> symbol;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, symbol, Object::GetPropertyOrElement(privates, name));
|
| - if (!symbol->IsSymbol()) {
|
| - DCHECK(symbol->IsUndefined());
|
| - symbol = isolate->factory()->NewPrivateSymbol();
|
| - Handle<Symbol>::cast(symbol)->set_name(*name);
|
| - Handle<Symbol>::cast(symbol)->set_is_own(true);
|
| - JSObject::SetProperty(Handle<JSObject>::cast(privates), name, symbol,
|
| - STRICT).Assert();
|
| - }
|
| - return *symbol;
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_NewSymbolWrapper) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0);
|
| - return *Object::ToObject(isolate, symbol).ToHandleChecked();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_SymbolDescription) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(Symbol, symbol, 0);
|
| - return symbol->name();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_SymbolRegistry) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 0);
|
| - return *isolate->GetSymbolRegistry();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_SymbolIsPrivate) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(Symbol, symbol, 0);
|
| - return isolate->heap()->ToBoolean(symbol->is_private());
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_CreateJSProxy) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
|
| - if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value();
|
| - return *isolate->factory()->NewJSProxy(handler, prototype);
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_CreateJSFunctionProxy) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 4);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, call_trap, 1);
|
| - RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy());
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, construct_trap, 2);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 3);
|
| - if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value();
|
| - return *isolate->factory()->NewJSFunctionProxy(handler, call_trap,
|
| - construct_trap, prototype);
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_IsJSProxy) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
|
| - return isolate->heap()->ToBoolean(obj->IsJSProxy());
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_IsJSFunctionProxy) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
|
| - return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_GetHandler) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
|
| - return proxy->handler();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_GetCallTrap) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
|
| - return proxy->call_trap();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_GetConstructTrap) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
|
| - return proxy->construct_trap();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_Fix) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0);
|
| - JSProxy::Fix(proxy);
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| RUNTIME_FUNCTION(Runtime_GetPrototype) {
|
| HandleScope scope(isolate);
|
| DCHECK(args.length() == 1);
|
| @@ -1007,3004 +442,1384 @@ RUNTIME_FUNCTION(Runtime_EnableAccessChecks) {
|
| }
|
|
|
|
|
| -static Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name) {
|
| +RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) {
|
| HandleScope scope(isolate);
|
| - Handle<Object> args[1] = {name};
|
| - THROW_NEW_ERROR_RETURN_FAILURE(
|
| - isolate, NewTypeError("var_redeclaration", HandleVector(args, 1)));
|
| + DCHECK(args.length() == 2);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| + CONVERT_SMI_ARG_CHECKED(properties, 1);
|
| + // Conservative upper limit to prevent fuzz tests from going OOM.
|
| + RUNTIME_ASSERT(properties <= 100000);
|
| + if (object->HasFastProperties() && !object->IsJSGlobalProxy()) {
|
| + JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
|
| + }
|
| + return *object;
|
| }
|
|
|
|
|
| -// May throw a RedeclarationError.
|
| -static Object* DeclareGlobals(Isolate* isolate, Handle<GlobalObject> global,
|
| - Handle<String> name, Handle<Object> value,
|
| - PropertyAttributes attr, bool is_var,
|
| - bool is_const, bool is_function) {
|
| - // Do the lookup own properties only, see ES5 erratum.
|
| - LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
|
| - Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
|
| - if (!maybe.has_value) return isolate->heap()->exception();
|
| -
|
| - if (it.IsFound()) {
|
| - PropertyAttributes old_attributes = maybe.value;
|
| - // The name was declared before; check for conflicting re-declarations.
|
| - if (is_const) return ThrowRedeclarationError(isolate, name);
|
| -
|
| - // Skip var re-declarations.
|
| - if (is_var) return isolate->heap()->undefined_value();
|
| -
|
| - DCHECK(is_function);
|
| - if ((old_attributes & DONT_DELETE) != 0) {
|
| - // Only allow reconfiguring globals to functions in user code (no
|
| - // natives, which are marked as read-only).
|
| - DCHECK((attr & READ_ONLY) == 0);
|
| -
|
| - // Check whether we can reconfigure the existing property into a
|
| - // function.
|
| - PropertyDetails old_details = it.property_details();
|
| - // TODO(verwaest): CALLBACKS invalidly includes ExecutableAccessInfo,
|
| - // which are actually data properties, not accessor properties.
|
| - if (old_details.IsReadOnly() || old_details.IsDontEnum() ||
|
| - old_details.type() == CALLBACKS) {
|
| - return ThrowRedeclarationError(isolate, name);
|
| - }
|
| - // If the existing property is not configurable, keep its attributes. Do
|
| - attr = old_attributes;
|
| - }
|
| - }
|
| +RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) {
|
| + HandleScope scope(isolate);
|
| + DCHECK(args.length() == 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
|
| + Object* length = prototype->length();
|
| + RUNTIME_ASSERT(length->IsSmi() && Smi::cast(length)->value() == 0);
|
| + RUNTIME_ASSERT(prototype->HasFastSmiOrObjectElements());
|
| + // This is necessary to enable fast checks for absence of elements
|
| + // on Array.prototype and below.
|
| + prototype->set_elements(isolate->heap()->empty_fixed_array());
|
| + return Smi::FromInt(0);
|
| +}
|
|
|
| - // Define or redefine own property.
|
| - RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
|
| - global, name, value, attr));
|
|
|
| - return isolate->heap()->undefined_value();
|
| +static void InstallBuiltin(Isolate* isolate, Handle<JSObject> holder,
|
| + const char* name, Builtins::Name builtin_name) {
|
| + Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
|
| + Handle<Code> code(isolate->builtins()->builtin(builtin_name));
|
| + Handle<JSFunction> optimized =
|
| + isolate->factory()->NewFunctionWithoutPrototype(key, code);
|
| + optimized->shared()->DontAdaptArguments();
|
| + JSObject::AddProperty(holder, key, optimized, NONE);
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
|
| +RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 3);
|
| - Handle<GlobalObject> global(isolate->global_object());
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
|
| - CONVERT_SMI_ARG_CHECKED(flags, 2);
|
| -
|
| - // Traverse the name/value pairs and set the properties.
|
| - int length = pairs->length();
|
| - for (int i = 0; i < length; i += 2) {
|
| - HandleScope scope(isolate);
|
| - Handle<String> name(String::cast(pairs->get(i)));
|
| - Handle<Object> initial_value(pairs->get(i + 1), isolate);
|
| -
|
| - // We have to declare a global const property. To capture we only
|
| - // assign to it when evaluating the assignment for "const x =
|
| - // <expr>" the initial value is the hole.
|
| - bool is_var = initial_value->IsUndefined();
|
| - bool is_const = initial_value->IsTheHole();
|
| - bool is_function = initial_value->IsSharedFunctionInfo();
|
| - DCHECK(is_var + is_const + is_function == 1);
|
| -
|
| - Handle<Object> value;
|
| - if (is_function) {
|
| - // Copy the function and update its context. Use it as value.
|
| - Handle<SharedFunctionInfo> shared =
|
| - Handle<SharedFunctionInfo>::cast(initial_value);
|
| - Handle<JSFunction> function =
|
| - isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
|
| - TENURED);
|
| - value = function;
|
| - } else {
|
| - value = isolate->factory()->undefined_value();
|
| - }
|
| + DCHECK(args.length() == 0);
|
| + Handle<JSObject> holder =
|
| + isolate->factory()->NewJSObject(isolate->object_function());
|
|
|
| - // Compute the property attributes. According to ECMA-262,
|
| - // the property must be non-configurable except in eval.
|
| - bool is_native = DeclareGlobalsNativeFlag::decode(flags);
|
| - bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
|
| - int attr = NONE;
|
| - if (is_const) attr |= READ_ONLY;
|
| - if (is_function && is_native) attr |= READ_ONLY;
|
| - if (!is_const && !is_eval) attr |= DONT_DELETE;
|
| -
|
| - Object* result = DeclareGlobals(isolate, global, name, value,
|
| - static_cast<PropertyAttributes>(attr),
|
| - is_var, is_const, is_function);
|
| - if (isolate->has_pending_exception()) return result;
|
| - }
|
| + InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
|
| + InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
|
| + InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
|
| + InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
|
| + InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
|
| + InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
|
| + InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
|
|
|
| - return isolate->heap()->undefined_value();
|
| + return *holder;
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
|
| +RUNTIME_FUNCTION(Runtime_ObjectFreeze) {
|
| HandleScope scope(isolate);
|
| - // args[0] == name
|
| - // args[1] == language_mode
|
| - // args[2] == value (optional)
|
| -
|
| - // Determine if we need to assign to the variable if it already
|
| - // exists (based on the number of arguments).
|
| - RUNTIME_ASSERT(args.length() == 3);
|
| + DCHECK(args.length() == 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
|
|
| - CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
|
| - CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
| + // %ObjectFreeze is a fast path and these cases are handled elsewhere.
|
| + RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() &&
|
| + !object->map()->is_observed() && !object->IsJSProxy());
|
|
|
| - Handle<GlobalObject> global(isolate->context()->global_object());
|
| Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result, Object::SetProperty(global, name, value, strict_mode));
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object));
|
| return *result;
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) {
|
| - HandleScope handle_scope(isolate);
|
| - // All constants are declared with an initial value. The name
|
| - // of the constant is the first argument and the initial value
|
| - // is the second.
|
| - RUNTIME_ASSERT(args.length() == 2);
|
| - CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
|
| +// Returns a single character string where first character equals
|
| +// string->Get(index).
|
| +static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
|
| + if (index < static_cast<uint32_t>(string->length())) {
|
| + Factory* factory = string->GetIsolate()->factory();
|
| + return factory->LookupSingleCharacterStringFromCode(
|
| + String::Flatten(string)->Get(index));
|
| + }
|
| + return Execution::CharAt(string, index);
|
| +}
|
|
|
| - Handle<GlobalObject> global = isolate->global_object();
|
|
|
| - // Lookup the property as own on the global object.
|
| - LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
|
| - Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
|
| - DCHECK(maybe.has_value);
|
| - PropertyAttributes old_attributes = maybe.value;
|
| -
|
| - PropertyAttributes attr =
|
| - static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
|
| - // Set the value if the property is either missing, or the property attributes
|
| - // allow setting the value without invoking an accessor.
|
| - if (it.IsFound()) {
|
| - // Ignore if we can't reconfigure the value.
|
| - if ((old_attributes & DONT_DELETE) != 0) {
|
| - if ((old_attributes & READ_ONLY) != 0 ||
|
| - it.state() == LookupIterator::ACCESSOR) {
|
| - return *value;
|
| - }
|
| - attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
|
| - }
|
| +MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate,
|
| + Handle<Object> object,
|
| + uint32_t index) {
|
| + // Handle [] indexing on Strings
|
| + if (object->IsString()) {
|
| + Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
|
| + if (!result->IsUndefined()) return result;
|
| }
|
|
|
| - RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
|
| - global, name, value, attr));
|
| + // Handle [] indexing on String objects
|
| + if (object->IsStringObjectWithCharacterAt(index)) {
|
| + Handle<JSValue> js_value = Handle<JSValue>::cast(object);
|
| + Handle<Object> result =
|
| + GetCharAt(Handle<String>(String::cast(js_value->value())), index);
|
| + if (!result->IsUndefined()) return result;
|
| + }
|
|
|
| - return *value;
|
| + Handle<Object> result;
|
| + if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
|
| + PrototypeIterator iter(isolate, object);
|
| + return Object::GetElement(isolate, PrototypeIterator::GetCurrent(iter),
|
| + index);
|
| + } else {
|
| + return Object::GetElement(isolate, object, index);
|
| + }
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_DeclareLookupSlot) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 4);
|
| -
|
| - // Declarations are always made in a function, native, or global context. In
|
| - // the case of eval code, the context passed is the context of the caller,
|
| - // which may be some nested context and not the declaration context.
|
| - CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 0);
|
| - Handle<Context> context(context_arg->declaration_context());
|
| - CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
|
| - CONVERT_SMI_ARG_CHECKED(attr_arg, 2);
|
| - PropertyAttributes attr = static_cast<PropertyAttributes>(attr_arg);
|
| - RUNTIME_ASSERT(attr == READ_ONLY || attr == NONE);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3);
|
| -
|
| - // TODO(verwaest): Unify the encoding indicating "var" with DeclareGlobals.
|
| - bool is_var = *initial_value == NULL;
|
| - bool is_const = initial_value->IsTheHole();
|
| - bool is_function = initial_value->IsJSFunction();
|
| - DCHECK(is_var + is_const + is_function == 1);
|
| -
|
| - int index;
|
| - PropertyAttributes attributes;
|
| - ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
|
| - BindingFlags binding_flags;
|
| - Handle<Object> holder =
|
| - context->Lookup(name, flags, &index, &attributes, &binding_flags);
|
| -
|
| - Handle<JSObject> object;
|
| - Handle<Object> value =
|
| - is_function ? initial_value
|
| - : Handle<Object>::cast(isolate->factory()->undefined_value());
|
| -
|
| - // TODO(verwaest): This case should probably not be covered by this function,
|
| - // but by DeclareGlobals instead.
|
| - if ((attributes != ABSENT && holder->IsJSGlobalObject()) ||
|
| - (context_arg->has_extension() &&
|
| - context_arg->extension()->IsJSGlobalObject())) {
|
| - return DeclareGlobals(isolate, Handle<JSGlobalObject>::cast(holder), name,
|
| - value, attr, is_var, is_const, is_function);
|
| +MUST_USE_RESULT
|
| +static MaybeHandle<Name> ToName(Isolate* isolate, Handle<Object> key) {
|
| + if (key->IsName()) {
|
| + return Handle<Name>::cast(key);
|
| + } else {
|
| + Handle<Object> converted;
|
| + ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
|
| + Execution::ToString(isolate, key), Name);
|
| + return Handle<Name>::cast(converted);
|
| }
|
| +}
|
|
|
| - if (attributes != ABSENT) {
|
| - // The name was declared before; check for conflicting re-declarations.
|
| - if (is_const || (attributes & READ_ONLY) != 0) {
|
| - return ThrowRedeclarationError(isolate, name);
|
| - }
|
| -
|
| - // Skip var re-declarations.
|
| - if (is_var) return isolate->heap()->undefined_value();
|
| -
|
| - DCHECK(is_function);
|
| - if (index >= 0) {
|
| - DCHECK(holder.is_identical_to(context));
|
| - context->set(index, *initial_value);
|
| - return isolate->heap()->undefined_value();
|
| - }
|
| -
|
| - object = Handle<JSObject>::cast(holder);
|
|
|
| - } else if (context->has_extension()) {
|
| - object = handle(JSObject::cast(context->extension()));
|
| - DCHECK(object->IsJSContextExtensionObject() || object->IsJSGlobalObject());
|
| +MaybeHandle<Object> Runtime::HasObjectProperty(Isolate* isolate,
|
| + Handle<JSReceiver> object,
|
| + Handle<Object> key) {
|
| + Maybe<bool> maybe;
|
| + // Check if the given key is an array index.
|
| + uint32_t index;
|
| + if (key->ToArrayIndex(&index)) {
|
| + maybe = JSReceiver::HasElement(object, index);
|
| } else {
|
| - DCHECK(context->IsFunctionContext());
|
| - object =
|
| - isolate->factory()->NewJSObject(isolate->context_extension_function());
|
| - context->set_extension(*object);
|
| - }
|
| + // Convert the key to a name - possibly by calling back into JavaScript.
|
| + Handle<Name> name;
|
| + ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
|
|
|
| - RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
|
| - object, name, value, attr));
|
| + maybe = JSReceiver::HasProperty(object, name);
|
| + }
|
|
|
| - return isolate->heap()->undefined_value();
|
| + if (!maybe.has_value) return MaybeHandle<Object>();
|
| + return isolate->factory()->ToBoolean(maybe.value);
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 3);
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
|
| - DCHECK(!value->IsTheHole());
|
| - // Initializations are always done in a function or native context.
|
| - CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1);
|
| - Handle<Context> context(context_arg->declaration_context());
|
| - CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
|
| -
|
| - int index;
|
| - PropertyAttributes attributes;
|
| - ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
|
| - BindingFlags binding_flags;
|
| - Handle<Object> holder =
|
| - context->Lookup(name, flags, &index, &attributes, &binding_flags);
|
| -
|
| - if (index >= 0) {
|
| - DCHECK(holder->IsContext());
|
| - // Property was found in a context. Perform the assignment if the constant
|
| - // was uninitialized.
|
| - Handle<Context> context = Handle<Context>::cast(holder);
|
| - DCHECK((attributes & READ_ONLY) != 0);
|
| - if (context->get(index)->IsTheHole()) context->set(index, *value);
|
| - return *value;
|
| +MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
|
| + Handle<Object> object,
|
| + Handle<Object> key) {
|
| + if (object->IsUndefined() || object->IsNull()) {
|
| + Handle<Object> args[2] = {key, object};
|
| + THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_load",
|
| + HandleVector(args, 2)),
|
| + Object);
|
| }
|
|
|
| - PropertyAttributes attr =
|
| - static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
|
| + // Check if the given key is an array index.
|
| + uint32_t index;
|
| + if (key->ToArrayIndex(&index)) {
|
| + return GetElementOrCharAt(isolate, object, index);
|
| + }
|
|
|
| - // Strict mode handling not needed (legacy const is disallowed in strict
|
| - // mode).
|
| + // Convert the key to a name - possibly by calling back into JavaScript.
|
| + Handle<Name> name;
|
| + ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
|
|
|
| - // The declared const was configurable, and may have been deleted in the
|
| - // meanwhile. If so, re-introduce the variable in the context extension.
|
| - DCHECK(context_arg->has_extension());
|
| - if (attributes == ABSENT) {
|
| - holder = handle(context_arg->extension(), isolate);
|
| + // Check if the name is trivially convertible to an index and get
|
| + // the element if so.
|
| + if (name->AsArrayIndex(&index)) {
|
| + return GetElementOrCharAt(isolate, object, index);
|
| } else {
|
| - // For JSContextExtensionObjects, the initializer can be run multiple times
|
| - // if in a for loop: for (var i = 0; i < 2; i++) { const x = i; }. Only the
|
| - // first assignment should go through. For JSGlobalObjects, additionally any
|
| - // code can run in between that modifies the declared property.
|
| - DCHECK(holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject());
|
| -
|
| - LookupIterator it(holder, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
|
| - Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
|
| - if (!maybe.has_value) return isolate->heap()->exception();
|
| - PropertyAttributes old_attributes = maybe.value;
|
| -
|
| - // Ignore if we can't reconfigure the value.
|
| - if ((old_attributes & DONT_DELETE) != 0) {
|
| - if ((old_attributes & READ_ONLY) != 0 ||
|
| - it.state() == LookupIterator::ACCESSOR) {
|
| - return *value;
|
| - }
|
| - attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
|
| - }
|
| + return Object::GetProperty(object, name);
|
| }
|
| -
|
| - RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, JSObject::SetOwnPropertyIgnoreAttributes(
|
| - Handle<JSObject>::cast(holder), name, value, attr));
|
| -
|
| - return *value;
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) {
|
| +RUNTIME_FUNCTION(Runtime_GetProperty) {
|
| HandleScope scope(isolate);
|
| DCHECK(args.length() == 2);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| - CONVERT_SMI_ARG_CHECKED(properties, 1);
|
| - // Conservative upper limit to prevent fuzz tests from going OOM.
|
| - RUNTIME_ASSERT(properties <= 100000);
|
| - if (object->HasFastProperties() && !object->IsJSGlobalProxy()) {
|
| - JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
|
| - }
|
| - return *object;
|
| +
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
|
| + Handle<Object> result;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, result, Runtime::GetObjectProperty(isolate, object, key));
|
| + return *result;
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) {
|
| +// KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
|
| +RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
|
| - Object* length = prototype->length();
|
| - RUNTIME_ASSERT(length->IsSmi() && Smi::cast(length)->value() == 0);
|
| - RUNTIME_ASSERT(prototype->HasFastSmiOrObjectElements());
|
| - // This is necessary to enable fast checks for absence of elements
|
| - // on Array.prototype and below.
|
| - prototype->set_elements(isolate->heap()->empty_fixed_array());
|
| - return Smi::FromInt(0);
|
| -}
|
| + DCHECK(args.length() == 2);
|
| +
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1);
|
|
|
| + // Fast cases for getting named properties of the receiver JSObject
|
| + // itself.
|
| + //
|
| + // The global proxy objects has to be excluded since LookupOwn on
|
| + // the global proxy object can return a valid result even though the
|
| + // global proxy object never has properties. This is the case
|
| + // because the global proxy object forwards everything to its hidden
|
| + // prototype including own lookups.
|
| + //
|
| + // Additionally, we need to make sure that we do not cache results
|
| + // for objects that require access checks.
|
| + if (receiver_obj->IsJSObject()) {
|
| + if (!receiver_obj->IsJSGlobalProxy() &&
|
| + !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) {
|
| + DisallowHeapAllocation no_allocation;
|
| + Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj);
|
| + Handle<Name> key = Handle<Name>::cast(key_obj);
|
| + if (receiver->HasFastProperties()) {
|
| + // Attempt to use lookup cache.
|
| + Handle<Map> receiver_map(receiver->map(), isolate);
|
| + KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
|
| + int index = keyed_lookup_cache->Lookup(receiver_map, key);
|
| + if (index != -1) {
|
| + // Doubles are not cached, so raw read the value.
|
| + return receiver->RawFastPropertyAt(
|
| + FieldIndex::ForKeyedLookupCacheIndex(*receiver_map, index));
|
| + }
|
| + // Lookup cache miss. Perform lookup and update the cache if
|
| + // appropriate.
|
| + LookupIterator it(receiver, key, LookupIterator::OWN);
|
| + if (it.state() == LookupIterator::DATA &&
|
| + it.property_details().type() == FIELD) {
|
| + FieldIndex field_index = it.GetFieldIndex();
|
| + // Do not track double fields in the keyed lookup cache. Reading
|
| + // double values requires boxing.
|
| + if (!it.representation().IsDouble()) {
|
| + keyed_lookup_cache->Update(receiver_map, key,
|
| + field_index.GetKeyedLookupCacheIndex());
|
| + }
|
| + AllowHeapAllocation allow_allocation;
|
| + return *JSObject::FastPropertyAt(receiver, it.representation(),
|
| + field_index);
|
| + }
|
| + } else {
|
| + // Attempt dictionary lookup.
|
| + NameDictionary* dictionary = receiver->property_dictionary();
|
| + int entry = dictionary->FindEntry(key);
|
| + if ((entry != NameDictionary::kNotFound) &&
|
| + (dictionary->DetailsAt(entry).type() == NORMAL)) {
|
| + Object* value = dictionary->ValueAt(entry);
|
| + if (!receiver->IsGlobalObject()) return value;
|
| + value = PropertyCell::cast(value)->value();
|
| + if (!value->IsTheHole()) return value;
|
| + // If value is the hole (meaning, absent) do the general lookup.
|
| + }
|
| + }
|
| + } else if (key_obj->IsSmi()) {
|
| + // JSObject without a name key. If the key is a Smi, check for a
|
| + // definite out-of-bounds access to elements, which is a strong indicator
|
| + // that subsequent accesses will also call the runtime. Proactively
|
| + // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
|
| + // doubles for those future calls in the case that the elements would
|
| + // become FAST_DOUBLE_ELEMENTS.
|
| + Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj);
|
| + ElementsKind elements_kind = js_object->GetElementsKind();
|
| + if (IsFastDoubleElementsKind(elements_kind)) {
|
| + Handle<Smi> key = Handle<Smi>::cast(key_obj);
|
| + if (key->value() >= js_object->elements()->length()) {
|
| + if (IsFastHoleyElementsKind(elements_kind)) {
|
| + elements_kind = FAST_HOLEY_ELEMENTS;
|
| + } else {
|
| + elements_kind = FAST_ELEMENTS;
|
| + }
|
| + RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, TransitionElements(js_object, elements_kind, isolate));
|
| + }
|
| + } else {
|
| + DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
|
| + !IsFastElementsKind(elements_kind));
|
| + }
|
| + }
|
| + } else if (receiver_obj->IsString() && key_obj->IsSmi()) {
|
| + // Fast case for string indexing using [] with a smi index.
|
| + Handle<String> str = Handle<String>::cast(receiver_obj);
|
| + int index = args.smi_at(1);
|
| + if (index >= 0 && index < str->length()) {
|
| + return *GetCharAt(str, index);
|
| + }
|
| + }
|
|
|
| -static void InstallBuiltin(Isolate* isolate, Handle<JSObject> holder,
|
| - const char* name, Builtins::Name builtin_name) {
|
| - Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
|
| - Handle<Code> code(isolate->builtins()->builtin(builtin_name));
|
| - Handle<JSFunction> optimized =
|
| - isolate->factory()->NewFunctionWithoutPrototype(key, code);
|
| - optimized->shared()->DontAdaptArguments();
|
| - JSObject::AddProperty(holder, key, optimized, NONE);
|
| + // Fall back to GetObjectProperty.
|
| + Handle<Object> result;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, result,
|
| + Runtime::GetObjectProperty(isolate, receiver_obj, key_obj));
|
| + return *result;
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 0);
|
| - Handle<JSObject> holder =
|
| - isolate->factory()->NewJSObject(isolate->object_function());
|
| +static bool IsValidAccessor(Handle<Object> obj) {
|
| + return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
|
| +}
|
|
|
| - InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
|
| - InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
|
| - InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
|
| - InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
|
| - InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
|
| - InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
|
| - InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
|
|
|
| - return *holder;
|
| +// Transform getter or setter into something DefineAccessor can handle.
|
| +static Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
|
| + Handle<Object> component) {
|
| + if (component->IsUndefined()) return isolate->factory()->undefined_value();
|
| + Handle<FunctionTemplateInfo> info =
|
| + Handle<FunctionTemplateInfo>::cast(component);
|
| + return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_IsSloppyModeFunction) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
|
| - if (!callable->IsJSFunction()) {
|
| - HandleScope scope(isolate);
|
| - Handle<Object> delegate;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, delegate, Execution::TryGetFunctionDelegate(
|
| - isolate, Handle<JSReceiver>(callable)));
|
| - callable = JSFunction::cast(*delegate);
|
| - }
|
| - JSFunction* function = JSFunction::cast(callable);
|
| - SharedFunctionInfo* shared = function->shared();
|
| - return isolate->heap()->ToBoolean(shared->strict_mode() == SLOPPY);
|
| +RUNTIME_FUNCTION(Runtime_DefineApiAccessorProperty) {
|
| + HandleScope scope(isolate);
|
| + DCHECK(args.length() == 5);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
|
| + CONVERT_SMI_ARG_CHECKED(attribute, 4);
|
| + RUNTIME_ASSERT(getter->IsUndefined() || getter->IsFunctionTemplateInfo());
|
| + RUNTIME_ASSERT(setter->IsUndefined() || setter->IsFunctionTemplateInfo());
|
| + RUNTIME_ASSERT(PropertyDetails::AttributesField::is_valid(
|
| + static_cast<PropertyAttributes>(attribute)));
|
| + RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, JSObject::DefineAccessor(
|
| + object, name, InstantiateAccessorComponent(isolate, getter),
|
| + InstantiateAccessorComponent(isolate, setter),
|
| + static_cast<PropertyAttributes>(attribute)));
|
| + return isolate->heap()->undefined_value();
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_GetDefaultReceiver) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
|
| +// Implements part of 8.12.9 DefineOwnProperty.
|
| +// There are 3 cases that lead here:
|
| +// Step 4b - define a new accessor property.
|
| +// Steps 9c & 12 - replace an existing data property with an accessor property.
|
| +// Step 12 - update an existing accessor property with an accessor or generic
|
| +// descriptor.
|
| +RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) {
|
| + HandleScope scope(isolate);
|
| + DCHECK(args.length() == 5);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
| + RUNTIME_ASSERT(!obj->IsNull());
|
| + CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
|
| + RUNTIME_ASSERT(IsValidAccessor(getter));
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
|
| + RUNTIME_ASSERT(IsValidAccessor(setter));
|
| + CONVERT_SMI_ARG_CHECKED(unchecked, 4);
|
| + RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
|
| + PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
|
|
|
| - if (!callable->IsJSFunction()) {
|
| - HandleScope scope(isolate);
|
| - Handle<Object> delegate;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, delegate, Execution::TryGetFunctionDelegate(
|
| - isolate, Handle<JSReceiver>(callable)));
|
| - callable = JSFunction::cast(*delegate);
|
| - }
|
| - JSFunction* function = JSFunction::cast(callable);
|
| + bool fast = obj->HasFastProperties();
|
| + RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, JSObject::DefineAccessor(obj, name, getter, setter, attr));
|
| + if (fast) JSObject::MigrateSlowToFast(obj, 0);
|
| + return isolate->heap()->undefined_value();
|
| +}
|
|
|
| - SharedFunctionInfo* shared = function->shared();
|
| - if (shared->native() || shared->strict_mode() == STRICT) {
|
| - return isolate->heap()->undefined_value();
|
| - }
|
| - // Returns undefined for strict or native functions, or
|
| - // the associated global receiver for "normal" functions.
|
|
|
| - return function->global_proxy();
|
| -}
|
| +// Implements part of 8.12.9 DefineOwnProperty.
|
| +// There are 3 cases that lead here:
|
| +// Step 4a - define a new data property.
|
| +// Steps 9b & 12 - replace an existing accessor property with a data property.
|
| +// Step 12 - update an existing data property with a data or generic
|
| +// descriptor.
|
| +RUNTIME_FUNCTION(Runtime_DefineDataPropertyUnchecked) {
|
| + HandleScope scope(isolate);
|
| + DCHECK(args.length() == 4);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
|
| + CONVERT_SMI_ARG_CHECKED(unchecked, 3);
|
| + RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
|
| + PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
|
|
|
| + LookupIterator it(js_object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
| + if (it.IsFound() && it.state() == LookupIterator::ACCESS_CHECK) {
|
| + if (!isolate->MayNamedAccess(js_object, name, v8::ACCESS_SET)) {
|
| + return isolate->heap()->undefined_value();
|
| + }
|
| + it.Next();
|
| + }
|
|
|
| -RUNTIME_FUNCTION(Runtime_FunctionGetName) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| + // Take special care when attributes are different and there is already
|
| + // a property.
|
| + if (it.state() == LookupIterator::ACCESSOR) {
|
| + // Use IgnoreAttributes version since a readonly property may be
|
| + // overridden and SetProperty does not allow this.
|
| + Handle<Object> result;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, result,
|
| + JSObject::SetOwnPropertyIgnoreAttributes(
|
| + js_object, name, obj_value, attr, JSObject::DONT_FORCE_FIELD));
|
| + return *result;
|
| + }
|
|
|
| - CONVERT_ARG_CHECKED(JSFunction, f, 0);
|
| - return f->shared()->name();
|
| + Handle<Object> result;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, result,
|
| + Runtime::DefineObjectProperty(js_object, name, obj_value, attr));
|
| + return *result;
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_FunctionSetName) {
|
| - SealHandleScope shs(isolate);
|
| +// Return property without being observable by accessors or interceptors.
|
| +RUNTIME_FUNCTION(Runtime_GetDataProperty) {
|
| + HandleScope scope(isolate);
|
| DCHECK(args.length() == 2);
|
| -
|
| - CONVERT_ARG_CHECKED(JSFunction, f, 0);
|
| - CONVERT_ARG_CHECKED(String, name, 1);
|
| - f->shared()->set_name(name);
|
| - return isolate->heap()->undefined_value();
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
| + return *JSObject::GetDataProperty(object, key);
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_FunctionNameShouldPrintAsAnonymous) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(JSFunction, f, 0);
|
| - return isolate->heap()->ToBoolean(
|
| - f->shared()->name_should_print_as_anonymous());
|
| -}
|
| -
|
| +MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
|
| + Handle<Object> object,
|
| + Handle<Object> key,
|
| + Handle<Object> value,
|
| + StrictMode strict_mode) {
|
| + if (object->IsUndefined() || object->IsNull()) {
|
| + Handle<Object> args[2] = {key, object};
|
| + THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_store",
|
| + HandleVector(args, 2)),
|
| + Object);
|
| + }
|
|
|
| -RUNTIME_FUNCTION(Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(JSFunction, f, 0);
|
| - f->shared()->set_name_should_print_as_anonymous(true);
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| + if (object->IsJSProxy()) {
|
| + Handle<Object> name_object;
|
| + if (key->IsSymbol()) {
|
| + name_object = key;
|
| + } else {
|
| + ASSIGN_RETURN_ON_EXCEPTION(isolate, name_object,
|
| + Execution::ToString(isolate, key), Object);
|
| + }
|
| + Handle<Name> name = Handle<Name>::cast(name_object);
|
| + return Object::SetProperty(Handle<JSProxy>::cast(object), name, value,
|
| + strict_mode);
|
| + }
|
|
|
| + // Check if the given key is an array index.
|
| + uint32_t index;
|
| + if (key->ToArrayIndex(&index)) {
|
| + // TODO(verwaest): Support non-JSObject receivers.
|
| + if (!object->IsJSObject()) return value;
|
| + Handle<JSObject> js_object = Handle<JSObject>::cast(object);
|
|
|
| -RUNTIME_FUNCTION(Runtime_FunctionIsArrow) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(JSFunction, f, 0);
|
| - return isolate->heap()->ToBoolean(f->shared()->is_arrow());
|
| -}
|
| + // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
|
| + // of a string using [] notation. We need to support this too in
|
| + // JavaScript.
|
| + // In the case of a String object we just need to redirect the assignment to
|
| + // the underlying string if the index is in range. Since the underlying
|
| + // string does nothing with the assignment then we can ignore such
|
| + // assignments.
|
| + if (js_object->IsStringObjectWithCharacterAt(index)) {
|
| + return value;
|
| + }
|
|
|
| + JSObject::ValidateElements(js_object);
|
| + if (js_object->HasExternalArrayElements() ||
|
| + js_object->HasFixedTypedArrayElements()) {
|
| + if (!value->IsNumber() && !value->IsUndefined()) {
|
| + ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
|
| + Execution::ToNumber(isolate, value), Object);
|
| + }
|
| + }
|
|
|
| -RUNTIME_FUNCTION(Runtime_FunctionIsConciseMethod) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(JSFunction, f, 0);
|
| - return isolate->heap()->ToBoolean(f->shared()->is_concise_method());
|
| -}
|
| + MaybeHandle<Object> result = JSObject::SetElement(
|
| + js_object, index, value, NONE, strict_mode, true, SET_PROPERTY);
|
| + JSObject::ValidateElements(js_object);
|
|
|
| + return result.is_null() ? result : value;
|
| + }
|
|
|
| -RUNTIME_FUNCTION(Runtime_FunctionRemovePrototype) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| + if (key->IsName()) {
|
| + Handle<Name> name = Handle<Name>::cast(key);
|
| + if (name->AsArrayIndex(&index)) {
|
| + // TODO(verwaest): Support non-JSObject receivers.
|
| + if (!object->IsJSObject()) return value;
|
| + Handle<JSObject> js_object = Handle<JSObject>::cast(object);
|
| + if (js_object->HasExternalArrayElements()) {
|
| + if (!value->IsNumber() && !value->IsUndefined()) {
|
| + ASSIGN_RETURN_ON_EXCEPTION(
|
| + isolate, value, Execution::ToNumber(isolate, value), Object);
|
| + }
|
| + }
|
| + return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
|
| + true, SET_PROPERTY);
|
| + } else {
|
| + if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
|
| + return Object::SetProperty(object, name, value, strict_mode);
|
| + }
|
| + }
|
|
|
| - CONVERT_ARG_CHECKED(JSFunction, f, 0);
|
| - RUNTIME_ASSERT(f->RemovePrototype());
|
| + // Call-back into JavaScript to convert the key to a string.
|
| + Handle<Object> converted;
|
| + ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
|
| + Execution::ToString(isolate, key), Object);
|
| + Handle<String> name = Handle<String>::cast(converted);
|
|
|
| - return isolate->heap()->undefined_value();
|
| + if (name->AsArrayIndex(&index)) {
|
| + // TODO(verwaest): Support non-JSObject receivers.
|
| + if (!object->IsJSObject()) return value;
|
| + Handle<JSObject> js_object = Handle<JSObject>::cast(object);
|
| + return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
|
| + true, SET_PROPERTY);
|
| + }
|
| + return Object::SetProperty(object, name, value, strict_mode);
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_FunctionGetScript) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| -
|
| - CONVERT_ARG_CHECKED(JSFunction, fun, 0);
|
| - Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
|
| - if (!script->IsScript()) return isolate->heap()->undefined_value();
|
| +MaybeHandle<Object> Runtime::DefineObjectProperty(Handle<JSObject> js_object,
|
| + Handle<Object> key,
|
| + Handle<Object> value,
|
| + PropertyAttributes attr) {
|
| + Isolate* isolate = js_object->GetIsolate();
|
| + // Check if the given key is an array index.
|
| + uint32_t index;
|
| + if (key->ToArrayIndex(&index)) {
|
| + // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
|
| + // of a string using [] notation. We need to support this too in
|
| + // JavaScript.
|
| + // In the case of a String object we just need to redirect the assignment to
|
| + // the underlying string if the index is in range. Since the underlying
|
| + // string does nothing with the assignment then we can ignore such
|
| + // assignments.
|
| + if (js_object->IsStringObjectWithCharacterAt(index)) {
|
| + return value;
|
| + }
|
|
|
| - return *Script::GetWrapper(Handle<Script>::cast(script));
|
| -}
|
| + return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
|
| + DEFINE_PROPERTY);
|
| + }
|
|
|
| + if (key->IsName()) {
|
| + Handle<Name> name = Handle<Name>::cast(key);
|
| + if (name->AsArrayIndex(&index)) {
|
| + return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
|
| + DEFINE_PROPERTY);
|
| + } else {
|
| + if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
|
| + return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value,
|
| + attr);
|
| + }
|
| + }
|
|
|
| -RUNTIME_FUNCTION(Runtime_FunctionGetSourceCode) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| + // Call-back into JavaScript to convert the key to a string.
|
| + Handle<Object> converted;
|
| + ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
|
| + Execution::ToString(isolate, key), Object);
|
| + Handle<String> name = Handle<String>::cast(converted);
|
|
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
|
| - Handle<SharedFunctionInfo> shared(f->shared());
|
| - return *shared->GetSourceCode();
|
| + if (name->AsArrayIndex(&index)) {
|
| + return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
|
| + DEFINE_PROPERTY);
|
| + } else {
|
| + return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value,
|
| + attr);
|
| + }
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_FunctionGetScriptSourcePosition) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| -
|
| - CONVERT_ARG_CHECKED(JSFunction, fun, 0);
|
| - int pos = fun->shared()->start_position();
|
| - return Smi::FromInt(pos);
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_FunctionGetPositionForOffset) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 2);
|
| -
|
| - CONVERT_ARG_CHECKED(Code, code, 0);
|
| - CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
|
| -
|
| - RUNTIME_ASSERT(0 <= offset && offset < code->Size());
|
| -
|
| - Address pc = code->address() + offset;
|
| - return Smi::FromInt(code->SourcePosition(pc));
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_FunctionSetInstanceClassName) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 2);
|
| -
|
| - CONVERT_ARG_CHECKED(JSFunction, fun, 0);
|
| - CONVERT_ARG_CHECKED(String, name, 1);
|
| - fun->SetInstanceClassName(name);
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_FunctionSetLength) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 2);
|
| -
|
| - CONVERT_ARG_CHECKED(JSFunction, fun, 0);
|
| - CONVERT_SMI_ARG_CHECKED(length, 1);
|
| - RUNTIME_ASSERT((length & 0xC0000000) == 0xC0000000 ||
|
| - (length & 0xC0000000) == 0x0);
|
| - fun->shared()->set_length(length);
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
|
| - RUNTIME_ASSERT(fun->should_have_prototype());
|
| - Accessors::FunctionSetPrototype(fun, value);
|
| - return args[0]; // return TOS
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_FunctionIsAPIFunction) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| -
|
| - CONVERT_ARG_CHECKED(JSFunction, f, 0);
|
| - return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_FunctionIsBuiltin) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| -
|
| - CONVERT_ARG_CHECKED(JSFunction, f, 0);
|
| - return isolate->heap()->ToBoolean(f->IsBuiltin());
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_SetCode) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, source, 1);
|
| -
|
| - Handle<SharedFunctionInfo> target_shared(target->shared());
|
| - Handle<SharedFunctionInfo> source_shared(source->shared());
|
| - RUNTIME_ASSERT(!source_shared->bound());
|
| -
|
| - if (!Compiler::EnsureCompiled(source, KEEP_EXCEPTION)) {
|
| - return isolate->heap()->exception();
|
| - }
|
| -
|
| - // Mark both, the source and the target, as un-flushable because the
|
| - // shared unoptimized code makes them impossible to enqueue in a list.
|
| - DCHECK(target_shared->code()->gc_metadata() == NULL);
|
| - DCHECK(source_shared->code()->gc_metadata() == NULL);
|
| - target_shared->set_dont_flush(true);
|
| - source_shared->set_dont_flush(true);
|
| -
|
| - // Set the code, scope info, formal parameter count, and the length
|
| - // of the target shared function info.
|
| - target_shared->ReplaceCode(source_shared->code());
|
| - target_shared->set_scope_info(source_shared->scope_info());
|
| - target_shared->set_length(source_shared->length());
|
| - target_shared->set_feedback_vector(source_shared->feedback_vector());
|
| - target_shared->set_formal_parameter_count(
|
| - source_shared->formal_parameter_count());
|
| - target_shared->set_script(source_shared->script());
|
| - target_shared->set_start_position_and_type(
|
| - source_shared->start_position_and_type());
|
| - target_shared->set_end_position(source_shared->end_position());
|
| - bool was_native = target_shared->native();
|
| - target_shared->set_compiler_hints(source_shared->compiler_hints());
|
| - target_shared->set_native(was_native);
|
| - target_shared->set_profiler_ticks(source_shared->profiler_ticks());
|
| -
|
| - // Set the code of the target function.
|
| - target->ReplaceCode(source_shared->code());
|
| - DCHECK(target->next_function_link()->IsUndefined());
|
| -
|
| - // Make sure we get a fresh copy of the literal vector to avoid cross
|
| - // context contamination.
|
| - Handle<Context> context(source->context());
|
| - int number_of_literals = source->NumberOfLiterals();
|
| - Handle<FixedArray> literals =
|
| - isolate->factory()->NewFixedArray(number_of_literals, TENURED);
|
| - if (number_of_literals > 0) {
|
| - literals->set(JSFunction::kLiteralNativeContextIndex,
|
| - context->native_context());
|
| - }
|
| - target->set_context(*context);
|
| - target->set_literals(*literals);
|
| -
|
| - if (isolate->logger()->is_logging_code_events() ||
|
| - isolate->cpu_profiler()->is_profiling()) {
|
| - isolate->logger()->LogExistingFunction(source_shared,
|
| - Handle<Code>(source_shared->code()));
|
| - }
|
| -
|
| - return *target;
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_ObjectFreeze) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| -
|
| - // %ObjectFreeze is a fast path and these cases are handled elsewhere.
|
| - RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() &&
|
| - !object->map()->is_observed() && !object->IsJSProxy());
|
| -
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object));
|
| - return *result;
|
| -}
|
| -
|
| -
|
| -// Returns a single character string where first character equals
|
| -// string->Get(index).
|
| -static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
|
| - if (index < static_cast<uint32_t>(string->length())) {
|
| - Factory* factory = string->GetIsolate()->factory();
|
| - return factory->LookupSingleCharacterStringFromCode(
|
| - String::Flatten(string)->Get(index));
|
| - }
|
| - return Execution::CharAt(string, index);
|
| -}
|
| -
|
| -
|
| -MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate,
|
| - Handle<Object> object,
|
| - uint32_t index) {
|
| - // Handle [] indexing on Strings
|
| - if (object->IsString()) {
|
| - Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
|
| - if (!result->IsUndefined()) return result;
|
| - }
|
| -
|
| - // Handle [] indexing on String objects
|
| - if (object->IsStringObjectWithCharacterAt(index)) {
|
| - Handle<JSValue> js_value = Handle<JSValue>::cast(object);
|
| - Handle<Object> result =
|
| - GetCharAt(Handle<String>(String::cast(js_value->value())), index);
|
| - if (!result->IsUndefined()) return result;
|
| - }
|
| -
|
| - Handle<Object> result;
|
| - if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
|
| - PrototypeIterator iter(isolate, object);
|
| - return Object::GetElement(isolate, PrototypeIterator::GetCurrent(iter),
|
| - index);
|
| - } else {
|
| - return Object::GetElement(isolate, object, index);
|
| - }
|
| -}
|
| -
|
| -
|
| -MUST_USE_RESULT
|
| -static MaybeHandle<Name> ToName(Isolate* isolate, Handle<Object> key) {
|
| - if (key->IsName()) {
|
| - return Handle<Name>::cast(key);
|
| - } else {
|
| - Handle<Object> converted;
|
| - ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
|
| - Execution::ToString(isolate, key), Name);
|
| - return Handle<Name>::cast(converted);
|
| - }
|
| -}
|
| -
|
| -
|
| -MaybeHandle<Object> Runtime::HasObjectProperty(Isolate* isolate,
|
| - Handle<JSReceiver> object,
|
| - Handle<Object> key) {
|
| - Maybe<bool> maybe;
|
| +MaybeHandle<Object> Runtime::DeleteObjectProperty(Isolate* isolate,
|
| + Handle<JSReceiver> receiver,
|
| + Handle<Object> key,
|
| + JSReceiver::DeleteMode mode) {
|
| // Check if the given key is an array index.
|
| uint32_t index;
|
| if (key->ToArrayIndex(&index)) {
|
| - maybe = JSReceiver::HasElement(object, index);
|
| - } else {
|
| - // Convert the key to a name - possibly by calling back into JavaScript.
|
| - Handle<Name> name;
|
| - ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
|
| -
|
| - maybe = JSReceiver::HasProperty(object, name);
|
| - }
|
| -
|
| - if (!maybe.has_value) return MaybeHandle<Object>();
|
| - return isolate->factory()->ToBoolean(maybe.value);
|
| -}
|
| -
|
| -
|
| -MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
|
| - Handle<Object> object,
|
| - Handle<Object> key) {
|
| - if (object->IsUndefined() || object->IsNull()) {
|
| - Handle<Object> args[2] = {key, object};
|
| - THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_load",
|
| - HandleVector(args, 2)),
|
| - Object);
|
| - }
|
| + // In Firefox/SpiderMonkey, Safari and Opera you can access the
|
| + // characters of a string using [] notation. In the case of a
|
| + // String object we just need to redirect the deletion to the
|
| + // underlying string if the index is in range. Since the
|
| + // underlying string does nothing with the deletion, we can ignore
|
| + // such deletions.
|
| + if (receiver->IsStringObjectWithCharacterAt(index)) {
|
| + return isolate->factory()->true_value();
|
| + }
|
|
|
| - // Check if the given key is an array index.
|
| - uint32_t index;
|
| - if (key->ToArrayIndex(&index)) {
|
| - return GetElementOrCharAt(isolate, object, index);
|
| + return JSReceiver::DeleteElement(receiver, index, mode);
|
| }
|
|
|
| - // Convert the key to a name - possibly by calling back into JavaScript.
|
| Handle<Name> name;
|
| - ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
|
| -
|
| - // Check if the name is trivially convertible to an index and get
|
| - // the element if so.
|
| - if (name->AsArrayIndex(&index)) {
|
| - return GetElementOrCharAt(isolate, object, index);
|
| + if (key->IsName()) {
|
| + name = Handle<Name>::cast(key);
|
| } else {
|
| - return Object::GetProperty(object, name);
|
| + // Call-back into JavaScript to convert the key to a string.
|
| + Handle<Object> converted;
|
| + ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
|
| + Execution::ToString(isolate, key), Object);
|
| + name = Handle<String>::cast(converted);
|
| }
|
| +
|
| + if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
|
| + return JSReceiver::DeleteProperty(receiver, name, mode);
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_GetProperty) {
|
| +RUNTIME_FUNCTION(Runtime_SetHiddenProperty) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| + RUNTIME_ASSERT(args.length() == 3);
|
|
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result, Runtime::GetObjectProperty(isolate, object, key));
|
| - return *result;
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(String, key, 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
| + RUNTIME_ASSERT(key->IsUniqueName());
|
| + return *JSObject::SetHiddenProperty(object, key, value);
|
| }
|
|
|
|
|
| -// KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
|
| -RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
|
| +RUNTIME_FUNCTION(Runtime_AddNamedProperty) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| + RUNTIME_ASSERT(args.length() == 4);
|
|
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
| + CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
|
| + RUNTIME_ASSERT(
|
| + (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
|
| + // Compute attributes.
|
| + PropertyAttributes attributes =
|
| + static_cast<PropertyAttributes>(unchecked_attributes);
|
|
|
| - // Fast cases for getting named properties of the receiver JSObject
|
| - // itself.
|
| - //
|
| - // The global proxy objects has to be excluded since LookupOwn on
|
| - // the global proxy object can return a valid result even though the
|
| - // global proxy object never has properties. This is the case
|
| - // because the global proxy object forwards everything to its hidden
|
| - // prototype including own lookups.
|
| - //
|
| - // Additionally, we need to make sure that we do not cache results
|
| - // for objects that require access checks.
|
| - if (receiver_obj->IsJSObject()) {
|
| - if (!receiver_obj->IsJSGlobalProxy() &&
|
| - !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) {
|
| - DisallowHeapAllocation no_allocation;
|
| - Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj);
|
| - Handle<Name> key = Handle<Name>::cast(key_obj);
|
| - if (receiver->HasFastProperties()) {
|
| - // Attempt to use lookup cache.
|
| - Handle<Map> receiver_map(receiver->map(), isolate);
|
| - KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
|
| - int index = keyed_lookup_cache->Lookup(receiver_map, key);
|
| - if (index != -1) {
|
| - // Doubles are not cached, so raw read the value.
|
| - return receiver->RawFastPropertyAt(
|
| - FieldIndex::ForKeyedLookupCacheIndex(*receiver_map, index));
|
| - }
|
| - // Lookup cache miss. Perform lookup and update the cache if
|
| - // appropriate.
|
| - LookupIterator it(receiver, key, LookupIterator::OWN);
|
| - if (it.state() == LookupIterator::DATA &&
|
| - it.property_details().type() == FIELD) {
|
| - FieldIndex field_index = it.GetFieldIndex();
|
| - // Do not track double fields in the keyed lookup cache. Reading
|
| - // double values requires boxing.
|
| - if (!it.representation().IsDouble()) {
|
| - keyed_lookup_cache->Update(receiver_map, key,
|
| - field_index.GetKeyedLookupCacheIndex());
|
| - }
|
| - AllowHeapAllocation allow_allocation;
|
| - return *JSObject::FastPropertyAt(receiver, it.representation(),
|
| - field_index);
|
| - }
|
| - } else {
|
| - // Attempt dictionary lookup.
|
| - NameDictionary* dictionary = receiver->property_dictionary();
|
| - int entry = dictionary->FindEntry(key);
|
| - if ((entry != NameDictionary::kNotFound) &&
|
| - (dictionary->DetailsAt(entry).type() == NORMAL)) {
|
| - Object* value = dictionary->ValueAt(entry);
|
| - if (!receiver->IsGlobalObject()) return value;
|
| - value = PropertyCell::cast(value)->value();
|
| - if (!value->IsTheHole()) return value;
|
| - // If value is the hole (meaning, absent) do the general lookup.
|
| - }
|
| - }
|
| - } else if (key_obj->IsSmi()) {
|
| - // JSObject without a name key. If the key is a Smi, check for a
|
| - // definite out-of-bounds access to elements, which is a strong indicator
|
| - // that subsequent accesses will also call the runtime. Proactively
|
| - // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
|
| - // doubles for those future calls in the case that the elements would
|
| - // become FAST_DOUBLE_ELEMENTS.
|
| - Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj);
|
| - ElementsKind elements_kind = js_object->GetElementsKind();
|
| - if (IsFastDoubleElementsKind(elements_kind)) {
|
| - Handle<Smi> key = Handle<Smi>::cast(key_obj);
|
| - if (key->value() >= js_object->elements()->length()) {
|
| - if (IsFastHoleyElementsKind(elements_kind)) {
|
| - elements_kind = FAST_HOLEY_ELEMENTS;
|
| - } else {
|
| - elements_kind = FAST_ELEMENTS;
|
| - }
|
| - RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, TransitionElements(js_object, elements_kind, isolate));
|
| - }
|
| - } else {
|
| - DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
|
| - !IsFastElementsKind(elements_kind));
|
| - }
|
| - }
|
| - } else if (receiver_obj->IsString() && key_obj->IsSmi()) {
|
| - // Fast case for string indexing using [] with a smi index.
|
| - Handle<String> str = Handle<String>::cast(receiver_obj);
|
| - int index = args.smi_at(1);
|
| - if (index >= 0 && index < str->length()) {
|
| - return *GetCharAt(str, index);
|
| - }
|
| - }
|
| -
|
| - // Fall back to GetObjectProperty.
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result,
|
| - Runtime::GetObjectProperty(isolate, receiver_obj, key_obj));
|
| - return *result;
|
| -}
|
| -
|
| -
|
| -static bool IsValidAccessor(Handle<Object> obj) {
|
| - return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
|
| -}
|
| -
|
| -
|
| -// Transform getter or setter into something DefineAccessor can handle.
|
| -static Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
|
| - Handle<Object> component) {
|
| - if (component->IsUndefined()) return isolate->factory()->undefined_value();
|
| - Handle<FunctionTemplateInfo> info =
|
| - Handle<FunctionTemplateInfo>::cast(component);
|
| - return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_DefineApiAccessorProperty) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 5);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
|
| - CONVERT_SMI_ARG_CHECKED(attribute, 4);
|
| - RUNTIME_ASSERT(getter->IsUndefined() || getter->IsFunctionTemplateInfo());
|
| - RUNTIME_ASSERT(setter->IsUndefined() || setter->IsFunctionTemplateInfo());
|
| - RUNTIME_ASSERT(PropertyDetails::AttributesField::is_valid(
|
| - static_cast<PropertyAttributes>(attribute)));
|
| - RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, JSObject::DefineAccessor(
|
| - object, name, InstantiateAccessorComponent(isolate, getter),
|
| - InstantiateAccessorComponent(isolate, setter),
|
| - static_cast<PropertyAttributes>(attribute)));
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| -// Implements part of 8.12.9 DefineOwnProperty.
|
| -// There are 3 cases that lead here:
|
| -// Step 4b - define a new accessor property.
|
| -// Steps 9c & 12 - replace an existing data property with an accessor property.
|
| -// Step 12 - update an existing accessor property with an accessor or generic
|
| -// descriptor.
|
| -RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 5);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
| - RUNTIME_ASSERT(!obj->IsNull());
|
| - CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
|
| - RUNTIME_ASSERT(IsValidAccessor(getter));
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
|
| - RUNTIME_ASSERT(IsValidAccessor(setter));
|
| - CONVERT_SMI_ARG_CHECKED(unchecked, 4);
|
| - RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
|
| - PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
|
| -
|
| - bool fast = obj->HasFastProperties();
|
| - RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, JSObject::DefineAccessor(obj, name, getter, setter, attr));
|
| - if (fast) JSObject::MigrateSlowToFast(obj, 0);
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| -// Implements part of 8.12.9 DefineOwnProperty.
|
| -// There are 3 cases that lead here:
|
| -// Step 4a - define a new data property.
|
| -// Steps 9b & 12 - replace an existing accessor property with a data property.
|
| -// Step 12 - update an existing data property with a data or generic
|
| -// descriptor.
|
| -RUNTIME_FUNCTION(Runtime_DefineDataPropertyUnchecked) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 4);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
|
| - CONVERT_SMI_ARG_CHECKED(unchecked, 3);
|
| - RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
|
| - PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
|
| -
|
| - LookupIterator it(js_object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
| - if (it.IsFound() && it.state() == LookupIterator::ACCESS_CHECK) {
|
| - if (!isolate->MayNamedAccess(js_object, name, v8::ACCESS_SET)) {
|
| - return isolate->heap()->undefined_value();
|
| - }
|
| - it.Next();
|
| - }
|
| -
|
| - // Take special care when attributes are different and there is already
|
| - // a property.
|
| - if (it.state() == LookupIterator::ACCESSOR) {
|
| - // Use IgnoreAttributes version since a readonly property may be
|
| - // overridden and SetProperty does not allow this.
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result,
|
| - JSObject::SetOwnPropertyIgnoreAttributes(
|
| - js_object, name, obj_value, attr, JSObject::DONT_FORCE_FIELD));
|
| - return *result;
|
| - }
|
| -
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result,
|
| - Runtime::DefineObjectProperty(js_object, name, obj_value, attr));
|
| - return *result;
|
| -}
|
| -
|
| -
|
| -// Return property without being observable by accessors or interceptors.
|
| -RUNTIME_FUNCTION(Runtime_GetDataProperty) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
| - return *JSObject::GetDataProperty(object, key);
|
| -}
|
| -
|
| -
|
| -MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
|
| - Handle<Object> object,
|
| - Handle<Object> key,
|
| - Handle<Object> value,
|
| - StrictMode strict_mode) {
|
| - if (object->IsUndefined() || object->IsNull()) {
|
| - Handle<Object> args[2] = {key, object};
|
| - THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_store",
|
| - HandleVector(args, 2)),
|
| - Object);
|
| - }
|
| -
|
| - if (object->IsJSProxy()) {
|
| - Handle<Object> name_object;
|
| - if (key->IsSymbol()) {
|
| - name_object = key;
|
| - } else {
|
| - ASSIGN_RETURN_ON_EXCEPTION(isolate, name_object,
|
| - Execution::ToString(isolate, key), Object);
|
| - }
|
| - Handle<Name> name = Handle<Name>::cast(name_object);
|
| - return Object::SetProperty(Handle<JSProxy>::cast(object), name, value,
|
| - strict_mode);
|
| - }
|
| -
|
| - // Check if the given key is an array index.
|
| - uint32_t index;
|
| - if (key->ToArrayIndex(&index)) {
|
| - // TODO(verwaest): Support non-JSObject receivers.
|
| - if (!object->IsJSObject()) return value;
|
| - Handle<JSObject> js_object = Handle<JSObject>::cast(object);
|
| -
|
| - // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
|
| - // of a string using [] notation. We need to support this too in
|
| - // JavaScript.
|
| - // In the case of a String object we just need to redirect the assignment to
|
| - // the underlying string if the index is in range. Since the underlying
|
| - // string does nothing with the assignment then we can ignore such
|
| - // assignments.
|
| - if (js_object->IsStringObjectWithCharacterAt(index)) {
|
| - return value;
|
| - }
|
| -
|
| - JSObject::ValidateElements(js_object);
|
| - if (js_object->HasExternalArrayElements() ||
|
| - js_object->HasFixedTypedArrayElements()) {
|
| - if (!value->IsNumber() && !value->IsUndefined()) {
|
| - ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
|
| - Execution::ToNumber(isolate, value), Object);
|
| - }
|
| - }
|
| -
|
| - MaybeHandle<Object> result = JSObject::SetElement(
|
| - js_object, index, value, NONE, strict_mode, true, SET_PROPERTY);
|
| - JSObject::ValidateElements(js_object);
|
| -
|
| - return result.is_null() ? result : value;
|
| - }
|
| -
|
| - if (key->IsName()) {
|
| - Handle<Name> name = Handle<Name>::cast(key);
|
| - if (name->AsArrayIndex(&index)) {
|
| - // TODO(verwaest): Support non-JSObject receivers.
|
| - if (!object->IsJSObject()) return value;
|
| - Handle<JSObject> js_object = Handle<JSObject>::cast(object);
|
| - if (js_object->HasExternalArrayElements()) {
|
| - if (!value->IsNumber() && !value->IsUndefined()) {
|
| - ASSIGN_RETURN_ON_EXCEPTION(
|
| - isolate, value, Execution::ToNumber(isolate, value), Object);
|
| - }
|
| - }
|
| - return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
|
| - true, SET_PROPERTY);
|
| - } else {
|
| - if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
|
| - return Object::SetProperty(object, name, value, strict_mode);
|
| - }
|
| - }
|
| -
|
| - // Call-back into JavaScript to convert the key to a string.
|
| - Handle<Object> converted;
|
| - ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
|
| - Execution::ToString(isolate, key), Object);
|
| - Handle<String> name = Handle<String>::cast(converted);
|
| -
|
| - if (name->AsArrayIndex(&index)) {
|
| - // TODO(verwaest): Support non-JSObject receivers.
|
| - if (!object->IsJSObject()) return value;
|
| - Handle<JSObject> js_object = Handle<JSObject>::cast(object);
|
| - return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
|
| - true, SET_PROPERTY);
|
| - }
|
| - return Object::SetProperty(object, name, value, strict_mode);
|
| -}
|
| -
|
| -
|
| -MaybeHandle<Object> Runtime::DefineObjectProperty(Handle<JSObject> js_object,
|
| - Handle<Object> key,
|
| - Handle<Object> value,
|
| - PropertyAttributes attr) {
|
| - Isolate* isolate = js_object->GetIsolate();
|
| - // Check if the given key is an array index.
|
| - uint32_t index;
|
| - if (key->ToArrayIndex(&index)) {
|
| - // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
|
| - // of a string using [] notation. We need to support this too in
|
| - // JavaScript.
|
| - // In the case of a String object we just need to redirect the assignment to
|
| - // the underlying string if the index is in range. Since the underlying
|
| - // string does nothing with the assignment then we can ignore such
|
| - // assignments.
|
| - if (js_object->IsStringObjectWithCharacterAt(index)) {
|
| - return value;
|
| - }
|
| -
|
| - return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
|
| - DEFINE_PROPERTY);
|
| - }
|
| -
|
| - if (key->IsName()) {
|
| - Handle<Name> name = Handle<Name>::cast(key);
|
| - if (name->AsArrayIndex(&index)) {
|
| - return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
|
| - DEFINE_PROPERTY);
|
| - } else {
|
| - if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
|
| - return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value,
|
| - attr);
|
| - }
|
| - }
|
| -
|
| - // Call-back into JavaScript to convert the key to a string.
|
| - Handle<Object> converted;
|
| - ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
|
| - Execution::ToString(isolate, key), Object);
|
| - Handle<String> name = Handle<String>::cast(converted);
|
| -
|
| - if (name->AsArrayIndex(&index)) {
|
| - return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
|
| - DEFINE_PROPERTY);
|
| - } else {
|
| - return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value,
|
| - attr);
|
| - }
|
| -}
|
| -
|
| -
|
| -MaybeHandle<Object> Runtime::DeleteObjectProperty(Isolate* isolate,
|
| - Handle<JSReceiver> receiver,
|
| - Handle<Object> key,
|
| - JSReceiver::DeleteMode mode) {
|
| - // Check if the given key is an array index.
|
| - uint32_t index;
|
| - if (key->ToArrayIndex(&index)) {
|
| - // In Firefox/SpiderMonkey, Safari and Opera you can access the
|
| - // characters of a string using [] notation. In the case of a
|
| - // String object we just need to redirect the deletion to the
|
| - // underlying string if the index is in range. Since the
|
| - // underlying string does nothing with the deletion, we can ignore
|
| - // such deletions.
|
| - if (receiver->IsStringObjectWithCharacterAt(index)) {
|
| - return isolate->factory()->true_value();
|
| - }
|
| -
|
| - return JSReceiver::DeleteElement(receiver, index, mode);
|
| - }
|
| -
|
| - Handle<Name> name;
|
| - if (key->IsName()) {
|
| - name = Handle<Name>::cast(key);
|
| - } else {
|
| - // Call-back into JavaScript to convert the key to a string.
|
| - Handle<Object> converted;
|
| - ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
|
| - Execution::ToString(isolate, key), Object);
|
| - name = Handle<String>::cast(converted);
|
| - }
|
| -
|
| - if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
|
| - return JSReceiver::DeleteProperty(receiver, name, mode);
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_SetHiddenProperty) {
|
| - HandleScope scope(isolate);
|
| - RUNTIME_ASSERT(args.length() == 3);
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(String, key, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
| - RUNTIME_ASSERT(key->IsUniqueName());
|
| - return *JSObject::SetHiddenProperty(object, key, value);
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_AddNamedProperty) {
|
| - HandleScope scope(isolate);
|
| - RUNTIME_ASSERT(args.length() == 4);
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
| - CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
|
| - RUNTIME_ASSERT(
|
| - (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
|
| - // Compute attributes.
|
| - PropertyAttributes attributes =
|
| - static_cast<PropertyAttributes>(unchecked_attributes);
|
| -
|
| -#ifdef DEBUG
|
| - uint32_t index = 0;
|
| - DCHECK(!key->ToArrayIndex(&index));
|
| - LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
| - Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
|
| - if (!maybe.has_value) return isolate->heap()->exception();
|
| - RUNTIME_ASSERT(!it.IsFound());
|
| -#endif
|
| -
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result,
|
| - JSObject::SetOwnPropertyIgnoreAttributes(object, key, value, attributes));
|
| - return *result;
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_AddPropertyForTemplate) {
|
| - HandleScope scope(isolate);
|
| - RUNTIME_ASSERT(args.length() == 4);
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
| - CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
|
| - RUNTIME_ASSERT(
|
| - (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
|
| - // Compute attributes.
|
| - PropertyAttributes attributes =
|
| - static_cast<PropertyAttributes>(unchecked_attributes);
|
| -
|
| -#ifdef DEBUG
|
| - bool duplicate;
|
| - if (key->IsName()) {
|
| - LookupIterator it(object, Handle<Name>::cast(key),
|
| - LookupIterator::OWN_SKIP_INTERCEPTOR);
|
| - Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
|
| - DCHECK(maybe.has_value);
|
| - duplicate = it.IsFound();
|
| - } else {
|
| - uint32_t index = 0;
|
| - RUNTIME_ASSERT(key->ToArrayIndex(&index));
|
| - Maybe<bool> maybe = JSReceiver::HasOwnElement(object, index);
|
| - if (!maybe.has_value) return isolate->heap()->exception();
|
| - duplicate = maybe.value;
|
| - }
|
| - if (duplicate) {
|
| - Handle<Object> args[1] = {key};
|
| - THROW_NEW_ERROR_RETURN_FAILURE(
|
| - isolate,
|
| - NewTypeError("duplicate_template_property", HandleVector(args, 1)));
|
| - }
|
| -#endif
|
| -
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result,
|
| - Runtime::DefineObjectProperty(object, key, value, attributes));
|
| - return *result;
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_SetProperty) {
|
| - HandleScope scope(isolate);
|
| - RUNTIME_ASSERT(args.length() == 4);
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
| - CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_arg, 3);
|
| - StrictMode strict_mode = strict_mode_arg;
|
| -
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result,
|
| - Runtime::SetObjectProperty(isolate, object, key, value, strict_mode));
|
| - return *result;
|
| -}
|
| -
|
| -
|
| -// Adds an element to an array.
|
| -// This is used to create an indexed data property into an array.
|
| -RUNTIME_FUNCTION(Runtime_AddElement) {
|
| - HandleScope scope(isolate);
|
| - RUNTIME_ASSERT(args.length() == 4);
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
| - CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
|
| - RUNTIME_ASSERT(
|
| - (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
|
| - // Compute attributes.
|
| - PropertyAttributes attributes =
|
| - static_cast<PropertyAttributes>(unchecked_attributes);
|
| -
|
| - uint32_t index = 0;
|
| - key->ToArrayIndex(&index);
|
| -
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result, JSObject::SetElement(object, index, value, attributes,
|
| - SLOPPY, false, DEFINE_PROPERTY));
|
| - return *result;
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
|
| - HandleScope scope(isolate);
|
| - RUNTIME_ASSERT(args.length() == 2);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Map, map, 1);
|
| - JSObject::TransitionElementsKind(array, map->elements_kind());
|
| - return *array;
|
| -}
|
| -
|
| -
|
| -// Set the native flag on the function.
|
| -// This is used to decide if we should transform null and undefined
|
| -// into the global object when doing call and apply.
|
| -RUNTIME_FUNCTION(Runtime_SetNativeFlag) {
|
| - SealHandleScope shs(isolate);
|
| - RUNTIME_ASSERT(args.length() == 1);
|
| -
|
| - CONVERT_ARG_CHECKED(Object, object, 0);
|
| -
|
| - if (object->IsJSFunction()) {
|
| - JSFunction* func = JSFunction::cast(object);
|
| - func->shared()->set_native(true);
|
| - }
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_SetInlineBuiltinFlag) {
|
| - SealHandleScope shs(isolate);
|
| - RUNTIME_ASSERT(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
| -
|
| - if (object->IsJSFunction()) {
|
| - JSFunction* func = JSFunction::cast(*object);
|
| - func->shared()->set_inline_builtin(true);
|
| - }
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_StoreArrayLiteralElement) {
|
| - HandleScope scope(isolate);
|
| - RUNTIME_ASSERT(args.length() == 5);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| - CONVERT_SMI_ARG_CHECKED(store_index, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
| - CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
|
| - CONVERT_SMI_ARG_CHECKED(literal_index, 4);
|
| -
|
| - Object* raw_literal_cell = literals->get(literal_index);
|
| - JSArray* boilerplate = NULL;
|
| - if (raw_literal_cell->IsAllocationSite()) {
|
| - AllocationSite* site = AllocationSite::cast(raw_literal_cell);
|
| - boilerplate = JSArray::cast(site->transition_info());
|
| - } else {
|
| - boilerplate = JSArray::cast(raw_literal_cell);
|
| - }
|
| - Handle<JSArray> boilerplate_object(boilerplate);
|
| - ElementsKind elements_kind = object->GetElementsKind();
|
| - DCHECK(IsFastElementsKind(elements_kind));
|
| - // Smis should never trigger transitions.
|
| - DCHECK(!value->IsSmi());
|
| -
|
| - if (value->IsNumber()) {
|
| - DCHECK(IsFastSmiElementsKind(elements_kind));
|
| - ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
|
| - ? FAST_HOLEY_DOUBLE_ELEMENTS
|
| - : FAST_DOUBLE_ELEMENTS;
|
| - if (IsMoreGeneralElementsKindTransition(
|
| - boilerplate_object->GetElementsKind(), transitioned_kind)) {
|
| - JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
|
| - }
|
| - JSObject::TransitionElementsKind(object, transitioned_kind);
|
| - DCHECK(IsFastDoubleElementsKind(object->GetElementsKind()));
|
| - FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
|
| - HeapNumber* number = HeapNumber::cast(*value);
|
| - double_array->set(store_index, number->Number());
|
| - } else {
|
| - if (!IsFastObjectElementsKind(elements_kind)) {
|
| - ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
|
| - ? FAST_HOLEY_ELEMENTS
|
| - : FAST_ELEMENTS;
|
| - JSObject::TransitionElementsKind(object, transitioned_kind);
|
| - ElementsKind boilerplate_elements_kind =
|
| - boilerplate_object->GetElementsKind();
|
| - if (IsMoreGeneralElementsKindTransition(boilerplate_elements_kind,
|
| - transitioned_kind)) {
|
| - JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
|
| - }
|
| - }
|
| - FixedArray* object_array = FixedArray::cast(object->elements());
|
| - object_array->set(store_index, *value);
|
| - }
|
| - return *object;
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_DebugPromiseRejectEvent) {
|
| - DCHECK(args.length() == 2);
|
| - HandleScope scope(isolate);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
|
| - isolate->debug()->OnPromiseReject(promise, value);
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_DeleteProperty) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 3);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
| - CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
|
| - JSReceiver::DeleteMode delete_mode = strict_mode == STRICT
|
| - ? JSReceiver::STRICT_DELETION
|
| - : JSReceiver::NORMAL_DELETION;
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result, JSReceiver::DeleteProperty(object, key, delete_mode));
|
| - return *result;
|
| -}
|
| -
|
| -
|
| -static Object* HasOwnPropertyImplementation(Isolate* isolate,
|
| - Handle<JSObject> object,
|
| - Handle<Name> key) {
|
| - Maybe<bool> maybe = JSReceiver::HasOwnProperty(object, key);
|
| - if (!maybe.has_value) return isolate->heap()->exception();
|
| - if (maybe.value) return isolate->heap()->true_value();
|
| - // Handle hidden prototypes. If there's a hidden prototype above this thing
|
| - // then we have to check it for properties, because they are supposed to
|
| - // look like they are on this object.
|
| - PrototypeIterator iter(isolate, object);
|
| - if (!iter.IsAtEnd() &&
|
| - Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter))
|
| - ->map()
|
| - ->is_hidden_prototype()) {
|
| - // TODO(verwaest): The recursion is not necessary for keys that are array
|
| - // indices. Removing this.
|
| - return HasOwnPropertyImplementation(
|
| - isolate, Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
|
| - key);
|
| - }
|
| - RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
|
| - return isolate->heap()->false_value();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_HasOwnProperty) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, object, 0)
|
| - CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
| -
|
| - uint32_t index;
|
| - const bool key_is_array_index = key->AsArrayIndex(&index);
|
| -
|
| - // Only JS objects can have properties.
|
| - if (object->IsJSObject()) {
|
| - Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
|
| - // Fast case: either the key is a real named property or it is not
|
| - // an array index and there are no interceptors or hidden
|
| - // prototypes.
|
| - Maybe<bool> maybe = JSObject::HasRealNamedProperty(js_obj, key);
|
| - if (!maybe.has_value) return isolate->heap()->exception();
|
| - DCHECK(!isolate->has_pending_exception());
|
| - if (maybe.value) {
|
| - return isolate->heap()->true_value();
|
| - }
|
| - Map* map = js_obj->map();
|
| - if (!key_is_array_index && !map->has_named_interceptor() &&
|
| - !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
|
| - return isolate->heap()->false_value();
|
| - }
|
| - // Slow case.
|
| - return HasOwnPropertyImplementation(isolate, Handle<JSObject>(js_obj),
|
| - Handle<Name>(key));
|
| - } else if (object->IsString() && key_is_array_index) {
|
| - // Well, there is one exception: Handle [] on strings.
|
| - Handle<String> string = Handle<String>::cast(object);
|
| - if (index < static_cast<uint32_t>(string->length())) {
|
| - return isolate->heap()->true_value();
|
| - }
|
| - }
|
| - return isolate->heap()->false_value();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_HasProperty) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
| -
|
| - Maybe<bool> maybe = JSReceiver::HasProperty(receiver, key);
|
| - if (!maybe.has_value) return isolate->heap()->exception();
|
| - return isolate->heap()->ToBoolean(maybe.value);
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_HasElement) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
|
| - CONVERT_SMI_ARG_CHECKED(index, 1);
|
| -
|
| - Maybe<bool> maybe = JSReceiver::HasElement(receiver, index);
|
| - if (!maybe.has_value) return isolate->heap()->exception();
|
| - return isolate->heap()->ToBoolean(maybe.value);
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_IsPropertyEnumerable) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
| -
|
| - Maybe<PropertyAttributes> maybe =
|
| - JSReceiver::GetOwnPropertyAttributes(object, key);
|
| - if (!maybe.has_value) return isolate->heap()->exception();
|
| - if (maybe.value == ABSENT) maybe.value = DONT_ENUM;
|
| - return isolate->heap()->ToBoolean((maybe.value & DONT_ENUM) == 0);
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_GetPropertyNames) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
|
| - Handle<JSArray> result;
|
| -
|
| - isolate->counters()->for_in()->Increment();
|
| - Handle<FixedArray> elements;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, elements,
|
| - JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
|
| - return *isolate->factory()->NewJSArrayWithElements(elements);
|
| -}
|
| -
|
| -
|
| -// Returns either a FixedArray as Runtime_GetPropertyNames,
|
| -// or, if the given object has an enum cache that contains
|
| -// all enumerable properties of the object and its prototypes
|
| -// have none, the map of the object. This is used to speed up
|
| -// the check for deletions during a for-in.
|
| -RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| -
|
| - CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
|
| -
|
| - if (raw_object->IsSimpleEnum()) return raw_object->map();
|
| -
|
| - HandleScope scope(isolate);
|
| - Handle<JSReceiver> object(raw_object);
|
| - Handle<FixedArray> content;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, content,
|
| - JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
|
| -
|
| - // Test again, since cache may have been built by preceding call.
|
| - if (object->IsSimpleEnum()) return object->map();
|
| -
|
| - return *content;
|
| -}
|
| -
|
| -
|
| -// Find the length of the prototype chain that is to be handled as one. If a
|
| -// prototype object is hidden it is to be viewed as part of the the object it
|
| -// is prototype for.
|
| -static int OwnPrototypeChainLength(JSObject* obj) {
|
| - int count = 1;
|
| - for (PrototypeIterator iter(obj->GetIsolate(), obj);
|
| - !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
|
| - count++;
|
| - }
|
| - return count;
|
| -}
|
| -
|
| -
|
| -// Return the names of the own named properties.
|
| -// args[0]: object
|
| -// args[1]: PropertyAttributes as int
|
| -RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| - if (!args[0]->IsJSObject()) {
|
| - return isolate->heap()->undefined_value();
|
| - }
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
| - CONVERT_SMI_ARG_CHECKED(filter_value, 1);
|
| - PropertyAttributes filter = static_cast<PropertyAttributes>(filter_value);
|
| -
|
| - // Skip the global proxy as it has no properties and always delegates to the
|
| - // real global object.
|
| - if (obj->IsJSGlobalProxy()) {
|
| - // Only collect names if access is permitted.
|
| - if (obj->IsAccessCheckNeeded() &&
|
| - !isolate->MayNamedAccess(obj, isolate->factory()->undefined_value(),
|
| - v8::ACCESS_KEYS)) {
|
| - isolate->ReportFailedAccessCheck(obj, v8::ACCESS_KEYS);
|
| - RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
|
| - return *isolate->factory()->NewJSArray(0);
|
| - }
|
| - PrototypeIterator iter(isolate, obj);
|
| - obj = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
|
| - }
|
| -
|
| - // Find the number of objects making up this.
|
| - int length = OwnPrototypeChainLength(*obj);
|
| -
|
| - // Find the number of own properties for each of the objects.
|
| - ScopedVector<int> own_property_count(length);
|
| - int total_property_count = 0;
|
| - {
|
| - PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
|
| - for (int i = 0; i < length; i++) {
|
| - DCHECK(!iter.IsAtEnd());
|
| - Handle<JSObject> jsproto =
|
| - Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
|
| - // Only collect names if access is permitted.
|
| - if (jsproto->IsAccessCheckNeeded() &&
|
| - !isolate->MayNamedAccess(jsproto,
|
| - isolate->factory()->undefined_value(),
|
| - v8::ACCESS_KEYS)) {
|
| - isolate->ReportFailedAccessCheck(jsproto, v8::ACCESS_KEYS);
|
| - RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
|
| - return *isolate->factory()->NewJSArray(0);
|
| - }
|
| - int n;
|
| - n = jsproto->NumberOfOwnProperties(filter);
|
| - own_property_count[i] = n;
|
| - total_property_count += n;
|
| - iter.Advance();
|
| - }
|
| - }
|
| -
|
| - // Allocate an array with storage for all the property names.
|
| - Handle<FixedArray> names =
|
| - isolate->factory()->NewFixedArray(total_property_count);
|
| -
|
| - // Get the property names.
|
| - int next_copy_index = 0;
|
| - int hidden_strings = 0;
|
| - {
|
| - PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
|
| - for (int i = 0; i < length; i++) {
|
| - DCHECK(!iter.IsAtEnd());
|
| - Handle<JSObject> jsproto =
|
| - Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
|
| - jsproto->GetOwnPropertyNames(*names, next_copy_index, filter);
|
| - if (i > 0) {
|
| - // Names from hidden prototypes may already have been added
|
| - // for inherited function template instances. Count the duplicates
|
| - // and stub them out; the final copy pass at the end ignores holes.
|
| - for (int j = next_copy_index;
|
| - j < next_copy_index + own_property_count[i]; j++) {
|
| - Object* name_from_hidden_proto = names->get(j);
|
| - for (int k = 0; k < next_copy_index; k++) {
|
| - if (names->get(k) != isolate->heap()->hidden_string()) {
|
| - Object* name = names->get(k);
|
| - if (name_from_hidden_proto == name) {
|
| - names->set(j, isolate->heap()->hidden_string());
|
| - hidden_strings++;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| - next_copy_index += own_property_count[i];
|
| -
|
| - // Hidden properties only show up if the filter does not skip strings.
|
| - if ((filter & STRING) == 0 && JSObject::HasHiddenProperties(jsproto)) {
|
| - hidden_strings++;
|
| - }
|
| - iter.Advance();
|
| - }
|
| - }
|
| -
|
| - // Filter out name of hidden properties object and
|
| - // hidden prototype duplicates.
|
| - if (hidden_strings > 0) {
|
| - Handle<FixedArray> old_names = names;
|
| - names = isolate->factory()->NewFixedArray(names->length() - hidden_strings);
|
| - int dest_pos = 0;
|
| - for (int i = 0; i < total_property_count; i++) {
|
| - Object* name = old_names->get(i);
|
| - if (name == isolate->heap()->hidden_string()) {
|
| - hidden_strings--;
|
| - continue;
|
| - }
|
| - names->set(dest_pos++, name);
|
| - }
|
| - DCHECK_EQ(0, hidden_strings);
|
| - }
|
| -
|
| - return *isolate->factory()->NewJSArrayWithElements(names);
|
| -}
|
| -
|
| -
|
| -// Return the names of the own indexed properties.
|
| -// args[0]: object
|
| -RUNTIME_FUNCTION(Runtime_GetOwnElementNames) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - if (!args[0]->IsJSObject()) {
|
| - return isolate->heap()->undefined_value();
|
| - }
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
| -
|
| - int n = obj->NumberOfOwnElements(static_cast<PropertyAttributes>(NONE));
|
| - Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
|
| - obj->GetOwnElementKeys(*names, static_cast<PropertyAttributes>(NONE));
|
| - return *isolate->factory()->NewJSArrayWithElements(names);
|
| -}
|
| -
|
| -
|
| -// Return information on whether an object has a named or indexed interceptor.
|
| -// args[0]: object
|
| -RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - if (!args[0]->IsJSObject()) {
|
| - return Smi::FromInt(0);
|
| - }
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
| -
|
| - int result = 0;
|
| - if (obj->HasNamedInterceptor()) result |= 2;
|
| - if (obj->HasIndexedInterceptor()) result |= 1;
|
| -
|
| - return Smi::FromInt(result);
|
| -}
|
| -
|
| -
|
| -// Return property names from named interceptor.
|
| -// args[0]: object
|
| -RUNTIME_FUNCTION(Runtime_GetNamedInterceptorPropertyNames) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
| -
|
| - if (obj->HasNamedInterceptor()) {
|
| - Handle<JSObject> result;
|
| - if (JSObject::GetKeysForNamedInterceptor(obj, obj).ToHandle(&result)) {
|
| - return *result;
|
| - }
|
| - }
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| -// Return element names from indexed interceptor.
|
| -// args[0]: object
|
| -RUNTIME_FUNCTION(Runtime_GetIndexedInterceptorElementNames) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
| -
|
| - if (obj->HasIndexedInterceptor()) {
|
| - Handle<JSObject> result;
|
| - if (JSObject::GetKeysForIndexedInterceptor(obj, obj).ToHandle(&result)) {
|
| - return *result;
|
| - }
|
| - }
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_OwnKeys) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
|
| - Handle<JSObject> object(raw_object);
|
| -
|
| - if (object->IsJSGlobalProxy()) {
|
| - // Do access checks before going to the global object.
|
| - if (object->IsAccessCheckNeeded() &&
|
| - !isolate->MayNamedAccess(object, isolate->factory()->undefined_value(),
|
| - v8::ACCESS_KEYS)) {
|
| - isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
|
| - RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
|
| - return *isolate->factory()->NewJSArray(0);
|
| - }
|
| -
|
| - PrototypeIterator iter(isolate, object);
|
| - // If proxy is detached we simply return an empty array.
|
| - if (iter.IsAtEnd()) return *isolate->factory()->NewJSArray(0);
|
| - object = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
|
| - }
|
| -
|
| - Handle<FixedArray> contents;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, contents, JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY));
|
| -
|
| - // Some fast paths through GetKeysInFixedArrayFor reuse a cached
|
| - // property array and since the result is mutable we have to create
|
| - // a fresh clone on each invocation.
|
| - int length = contents->length();
|
| - Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
|
| - for (int i = 0; i < length; i++) {
|
| - Object* entry = contents->get(i);
|
| - if (entry->IsString()) {
|
| - copy->set(i, entry);
|
| - } else {
|
| - DCHECK(entry->IsNumber());
|
| - HandleScope scope(isolate);
|
| - Handle<Object> entry_handle(entry, isolate);
|
| - Handle<Object> entry_str =
|
| - isolate->factory()->NumberToString(entry_handle);
|
| - copy->set(i, *entry_str);
|
| - }
|
| - }
|
| - return *isolate->factory()->NewJSArrayWithElements(copy);
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_GetArgumentsProperty) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, raw_key, 0);
|
| -
|
| - // Compute the frame holding the arguments.
|
| - JavaScriptFrameIterator it(isolate);
|
| - it.AdvanceToArgumentsFrame();
|
| - JavaScriptFrame* frame = it.frame();
|
| +#ifdef DEBUG
|
| + uint32_t index = 0;
|
| + DCHECK(!key->ToArrayIndex(&index));
|
| + LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
| + Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
|
| + if (!maybe.has_value) return isolate->heap()->exception();
|
| + RUNTIME_ASSERT(!it.IsFound());
|
| +#endif
|
|
|
| - // Get the actual number of provided arguments.
|
| - const uint32_t n = frame->ComputeParametersCount();
|
| + Handle<Object> result;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, result,
|
| + JSObject::SetOwnPropertyIgnoreAttributes(object, key, value, attributes));
|
| + return *result;
|
| +}
|
|
|
| - // Try to convert the key to an index. If successful and within
|
| - // index return the the argument from the frame.
|
| - uint32_t index;
|
| - if (raw_key->ToArrayIndex(&index) && index < n) {
|
| - return frame->GetParameter(index);
|
| - }
|
|
|
| +RUNTIME_FUNCTION(Runtime_AddPropertyForTemplate) {
|
| HandleScope scope(isolate);
|
| - if (raw_key->IsSymbol()) {
|
| - Handle<Symbol> symbol = Handle<Symbol>::cast(raw_key);
|
| - if (symbol->Equals(isolate->native_context()->iterator_symbol())) {
|
| - return isolate->native_context()->array_values_iterator();
|
| - }
|
| - // Lookup in the initial Object.prototype object.
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result,
|
| - Object::GetProperty(isolate->initial_object_prototype(),
|
| - Handle<Symbol>::cast(raw_key)));
|
| - return *result;
|
| - }
|
| + RUNTIME_ASSERT(args.length() == 4);
|
|
|
| - // Convert the key to a string.
|
| - Handle<Object> converted;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, converted,
|
| - Execution::ToString(isolate, raw_key));
|
| - Handle<String> key = Handle<String>::cast(converted);
|
| -
|
| - // Try to convert the string key into an array index.
|
| - if (key->AsArrayIndex(&index)) {
|
| - if (index < n) {
|
| - return frame->GetParameter(index);
|
| - } else {
|
| - Handle<Object> initial_prototype(isolate->initial_object_prototype());
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result,
|
| - Object::GetElement(isolate, initial_prototype, index));
|
| - return *result;
|
| - }
|
| - }
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
| + CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
|
| + RUNTIME_ASSERT(
|
| + (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
|
| + // Compute attributes.
|
| + PropertyAttributes attributes =
|
| + static_cast<PropertyAttributes>(unchecked_attributes);
|
|
|
| - // Handle special arguments properties.
|
| - if (String::Equals(isolate->factory()->length_string(), key)) {
|
| - return Smi::FromInt(n);
|
| +#ifdef DEBUG
|
| + bool duplicate;
|
| + if (key->IsName()) {
|
| + LookupIterator it(object, Handle<Name>::cast(key),
|
| + LookupIterator::OWN_SKIP_INTERCEPTOR);
|
| + Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
|
| + DCHECK(maybe.has_value);
|
| + duplicate = it.IsFound();
|
| + } else {
|
| + uint32_t index = 0;
|
| + RUNTIME_ASSERT(key->ToArrayIndex(&index));
|
| + Maybe<bool> maybe = JSReceiver::HasOwnElement(object, index);
|
| + if (!maybe.has_value) return isolate->heap()->exception();
|
| + duplicate = maybe.value;
|
| }
|
| - if (String::Equals(isolate->factory()->callee_string(), key)) {
|
| - JSFunction* function = frame->function();
|
| - if (function->shared()->strict_mode() == STRICT) {
|
| - THROW_NEW_ERROR_RETURN_FAILURE(
|
| - isolate, NewTypeError("strict_arguments_callee",
|
| - HandleVector<Object>(NULL, 0)));
|
| - }
|
| - return function;
|
| + if (duplicate) {
|
| + Handle<Object> args[1] = {key};
|
| + THROW_NEW_ERROR_RETURN_FAILURE(
|
| + isolate,
|
| + NewTypeError("duplicate_template_property", HandleVector(args, 1)));
|
| }
|
| +#endif
|
|
|
| - // Lookup in the initial Object.prototype object.
|
| Handle<Object> result;
|
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| isolate, result,
|
| - Object::GetProperty(isolate->initial_object_prototype(), key));
|
| + Runtime::DefineObjectProperty(object, key, value, attributes));
|
| return *result;
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_ToFastProperties) {
|
| +RUNTIME_FUNCTION(Runtime_SetProperty) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
| - if (object->IsJSObject() && !object->IsGlobalObject()) {
|
| - JSObject::MigrateSlowToFast(Handle<JSObject>::cast(object), 0);
|
| - }
|
| - return *object;
|
| -}
|
| -
|
| + RUNTIME_ASSERT(args.length() == 4);
|
|
|
| -RUNTIME_FUNCTION(Runtime_ToBool) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(Object, object, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
| + CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_arg, 3);
|
| + StrictMode strict_mode = strict_mode_arg;
|
|
|
| - return isolate->heap()->ToBoolean(object->BooleanValue());
|
| + Handle<Object> result;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, result,
|
| + Runtime::SetObjectProperty(isolate, object, key, value, strict_mode));
|
| + return *result;
|
| }
|
|
|
|
|
| -// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
|
| -// Possible optimizations: put the type string into the oddballs.
|
| -RUNTIME_FUNCTION(Runtime_Typeof) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(Object, obj, 0);
|
| - if (obj->IsNumber()) return isolate->heap()->number_string();
|
| - HeapObject* heap_obj = HeapObject::cast(obj);
|
| +// Adds an element to an array.
|
| +// This is used to create an indexed data property into an array.
|
| +RUNTIME_FUNCTION(Runtime_AddElement) {
|
| + HandleScope scope(isolate);
|
| + RUNTIME_ASSERT(args.length() == 4);
|
|
|
| - // typeof an undetectable object is 'undefined'
|
| - if (heap_obj->map()->is_undetectable()) {
|
| - return isolate->heap()->undefined_string();
|
| - }
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
| + CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
|
| + RUNTIME_ASSERT(
|
| + (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
|
| + // Compute attributes.
|
| + PropertyAttributes attributes =
|
| + static_cast<PropertyAttributes>(unchecked_attributes);
|
|
|
| - InstanceType instance_type = heap_obj->map()->instance_type();
|
| - if (instance_type < FIRST_NONSTRING_TYPE) {
|
| - return isolate->heap()->string_string();
|
| - }
|
| + uint32_t index = 0;
|
| + key->ToArrayIndex(&index);
|
|
|
| - switch (instance_type) {
|
| - case ODDBALL_TYPE:
|
| - if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
|
| - return isolate->heap()->boolean_string();
|
| - }
|
| - if (heap_obj->IsNull()) {
|
| - return isolate->heap()->object_string();
|
| - }
|
| - DCHECK(heap_obj->IsUndefined());
|
| - return isolate->heap()->undefined_string();
|
| - case SYMBOL_TYPE:
|
| - return isolate->heap()->symbol_string();
|
| - case JS_FUNCTION_TYPE:
|
| - case JS_FUNCTION_PROXY_TYPE:
|
| - return isolate->heap()->function_string();
|
| - default:
|
| - // For any kind of object not handled above, the spec rule for
|
| - // host objects gives that it is okay to return "object"
|
| - return isolate->heap()->object_string();
|
| - }
|
| + Handle<Object> result;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, result, JSObject::SetElement(object, index, value, attributes,
|
| + SLOPPY, false, DEFINE_PROPERTY));
|
| + return *result;
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_Booleanize) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 2);
|
| - CONVERT_ARG_CHECKED(Object, value_raw, 0);
|
| - CONVERT_SMI_ARG_CHECKED(token_raw, 1);
|
| - intptr_t value = reinterpret_cast<intptr_t>(value_raw);
|
| - Token::Value token = static_cast<Token::Value>(token_raw);
|
| - switch (token) {
|
| - case Token::EQ:
|
| - case Token::EQ_STRICT:
|
| - return isolate->heap()->ToBoolean(value == 0);
|
| - case Token::NE:
|
| - case Token::NE_STRICT:
|
| - return isolate->heap()->ToBoolean(value != 0);
|
| - case Token::LT:
|
| - return isolate->heap()->ToBoolean(value < 0);
|
| - case Token::GT:
|
| - return isolate->heap()->ToBoolean(value > 0);
|
| - case Token::LTE:
|
| - return isolate->heap()->ToBoolean(value <= 0);
|
| - case Token::GTE:
|
| - return isolate->heap()->ToBoolean(value >= 0);
|
| - default:
|
| - // This should only happen during natives fuzzing.
|
| - return isolate->heap()->undefined_value();
|
| - }
|
| +RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
|
| + HandleScope scope(isolate);
|
| + RUNTIME_ASSERT(args.length() == 2);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Map, map, 1);
|
| + JSObject::TransitionElementsKind(array, map->elements_kind());
|
| + return *array;
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_NewStringWrapper) {
|
| +RUNTIME_FUNCTION(Runtime_DebugPromiseRejectEvent) {
|
| + DCHECK(args.length() == 2);
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(String, value, 0);
|
| - return *Object::ToObject(isolate, value).ToHandleChecked();
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
|
| + isolate->debug()->OnPromiseReject(promise, value);
|
| + return isolate->heap()->undefined_value();
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) {
|
| +RUNTIME_FUNCTION(Runtime_DeleteProperty) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 0);
|
| - return *isolate->factory()->NewHeapNumber(0);
|
| + DCHECK(args.length() == 3);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
| + CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
|
| + JSReceiver::DeleteMode delete_mode = strict_mode == STRICT
|
| + ? JSReceiver::STRICT_DELETION
|
| + : JSReceiver::NORMAL_DELETION;
|
| + Handle<Object> result;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, result, JSReceiver::DeleteProperty(object, key, delete_mode));
|
| + return *result;
|
| }
|
|
|
|
|
| -static Handle<JSObject> NewSloppyArguments(Isolate* isolate,
|
| - Handle<JSFunction> callee,
|
| - Object** parameters,
|
| - int argument_count) {
|
| - Handle<JSObject> result =
|
| - isolate->factory()->NewArgumentsObject(callee, argument_count);
|
| -
|
| - // Allocate the elements if needed.
|
| - int parameter_count = callee->shared()->formal_parameter_count();
|
| - if (argument_count > 0) {
|
| - if (parameter_count > 0) {
|
| - int mapped_count = Min(argument_count, parameter_count);
|
| - Handle<FixedArray> parameter_map =
|
| - isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
|
| - parameter_map->set_map(isolate->heap()->sloppy_arguments_elements_map());
|
| -
|
| - Handle<Map> map = Map::Copy(handle(result->map()));
|
| - map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS);
|
| -
|
| - result->set_map(*map);
|
| - result->set_elements(*parameter_map);
|
| -
|
| - // Store the context and the arguments array at the beginning of the
|
| - // parameter map.
|
| - Handle<Context> context(isolate->context());
|
| - Handle<FixedArray> arguments =
|
| - isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
|
| - parameter_map->set(0, *context);
|
| - parameter_map->set(1, *arguments);
|
| -
|
| - // Loop over the actual parameters backwards.
|
| - int index = argument_count - 1;
|
| - while (index >= mapped_count) {
|
| - // These go directly in the arguments array and have no
|
| - // corresponding slot in the parameter map.
|
| - arguments->set(index, *(parameters - index - 1));
|
| - --index;
|
| - }
|
| -
|
| - Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
|
| - while (index >= 0) {
|
| - // Detect duplicate names to the right in the parameter list.
|
| - Handle<String> name(scope_info->ParameterName(index));
|
| - int context_local_count = scope_info->ContextLocalCount();
|
| - bool duplicate = false;
|
| - for (int j = index + 1; j < parameter_count; ++j) {
|
| - if (scope_info->ParameterName(j) == *name) {
|
| - duplicate = true;
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (duplicate) {
|
| - // This goes directly in the arguments array with a hole in the
|
| - // parameter map.
|
| - arguments->set(index, *(parameters - index - 1));
|
| - parameter_map->set_the_hole(index + 2);
|
| - } else {
|
| - // The context index goes in the parameter map with a hole in the
|
| - // arguments array.
|
| - int context_index = -1;
|
| - for (int j = 0; j < context_local_count; ++j) {
|
| - if (scope_info->ContextLocalName(j) == *name) {
|
| - context_index = j;
|
| - break;
|
| - }
|
| - }
|
| - DCHECK(context_index >= 0);
|
| - arguments->set_the_hole(index);
|
| - parameter_map->set(
|
| - index + 2,
|
| - Smi::FromInt(Context::MIN_CONTEXT_SLOTS + context_index));
|
| - }
|
| -
|
| - --index;
|
| - }
|
| - } else {
|
| - // If there is no aliasing, the arguments object elements are not
|
| - // special in any way.
|
| - Handle<FixedArray> elements =
|
| - isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
|
| - result->set_elements(*elements);
|
| - for (int i = 0; i < argument_count; ++i) {
|
| - elements->set(i, *(parameters - i - 1));
|
| - }
|
| - }
|
| +static Object* HasOwnPropertyImplementation(Isolate* isolate,
|
| + Handle<JSObject> object,
|
| + Handle<Name> key) {
|
| + Maybe<bool> maybe = JSReceiver::HasOwnProperty(object, key);
|
| + if (!maybe.has_value) return isolate->heap()->exception();
|
| + if (maybe.value) return isolate->heap()->true_value();
|
| + // Handle hidden prototypes. If there's a hidden prototype above this thing
|
| + // then we have to check it for properties, because they are supposed to
|
| + // look like they are on this object.
|
| + PrototypeIterator iter(isolate, object);
|
| + if (!iter.IsAtEnd() &&
|
| + Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter))
|
| + ->map()
|
| + ->is_hidden_prototype()) {
|
| + // TODO(verwaest): The recursion is not necessary for keys that are array
|
| + // indices. Removing this.
|
| + return HasOwnPropertyImplementation(
|
| + isolate, Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
|
| + key);
|
| }
|
| - return result;
|
| + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
|
| + return isolate->heap()->false_value();
|
| }
|
|
|
|
|
| -static Handle<JSObject> NewStrictArguments(Isolate* isolate,
|
| - Handle<JSFunction> callee,
|
| - Object** parameters,
|
| - int argument_count) {
|
| - Handle<JSObject> result =
|
| - isolate->factory()->NewArgumentsObject(callee, argument_count);
|
| +RUNTIME_FUNCTION(Runtime_HasOwnProperty) {
|
| + HandleScope scope(isolate);
|
| + DCHECK(args.length() == 2);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, object, 0)
|
| + CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
| +
|
| + uint32_t index;
|
| + const bool key_is_array_index = key->AsArrayIndex(&index);
|
|
|
| - if (argument_count > 0) {
|
| - Handle<FixedArray> array =
|
| - isolate->factory()->NewUninitializedFixedArray(argument_count);
|
| - DisallowHeapAllocation no_gc;
|
| - WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
|
| - for (int i = 0; i < argument_count; i++) {
|
| - array->set(i, *--parameters, mode);
|
| + // Only JS objects can have properties.
|
| + if (object->IsJSObject()) {
|
| + Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
|
| + // Fast case: either the key is a real named property or it is not
|
| + // an array index and there are no interceptors or hidden
|
| + // prototypes.
|
| + Maybe<bool> maybe = JSObject::HasRealNamedProperty(js_obj, key);
|
| + if (!maybe.has_value) return isolate->heap()->exception();
|
| + DCHECK(!isolate->has_pending_exception());
|
| + if (maybe.value) {
|
| + return isolate->heap()->true_value();
|
| + }
|
| + Map* map = js_obj->map();
|
| + if (!key_is_array_index && !map->has_named_interceptor() &&
|
| + !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
|
| + return isolate->heap()->false_value();
|
| + }
|
| + // Slow case.
|
| + return HasOwnPropertyImplementation(isolate, Handle<JSObject>(js_obj),
|
| + Handle<Name>(key));
|
| + } else if (object->IsString() && key_is_array_index) {
|
| + // Well, there is one exception: Handle [] on strings.
|
| + Handle<String> string = Handle<String>::cast(object);
|
| + if (index < static_cast<uint32_t>(string->length())) {
|
| + return isolate->heap()->true_value();
|
| }
|
| - result->set_elements(*array);
|
| }
|
| - return result;
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_NewArguments) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
|
| - JavaScriptFrameIterator it(isolate);
|
| -
|
| - // Find the frame that holds the actual arguments passed to the function.
|
| - it.AdvanceToArgumentsFrame();
|
| - JavaScriptFrame* frame = it.frame();
|
| -
|
| - // Determine parameter location on the stack and dispatch on language mode.
|
| - int argument_count = frame->GetArgumentsLength();
|
| - Object** parameters = reinterpret_cast<Object**>(frame->GetParameterSlot(-1));
|
| - return callee->shared()->strict_mode() == STRICT
|
| - ? *NewStrictArguments(isolate, callee, parameters, argument_count)
|
| - : *NewSloppyArguments(isolate, callee, parameters, argument_count);
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 3);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
|
| - Object** parameters = reinterpret_cast<Object**>(args[1]);
|
| - CONVERT_SMI_ARG_CHECKED(argument_count, 2);
|
| - return *NewSloppyArguments(isolate, callee, parameters, argument_count);
|
| + return isolate->heap()->false_value();
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_NewStrictArguments) {
|
| +RUNTIME_FUNCTION(Runtime_HasProperty) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 3);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0)
|
| - Object** parameters = reinterpret_cast<Object**>(args[1]);
|
| - CONVERT_SMI_ARG_CHECKED(argument_count, 2);
|
| - return *NewStrictArguments(isolate, callee, parameters, argument_count);
|
| -}
|
| -
|
| + DCHECK(args.length() == 2);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
|
|
| -RUNTIME_FUNCTION(Runtime_NewClosureFromStubFailure) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
|
| - Handle<Context> context(isolate->context());
|
| - PretenureFlag pretenure_flag = NOT_TENURED;
|
| - return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
|
| - pretenure_flag);
|
| + Maybe<bool> maybe = JSReceiver::HasProperty(receiver, key);
|
| + if (!maybe.has_value) return isolate->heap()->exception();
|
| + return isolate->heap()->ToBoolean(maybe.value);
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_NewClosure) {
|
| +RUNTIME_FUNCTION(Runtime_HasElement) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 3);
|
| - CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
|
| - CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
|
| -
|
| - // The caller ensures that we pretenure closures that are assigned
|
| - // directly to properties.
|
| - PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
|
| - return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
|
| - pretenure_flag);
|
| -}
|
| -
|
| -
|
| -// Find the arguments of the JavaScript function invocation that called
|
| -// into C++ code. Collect these in a newly allocated array of handles (possibly
|
| -// prefixed by a number of empty handles).
|
| -static SmartArrayPointer<Handle<Object> > GetCallerArguments(Isolate* isolate,
|
| - int prefix_argc,
|
| - int* total_argc) {
|
| - // Find frame containing arguments passed to the caller.
|
| - JavaScriptFrameIterator it(isolate);
|
| - JavaScriptFrame* frame = it.frame();
|
| - List<JSFunction*> functions(2);
|
| - frame->GetFunctions(&functions);
|
| - if (functions.length() > 1) {
|
| - int inlined_jsframe_index = functions.length() - 1;
|
| - JSFunction* inlined_function = functions[inlined_jsframe_index];
|
| - SlotRefValueBuilder slot_refs(
|
| - frame, inlined_jsframe_index,
|
| - inlined_function->shared()->formal_parameter_count());
|
| -
|
| - int args_count = slot_refs.args_length();
|
| -
|
| - *total_argc = prefix_argc + args_count;
|
| - SmartArrayPointer<Handle<Object> > param_data(
|
| - NewArray<Handle<Object> >(*total_argc));
|
| - slot_refs.Prepare(isolate);
|
| - for (int i = 0; i < args_count; i++) {
|
| - Handle<Object> val = slot_refs.GetNext(isolate, 0);
|
| - param_data[prefix_argc + i] = val;
|
| - }
|
| - slot_refs.Finish(isolate);
|
| + DCHECK(args.length() == 2);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
|
| + CONVERT_SMI_ARG_CHECKED(index, 1);
|
|
|
| - return param_data;
|
| - } else {
|
| - it.AdvanceToArgumentsFrame();
|
| - frame = it.frame();
|
| - int args_count = frame->ComputeParametersCount();
|
| -
|
| - *total_argc = prefix_argc + args_count;
|
| - SmartArrayPointer<Handle<Object> > param_data(
|
| - NewArray<Handle<Object> >(*total_argc));
|
| - for (int i = 0; i < args_count; i++) {
|
| - Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
|
| - param_data[prefix_argc + i] = val;
|
| - }
|
| - return param_data;
|
| - }
|
| + Maybe<bool> maybe = JSReceiver::HasElement(receiver, index);
|
| + if (!maybe.has_value) return isolate->heap()->exception();
|
| + return isolate->heap()->ToBoolean(maybe.value);
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_FunctionBindArguments) {
|
| +RUNTIME_FUNCTION(Runtime_IsPropertyEnumerable) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 4);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, bindee, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, this_object, 2);
|
| - CONVERT_NUMBER_ARG_HANDLE_CHECKED(new_length, 3);
|
| -
|
| - // TODO(lrn): Create bound function in C++ code from premade shared info.
|
| - bound_function->shared()->set_bound(true);
|
| - // Get all arguments of calling function (Function.prototype.bind).
|
| - int argc = 0;
|
| - SmartArrayPointer<Handle<Object> > arguments =
|
| - GetCallerArguments(isolate, 0, &argc);
|
| - // Don't count the this-arg.
|
| - if (argc > 0) {
|
| - RUNTIME_ASSERT(arguments[0].is_identical_to(this_object));
|
| - argc--;
|
| - } else {
|
| - RUNTIME_ASSERT(this_object->IsUndefined());
|
| - }
|
| - // Initialize array of bindings (function, this, and any existing arguments
|
| - // if the function was already bound).
|
| - Handle<FixedArray> new_bindings;
|
| - int i;
|
| - if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
|
| - Handle<FixedArray> old_bindings(
|
| - JSFunction::cast(*bindee)->function_bindings());
|
| - RUNTIME_ASSERT(old_bindings->length() > JSFunction::kBoundFunctionIndex);
|
| - new_bindings =
|
| - isolate->factory()->NewFixedArray(old_bindings->length() + argc);
|
| - bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex),
|
| - isolate);
|
| - i = 0;
|
| - for (int n = old_bindings->length(); i < n; i++) {
|
| - new_bindings->set(i, old_bindings->get(i));
|
| - }
|
| - } else {
|
| - int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
|
| - new_bindings = isolate->factory()->NewFixedArray(array_size);
|
| - new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
|
| - new_bindings->set(JSFunction::kBoundThisIndex, *this_object);
|
| - i = 2;
|
| - }
|
| - // Copy arguments, skipping the first which is "this_arg".
|
| - for (int j = 0; j < argc; j++, i++) {
|
| - new_bindings->set(i, *arguments[j + 1]);
|
| - }
|
| - new_bindings->set_map_no_write_barrier(
|
| - isolate->heap()->fixed_cow_array_map());
|
| - bound_function->set_function_bindings(*new_bindings);
|
| -
|
| - // Update length. Have to remove the prototype first so that map migration
|
| - // is happy about the number of fields.
|
| - RUNTIME_ASSERT(bound_function->RemovePrototype());
|
| - Handle<Map> bound_function_map(
|
| - isolate->native_context()->bound_function_map());
|
| - JSObject::MigrateToMap(bound_function, bound_function_map);
|
| - Handle<String> length_string = isolate->factory()->length_string();
|
| - PropertyAttributes attr =
|
| - static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
|
| - RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, JSObject::SetOwnPropertyIgnoreAttributes(
|
| - bound_function, length_string, new_length, attr));
|
| - return *bound_function;
|
| -}
|
| + DCHECK(args.length() == 2);
|
|
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
|
|
| -RUNTIME_FUNCTION(Runtime_BoundFunctionGetBindings) {
|
| - HandleScope handles(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
|
| - if (callable->IsJSFunction()) {
|
| - Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
|
| - if (function->shared()->bound()) {
|
| - Handle<FixedArray> bindings(function->function_bindings());
|
| - RUNTIME_ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
|
| - return *isolate->factory()->NewJSArrayWithElements(bindings);
|
| - }
|
| - }
|
| - return isolate->heap()->undefined_value();
|
| + Maybe<PropertyAttributes> maybe =
|
| + JSReceiver::GetOwnPropertyAttributes(object, key);
|
| + if (!maybe.has_value) return isolate->heap()->exception();
|
| + if (maybe.value == ABSENT) maybe.value = DONT_ENUM;
|
| + return isolate->heap()->ToBoolean((maybe.value & DONT_ENUM) == 0);
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_NewObjectFromBound) {
|
| +RUNTIME_FUNCTION(Runtime_GetPropertyNames) {
|
| HandleScope scope(isolate);
|
| DCHECK(args.length() == 1);
|
| - // First argument is a function to use as a constructor.
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
|
| - RUNTIME_ASSERT(function->shared()->bound());
|
| -
|
| - // The argument is a bound function. Extract its bound arguments
|
| - // and callable.
|
| - Handle<FixedArray> bound_args =
|
| - Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
|
| - int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
|
| - Handle<Object> bound_function(
|
| - JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)),
|
| - isolate);
|
| - DCHECK(!bound_function->IsJSFunction() ||
|
| - !Handle<JSFunction>::cast(bound_function)->shared()->bound());
|
| -
|
| - int total_argc = 0;
|
| - SmartArrayPointer<Handle<Object> > param_data =
|
| - GetCallerArguments(isolate, bound_argc, &total_argc);
|
| - for (int i = 0; i < bound_argc; i++) {
|
| - param_data[i] = Handle<Object>(
|
| - bound_args->get(JSFunction::kBoundArgumentsStartIndex + i), isolate);
|
| - }
|
| -
|
| - if (!bound_function->IsJSFunction()) {
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, bound_function,
|
| - Execution::TryGetConstructorDelegate(isolate, bound_function));
|
| - }
|
| - DCHECK(bound_function->IsJSFunction());
|
| + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
|
| + Handle<JSArray> result;
|
|
|
| - Handle<Object> result;
|
| + isolate->counters()->for_in()->Increment();
|
| + Handle<FixedArray> elements;
|
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result, Execution::New(Handle<JSFunction>::cast(bound_function),
|
| - total_argc, param_data.get()));
|
| - return *result;
|
| + isolate, elements,
|
| + JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
|
| + return *isolate->factory()->NewJSArrayWithElements(elements);
|
| }
|
|
|
|
|
| -static Object* Runtime_NewObjectHelper(Isolate* isolate,
|
| - Handle<Object> constructor,
|
| - Handle<AllocationSite> site) {
|
| - // If the constructor isn't a proper function we throw a type error.
|
| - if (!constructor->IsJSFunction()) {
|
| - Vector<Handle<Object> > arguments = HandleVector(&constructor, 1);
|
| - THROW_NEW_ERROR_RETURN_FAILURE(isolate,
|
| - NewTypeError("not_constructor", arguments));
|
| - }
|
| -
|
| - Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
|
| -
|
| - // If function should not have prototype, construction is not allowed. In this
|
| - // case generated code bailouts here, since function has no initial_map.
|
| - if (!function->should_have_prototype() && !function->shared()->bound()) {
|
| - Vector<Handle<Object> > arguments = HandleVector(&constructor, 1);
|
| - THROW_NEW_ERROR_RETURN_FAILURE(isolate,
|
| - NewTypeError("not_constructor", arguments));
|
| - }
|
| -
|
| - Debug* debug = isolate->debug();
|
| - // Handle stepping into constructors if step into is active.
|
| - if (debug->StepInActive()) {
|
| - debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
|
| - }
|
| +// Returns either a FixedArray as Runtime_GetPropertyNames,
|
| +// or, if the given object has an enum cache that contains
|
| +// all enumerable properties of the object and its prototypes
|
| +// have none, the map of the object. This is used to speed up
|
| +// the check for deletions during a for-in.
|
| +RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) {
|
| + SealHandleScope shs(isolate);
|
| + DCHECK(args.length() == 1);
|
|
|
| - if (function->has_initial_map()) {
|
| - if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
|
| - // The 'Function' function ignores the receiver object when
|
| - // called using 'new' and creates a new JSFunction object that
|
| - // is returned. The receiver object is only used for error
|
| - // reporting if an error occurs when constructing the new
|
| - // JSFunction. Factory::NewJSObject() should not be used to
|
| - // allocate JSFunctions since it does not properly initialize
|
| - // the shared part of the function. Since the receiver is
|
| - // ignored anyway, we use the global object as the receiver
|
| - // instead of a new JSFunction object. This way, errors are
|
| - // reported the same way whether or not 'Function' is called
|
| - // using 'new'.
|
| - return isolate->global_proxy();
|
| - }
|
| - }
|
| + CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
|
|
|
| - // The function should be compiled for the optimization hints to be
|
| - // available.
|
| - Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
|
| + if (raw_object->IsSimpleEnum()) return raw_object->map();
|
|
|
| - Handle<JSObject> result;
|
| - if (site.is_null()) {
|
| - result = isolate->factory()->NewJSObject(function);
|
| - } else {
|
| - result = isolate->factory()->NewJSObjectWithMemento(function, site);
|
| - }
|
| + HandleScope scope(isolate);
|
| + Handle<JSReceiver> object(raw_object);
|
| + Handle<FixedArray> content;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, content,
|
| + JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
|
|
|
| - isolate->counters()->constructed_objects()->Increment();
|
| - isolate->counters()->constructed_objects_runtime()->Increment();
|
| + // Test again, since cache may have been built by preceding call.
|
| + if (object->IsSimpleEnum()) return object->map();
|
|
|
| - return *result;
|
| + return *content;
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_NewObject) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0);
|
| - return Runtime_NewObjectHelper(isolate, constructor,
|
| - Handle<AllocationSite>::null());
|
| +// Find the length of the prototype chain that is to be handled as one. If a
|
| +// prototype object is hidden it is to be viewed as part of the the object it
|
| +// is prototype for.
|
| +static int OwnPrototypeChainLength(JSObject* obj) {
|
| + int count = 1;
|
| + for (PrototypeIterator iter(obj->GetIsolate(), obj);
|
| + !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
|
| + count++;
|
| + }
|
| + return count;
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_NewObjectWithAllocationSite) {
|
| +// Return the names of the own named properties.
|
| +// args[0]: object
|
| +// args[1]: PropertyAttributes as int
|
| +RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) {
|
| HandleScope scope(isolate);
|
| DCHECK(args.length() == 2);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, feedback, 0);
|
| - Handle<AllocationSite> site;
|
| - if (feedback->IsAllocationSite()) {
|
| - // The feedback can be an AllocationSite or undefined.
|
| - site = Handle<AllocationSite>::cast(feedback);
|
| + if (!args[0]->IsJSObject()) {
|
| + return isolate->heap()->undefined_value();
|
| }
|
| - return Runtime_NewObjectHelper(isolate, constructor, site);
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
|
| - function->CompleteInobjectSlackTracking();
|
| -
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
| + CONVERT_SMI_ARG_CHECKED(filter_value, 1);
|
| + PropertyAttributes filter = static_cast<PropertyAttributes>(filter_value);
|
|
|
| -RUNTIME_FUNCTION(Runtime_CheckIsBootstrapping) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 0);
|
| - RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| + // Skip the global proxy as it has no properties and always delegates to the
|
| + // real global object.
|
| + if (obj->IsJSGlobalProxy()) {
|
| + // Only collect names if access is permitted.
|
| + if (obj->IsAccessCheckNeeded() &&
|
| + !isolate->MayNamedAccess(obj, isolate->factory()->undefined_value(),
|
| + v8::ACCESS_KEYS)) {
|
| + isolate->ReportFailedAccessCheck(obj, v8::ACCESS_KEYS);
|
| + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
|
| + return *isolate->factory()->NewJSArray(0);
|
| + }
|
| + PrototypeIterator iter(isolate, obj);
|
| + obj = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
|
| + }
|
|
|
| + // Find the number of objects making up this.
|
| + int length = OwnPrototypeChainLength(*obj);
|
|
|
| -RUNTIME_FUNCTION(Runtime_GetRootNaN) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 0);
|
| - RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
|
| - return isolate->heap()->nan_value();
|
| -}
|
| + // Find the number of own properties for each of the objects.
|
| + ScopedVector<int> own_property_count(length);
|
| + int total_property_count = 0;
|
| + {
|
| + PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
|
| + for (int i = 0; i < length; i++) {
|
| + DCHECK(!iter.IsAtEnd());
|
| + Handle<JSObject> jsproto =
|
| + Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
|
| + // Only collect names if access is permitted.
|
| + if (jsproto->IsAccessCheckNeeded() &&
|
| + !isolate->MayNamedAccess(jsproto,
|
| + isolate->factory()->undefined_value(),
|
| + v8::ACCESS_KEYS)) {
|
| + isolate->ReportFailedAccessCheck(jsproto, v8::ACCESS_KEYS);
|
| + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
|
| + return *isolate->factory()->NewJSArray(0);
|
| + }
|
| + int n;
|
| + n = jsproto->NumberOfOwnProperties(filter);
|
| + own_property_count[i] = n;
|
| + total_property_count += n;
|
| + iter.Advance();
|
| + }
|
| + }
|
|
|
| + // Allocate an array with storage for all the property names.
|
| + Handle<FixedArray> names =
|
| + isolate->factory()->NewFixedArray(total_property_count);
|
|
|
| -RUNTIME_FUNCTION(Runtime_Call) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() >= 2);
|
| - int argc = args.length() - 2;
|
| - CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
|
| - Object* receiver = args[0];
|
| -
|
| - // If there are too many arguments, allocate argv via malloc.
|
| - const int argv_small_size = 10;
|
| - Handle<Object> argv_small_buffer[argv_small_size];
|
| - SmartArrayPointer<Handle<Object> > argv_large_buffer;
|
| - Handle<Object>* argv = argv_small_buffer;
|
| - if (argc > argv_small_size) {
|
| - argv = new Handle<Object>[argc];
|
| - if (argv == NULL) return isolate->StackOverflow();
|
| - argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
|
| + // Get the property names.
|
| + int next_copy_index = 0;
|
| + int hidden_strings = 0;
|
| + {
|
| + PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
|
| + for (int i = 0; i < length; i++) {
|
| + DCHECK(!iter.IsAtEnd());
|
| + Handle<JSObject> jsproto =
|
| + Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
|
| + jsproto->GetOwnPropertyNames(*names, next_copy_index, filter);
|
| + if (i > 0) {
|
| + // Names from hidden prototypes may already have been added
|
| + // for inherited function template instances. Count the duplicates
|
| + // and stub them out; the final copy pass at the end ignores holes.
|
| + for (int j = next_copy_index;
|
| + j < next_copy_index + own_property_count[i]; j++) {
|
| + Object* name_from_hidden_proto = names->get(j);
|
| + for (int k = 0; k < next_copy_index; k++) {
|
| + if (names->get(k) != isolate->heap()->hidden_string()) {
|
| + Object* name = names->get(k);
|
| + if (name_from_hidden_proto == name) {
|
| + names->set(j, isolate->heap()->hidden_string());
|
| + hidden_strings++;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| + next_copy_index += own_property_count[i];
|
| +
|
| + // Hidden properties only show up if the filter does not skip strings.
|
| + if ((filter & STRING) == 0 && JSObject::HasHiddenProperties(jsproto)) {
|
| + hidden_strings++;
|
| + }
|
| + iter.Advance();
|
| + }
|
| }
|
|
|
| - for (int i = 0; i < argc; ++i) {
|
| - argv[i] = Handle<Object>(args[1 + i], isolate);
|
| + // Filter out name of hidden properties object and
|
| + // hidden prototype duplicates.
|
| + if (hidden_strings > 0) {
|
| + Handle<FixedArray> old_names = names;
|
| + names = isolate->factory()->NewFixedArray(names->length() - hidden_strings);
|
| + int dest_pos = 0;
|
| + for (int i = 0; i < total_property_count; i++) {
|
| + Object* name = old_names->get(i);
|
| + if (name == isolate->heap()->hidden_string()) {
|
| + hidden_strings--;
|
| + continue;
|
| + }
|
| + names->set(dest_pos++, name);
|
| + }
|
| + DCHECK_EQ(0, hidden_strings);
|
| }
|
|
|
| - Handle<JSReceiver> hfun(fun);
|
| - Handle<Object> hreceiver(receiver, isolate);
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result,
|
| - Execution::Call(isolate, hfun, hreceiver, argc, argv, true));
|
| - return *result;
|
| + return *isolate->factory()->NewJSArrayWithElements(names);
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_Apply) {
|
| +// Return the names of the own indexed properties.
|
| +// args[0]: object
|
| +RUNTIME_FUNCTION(Runtime_GetOwnElementNames) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 5);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
|
| - CONVERT_INT32_ARG_CHECKED(offset, 3);
|
| - CONVERT_INT32_ARG_CHECKED(argc, 4);
|
| - RUNTIME_ASSERT(offset >= 0);
|
| - // Loose upper bound to allow fuzzing. We'll most likely run out of
|
| - // stack space before hitting this limit.
|
| - static int kMaxArgc = 1000000;
|
| - RUNTIME_ASSERT(argc >= 0 && argc <= kMaxArgc);
|
| -
|
| - // If there are too many arguments, allocate argv via malloc.
|
| - const int argv_small_size = 10;
|
| - Handle<Object> argv_small_buffer[argv_small_size];
|
| - SmartArrayPointer<Handle<Object> > argv_large_buffer;
|
| - Handle<Object>* argv = argv_small_buffer;
|
| - if (argc > argv_small_size) {
|
| - argv = new Handle<Object>[argc];
|
| - if (argv == NULL) return isolate->StackOverflow();
|
| - argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
|
| - }
|
| -
|
| - for (int i = 0; i < argc; ++i) {
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, argv[i], Object::GetElement(isolate, arguments, offset + i));
|
| + DCHECK(args.length() == 1);
|
| + if (!args[0]->IsJSObject()) {
|
| + return isolate->heap()->undefined_value();
|
| }
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
|
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, result,
|
| - Execution::Call(isolate, fun, receiver, argc, argv, true));
|
| - return *result;
|
| + int n = obj->NumberOfOwnElements(static_cast<PropertyAttributes>(NONE));
|
| + Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
|
| + obj->GetOwnElementKeys(*names, static_cast<PropertyAttributes>(NONE));
|
| + return *isolate->factory()->NewJSArrayWithElements(names);
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_GetFunctionDelegate) {
|
| +// Return information on whether an object has a named or indexed interceptor.
|
| +// args[0]: object
|
| +RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) {
|
| HandleScope scope(isolate);
|
| DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
| - RUNTIME_ASSERT(!object->IsJSFunction());
|
| - return *Execution::GetFunctionDelegate(isolate, object);
|
| -}
|
| + if (!args[0]->IsJSObject()) {
|
| + return Smi::FromInt(0);
|
| + }
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
|
|
| + int result = 0;
|
| + if (obj->HasNamedInterceptor()) result |= 2;
|
| + if (obj->HasIndexedInterceptor()) result |= 1;
|
|
|
| -RUNTIME_FUNCTION(Runtime_GetConstructorDelegate) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
| - RUNTIME_ASSERT(!object->IsJSFunction());
|
| - return *Execution::GetConstructorDelegate(isolate, object);
|
| + return Smi::FromInt(result);
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_NewGlobalContext) {
|
| +// Return property names from named interceptor.
|
| +// args[0]: object
|
| +RUNTIME_FUNCTION(Runtime_GetNamedInterceptorPropertyNames) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
|
| - Handle<Context> result =
|
| - isolate->factory()->NewGlobalContext(function, scope_info);
|
| + DCHECK(args.length() == 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
|
|
| - DCHECK(function->context() == isolate->context());
|
| - DCHECK(function->context()->global_object() == result->global_object());
|
| - result->global_object()->set_global_context(*result);
|
| - return *result;
|
| + if (obj->HasNamedInterceptor()) {
|
| + Handle<JSObject> result;
|
| + if (JSObject::GetKeysForNamedInterceptor(obj, obj).ToHandle(&result)) {
|
| + return *result;
|
| + }
|
| + }
|
| + return isolate->heap()->undefined_value();
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
|
| +// Return element names from indexed interceptor.
|
| +// args[0]: object
|
| +RUNTIME_FUNCTION(Runtime_GetIndexedInterceptorElementNames) {
|
| HandleScope scope(isolate);
|
| DCHECK(args.length() == 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
|
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
|
| -
|
| - DCHECK(function->context() == isolate->context());
|
| - int length = function->shared()->scope_info()->ContextLength();
|
| - return *isolate->factory()->NewFunctionContext(length, function);
|
| + if (obj->HasIndexedInterceptor()) {
|
| + Handle<JSObject> result;
|
| + if (JSObject::GetKeysForIndexedInterceptor(obj, obj).ToHandle(&result)) {
|
| + return *result;
|
| + }
|
| + }
|
| + return isolate->heap()->undefined_value();
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_PushWithContext) {
|
| +RUNTIME_FUNCTION(Runtime_OwnKeys) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| - Handle<JSReceiver> extension_object;
|
| - if (args[0]->IsJSReceiver()) {
|
| - extension_object = args.at<JSReceiver>(0);
|
| - } else {
|
| - // Try to convert the object to a proper JavaScript object.
|
| - MaybeHandle<JSReceiver> maybe_object =
|
| - Object::ToObject(isolate, args.at<Object>(0));
|
| - if (!maybe_object.ToHandle(&extension_object)) {
|
| - Handle<Object> handle = args.at<Object>(0);
|
| - THROW_NEW_ERROR_RETURN_FAILURE(
|
| - isolate, NewTypeError("with_expression", HandleVector(&handle, 1)));
|
| + DCHECK(args.length() == 1);
|
| + CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
|
| + Handle<JSObject> object(raw_object);
|
| +
|
| + if (object->IsJSGlobalProxy()) {
|
| + // Do access checks before going to the global object.
|
| + if (object->IsAccessCheckNeeded() &&
|
| + !isolate->MayNamedAccess(object, isolate->factory()->undefined_value(),
|
| + v8::ACCESS_KEYS)) {
|
| + isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
|
| + RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
|
| + return *isolate->factory()->NewJSArray(0);
|
| }
|
| - }
|
|
|
| - Handle<JSFunction> function;
|
| - if (args[1]->IsSmi()) {
|
| - // A smi sentinel indicates a context nested inside global code rather
|
| - // than some function. There is a canonical empty function that can be
|
| - // gotten from the native context.
|
| - function = handle(isolate->native_context()->closure());
|
| - } else {
|
| - function = args.at<JSFunction>(1);
|
| + PrototypeIterator iter(isolate, object);
|
| + // If proxy is detached we simply return an empty array.
|
| + if (iter.IsAtEnd()) return *isolate->factory()->NewJSArray(0);
|
| + object = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
|
| }
|
|
|
| - Handle<Context> current(isolate->context());
|
| - Handle<Context> context =
|
| - isolate->factory()->NewWithContext(function, current, extension_object);
|
| - isolate->set_context(*context);
|
| - return *context;
|
| -}
|
| -
|
| + Handle<FixedArray> contents;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, contents, JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY));
|
|
|
| -RUNTIME_FUNCTION(Runtime_PushCatchContext) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 3);
|
| - CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 1);
|
| - Handle<JSFunction> function;
|
| - if (args[2]->IsSmi()) {
|
| - // A smi sentinel indicates a context nested inside global code rather
|
| - // than some function. There is a canonical empty function that can be
|
| - // gotten from the native context.
|
| - function = handle(isolate->native_context()->closure());
|
| - } else {
|
| - function = args.at<JSFunction>(2);
|
| + // Some fast paths through GetKeysInFixedArrayFor reuse a cached
|
| + // property array and since the result is mutable we have to create
|
| + // a fresh clone on each invocation.
|
| + int length = contents->length();
|
| + Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
|
| + for (int i = 0; i < length; i++) {
|
| + Object* entry = contents->get(i);
|
| + if (entry->IsString()) {
|
| + copy->set(i, entry);
|
| + } else {
|
| + DCHECK(entry->IsNumber());
|
| + HandleScope scope(isolate);
|
| + Handle<Object> entry_handle(entry, isolate);
|
| + Handle<Object> entry_str =
|
| + isolate->factory()->NumberToString(entry_handle);
|
| + copy->set(i, *entry_str);
|
| + }
|
| }
|
| - Handle<Context> current(isolate->context());
|
| - Handle<Context> context = isolate->factory()->NewCatchContext(
|
| - function, current, name, thrown_object);
|
| - isolate->set_context(*context);
|
| - return *context;
|
| + return *isolate->factory()->NewJSArrayWithElements(copy);
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_PushBlockContext) {
|
| +RUNTIME_FUNCTION(Runtime_ToFastProperties) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| - CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
|
| - Handle<JSFunction> function;
|
| - if (args[1]->IsSmi()) {
|
| - // A smi sentinel indicates a context nested inside global code rather
|
| - // than some function. There is a canonical empty function that can be
|
| - // gotten from the native context.
|
| - function = handle(isolate->native_context()->closure());
|
| - } else {
|
| - function = args.at<JSFunction>(1);
|
| + DCHECK(args.length() == 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
|
| + if (object->IsJSObject() && !object->IsGlobalObject()) {
|
| + JSObject::MigrateSlowToFast(Handle<JSObject>::cast(object), 0);
|
| }
|
| - Handle<Context> current(isolate->context());
|
| - Handle<Context> context =
|
| - isolate->factory()->NewBlockContext(function, current, scope_info);
|
| - isolate->set_context(*context);
|
| - return *context;
|
| + return *object;
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_IsJSModule) {
|
| +RUNTIME_FUNCTION(Runtime_ToBool) {
|
| SealHandleScope shs(isolate);
|
| DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(Object, obj, 0);
|
| - return isolate->heap()->ToBoolean(obj->IsJSModule());
|
| + CONVERT_ARG_CHECKED(Object, object, 0);
|
| +
|
| + return isolate->heap()->ToBoolean(object->BooleanValue());
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_PushModuleContext) {
|
| +// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
|
| +// Possible optimizations: put the type string into the oddballs.
|
| +RUNTIME_FUNCTION(Runtime_Typeof) {
|
| SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 2);
|
| - CONVERT_SMI_ARG_CHECKED(index, 0);
|
| -
|
| - if (!args[1]->IsScopeInfo()) {
|
| - // Module already initialized. Find hosting context and retrieve context.
|
| - Context* host = Context::cast(isolate->context())->global_context();
|
| - Context* context = Context::cast(host->get(index));
|
| - DCHECK(context->previous() == isolate->context());
|
| - isolate->set_context(context);
|
| - return context;
|
| - }
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
|
| + DCHECK(args.length() == 1);
|
| + CONVERT_ARG_CHECKED(Object, obj, 0);
|
| + if (obj->IsNumber()) return isolate->heap()->number_string();
|
| + HeapObject* heap_obj = HeapObject::cast(obj);
|
|
|
| - // Allocate module context.
|
| - HandleScope scope(isolate);
|
| - Factory* factory = isolate->factory();
|
| - Handle<Context> context = factory->NewModuleContext(scope_info);
|
| - Handle<JSModule> module = factory->NewJSModule(context, scope_info);
|
| - context->set_module(*module);
|
| - Context* previous = isolate->context();
|
| - context->set_previous(previous);
|
| - context->set_closure(previous->closure());
|
| - context->set_global_object(previous->global_object());
|
| - isolate->set_context(*context);
|
| + // typeof an undetectable object is 'undefined'
|
| + if (heap_obj->map()->is_undetectable()) {
|
| + return isolate->heap()->undefined_string();
|
| + }
|
|
|
| - // Find hosting scope and initialize internal variable holding module there.
|
| - previous->global_context()->set(index, *context);
|
| + InstanceType instance_type = heap_obj->map()->instance_type();
|
| + if (instance_type < FIRST_NONSTRING_TYPE) {
|
| + return isolate->heap()->string_string();
|
| + }
|
|
|
| - return *context;
|
| + switch (instance_type) {
|
| + case ODDBALL_TYPE:
|
| + if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
|
| + return isolate->heap()->boolean_string();
|
| + }
|
| + if (heap_obj->IsNull()) {
|
| + return isolate->heap()->object_string();
|
| + }
|
| + DCHECK(heap_obj->IsUndefined());
|
| + return isolate->heap()->undefined_string();
|
| + case SYMBOL_TYPE:
|
| + return isolate->heap()->symbol_string();
|
| + case JS_FUNCTION_TYPE:
|
| + case JS_FUNCTION_PROXY_TYPE:
|
| + return isolate->heap()->function_string();
|
| + default:
|
| + // For any kind of object not handled above, the spec rule for
|
| + // host objects gives that it is okay to return "object"
|
| + return isolate->heap()->object_string();
|
| + }
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_DeclareModules) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
|
| - Context* host_context = isolate->context();
|
| -
|
| - for (int i = 0; i < descriptions->length(); ++i) {
|
| - Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
|
| - int host_index = description->host_index();
|
| - Handle<Context> context(Context::cast(host_context->get(host_index)));
|
| - Handle<JSModule> module(context->module());
|
| -
|
| - for (int j = 0; j < description->length(); ++j) {
|
| - Handle<String> name(description->name(j));
|
| - VariableMode mode = description->mode(j);
|
| - int index = description->index(j);
|
| - switch (mode) {
|
| - case VAR:
|
| - case LET:
|
| - case CONST:
|
| - case CONST_LEGACY: {
|
| - PropertyAttributes attr =
|
| - IsImmutableVariableMode(mode) ? FROZEN : SEALED;
|
| - Handle<AccessorInfo> info =
|
| - Accessors::MakeModuleExport(name, index, attr);
|
| - Handle<Object> result =
|
| - JSObject::SetAccessor(module, info).ToHandleChecked();
|
| - DCHECK(!result->IsUndefined());
|
| - USE(result);
|
| - break;
|
| - }
|
| - case MODULE: {
|
| - Object* referenced_context = Context::cast(host_context)->get(index);
|
| - Handle<JSModule> value(Context::cast(referenced_context)->module());
|
| - JSObject::SetOwnPropertyIgnoreAttributes(module, name, value, FROZEN)
|
| - .Assert();
|
| - break;
|
| - }
|
| - case INTERNAL:
|
| - case TEMPORARY:
|
| - case DYNAMIC:
|
| - case DYNAMIC_GLOBAL:
|
| - case DYNAMIC_LOCAL:
|
| - UNREACHABLE();
|
| - }
|
| - }
|
| -
|
| - JSObject::PreventExtensions(module).Assert();
|
| +RUNTIME_FUNCTION(Runtime_Booleanize) {
|
| + SealHandleScope shs(isolate);
|
| + DCHECK(args.length() == 2);
|
| + CONVERT_ARG_CHECKED(Object, value_raw, 0);
|
| + CONVERT_SMI_ARG_CHECKED(token_raw, 1);
|
| + intptr_t value = reinterpret_cast<intptr_t>(value_raw);
|
| + Token::Value token = static_cast<Token::Value>(token_raw);
|
| + switch (token) {
|
| + case Token::EQ:
|
| + case Token::EQ_STRICT:
|
| + return isolate->heap()->ToBoolean(value == 0);
|
| + case Token::NE:
|
| + case Token::NE_STRICT:
|
| + return isolate->heap()->ToBoolean(value != 0);
|
| + case Token::LT:
|
| + return isolate->heap()->ToBoolean(value < 0);
|
| + case Token::GT:
|
| + return isolate->heap()->ToBoolean(value > 0);
|
| + case Token::LTE:
|
| + return isolate->heap()->ToBoolean(value <= 0);
|
| + case Token::GTE:
|
| + return isolate->heap()->ToBoolean(value >= 0);
|
| + default:
|
| + // This should only happen during natives fuzzing.
|
| + return isolate->heap()->undefined_value();
|
| }
|
| -
|
| - DCHECK(!isolate->has_pending_exception());
|
| - return isolate->heap()->undefined_value();
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
|
| +RUNTIME_FUNCTION(Runtime_NewStringWrapper) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 2);
|
| -
|
| - CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
|
| -
|
| - int index;
|
| - PropertyAttributes attributes;
|
| - ContextLookupFlags flags = FOLLOW_CHAINS;
|
| - BindingFlags binding_flags;
|
| - Handle<Object> holder =
|
| - context->Lookup(name, flags, &index, &attributes, &binding_flags);
|
| -
|
| - // If the slot was not found the result is true.
|
| - if (holder.is_null()) {
|
| - return isolate->heap()->true_value();
|
| - }
|
| -
|
| - // If the slot was found in a context, it should be DONT_DELETE.
|
| - if (holder->IsContext()) {
|
| - return isolate->heap()->false_value();
|
| - }
|
| -
|
| - // The slot was found in a JSObject, either a context extension object,
|
| - // the global object, or the subject of a with. Try to delete it
|
| - // (respecting DONT_DELETE).
|
| - Handle<JSObject> object = Handle<JSObject>::cast(holder);
|
| - Handle<Object> result;
|
| - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
|
| - JSReceiver::DeleteProperty(object, name));
|
| - return *result;
|
| + DCHECK(args.length() == 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(String, value, 0);
|
| + return *Object::ToObject(isolate, value).ToHandleChecked();
|
| }
|
|
|
|
|
| -static Object* ComputeReceiverForNonGlobal(Isolate* isolate, JSObject* holder) {
|
| - DCHECK(!holder->IsGlobalObject());
|
| - Context* top = isolate->context();
|
| - // Get the context extension function.
|
| - JSFunction* context_extension_function =
|
| - top->native_context()->context_extension_function();
|
| - // If the holder isn't a context extension object, we just return it
|
| - // as the receiver. This allows arguments objects to be used as
|
| - // receivers, but only if they are put in the context scope chain
|
| - // explicitly via a with-statement.
|
| - Object* constructor = holder->map()->constructor();
|
| - if (constructor != context_extension_function) return holder;
|
| - // Fall back to using the global object as the implicit receiver if
|
| - // the property turns out to be a local variable allocated in a
|
| - // context extension object - introduced via eval.
|
| - return isolate->heap()->undefined_value();
|
| +RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) {
|
| + HandleScope scope(isolate);
|
| + DCHECK(args.length() == 0);
|
| + return *isolate->factory()->NewHeapNumber(0);
|
| }
|
|
|
|
|
| -static ObjectPair LoadLookupSlotHelper(Arguments args, Isolate* isolate,
|
| - bool throw_error) {
|
| - HandleScope scope(isolate);
|
| - DCHECK_EQ(2, args.length());
|
| -
|
| - if (!args[0]->IsContext() || !args[1]->IsString()) {
|
| - return MakePair(isolate->ThrowIllegalOperation(), NULL);
|
| +static Object* Runtime_NewObjectHelper(Isolate* isolate,
|
| + Handle<Object> constructor,
|
| + Handle<AllocationSite> site) {
|
| + // If the constructor isn't a proper function we throw a type error.
|
| + if (!constructor->IsJSFunction()) {
|
| + Vector<Handle<Object> > arguments = HandleVector(&constructor, 1);
|
| + THROW_NEW_ERROR_RETURN_FAILURE(isolate,
|
| + NewTypeError("not_constructor", arguments));
|
| }
|
| - Handle<Context> context = args.at<Context>(0);
|
| - Handle<String> name = args.at<String>(1);
|
| -
|
| - int index;
|
| - PropertyAttributes attributes;
|
| - ContextLookupFlags flags = FOLLOW_CHAINS;
|
| - BindingFlags binding_flags;
|
| - Handle<Object> holder =
|
| - context->Lookup(name, flags, &index, &attributes, &binding_flags);
|
| - if (isolate->has_pending_exception()) {
|
| - return MakePair(isolate->heap()->exception(), NULL);
|
| +
|
| + Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
|
| +
|
| + // If function should not have prototype, construction is not allowed. In this
|
| + // case generated code bailouts here, since function has no initial_map.
|
| + if (!function->should_have_prototype() && !function->shared()->bound()) {
|
| + Vector<Handle<Object> > arguments = HandleVector(&constructor, 1);
|
| + THROW_NEW_ERROR_RETURN_FAILURE(isolate,
|
| + NewTypeError("not_constructor", arguments));
|
| }
|
|
|
| - // If the index is non-negative, the slot has been found in a context.
|
| - if (index >= 0) {
|
| - DCHECK(holder->IsContext());
|
| - // If the "property" we were looking for is a local variable, the
|
| - // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
|
| - Handle<Object> receiver = isolate->factory()->undefined_value();
|
| - Object* value = Context::cast(*holder)->get(index);
|
| - // Check for uninitialized bindings.
|
| - switch (binding_flags) {
|
| - case MUTABLE_CHECK_INITIALIZED:
|
| - case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
|
| - if (value->IsTheHole()) {
|
| - Handle<Object> error;
|
| - MaybeHandle<Object> maybe_error =
|
| - isolate->factory()->NewReferenceError("not_defined",
|
| - HandleVector(&name, 1));
|
| - if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
|
| - return MakePair(isolate->heap()->exception(), NULL);
|
| - }
|
| - // FALLTHROUGH
|
| - case MUTABLE_IS_INITIALIZED:
|
| - case IMMUTABLE_IS_INITIALIZED:
|
| - case IMMUTABLE_IS_INITIALIZED_HARMONY:
|
| - DCHECK(!value->IsTheHole());
|
| - return MakePair(value, *receiver);
|
| - case IMMUTABLE_CHECK_INITIALIZED:
|
| - if (value->IsTheHole()) {
|
| - DCHECK((attributes & READ_ONLY) != 0);
|
| - value = isolate->heap()->undefined_value();
|
| - }
|
| - return MakePair(value, *receiver);
|
| - case MISSING_BINDING:
|
| - UNREACHABLE();
|
| - return MakePair(NULL, NULL);
|
| - }
|
| + Debug* debug = isolate->debug();
|
| + // Handle stepping into constructors if step into is active.
|
| + if (debug->StepInActive()) {
|
| + debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
|
| }
|
|
|
| - // Otherwise, if the slot was found the holder is a context extension
|
| - // object, subject of a with, or a global object. We read the named
|
| - // property from it.
|
| - if (!holder.is_null()) {
|
| - Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
|
| -#ifdef DEBUG
|
| - if (!object->IsJSProxy()) {
|
| - Maybe<bool> maybe = JSReceiver::HasProperty(object, name);
|
| - DCHECK(maybe.has_value);
|
| - DCHECK(maybe.value);
|
| + if (function->has_initial_map()) {
|
| + if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
|
| + // The 'Function' function ignores the receiver object when
|
| + // called using 'new' and creates a new JSFunction object that
|
| + // is returned. The receiver object is only used for error
|
| + // reporting if an error occurs when constructing the new
|
| + // JSFunction. Factory::NewJSObject() should not be used to
|
| + // allocate JSFunctions since it does not properly initialize
|
| + // the shared part of the function. Since the receiver is
|
| + // ignored anyway, we use the global object as the receiver
|
| + // instead of a new JSFunction object. This way, errors are
|
| + // reported the same way whether or not 'Function' is called
|
| + // using 'new'.
|
| + return isolate->global_proxy();
|
| }
|
| -#endif
|
| - // GetProperty below can cause GC.
|
| - Handle<Object> receiver_handle(
|
| - object->IsGlobalObject()
|
| - ? Object::cast(isolate->heap()->undefined_value())
|
| - : object->IsJSProxy() ? static_cast<Object*>(*object)
|
| - : ComputeReceiverForNonGlobal(
|
| - isolate, JSObject::cast(*object)),
|
| - isolate);
|
| -
|
| - // No need to unhole the value here. This is taken care of by the
|
| - // GetProperty function.
|
| - Handle<Object> value;
|
| - ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
| - isolate, value, Object::GetProperty(object, name),
|
| - MakePair(isolate->heap()->exception(), NULL));
|
| - return MakePair(*value, *receiver_handle);
|
| }
|
|
|
| - if (throw_error) {
|
| - // The property doesn't exist - throw exception.
|
| - Handle<Object> error;
|
| - MaybeHandle<Object> maybe_error = isolate->factory()->NewReferenceError(
|
| - "not_defined", HandleVector(&name, 1));
|
| - if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
|
| - return MakePair(isolate->heap()->exception(), NULL);
|
| + // The function should be compiled for the optimization hints to be
|
| + // available.
|
| + Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
|
| +
|
| + Handle<JSObject> result;
|
| + if (site.is_null()) {
|
| + result = isolate->factory()->NewJSObject(function);
|
| } else {
|
| - // The property doesn't exist - return undefined.
|
| - return MakePair(isolate->heap()->undefined_value(),
|
| - isolate->heap()->undefined_value());
|
| + result = isolate->factory()->NewJSObjectWithMemento(function, site);
|
| }
|
| +
|
| + isolate->counters()->constructed_objects()->Increment();
|
| + isolate->counters()->constructed_objects_runtime()->Increment();
|
| +
|
| + return *result;
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlot) {
|
| - return LoadLookupSlotHelper(args, isolate, true);
|
| +RUNTIME_FUNCTION(Runtime_NewObject) {
|
| + HandleScope scope(isolate);
|
| + DCHECK(args.length() == 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0);
|
| + return Runtime_NewObjectHelper(isolate, constructor,
|
| + Handle<AllocationSite>::null());
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotNoReferenceError) {
|
| - return LoadLookupSlotHelper(args, isolate, false);
|
| +RUNTIME_FUNCTION(Runtime_NewObjectWithAllocationSite) {
|
| + HandleScope scope(isolate);
|
| + DCHECK(args.length() == 2);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, feedback, 0);
|
| + Handle<AllocationSite> site;
|
| + if (feedback->IsAllocationSite()) {
|
| + // The feedback can be an AllocationSite or undefined.
|
| + site = Handle<AllocationSite>::cast(feedback);
|
| + }
|
| + return Runtime_NewObjectHelper(isolate, constructor, site);
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_StoreLookupSlot) {
|
| +RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) {
|
| HandleScope scope(isolate);
|
| - DCHECK(args.length() == 4);
|
| + DCHECK(args.length() == 1);
|
|
|
| - CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
|
| - CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 3);
|
| -
|
| - int index;
|
| - PropertyAttributes attributes;
|
| - ContextLookupFlags flags = FOLLOW_CHAINS;
|
| - BindingFlags binding_flags;
|
| - Handle<Object> holder =
|
| - context->Lookup(name, flags, &index, &attributes, &binding_flags);
|
| - // In case of JSProxy, an exception might have been thrown.
|
| - if (isolate->has_pending_exception()) return isolate->heap()->exception();
|
| -
|
| - // The property was found in a context slot.
|
| - if (index >= 0) {
|
| - if ((attributes & READ_ONLY) == 0) {
|
| - Handle<Context>::cast(holder)->set(index, *value);
|
| - } else if (strict_mode == STRICT) {
|
| - // Setting read only property in strict mode.
|
| - THROW_NEW_ERROR_RETURN_FAILURE(
|
| - isolate,
|
| - NewTypeError("strict_cannot_assign", HandleVector(&name, 1)));
|
| - }
|
| - return *value;
|
| - }
|
| + CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
|
| + function->CompleteInobjectSlackTracking();
|
|
|
| - // Slow case: The property is not in a context slot. It is either in a
|
| - // context extension object, a property of the subject of a with, or a
|
| - // property of the global object.
|
| - Handle<JSReceiver> object;
|
| - if (attributes != ABSENT) {
|
| - // The property exists on the holder.
|
| - object = Handle<JSReceiver>::cast(holder);
|
| - } else if (strict_mode == STRICT) {
|
| - // If absent in strict mode: throw.
|
| - THROW_NEW_ERROR_RETURN_FAILURE(
|
| - isolate, NewReferenceError("not_defined", HandleVector(&name, 1)));
|
| - } else {
|
| - // If absent in sloppy mode: add the property to the global object.
|
| - object = Handle<JSReceiver>(context->global_object());
|
| - }
|
| + return isolate->heap()->undefined_value();
|
| +}
|
|
|
| - RETURN_FAILURE_ON_EXCEPTION(
|
| - isolate, Object::SetProperty(object, name, value, strict_mode));
|
|
|
| - return *value;
|
| +RUNTIME_FUNCTION(Runtime_CheckIsBootstrapping) {
|
| + SealHandleScope shs(isolate);
|
| + DCHECK(args.length() == 0);
|
| + RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
|
| + return isolate->heap()->undefined_value();
|
| +}
|
| +
|
| +
|
| +RUNTIME_FUNCTION(Runtime_GetRootNaN) {
|
| + SealHandleScope shs(isolate);
|
| + DCHECK(args.length() == 0);
|
| + RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
|
| + return isolate->heap()->nan_value();
|
| }
|
|
|
|
|
| @@ -4078,53 +1893,6 @@ RUNTIME_FUNCTION(Runtime_Interrupt) {
|
| }
|
|
|
|
|
| -static int StackSize(Isolate* isolate) {
|
| - int n = 0;
|
| - for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
|
| - return n;
|
| -}
|
| -
|
| -
|
| -static void PrintTransition(Isolate* isolate, Object* result) {
|
| - // indentation
|
| - {
|
| - const int nmax = 80;
|
| - int n = StackSize(isolate);
|
| - if (n <= nmax)
|
| - PrintF("%4d:%*s", n, n, "");
|
| - else
|
| - PrintF("%4d:%*s", n, nmax, "...");
|
| - }
|
| -
|
| - if (result == NULL) {
|
| - JavaScriptFrame::PrintTop(isolate, stdout, true, false);
|
| - PrintF(" {\n");
|
| - } else {
|
| - // function result
|
| - PrintF("} -> ");
|
| - result->ShortPrint();
|
| - PrintF("\n");
|
| - }
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_TraceEnter) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 0);
|
| - PrintTransition(isolate, NULL);
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_TraceExit) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(Object, obj, 0);
|
| - PrintTransition(isolate, obj);
|
| - return obj; // return TOS
|
| -}
|
| -
|
| -
|
| RUNTIME_FUNCTION(Runtime_GlobalProxy) {
|
| SealHandleScope shs(isolate);
|
| DCHECK(args.length() == 1);
|
| @@ -5206,119 +2974,6 @@ RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) {
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(Runtime_IsObserved) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| -
|
| - if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value();
|
| - CONVERT_ARG_CHECKED(JSReceiver, obj, 0);
|
| - DCHECK(!obj->IsJSGlobalProxy() || !obj->map()->is_observed());
|
| - return isolate->heap()->ToBoolean(obj->map()->is_observed());
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_SetIsObserved) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
|
| - RUNTIME_ASSERT(!obj->IsJSGlobalProxy());
|
| - if (obj->IsJSProxy()) return isolate->heap()->undefined_value();
|
| - RUNTIME_ASSERT(!obj->map()->is_observed());
|
| -
|
| - DCHECK(obj->IsJSObject());
|
| - JSObject::SetObserved(Handle<JSObject>::cast(obj));
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, microtask, 0);
|
| - isolate->EnqueueMicrotask(microtask);
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_RunMicrotasks) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 0);
|
| - isolate->RunMicrotasks();
|
| - return isolate->heap()->undefined_value();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_GetObservationState) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 0);
|
| - return isolate->heap()->observation_state();
|
| -}
|
| -
|
| -
|
| -static bool ContextsHaveSameOrigin(Handle<Context> context1,
|
| - Handle<Context> context2) {
|
| - return context1->security_token() == context2->security_token();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_ObserverObjectAndRecordHaveSameOrigin) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 3);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, record, 2);
|
| -
|
| - Handle<Context> observer_context(observer->context()->native_context());
|
| - Handle<Context> object_context(object->GetCreationContext());
|
| - Handle<Context> record_context(record->GetCreationContext());
|
| -
|
| - return isolate->heap()->ToBoolean(
|
| - ContextsHaveSameOrigin(object_context, observer_context) &&
|
| - ContextsHaveSameOrigin(object_context, record_context));
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_ObjectWasCreatedInCurrentOrigin) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| -
|
| - Handle<Context> creation_context(object->GetCreationContext(), isolate);
|
| - return isolate->heap()->ToBoolean(
|
| - ContextsHaveSameOrigin(creation_context, isolate->native_context()));
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_GetObjectContextObjectObserve) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| -
|
| - Handle<Context> context(object->GetCreationContext(), isolate);
|
| - return context->native_object_observe();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_GetObjectContextObjectGetNotifier) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
| -
|
| - Handle<Context> context(object->GetCreationContext(), isolate);
|
| - return context->native_object_get_notifier();
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(Runtime_GetObjectContextNotifierPerformChange) {
|
| - HandleScope scope(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_HANDLE_CHECKED(JSObject, object_info, 0);
|
| -
|
| - Handle<Context> context(object_info->GetCreationContext(), isolate);
|
| - return context->native_object_notifier_perform_change();
|
| -}
|
| -
|
| -
|
| static Object* ArrayConstructorCommon(Isolate* isolate,
|
| Handle<JSFunction> constructor,
|
| Handle<AllocationSite> site,
|
| @@ -5572,23 +3227,6 @@ U(DebugBreakInOptimizedCode)
|
| #undef U
|
|
|
|
|
| -RUNTIME_FUNCTION(RuntimeReference_IsSmi) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(Object, obj, 0);
|
| - return isolate->heap()->ToBoolean(obj->IsSmi());
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(RuntimeReference_IsNonNegativeSmi) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(Object, obj, 0);
|
| - return isolate->heap()->ToBoolean(obj->IsSmi() &&
|
| - Smi::cast(obj)->value() >= 0);
|
| -}
|
| -
|
| -
|
| RUNTIME_FUNCTION(RuntimeReference_IsArray) {
|
| SealHandleScope shs(isolate);
|
| DCHECK(args.length() == 1);
|
| @@ -5597,43 +3235,6 @@ RUNTIME_FUNCTION(RuntimeReference_IsArray) {
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(RuntimeReference_IsRegExp) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(Object, obj, 0);
|
| - return isolate->heap()->ToBoolean(obj->IsJSRegExp());
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(RuntimeReference_IsConstructCall) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 0);
|
| - JavaScriptFrameIterator it(isolate);
|
| - JavaScriptFrame* frame = it.frame();
|
| - return isolate->heap()->ToBoolean(frame->IsConstructor());
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(RuntimeReference_CallFunction) {
|
| - SealHandleScope shs(isolate);
|
| - return __RT_impl_Runtime_Call(args, isolate);
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(RuntimeReference_ArgumentsLength) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 0);
|
| - JavaScriptFrameIterator it(isolate);
|
| - JavaScriptFrame* frame = it.frame();
|
| - return Smi::FromInt(frame->GetArgumentsLength());
|
| -}
|
| -
|
| -
|
| -RUNTIME_FUNCTION(RuntimeReference_Arguments) {
|
| - SealHandleScope shs(isolate);
|
| - return __RT_impl_Runtime_GetArgumentsProperty(args, isolate);
|
| -}
|
| -
|
|
|
| RUNTIME_FUNCTION(RuntimeReference_ValueOf) {
|
| SealHandleScope shs(isolate);
|
| @@ -5679,14 +3280,6 @@ RUNTIME_FUNCTION(RuntimeReference_IsObject) {
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(RuntimeReference_IsFunction) {
|
| - SealHandleScope shs(isolate);
|
| - DCHECK(args.length() == 1);
|
| - CONVERT_ARG_CHECKED(Object, obj, 0);
|
| - return isolate->heap()->ToBoolean(obj->IsJSFunction());
|
| -}
|
| -
|
| -
|
| RUNTIME_FUNCTION(RuntimeReference_IsUndetectableObject) {
|
| SealHandleScope shs(isolate);
|
| DCHECK(args.length() == 1);
|
|
|