HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Lollipop MR1
|
5.1.0_r3
下载
查看原文件
收藏
根目录
external
chromium_org
v8
src
runtime.cc
// Copyright 2012 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include
#include
#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/cpu-profiler.h" #include "src/date.h" #include "src/dateparser-inl.h" #include "src/debug.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/json-parser.h" #include "src/json-stringifier.h" #include "src/jsregexp-inl.h" #include "src/jsregexp.h" #include "src/liveedit.h" #include "src/misc-intrinsics.h" #include "src/parser.h" #include "src/prototype.h" #include "src/runtime.h" #include "src/runtime-profiler.h" #include "src/scopeinfo.h" #include "src/smart-pointers.h" #include "src/string-search.h" #include "src/uri.h" #include "src/utils.h" #include "src/v8threads.h" #include "src/vm-state-inl.h" #include "third_party/fdlibm/fdlibm.h" #ifdef V8_I18N_SUPPORT #include "src/i18n.h" #include "unicode/brkiter.h" #include "unicode/calendar.h" #include "unicode/coll.h" #include "unicode/curramt.h" #include "unicode/datefmt.h" #include "unicode/dcfmtsym.h" #include "unicode/decimfmt.h" #include "unicode/dtfmtsym.h" #include "unicode/dtptngen.h" #include "unicode/locid.h" #include "unicode/numfmt.h" #include "unicode/numsys.h" #include "unicode/rbbi.h" #include "unicode/smpdtfmt.h" #include "unicode/timezone.h" #include "unicode/uchar.h" #include "unicode/ucol.h" #include "unicode/ucurr.h" #include "unicode/uloc.h" #include "unicode/unum.h" #include "unicode/uversion.h" #endif #ifndef _STLP_VENDOR_CSTD // STLPort doesn't import fpclassify and isless into the std namespace. using std::fpclassify; using std::isless; #endif namespace v8 { namespace internal { #define RUNTIME_ASSERT(value) \ if (!(value)) return isolate->ThrowIllegalOperation(); #define RUNTIME_ASSERT_HANDLIFIED(value, T) \ if (!(value)) { \ isolate->ThrowIllegalOperation(); \ return MaybeHandle
(); \ } // Cast the given object to a value of the specified type and store // it in a variable with the given name. If the object is not of the // expected type call IllegalOperation and return. #define CONVERT_ARG_CHECKED(Type, name, index) \ RUNTIME_ASSERT(args[index]->Is##Type()); \ Type* name = Type::cast(args[index]); #define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \ RUNTIME_ASSERT(args[index]->Is##Type()); \ Handle
name = args.at
(index); #define CONVERT_NUMBER_ARG_HANDLE_CHECKED(name, index) \ RUNTIME_ASSERT(args[index]->IsNumber()); \ Handle
name = args.at
(index); // Cast the given object to a boolean and store it in a variable with // the given name. If the object is not a boolean call IllegalOperation // and return. #define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \ RUNTIME_ASSERT(args[index]->IsBoolean()); \ bool name = args[index]->IsTrue(); // Cast the given argument to a Smi and store its value in an int variable // with the given name. If the argument is not a Smi call IllegalOperation // and return. #define CONVERT_SMI_ARG_CHECKED(name, index) \ RUNTIME_ASSERT(args[index]->IsSmi()); \ int name = args.smi_at(index); // Cast the given argument to a double and store it in a variable with // the given name. If the argument is not a number (as opposed to // the number not-a-number) call IllegalOperation and return. #define CONVERT_DOUBLE_ARG_CHECKED(name, index) \ RUNTIME_ASSERT(args[index]->IsNumber()); \ double name = args.number_at(index); // Call the specified converter on the object *comand store the result in // a variable of the specified type with the given name. If the // object is not a Number call IllegalOperation and return. #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ RUNTIME_ASSERT(obj->IsNumber()); \ type name = NumberTo##Type(obj); // Cast the given argument to PropertyDetails and store its value in a // variable with the given name. If the argument is not a Smi call // IllegalOperation and return. #define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \ RUNTIME_ASSERT(args[index]->IsSmi()); \ PropertyDetails name = PropertyDetails(Smi::cast(args[index])); // Assert that the given argument has a valid value for a StrictMode // and store it in a StrictMode variable with the given name. #define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \ RUNTIME_ASSERT(args[index]->IsSmi()); \ RUNTIME_ASSERT(args.smi_at(index) == STRICT || \ args.smi_at(index) == SLOPPY); \ StrictMode name = static_cast
(args.smi_at(index)); // Assert that the given argument is a number within the Int32 range // and convert it to int32_t. If the argument is not an Int32 call // IllegalOperation and return. #define CONVERT_INT32_ARG_CHECKED(name, index) \ RUNTIME_ASSERT(args[index]->IsNumber()); \ int32_t name = 0; \ RUNTIME_ASSERT(args[index]->ToInt32(&name)); static Handle
ComputeObjectLiteralMap( Handle
context, Handle
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
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
CreateLiteralBoilerplate( Isolate* isolate, Handle
literals, Handle
constant_properties); MUST_USE_RESULT static MaybeHandle
CreateObjectLiteralBoilerplate( Isolate* isolate, Handle
literals, Handle
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 = Handle
(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 = has_function_literal ? Handle
(context->object_function()->initial_map()) : ComputeObjectLiteralMap(context, constant_properties, &is_result_from_cache); PretenureFlag pretenure_flag = isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED; Handle
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
key(constant_properties->get(index+0), isolate); Handle
value(constant_properties->get(index+1), isolate); if (value->IsFixedArray()) { // The value contains the constant_properties of a // simple object or array literal. Handle
array = Handle
::cast(value); ASSIGN_RETURN_ON_EXCEPTION( isolate, value, CreateLiteralBoilerplate(isolate, literals, array), Object); } MaybeHandle
maybe_result; uint32_t element_index = 0; if (key->IsInternalizedString()) { if (Handle
::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
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
buffer(arr, arraysize(arr)); const char* str = DoubleToCString(num, buffer); Handle
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
TransitionElements( Handle
object, ElementsKind to_kind, Isolate* isolate) { HandleScope scope(isolate); if (!object->IsJSObject()) { isolate->ThrowIllegalOperation(); return MaybeHandle
(); } ElementsKind from_kind = Handle
::cast(object)->map()->elements_kind(); if (Map::IsValidElementsTransition(from_kind, to_kind)) { JSObject::TransitionElementsKind(Handle
::cast(object), to_kind); return object; } isolate->ThrowIllegalOperation(); return MaybeHandle
(); } MaybeHandle
Runtime::CreateArrayLiteralBoilerplate( Isolate* isolate, Handle
literals, Handle
elements) { // Create the JSArray. Handle
constructor( JSFunction::NativeContextFromLiterals(*literals)->array_function()); PretenureFlag pretenure_flag = isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED; Handle
object = Handle
::cast( isolate->factory()->NewJSObject(constructor, pretenure_flag)); ElementsKind constant_elements_kind = static_cast
(Smi::cast(elements->get(0))->value()); Handle
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
copied_elements_values; if (IsFastDoubleElementsKind(constant_elements_kind)) { copied_elements_values = isolate->factory()->CopyFixedDoubleArray( Handle
::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
fixed_array_values = Handle
::cast(copied_elements_values); for (int i = 0; i < fixed_array_values->length(); i++) { DCHECK(!fixed_array_values->get(i)->IsFixedArray()); } #endif } else { Handle
fixed_array_values = Handle
::cast(constant_elements_values); Handle
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
fa(FixedArray::cast(fixed_array_values->get(i))); Handle
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
CreateLiteralBoilerplate( Isolate* isolate, Handle
literals, Handle
array) { Handle
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
(); } } 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
literal_site(literals->get(literals_index), isolate); Handle
site; Handle
boilerplate; if (*literal_site == isolate->heap()->undefined_value()) { Handle
raw_boilerplate; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, raw_boilerplate, CreateObjectLiteralBoilerplate( isolate, literals, constant_properties, should_have_fast_elements, has_function_literal)); boilerplate = Handle
::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
::cast(literal_site); boilerplate = Handle
(JSObject::cast(site->transition_info()), isolate); } AllocationSiteUsageContext usage_context(isolate, site, true); usage_context.EnterNewScope(); MaybeHandle
maybe_copy = JSObject::DeepCopy( boilerplate, &usage_context); usage_context.ExitScope(site, boilerplate); Handle
copy; ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, copy, maybe_copy); return *copy; } MUST_USE_RESULT static MaybeHandle
GetLiteralAllocationSite( Isolate* isolate, Handle
literals, int literals_index, Handle
elements) { // Check if boilerplate exists. If not, create it first. Handle
literal_site(literals->get(literals_index), isolate); Handle
site; if (*literal_site == isolate->heap()->undefined_value()) { DCHECK(*elements != isolate->heap()->empty_fixed_array()); Handle
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
::cast(boilerplate), &creation_context).is_null()) { return Handle
::null(); } creation_context.ExitScope(site, Handle
::cast(boilerplate)); literals->set(literals_index, *site); } else { site = Handle
::cast(literal_site); } return site; } static MaybeHandle
CreateArrayLiteralImpl(Isolate* isolate, Handle
literals, int literals_index, Handle
elements, int flags) { RUNTIME_ASSERT_HANDLIFIED(literals_index >= 0 && literals_index < literals->length(), JSObject); Handle
site; ASSIGN_RETURN_ON_EXCEPTION( isolate, site, GetLiteralAllocationSite(isolate, literals, literals_index, elements), JSObject); bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0; Handle
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
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
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
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 = 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 = 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 = 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
registry = isolate->GetSymbolRegistry(); Handle
part = isolate->factory()->private_intern_string(); Handle
privates; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, privates, Object::GetPropertyOrElement(registry, part)); Handle
symbol; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, symbol, Object::GetPropertyOrElement(privates, name)); if (!symbol->IsSymbol()) { DCHECK(symbol->IsUndefined()); symbol = isolate->factory()->NewPrivateSymbol(); Handle
::cast(symbol)->set_name(*name); Handle
::cast(symbol)->set_is_own(true); JSObject::SetProperty(Handle
::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(); } void Runtime::FreeArrayBuffer(Isolate* isolate, JSArrayBuffer* phantom_array_buffer) { if (phantom_array_buffer->should_be_freed()) { DCHECK(phantom_array_buffer->is_external()); free(phantom_array_buffer->backing_store()); } if (phantom_array_buffer->is_external()) return; size_t allocated_length = NumberToSize( isolate, phantom_array_buffer->byte_length()); reinterpret_cast
(isolate) ->AdjustAmountOfExternalAllocatedMemory( -static_cast
(allocated_length)); CHECK(V8::ArrayBufferAllocator() != NULL); V8::ArrayBufferAllocator()->Free( phantom_array_buffer->backing_store(), allocated_length); } void Runtime::SetupArrayBuffer(Isolate* isolate, Handle
array_buffer, bool is_external, void* data, size_t allocated_length) { DCHECK(array_buffer->GetInternalFieldCount() == v8::ArrayBuffer::kInternalFieldCount); for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) { array_buffer->SetInternalField(i, Smi::FromInt(0)); } array_buffer->set_backing_store(data); array_buffer->set_flag(Smi::FromInt(0)); array_buffer->set_is_external(is_external); Handle
byte_length = isolate->factory()->NewNumberFromSize(allocated_length); CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber()); array_buffer->set_byte_length(*byte_length); array_buffer->set_weak_next(isolate->heap()->array_buffers_list()); isolate->heap()->set_array_buffers_list(*array_buffer); array_buffer->set_weak_first_view(isolate->heap()->undefined_value()); } bool Runtime::SetupArrayBufferAllocatingData( Isolate* isolate, Handle
array_buffer, size_t allocated_length, bool initialize) { void* data; CHECK(V8::ArrayBufferAllocator() != NULL); if (allocated_length != 0) { if (initialize) { data = V8::ArrayBufferAllocator()->Allocate(allocated_length); } else { data = V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length); } if (data == NULL) return false; } else { data = NULL; } SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length); reinterpret_cast
(isolate) ->AdjustAmountOfExternalAllocatedMemory(allocated_length); return true; } void Runtime::NeuterArrayBuffer(Handle
array_buffer) { Isolate* isolate = array_buffer->GetIsolate(); for (Handle
view_obj(array_buffer->weak_first_view(), isolate); !view_obj->IsUndefined();) { Handle
view(JSArrayBufferView::cast(*view_obj)); if (view->IsJSTypedArray()) { JSTypedArray::cast(*view)->Neuter(); } else if (view->IsJSDataView()) { JSDataView::cast(*view)->Neuter(); } else { UNREACHABLE(); } view_obj = handle(view->weak_next(), isolate); } array_buffer->Neuter(); } RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1); if (!holder->byte_length()->IsUndefined()) { // ArrayBuffer is already initialized; probably a fuzz test. return *holder; } size_t allocated_length = 0; if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewRangeError("invalid_array_buffer_length", HandleVector
(NULL, 0))); } if (!Runtime::SetupArrayBufferAllocatingData(isolate, holder, allocated_length)) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewRangeError("invalid_array_buffer_length", HandleVector
(NULL, 0))); } return *holder; } RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) { SealHandleScope shs(isolate); DCHECK(args.length() == 1); CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0); return holder->byte_length(); } RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) { HandleScope scope(isolate); DCHECK(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0); CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1); CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2); RUNTIME_ASSERT(!source.is_identical_to(target)); size_t start = 0; RUNTIME_ASSERT(TryNumberToSize(isolate, *first, &start)); size_t target_length = NumberToSize(isolate, target->byte_length()); if (target_length == 0) return isolate->heap()->undefined_value(); size_t source_byte_length = NumberToSize(isolate, source->byte_length()); RUNTIME_ASSERT(start <= source_byte_length); RUNTIME_ASSERT(source_byte_length - start >= target_length); uint8_t* source_data = reinterpret_cast
(source->backing_store()); uint8_t* target_data = reinterpret_cast
(target->backing_store()); CopyBytes(target_data, source_data + start, target_length); return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_CHECKED(Object, object, 0); return isolate->heap()->ToBoolean(object->IsJSArrayBufferView()); } RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0); if (array_buffer->backing_store() == NULL) { CHECK(Smi::FromInt(0) == array_buffer->byte_length()); return isolate->heap()->undefined_value(); } DCHECK(!array_buffer->is_external()); void* backing_store = array_buffer->backing_store(); size_t byte_length = NumberToSize(isolate, array_buffer->byte_length()); array_buffer->set_is_external(true); Runtime::NeuterArrayBuffer(array_buffer); V8::ArrayBufferAllocator()->Free(backing_store, byte_length); return isolate->heap()->undefined_value(); } void Runtime::ArrayIdToTypeAndSize( int arrayId, ExternalArrayType* array_type, ElementsKind* external_elements_kind, ElementsKind* fixed_elements_kind, size_t* element_size) { switch (arrayId) { #define ARRAY_ID_CASE(Type, type, TYPE, ctype, size) \ case ARRAY_ID_##TYPE: \ *array_type = kExternal##Type##Array; \ *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \ *fixed_elements_kind = TYPE##_ELEMENTS; \ *element_size = size; \ break; TYPED_ARRAYS(ARRAY_ID_CASE) #undef ARRAY_ID_CASE default: UNREACHABLE(); } } RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) { HandleScope scope(isolate); DCHECK(args.length() == 5); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); CONVERT_SMI_ARG_CHECKED(arrayId, 1); CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2); CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3); CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4); RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST && arrayId <= Runtime::ARRAY_ID_LAST); ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. size_t element_size = 1; // Bogus initialization. ElementsKind external_elements_kind = EXTERNAL_INT8_ELEMENTS; // Bogus initialization. ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization. Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind, &fixed_elements_kind, &element_size); RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind); size_t byte_offset = 0; size_t byte_length = 0; RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset_object, &byte_offset)); RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length_object, &byte_length)); if (maybe_buffer->IsJSArrayBuffer()) { Handle
buffer = Handle
::cast(maybe_buffer); size_t array_buffer_byte_length = NumberToSize(isolate, buffer->byte_length()); RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length); RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length); } else { RUNTIME_ASSERT(maybe_buffer->IsNull()); } RUNTIME_ASSERT(byte_length % element_size == 0); size_t length = byte_length / element_size; if (length > static_cast
(Smi::kMaxValue)) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewRangeError("invalid_typed_array_length", HandleVector
(NULL, 0))); } // All checks are done, now we can modify objects. DCHECK(holder->GetInternalFieldCount() == v8::ArrayBufferView::kInternalFieldCount); for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { holder->SetInternalField(i, Smi::FromInt(0)); } Handle
length_obj = isolate->factory()->NewNumberFromSize(length); holder->set_length(*length_obj); holder->set_byte_offset(*byte_offset_object); holder->set_byte_length(*byte_length_object); if (!maybe_buffer->IsNull()) { Handle
buffer = Handle
::cast(maybe_buffer); holder->set_buffer(*buffer); holder->set_weak_next(buffer->weak_first_view()); buffer->set_weak_first_view(*holder); Handle
elements = isolate->factory()->NewExternalArray( static_cast
(length), array_type, static_cast
(buffer->backing_store()) + byte_offset); Handle
map = JSObject::GetElementsTransitionMap(holder, external_elements_kind); JSObject::SetMapAndElements(holder, map, elements); DCHECK(IsExternalArrayElementsKind(holder->map()->elements_kind())); } else { holder->set_buffer(Smi::FromInt(0)); holder->set_weak_next(isolate->heap()->undefined_value()); Handle
elements = isolate->factory()->NewFixedTypedArray( static_cast
(length), array_type); holder->set_elements(*elements); } return isolate->heap()->undefined_value(); } // Initializes a typed array from an array-like object. // If an array-like object happens to be a typed array of the same type, // initializes backing store using memove. // // Returns true if backing store was initialized or false otherwise. RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) { HandleScope scope(isolate); DCHECK(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); CONVERT_SMI_ARG_CHECKED(arrayId, 1); CONVERT_ARG_HANDLE_CHECKED(Object, source, 2); CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3); RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST && arrayId <= Runtime::ARRAY_ID_LAST); ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. size_t element_size = 1; // Bogus initialization. ElementsKind external_elements_kind = EXTERNAL_INT8_ELEMENTS; // Bogus intialization. ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization. Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind, &fixed_elements_kind, &element_size); RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind); Handle
buffer = isolate->factory()->NewJSArrayBuffer(); if (source->IsJSTypedArray() && JSTypedArray::cast(*source)->type() == array_type) { length_obj = Handle
(JSTypedArray::cast(*source)->length(), isolate); } size_t length = 0; RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length)); if ((length > static_cast
(Smi::kMaxValue)) || (length > (kMaxInt / element_size))) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewRangeError("invalid_typed_array_length", HandleVector
(NULL, 0))); } size_t byte_length = length * element_size; DCHECK(holder->GetInternalFieldCount() == v8::ArrayBufferView::kInternalFieldCount); for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { holder->SetInternalField(i, Smi::FromInt(0)); } // NOTE: not initializing backing store. // We assume that the caller of this function will initialize holder // with the loop // for(i = 0; i < length; i++) { holder[i] = source[i]; } // We assume that the caller of this function is always a typed array // constructor. // If source is a typed array, this loop will always run to completion, // so we are sure that the backing store will be initialized. // Otherwise, the indexing operation might throw, so the loop will not // run to completion and the typed array might remain partly initialized. // However we further assume that the caller of this function is a typed array // constructor, and the exception will propagate out of the constructor, // therefore uninitialized memory will not be accessible by a user program. // // TODO(dslomov): revise this once we support subclassing. if (!Runtime::SetupArrayBufferAllocatingData( isolate, buffer, byte_length, false)) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewRangeError("invalid_array_buffer_length", HandleVector
(NULL, 0))); } holder->set_buffer(*buffer); holder->set_byte_offset(Smi::FromInt(0)); Handle
byte_length_obj( isolate->factory()->NewNumberFromSize(byte_length)); holder->set_byte_length(*byte_length_obj); holder->set_length(*length_obj); holder->set_weak_next(buffer->weak_first_view()); buffer->set_weak_first_view(*holder); Handle
elements = isolate->factory()->NewExternalArray( static_cast
(length), array_type, static_cast
(buffer->backing_store())); Handle
map = JSObject::GetElementsTransitionMap( holder, external_elements_kind); JSObject::SetMapAndElements(holder, map, elements); if (source->IsJSTypedArray()) { Handle
typed_array(JSTypedArray::cast(*source)); if (typed_array->type() == holder->type()) { uint8_t* backing_store = static_cast
( typed_array->GetBuffer()->backing_store()); size_t source_byte_offset = NumberToSize(isolate, typed_array->byte_offset()); memcpy( buffer->backing_store(), backing_store + source_byte_offset, byte_length); return isolate->heap()->true_value(); } } return isolate->heap()->false_value(); } #define BUFFER_VIEW_GETTER(Type, getter, accessor) \ RUNTIME_FUNCTION(Runtime_##Type##Get##getter) { \ HandleScope scope(isolate); \ DCHECK(args.length() == 1); \ CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \ return holder->accessor(); \ } BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length) BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset) BUFFER_VIEW_GETTER(TypedArray, Length, length) BUFFER_VIEW_GETTER(DataView, Buffer, buffer) #undef BUFFER_VIEW_GETTER RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); return *holder->GetBuffer(); } // Return codes for Runtime_TypedArraySetFastCases. // Should be synchronized with typedarray.js natives. enum TypedArraySetResultCodes { // Set from typed array of the same type. // This is processed by TypedArraySetFastCases TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0, // Set from typed array of the different type, overlapping in memory. TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1, // Set from typed array of the different type, non-overlapping. TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2, // Set from non-typed array. TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3 }; RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) { HandleScope scope(isolate); DCHECK(args.length() == 3); if (!args[0]->IsJSTypedArray()) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError("not_typed_array", HandleVector
(NULL, 0))); } if (!args[1]->IsJSTypedArray()) return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1); CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2); Handle
target(JSTypedArray::cast(*target_obj)); Handle
source(JSTypedArray::cast(*source_obj)); size_t offset = 0; RUNTIME_ASSERT(TryNumberToSize(isolate, *offset_obj, &offset)); size_t target_length = NumberToSize(isolate, target->length()); size_t source_length = NumberToSize(isolate, source->length()); size_t target_byte_length = NumberToSize(isolate, target->byte_length()); size_t source_byte_length = NumberToSize(isolate, source->byte_length()); if (offset > target_length || offset + source_length > target_length || offset + source_length < offset) { // overflow THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewRangeError("typed_array_set_source_too_large", HandleVector
(NULL, 0))); } size_t target_offset = NumberToSize(isolate, target->byte_offset()); size_t source_offset = NumberToSize(isolate, source->byte_offset()); uint8_t* target_base = static_cast
( target->GetBuffer()->backing_store()) + target_offset; uint8_t* source_base = static_cast
( source->GetBuffer()->backing_store()) + source_offset; // Typed arrays of the same type: use memmove. if (target->type() == source->type()) { memmove(target_base + offset * target->element_size(), source_base, source_byte_length); return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE); } // Typed arrays of different types over the same backing store if ((source_base <= target_base && source_base + source_byte_length > target_base) || (target_base <= source_base && target_base + target_byte_length > source_base)) { // We do not support overlapping ArrayBuffers DCHECK( target->GetBuffer()->backing_store() == source->GetBuffer()->backing_store()); return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING); } else { // Non-overlapping typed arrays return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING); } } RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) { DCHECK(args.length() == 0); DCHECK_OBJECT_SIZE( FLAG_typed_array_max_size_in_heap + FixedTypedArrayBase::kDataOffset); return Smi::FromInt(FLAG_typed_array_max_size_in_heap); } RUNTIME_FUNCTION(Runtime_DataViewInitialize) { HandleScope scope(isolate); DCHECK(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1); CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2); CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3); DCHECK(holder->GetInternalFieldCount() == v8::ArrayBufferView::kInternalFieldCount); for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { holder->SetInternalField(i, Smi::FromInt(0)); } size_t buffer_length = 0; size_t offset = 0; size_t length = 0; RUNTIME_ASSERT( TryNumberToSize(isolate, buffer->byte_length(), &buffer_length)); RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset)); RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length)); // TODO(jkummerow): When we have a "safe numerics" helper class, use it here. // Entire range [offset, offset + length] must be in bounds. RUNTIME_ASSERT(offset <= buffer_length); RUNTIME_ASSERT(offset + length <= buffer_length); // No overflow. RUNTIME_ASSERT(offset + length >= offset); holder->set_buffer(*buffer); holder->set_byte_offset(*byte_offset); holder->set_byte_length(*byte_length); holder->set_weak_next(buffer->weak_first_view()); buffer->set_weak_first_view(*holder); return isolate->heap()->undefined_value(); } inline static bool NeedToFlipBytes(bool is_little_endian) { #ifdef V8_TARGET_LITTLE_ENDIAN return !is_little_endian; #else return is_little_endian; #endif } template
inline void CopyBytes(uint8_t* target, uint8_t* source) { for (int i = 0; i < n; i++) { *(target++) = *(source++); } } template
inline void FlipBytes(uint8_t* target, uint8_t* source) { source = source + (n-1); for (int i = 0; i < n; i++) { *(target++) = *(source--); } } template
inline static bool DataViewGetValue( Isolate* isolate, Handle
data_view, Handle
byte_offset_obj, bool is_little_endian, T* result) { size_t byte_offset = 0; if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) { return false; } Handle
buffer(JSArrayBuffer::cast(data_view->buffer())); size_t data_view_byte_offset = NumberToSize(isolate, data_view->byte_offset()); size_t data_view_byte_length = NumberToSize(isolate, data_view->byte_length()); if (byte_offset + sizeof(T) > data_view_byte_length || byte_offset + sizeof(T) < byte_offset) { // overflow return false; } union Value { T data; uint8_t bytes[sizeof(T)]; }; Value value; size_t buffer_offset = data_view_byte_offset + byte_offset; DCHECK( NumberToSize(isolate, buffer->byte_length()) >= buffer_offset + sizeof(T)); uint8_t* source = static_cast
(buffer->backing_store()) + buffer_offset; if (NeedToFlipBytes(is_little_endian)) { FlipBytes
(value.bytes, source); } else { CopyBytes
(value.bytes, source); } *result = value.data; return true; } template
static bool DataViewSetValue( Isolate* isolate, Handle
data_view, Handle
byte_offset_obj, bool is_little_endian, T data) { size_t byte_offset = 0; if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) { return false; } Handle
buffer(JSArrayBuffer::cast(data_view->buffer())); size_t data_view_byte_offset = NumberToSize(isolate, data_view->byte_offset()); size_t data_view_byte_length = NumberToSize(isolate, data_view->byte_length()); if (byte_offset + sizeof(T) > data_view_byte_length || byte_offset + sizeof(T) < byte_offset) { // overflow return false; } union Value { T data; uint8_t bytes[sizeof(T)]; }; Value value; value.data = data; size_t buffer_offset = data_view_byte_offset + byte_offset; DCHECK( NumberToSize(isolate, buffer->byte_length()) >= buffer_offset + sizeof(T)); uint8_t* target = static_cast
(buffer->backing_store()) + buffer_offset; if (NeedToFlipBytes(is_little_endian)) { FlipBytes
(target, value.bytes); } else { CopyBytes
(target, value.bytes); } return true; } #define DATA_VIEW_GETTER(TypeName, Type, Converter) \ RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) { \ HandleScope scope(isolate); \ DCHECK(args.length() == 3); \ CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \ CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \ Type result; \ if (DataViewGetValue(isolate, holder, offset, is_little_endian, \ &result)) { \ return *isolate->factory()->Converter(result); \ } else { \ THROW_NEW_ERROR_RETURN_FAILURE( \ isolate, NewRangeError("invalid_data_view_accessor_offset", \ HandleVector
(NULL, 0))); \ } \ } DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint) DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt) DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint) DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt) DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint) DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt) DATA_VIEW_GETTER(Float32, float, NewNumber) DATA_VIEW_GETTER(Float64, double, NewNumber) #undef DATA_VIEW_GETTER template
static T DataViewConvertValue(double value); template <> int8_t DataViewConvertValue
(double value) { return static_cast
(DoubleToInt32(value)); } template <> int16_t DataViewConvertValue
(double value) { return static_cast
(DoubleToInt32(value)); } template <> int32_t DataViewConvertValue
(double value) { return DoubleToInt32(value); } template <> uint8_t DataViewConvertValue
(double value) { return static_cast
(DoubleToUint32(value)); } template <> uint16_t DataViewConvertValue
(double value) { return static_cast
(DoubleToUint32(value)); } template <> uint32_t DataViewConvertValue
(double value) { return DoubleToUint32(value); } template <> float DataViewConvertValue
(double value) { return static_cast
(value); } template <> double DataViewConvertValue
(double value) { return value; } #define DATA_VIEW_SETTER(TypeName, Type) \ RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) { \ HandleScope scope(isolate); \ DCHECK(args.length() == 4); \ CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \ CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); \ CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \ Type v = DataViewConvertValue
(value->Number()); \ if (DataViewSetValue(isolate, holder, offset, is_little_endian, v)) { \ return isolate->heap()->undefined_value(); \ } else { \ THROW_NEW_ERROR_RETURN_FAILURE( \ isolate, NewRangeError("invalid_data_view_accessor_offset", \ HandleVector
(NULL, 0))); \ } \ } DATA_VIEW_SETTER(Uint8, uint8_t) DATA_VIEW_SETTER(Int8, int8_t) DATA_VIEW_SETTER(Uint16, uint16_t) DATA_VIEW_SETTER(Int16, int16_t) DATA_VIEW_SETTER(Uint32, uint32_t) DATA_VIEW_SETTER(Int32, int32_t) DATA_VIEW_SETTER(Float32, float) DATA_VIEW_SETTER(Float64, double) #undef DATA_VIEW_SETTER RUNTIME_FUNCTION(Runtime_SetInitialize) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); Handle
table = isolate->factory()->NewOrderedHashSet(); holder->set_table(*table); return *holder; } RUNTIME_FUNCTION(Runtime_SetAdd) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); Handle
table(OrderedHashSet::cast(holder->table())); table = OrderedHashSet::Add(table, key); holder->set_table(*table); return *holder; } RUNTIME_FUNCTION(Runtime_SetHas) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); Handle
table(OrderedHashSet::cast(holder->table())); return isolate->heap()->ToBoolean(table->Contains(key)); } RUNTIME_FUNCTION(Runtime_SetDelete) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); Handle
table(OrderedHashSet::cast(holder->table())); bool was_present = false; table = OrderedHashSet::Remove(table, key, &was_present); holder->set_table(*table); return isolate->heap()->ToBoolean(was_present); } RUNTIME_FUNCTION(Runtime_SetClear) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); Handle
table(OrderedHashSet::cast(holder->table())); table = OrderedHashSet::Clear(table); holder->set_table(*table); return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_SetGetSize) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); Handle
table(OrderedHashSet::cast(holder->table())); return Smi::FromInt(table->NumberOfElements()); } RUNTIME_FUNCTION(Runtime_SetIteratorInitialize) { HandleScope scope(isolate); DCHECK(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0); CONVERT_ARG_HANDLE_CHECKED(JSSet, set, 1); CONVERT_SMI_ARG_CHECKED(kind, 2) RUNTIME_ASSERT(kind == JSSetIterator::kKindValues || kind == JSSetIterator::kKindEntries); Handle
table(OrderedHashSet::cast(set->table())); holder->set_table(*table); holder->set_index(Smi::FromInt(0)); holder->set_kind(Smi::FromInt(kind)); return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_SetIteratorNext) { SealHandleScope shs(isolate); DCHECK(args.length() == 2); CONVERT_ARG_CHECKED(JSSetIterator, holder, 0); CONVERT_ARG_CHECKED(JSArray, value_array, 1); return holder->Next(value_array); } RUNTIME_FUNCTION(Runtime_MapInitialize) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); Handle
table = isolate->factory()->NewOrderedHashMap(); holder->set_table(*table); return *holder; } RUNTIME_FUNCTION(Runtime_MapGet) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); Handle
table(OrderedHashMap::cast(holder->table())); Handle
lookup(table->Lookup(key), isolate); return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup; } RUNTIME_FUNCTION(Runtime_MapHas) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); Handle
table(OrderedHashMap::cast(holder->table())); Handle
lookup(table->Lookup(key), isolate); return isolate->heap()->ToBoolean(!lookup->IsTheHole()); } RUNTIME_FUNCTION(Runtime_MapDelete) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); Handle
table(OrderedHashMap::cast(holder->table())); bool was_present = false; Handle
new_table = OrderedHashMap::Remove(table, key, &was_present); holder->set_table(*new_table); return isolate->heap()->ToBoolean(was_present); } RUNTIME_FUNCTION(Runtime_MapClear) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); Handle
table(OrderedHashMap::cast(holder->table())); table = OrderedHashMap::Clear(table); holder->set_table(*table); return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_MapSet) { HandleScope scope(isolate); DCHECK(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); Handle
table(OrderedHashMap::cast(holder->table())); Handle
new_table = OrderedHashMap::Put(table, key, value); holder->set_table(*new_table); return *holder; } RUNTIME_FUNCTION(Runtime_MapGetSize) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); Handle
table(OrderedHashMap::cast(holder->table())); return Smi::FromInt(table->NumberOfElements()); } RUNTIME_FUNCTION(Runtime_MapIteratorInitialize) { HandleScope scope(isolate); DCHECK(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0); CONVERT_ARG_HANDLE_CHECKED(JSMap, map, 1); CONVERT_SMI_ARG_CHECKED(kind, 2) RUNTIME_ASSERT(kind == JSMapIterator::kKindKeys || kind == JSMapIterator::kKindValues || kind == JSMapIterator::kKindEntries); Handle
table(OrderedHashMap::cast(map->table())); holder->set_table(*table); holder->set_index(Smi::FromInt(0)); holder->set_kind(Smi::FromInt(kind)); return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0); Handle
table(ObjectHashTable::cast(holder->table())); Handle
entries = isolate->factory()->NewFixedArray(table->NumberOfElements() * 2); { DisallowHeapAllocation no_gc; int number_of_non_hole_elements = 0; for (int i = 0; i < table->Capacity(); i++) { Handle
key(table->KeyAt(i), isolate); if (table->IsKey(*key)) { entries->set(number_of_non_hole_elements++, *key); Object* value = table->Lookup(key); entries->set(number_of_non_hole_elements++, value); } } DCHECK_EQ(table->NumberOfElements() * 2, number_of_non_hole_elements); } return *isolate->factory()->NewJSArrayWithElements(entries); } RUNTIME_FUNCTION(Runtime_MapIteratorNext) { SealHandleScope shs(isolate); DCHECK(args.length() == 2); CONVERT_ARG_CHECKED(JSMapIterator, holder, 0); CONVERT_ARG_CHECKED(JSArray, value_array, 1); return holder->Next(value_array); } static Handle
WeakCollectionInitialize( Isolate* isolate, Handle
weak_collection) { DCHECK(weak_collection->map()->inobject_properties() == 0); Handle
table = ObjectHashTable::New(isolate, 0); weak_collection->set_table(*table); return weak_collection; } RUNTIME_FUNCTION(Runtime_WeakCollectionInitialize) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); return *WeakCollectionInitialize(isolate, weak_collection); } RUNTIME_FUNCTION(Runtime_WeakCollectionGet) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); Handle
table( ObjectHashTable::cast(weak_collection->table())); RUNTIME_ASSERT(table->IsKey(*key)); Handle
lookup(table->Lookup(key), isolate); return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup; } RUNTIME_FUNCTION(Runtime_WeakCollectionHas) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); Handle
table( ObjectHashTable::cast(weak_collection->table())); RUNTIME_ASSERT(table->IsKey(*key)); Handle
lookup(table->Lookup(key), isolate); return isolate->heap()->ToBoolean(!lookup->IsTheHole()); } RUNTIME_FUNCTION(Runtime_WeakCollectionDelete) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); Handle
table(ObjectHashTable::cast( weak_collection->table())); RUNTIME_ASSERT(table->IsKey(*key)); bool was_present = false; Handle
new_table = ObjectHashTable::Remove(table, key, &was_present); weak_collection->set_table(*new_table); return isolate->heap()->ToBoolean(was_present); } RUNTIME_FUNCTION(Runtime_WeakCollectionSet) { HandleScope scope(isolate); DCHECK(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); Handle
table( ObjectHashTable::cast(weak_collection->table())); RUNTIME_ASSERT(table->IsKey(*key)); Handle
new_table = ObjectHashTable::Put(table, key, value); weak_collection->set_table(*new_table); return *weak_collection; } RUNTIME_FUNCTION(Runtime_GetWeakSetValues) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0); Handle
table(ObjectHashTable::cast(holder->table())); Handle
values = isolate->factory()->NewFixedArray(table->NumberOfElements()); { DisallowHeapAllocation no_gc; int number_of_non_hole_elements = 0; for (int i = 0; i < table->Capacity(); i++) { Handle
key(table->KeyAt(i), isolate); if (table->IsKey(*key)) { values->set(number_of_non_hole_elements++, *key); } } DCHECK_EQ(table->NumberOfElements(), number_of_non_hole_elements); } return *isolate->factory()->NewJSArrayWithElements(values); } RUNTIME_FUNCTION(Runtime_GetPrototype) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); // We don't expect access checks to be needed on JSProxy objects. DCHECK(!obj->IsAccessCheckNeeded() || obj->IsJSObject()); PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER); do { if (PrototypeIterator::GetCurrent(iter)->IsAccessCheckNeeded() && !isolate->MayNamedAccess( Handle
::cast(PrototypeIterator::GetCurrent(iter)), isolate->factory()->proto_string(), v8::ACCESS_GET)) { isolate->ReportFailedAccessCheck( Handle
::cast(PrototypeIterator::GetCurrent(iter)), v8::ACCESS_GET); RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); return isolate->heap()->undefined_value(); } iter.AdvanceIgnoringProxies(); if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { return *PrototypeIterator::GetCurrent(iter); } } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)); return *PrototypeIterator::GetCurrent(iter); } static inline Handle
GetPrototypeSkipHiddenPrototypes( Isolate* isolate, Handle
receiver) { PrototypeIterator iter(isolate, receiver); while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { return PrototypeIterator::GetCurrent(iter); } iter.Advance(); } return PrototypeIterator::GetCurrent(iter); } RUNTIME_FUNCTION(Runtime_InternalSetPrototype) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); DCHECK(!obj->IsAccessCheckNeeded()); DCHECK(!obj->map()->is_observed()); Handle
result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, JSObject::SetPrototype(obj, prototype, false)); return *result; } RUNTIME_FUNCTION(Runtime_SetPrototype) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); if (obj->IsAccessCheckNeeded() && !isolate->MayNamedAccess( obj, isolate->factory()->proto_string(), v8::ACCESS_SET)) { isolate->ReportFailedAccessCheck(obj, v8::ACCESS_SET); RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); return isolate->heap()->undefined_value(); } if (obj->map()->is_observed()) { Handle
old_value = GetPrototypeSkipHiddenPrototypes(isolate, obj); Handle
result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, JSObject::SetPrototype(obj, prototype, true)); Handle
new_value = GetPrototypeSkipHiddenPrototypes(isolate, obj); if (!new_value->SameValue(*old_value)) { JSObject::EnqueueChangeRecord(obj, "setPrototype", isolate->factory()->proto_string(), old_value); } return *result; } Handle
result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, JSObject::SetPrototype(obj, prototype, true)); return *result; } RUNTIME_FUNCTION(Runtime_IsInPrototypeChain) { HandleScope shs(isolate); DCHECK(args.length() == 2); // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8). CONVERT_ARG_HANDLE_CHECKED(Object, O, 0); CONVERT_ARG_HANDLE_CHECKED(Object, V, 1); PrototypeIterator iter(isolate, V, PrototypeIterator::START_AT_RECEIVER); while (true) { iter.AdvanceIgnoringProxies(); if (iter.IsAtEnd()) return isolate->heap()->false_value(); if (iter.IsAtEnd(O)) return isolate->heap()->true_value(); } } // Enumerator used as indices into the array returned from GetOwnProperty enum PropertyDescriptorIndices { IS_ACCESSOR_INDEX, VALUE_INDEX, GETTER_INDEX, SETTER_INDEX, WRITABLE_INDEX, ENUMERABLE_INDEX, CONFIGURABLE_INDEX, DESCRIPTOR_SIZE }; MUST_USE_RESULT static MaybeHandle
GetOwnProperty(Isolate* isolate, Handle
obj, Handle
name) { Heap* heap = isolate->heap(); Factory* factory = isolate->factory(); PropertyAttributes attrs; uint32_t index = 0; Handle
value; MaybeHandle
maybe_accessors; // TODO(verwaest): Unify once indexed properties can be handled by the // LookupIterator. if (name->AsArrayIndex(&index)) { // Get attributes. Maybe
maybe = JSReceiver::GetOwnElementAttribute(obj, index); if (!maybe.has_value) return MaybeHandle
(); attrs = maybe.value; if (attrs == ABSENT) return factory->undefined_value(); // Get AccessorPair if present. maybe_accessors = JSObject::GetOwnElementAccessorPair(obj, index); // Get value if not an AccessorPair. if (maybe_accessors.is_null()) { ASSIGN_RETURN_ON_EXCEPTION(isolate, value, Runtime::GetElementOrCharAt(isolate, obj, index), Object); } } else { // Get attributes. LookupIterator it(obj, name, LookupIterator::HIDDEN); Maybe
maybe = JSObject::GetPropertyAttributes(&it); if (!maybe.has_value) return MaybeHandle
(); attrs = maybe.value; if (attrs == ABSENT) return factory->undefined_value(); // Get AccessorPair if present. if (it.state() == LookupIterator::ACCESSOR && it.GetAccessors()->IsAccessorPair()) { maybe_accessors = Handle
::cast(it.GetAccessors()); } // Get value if not an AccessorPair. if (maybe_accessors.is_null()) { ASSIGN_RETURN_ON_EXCEPTION( isolate, value, Object::GetProperty(&it), Object); } } DCHECK(!isolate->has_pending_exception()); Handle
elms = factory->NewFixedArray(DESCRIPTOR_SIZE); elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0)); elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0)); elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(!maybe_accessors.is_null())); Handle
accessors; if (maybe_accessors.ToHandle(&accessors)) { Handle
getter(accessors->GetComponent(ACCESSOR_GETTER), isolate); Handle
setter(accessors->GetComponent(ACCESSOR_SETTER), isolate); elms->set(GETTER_INDEX, *getter); elms->set(SETTER_INDEX, *setter); } else { elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0)); elms->set(VALUE_INDEX, *value); } return factory->NewJSArrayWithElements(elms); } // Returns an array with the property description: // if args[1] is not a property on args[0] // returns undefined // if args[1] is a data property on args[0] // [false, value, Writeable, Enumerable, Configurable] // if args[1] is an accessor on args[0] // [true, GetFunction, SetFunction, Enumerable, Configurable] RUNTIME_FUNCTION(Runtime_GetOwnProperty) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); Handle
result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, GetOwnProperty(isolate, obj, name)); return *result; } RUNTIME_FUNCTION(Runtime_PreventExtensions) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); Handle
result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, JSObject::PreventExtensions(obj)); return *result; } RUNTIME_FUNCTION(Runtime_ToMethod) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1); Handle
clone = JSFunction::CloneClosure(fun); Handle
home_object_symbol(isolate->heap()->home_object_symbol()); JSObject::SetOwnPropertyIgnoreAttributes(clone, home_object_symbol, home_object, DONT_ENUM).Assert(); return *clone; } RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) { DCHECK(args.length() == 0); return isolate->heap()->home_object_symbol(); } RUNTIME_FUNCTION(Runtime_LoadFromSuper) { HandleScope scope(isolate); DCHECK(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 0); CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1); CONVERT_ARG_HANDLE_CHECKED(Name, name, 2); if (home_object->IsAccessCheckNeeded() && !isolate->MayNamedAccess(home_object, name, v8::ACCESS_GET)) { isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_GET); RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); } PrototypeIterator iter(isolate, home_object); Handle
proto = PrototypeIterator::GetCurrent(iter); if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value(); LookupIterator it(receiver, name, Handle
::cast(proto)); Handle
result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it)); return *result; } RUNTIME_FUNCTION(Runtime_IsExtensible) { SealHandleScope shs(isolate); DCHECK(args.length() == 1); CONVERT_ARG_CHECKED(JSObject, obj, 0); if (obj->IsJSGlobalProxy()) { PrototypeIterator iter(isolate, obj); if (iter.IsAtEnd()) return isolate->heap()->false_value(); DCHECK(iter.GetCurrent()->IsJSGlobalObject()); obj = JSObject::cast(iter.GetCurrent()); } return isolate->heap()->ToBoolean(obj->map()->is_extensible()); } RUNTIME_FUNCTION(Runtime_RegExpCompile) { HandleScope scope(isolate); DCHECK(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0); CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); CONVERT_ARG_HANDLE_CHECKED(String, flags, 2); Handle
result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, RegExpImpl::Compile(re, pattern, flags)); return *result; } RUNTIME_FUNCTION(Runtime_CreateApiFunction) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0); CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); return *isolate->factory()->CreateApiFunction(data, prototype); } RUNTIME_FUNCTION(Runtime_IsTemplate) { SealHandleScope shs(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(Object, arg, 0); bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo(); return isolate->heap()->ToBoolean(result); } RUNTIME_FUNCTION(Runtime_GetTemplateField) { SealHandleScope shs(isolate); DCHECK(args.length() == 2); CONVERT_ARG_CHECKED(HeapObject, templ, 0); CONVERT_SMI_ARG_CHECKED(index, 1); int offset = index * kPointerSize + HeapObject::kHeaderSize; InstanceType type = templ->map()->instance_type(); RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE || type == OBJECT_TEMPLATE_INFO_TYPE); RUNTIME_ASSERT(offset > 0); if (type == FUNCTION_TEMPLATE_INFO_TYPE) { RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize); } else { RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize); } return *HeapObject::RawField(templ, offset); } RUNTIME_FUNCTION(Runtime_DisableAccessChecks) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0); Handle
old_map(object->map()); bool needs_access_checks = old_map->is_access_check_needed(); if (needs_access_checks) { // Copy map so it won't interfere constructor's initial map. Handle
new_map = Map::Copy(old_map); new_map->set_is_access_check_needed(false); JSObject::MigrateToMap(Handle
::cast(object), new_map); } return isolate->heap()->ToBoolean(needs_access_checks); } RUNTIME_FUNCTION(Runtime_EnableAccessChecks) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); Handle
old_map(object->map()); RUNTIME_ASSERT(!old_map->is_access_check_needed()); // Copy map so it won't interfere constructor's initial map. Handle
new_map = Map::Copy(old_map); new_map->set_is_access_check_needed(true); JSObject::MigrateToMap(object, new_map); return isolate->heap()->undefined_value(); } static Object* ThrowRedeclarationError(Isolate* isolate, Handle
name) { HandleScope scope(isolate); Handle
args[1] = { name }; THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError("var_redeclaration", HandleVector(args, 1))); } // May throw a RedeclarationError. static Object* DeclareGlobals(Isolate* isolate, Handle
global, Handle
name, Handle
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
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; } } // Define or redefine own property. RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes( global, name, value, attr)); return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_DeclareGlobals) { HandleScope scope(isolate); DCHECK(args.length() == 3); Handle
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