/deps/v8/src/runtime.cc
C++ | 14385 lines | 10694 code | 2137 blank | 1554 comment | 2149 complexity | 6eb8f07386c56851f7b612a3c3f30c3e MD5 | raw file
Possible License(s): 0BSD, BSD-3-Clause, MPL-2.0-no-copyleft-exception, GPL-2.0, ISC, Apache-2.0, MIT, AGPL-3.0
Large files files are truncated, but you can click here to view the full file
- // Copyright 2012 the V8 project authors. All rights reserved.
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- //
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following
- // disclaimer in the documentation and/or other materials provided
- // with the distribution.
- // * Neither the name of Google Inc. nor the names of its
- // contributors may be used to endorse or promote products derived
- // from this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- #include <stdlib.h>
- #include <limits>
- #include "v8.h"
- #include "accessors.h"
- #include "api.h"
- #include "arguments.h"
- #include "bootstrapper.h"
- #include "codegen.h"
- #include "compilation-cache.h"
- #include "compiler.h"
- #include "cpu.h"
- #include "cpu-profiler.h"
- #include "dateparser-inl.h"
- #include "debug.h"
- #include "deoptimizer.h"
- #include "date.h"
- #include "execution.h"
- #include "full-codegen.h"
- #include "global-handles.h"
- #include "isolate-inl.h"
- #include "jsregexp.h"
- #include "jsregexp-inl.h"
- #include "json-parser.h"
- #include "json-stringifier.h"
- #include "liveedit.h"
- #include "misc-intrinsics.h"
- #include "parser.h"
- #include "platform.h"
- #include "runtime-profiler.h"
- #include "runtime.h"
- #include "scopeinfo.h"
- #include "smart-pointers.h"
- #include "string-search.h"
- #include "stub-cache.h"
- #include "uri.h"
- #include "v8conversions.h"
- #include "v8threads.h"
- #include "vm-state-inl.h"
- #ifdef V8_I18N_SUPPORT
- #include "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/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();
- // 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<Type> name = args.at<Type>(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 StrictModeFlag
- // and store it in a StrictModeFlag variable with the given name.
- #define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
- RUNTIME_ASSERT(args[index]->IsSmi()); \
- RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
- args.smi_at(index) == kNonStrictMode); \
- StrictModeFlag name = \
- static_cast<StrictModeFlag>(args.smi_at(index));
- // Assert that the given argument has a valid value for a LanguageMode
- // and store it in a LanguageMode variable with the given name.
- #define CONVERT_LANGUAGE_MODE_ARG(name, index) \
- ASSERT(args[index]->IsSmi()); \
- ASSERT(args.smi_at(index) == CLASSIC_MODE || \
- args.smi_at(index) == STRICT_MODE || \
- args.smi_at(index) == EXTENDED_MODE); \
- LanguageMode name = \
- static_cast<LanguageMode>(args.smi_at(index));
- 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.
- // ASSERT to make sure that the if condition after the loop is false.
- ASSERT(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);
- }
- }
- ASSERT(index == number_of_string_keys);
- }
- *is_result_from_cache = true;
- return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
- }
- *is_result_from_cache = false;
- return isolate->factory()->CopyMap(
- Handle<Map>(context->object_function()->initial_map()),
- number_of_properties);
- }
- static Handle<Object> CreateLiteralBoilerplate(
- Isolate* isolate,
- Handle<FixedArray> literals,
- Handle<FixedArray> constant_properties);
- static Handle<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);
- Handle<JSObject> boilerplate =
- isolate->factory()->NewJSObjectFromMap(
- map, isolate->heap()->GetPretenureMode());
- // 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();
- if (should_transform || has_function_literal) {
- // Normalize the properties of object to avoid n^2 behavior
- // when extending the object multiple properties. Indicate the number of
- // properties to be added.
- 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);
- value = CreateLiteralBoilerplate(isolate, literals, array);
- if (value.is_null()) return value;
- }
- Handle<Object> result;
- uint32_t element_index = 0;
- JSReceiver::StoreMode mode = value->IsJSObject()
- ? JSReceiver::FORCE_FIELD
- : JSReceiver::ALLOW_AS_CONSTANT;
- if (key->IsInternalizedString()) {
- if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
- // Array index as string (uint32).
- result = JSObject::SetOwnElement(
- boilerplate, element_index, value, kNonStrictMode);
- } else {
- Handle<String> name(String::cast(*key));
- ASSERT(!name->AsArrayIndex(&element_index));
- result = JSObject::SetLocalPropertyIgnoreAttributes(
- boilerplate, name, value, NONE,
- Object::OPTIMAL_REPRESENTATION, mode);
- }
- } else if (key->ToArrayIndex(&element_index)) {
- // Array index (uint32).
- result = JSObject::SetOwnElement(
- boilerplate, element_index, value, kNonStrictMode);
- } else {
- // Non-uint32 number.
- ASSERT(key->IsNumber());
- double num = key->Number();
- char arr[100];
- Vector<char> buffer(arr, ARRAY_SIZE(arr));
- const char* str = DoubleToCString(num, buffer);
- Handle<String> name =
- isolate->factory()->NewStringFromAscii(CStrVector(str));
- result = JSObject::SetLocalPropertyIgnoreAttributes(
- boilerplate, name, value, NONE,
- Object::OPTIMAL_REPRESENTATION, mode);
- }
- // 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.
- if (result.is_null()) return result;
- }
- // 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::TransformToFastProperties(
- boilerplate, boilerplate->map()->unused_property_fields());
- }
- return boilerplate;
- }
- MaybeObject* TransitionElements(Handle<Object> object,
- ElementsKind to_kind,
- Isolate* isolate) {
- HandleScope scope(isolate);
- if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
- ElementsKind from_kind =
- Handle<JSObject>::cast(object)->map()->elements_kind();
- if (Map::IsValidElementsTransition(from_kind, to_kind)) {
- Handle<Object> result = JSObject::TransitionElementsKind(
- Handle<JSObject>::cast(object), to_kind);
- if (result.is_null()) return isolate->ThrowIllegalOperation();
- return *result;
- }
- return isolate->ThrowIllegalOperation();
- }
- static const int kSmiLiteralMinimumLength = 1024;
- Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
- Isolate* isolate,
- Handle<FixedArray> literals,
- Handle<FixedArray> elements) {
- // Create the JSArray.
- Handle<JSFunction> constructor(
- JSFunction::NativeContextFromLiterals(*literals)->array_function());
- Handle<JSArray> object = Handle<JSArray>::cast(
- isolate->factory()->NewJSObject(
- constructor, isolate->heap()->GetPretenureMode()));
- ElementsKind constant_elements_kind =
- static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
- Handle<FixedArrayBase> constant_elements_values(
- FixedArrayBase::cast(elements->get(1)));
- ASSERT(IsFastElementsKind(constant_elements_kind));
- Context* native_context = isolate->context()->native_context();
- Object* maybe_maps_array = native_context->js_array_maps();
- ASSERT(!maybe_maps_array->IsUndefined());
- Object* maybe_map = FixedArray::cast(maybe_maps_array)->get(
- constant_elements_kind);
- ASSERT(maybe_map->IsMap());
- object->set_map(Map::cast(maybe_map));
- Handle<FixedArrayBase> copied_elements_values;
- if (IsFastDoubleElementsKind(constant_elements_kind)) {
- ASSERT(FLAG_smi_only_arrays);
- copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
- Handle<FixedDoubleArray>::cast(constant_elements_values));
- } else {
- ASSERT(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++) {
- ASSERT(!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++) {
- Object* current = fixed_array_values->get(i);
- if (current->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 =
- CreateLiteralBoilerplate(isolate, literals, fa);
- if (result.is_null()) return result;
- fixed_array_values_copy->set(i, *result);
- }
- }
- }
- }
- object->set_elements(*copied_elements_values);
- object->set_length(Smi::FromInt(copied_elements_values->length()));
- // Ensure that the boilerplate object has FAST_*_ELEMENTS, unless the flag is
- // on or the object is larger than the threshold.
- if (!FLAG_smi_only_arrays &&
- constant_elements_values->length() < kSmiLiteralMinimumLength) {
- ElementsKind elements_kind = object->GetElementsKind();
- if (!IsFastObjectElementsKind(elements_kind)) {
- if (IsFastHoleyElementsKind(elements_kind)) {
- CHECK(!TransitionElements(object, FAST_HOLEY_ELEMENTS,
- isolate)->IsFailure());
- } else {
- CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
- }
- }
- }
- object->ValidateElements();
- return object;
- }
- static Handle<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 Handle<Object>::null();
- }
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
- HandleScope scope(isolate);
- ASSERT(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;
- // Check if boilerplate exists. If not, create it first.
- Handle<Object> boilerplate(literals->get(literals_index), isolate);
- if (*boilerplate == isolate->heap()->undefined_value()) {
- boilerplate = CreateObjectLiteralBoilerplate(isolate,
- literals,
- constant_properties,
- should_have_fast_elements,
- has_function_literal);
- RETURN_IF_EMPTY_HANDLE(isolate, boilerplate);
- // Update the functions literal and return the boilerplate.
- literals->set(literals_index, *boilerplate);
- }
- return JSObject::cast(*boilerplate)->DeepCopy(isolate);
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
- HandleScope scope(isolate);
- ASSERT(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;
- // Check if boilerplate exists. If not, create it first.
- Handle<Object> boilerplate(literals->get(literals_index), isolate);
- if (*boilerplate == isolate->heap()->undefined_value()) {
- boilerplate = CreateObjectLiteralBoilerplate(isolate,
- literals,
- constant_properties,
- should_have_fast_elements,
- has_function_literal);
- RETURN_IF_EMPTY_HANDLE(isolate, boilerplate);
- // Update the functions literal and return the boilerplate.
- literals->set(literals_index, *boilerplate);
- }
- return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
- }
- static Handle<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()) {
- ASSERT(*elements != isolate->heap()->empty_fixed_array());
- Handle<Object> boilerplate =
- Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
- if (boilerplate.is_null()) return site;
- site = isolate->factory()->NewAllocationSite();
- site->set_transition_info(*boilerplate);
- literals->set(literals_index, *site);
- } else {
- site = Handle<AllocationSite>::cast(literal_site);
- }
- return site;
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
- HandleScope scope(isolate);
- ASSERT(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<AllocationSite> site = GetLiteralAllocationSite(isolate, literals,
- literals_index, elements);
- RETURN_IF_EMPTY_HANDLE(isolate, site);
- JSObject* boilerplate = JSObject::cast(site->transition_info());
- return boilerplate->DeepCopy(isolate);
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
- HandleScope scope(isolate);
- ASSERT(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<AllocationSite> site = GetLiteralAllocationSite(isolate, literals,
- literals_index, elements);
- RETURN_IF_EMPTY_HANDLE(isolate, site);
- JSObject* boilerplate = JSObject::cast(site->transition_info());
- if (boilerplate->elements()->map() ==
- isolate->heap()->fixed_cow_array_map()) {
- isolate->counters()->cow_arrays_created_runtime()->Increment();
- }
- AllocationSiteMode mode = AllocationSite::GetMode(
- boilerplate->GetElementsKind());
- if (mode == TRACK_ALLOCATION_SITE) {
- return isolate->heap()->CopyJSObjectWithAllocationSite(
- boilerplate, *site);
- }
- return isolate->heap()->CopyJSObject(boilerplate);
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 1);
- Handle<Object> name(args[0], isolate);
- RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
- Symbol* symbol;
- MaybeObject* maybe = isolate->heap()->AllocateSymbol();
- if (!maybe->To(&symbol)) return maybe;
- if (name->IsString()) symbol->set_name(*name);
- return symbol;
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolName) {
- SealHandleScope shs(isolate);
- ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(Symbol, symbol, 0);
- return symbol->name();
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
- SealHandleScope shs(isolate);
- ASSERT(args.length() == 2);
- CONVERT_ARG_CHECKED(JSReceiver, handler, 0);
- Object* prototype = args[1];
- Object* used_prototype =
- prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
- return isolate->heap()->AllocateJSProxy(handler, used_prototype);
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
- SealHandleScope shs(isolate);
- ASSERT(args.length() == 4);
- CONVERT_ARG_CHECKED(JSReceiver, handler, 0);
- Object* call_trap = args[1];
- RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy());
- CONVERT_ARG_CHECKED(JSFunction, construct_trap, 2);
- Object* prototype = args[3];
- Object* used_prototype =
- prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
- return isolate->heap()->AllocateJSFunctionProxy(
- handler, call_trap, construct_trap, used_prototype);
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
- SealHandleScope shs(isolate);
- ASSERT(args.length() == 1);
- Object* obj = args[0];
- return isolate->heap()->ToBoolean(obj->IsJSProxy());
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
- SealHandleScope shs(isolate);
- ASSERT(args.length() == 1);
- Object* obj = args[0];
- return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
- SealHandleScope shs(isolate);
- ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
- return proxy->handler();
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
- SealHandleScope shs(isolate);
- ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
- return proxy->call_trap();
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
- SealHandleScope shs(isolate);
- ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
- return proxy->construct_trap();
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
- SealHandleScope shs(isolate);
- ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
- proxy->Fix();
- return isolate->heap()->undefined_value();
- }
- void Runtime::FreeArrayBuffer(Isolate* isolate,
- JSArrayBuffer* phantom_array_buffer) {
- if (phantom_array_buffer->is_external()) return;
- size_t allocated_length = NumberToSize(
- isolate, phantom_array_buffer->byte_length());
- isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
- -static_cast<intptr_t>(allocated_length));
- CHECK(V8::ArrayBufferAllocator() != NULL);
- V8::ArrayBufferAllocator()->Free(
- phantom_array_buffer->backing_store(),
- allocated_length);
- }
- void Runtime::SetupArrayBuffer(Isolate* isolate,
- Handle<JSArrayBuffer> array_buffer,
- bool is_external,
- void* data,
- size_t allocated_length) {
- ASSERT(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<Object> 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<JSArrayBuffer> 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);
- isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length);
- return true;
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 2);
- CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
- CONVERT_ARG_HANDLE_CHECKED(Object, byteLength, 1);
- size_t allocated_length;
- if (byteLength->IsSmi()) {
- allocated_length = Smi::cast(*byteLength)->value();
- } else {
- ASSERT(byteLength->IsHeapNumber());
- double value = HeapNumber::cast(*byteLength)->value();
- ASSERT(value >= 0);
- if (value > std::numeric_limits<size_t>::max()) {
- return isolate->Throw(
- *isolate->factory()->NewRangeError("invalid_array_buffer_length",
- HandleVector<Object>(NULL, 0)));
- }
- allocated_length = static_cast<size_t>(value);
- }
- if (!Runtime::SetupArrayBufferAllocatingData(isolate,
- holder, allocated_length)) {
- return isolate->Throw(*isolate->factory()->
- NewRangeError("invalid_array_buffer_length",
- HandleVector<Object>(NULL, 0)));
- }
- return *holder;
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetByteLength) {
- SealHandleScope shs(isolate);
- ASSERT(args.length() == 1);
- CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
- return holder->byte_length();
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 3);
- CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
- CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
- CONVERT_DOUBLE_ARG_CHECKED(first, 2);
- size_t start = static_cast<size_t>(first);
- size_t target_length = NumberToSize(isolate, target->byte_length());
- if (target_length == 0) return isolate->heap()->undefined_value();
- ASSERT(NumberToSize(isolate, source->byte_length()) - target_length >= start);
- uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
- uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
- CopyBytes(target_data, source_data + start, target_length);
- return isolate->heap()->undefined_value();
- }
- enum TypedArrayId {
- // arrayIds below should be synchromized with typedarray.js natives.
- ARRAY_ID_UINT8 = 1,
- ARRAY_ID_INT8 = 2,
- ARRAY_ID_UINT16 = 3,
- ARRAY_ID_INT16 = 4,
- ARRAY_ID_UINT32 = 5,
- ARRAY_ID_INT32 = 6,
- ARRAY_ID_FLOAT32 = 7,
- ARRAY_ID_FLOAT64 = 8,
- ARRAY_ID_UINT8C = 9
- };
- static void ArrayIdToTypeAndSize(
- int arrayId, ExternalArrayType* array_type, size_t* element_size) {
- switch (arrayId) {
- case ARRAY_ID_UINT8:
- *array_type = kExternalUnsignedByteArray;
- *element_size = 1;
- break;
- case ARRAY_ID_INT8:
- *array_type = kExternalByteArray;
- *element_size = 1;
- break;
- case ARRAY_ID_UINT16:
- *array_type = kExternalUnsignedShortArray;
- *element_size = 2;
- break;
- case ARRAY_ID_INT16:
- *array_type = kExternalShortArray;
- *element_size = 2;
- break;
- case ARRAY_ID_UINT32:
- *array_type = kExternalUnsignedIntArray;
- *element_size = 4;
- break;
- case ARRAY_ID_INT32:
- *array_type = kExternalIntArray;
- *element_size = 4;
- break;
- case ARRAY_ID_FLOAT32:
- *array_type = kExternalFloatArray;
- *element_size = 4;
- break;
- case ARRAY_ID_FLOAT64:
- *array_type = kExternalDoubleArray;
- *element_size = 8;
- break;
- case ARRAY_ID_UINT8C:
- *array_type = kExternalPixelArray;
- *element_size = 1;
- break;
- default:
- UNREACHABLE();
- }
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 5);
- CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
- CONVERT_SMI_ARG_CHECKED(arrayId, 1);
- CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2);
- CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3);
- CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
- ASSERT(holder->GetInternalFieldCount() ==
- v8::ArrayBufferView::kInternalFieldCount);
- for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
- holder->SetInternalField(i, Smi::FromInt(0));
- }
- ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
- size_t element_size = 1; // Bogus initialization.
- ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
- holder->set_buffer(*buffer);
- holder->set_byte_offset(*byte_offset_object);
- holder->set_byte_length(*byte_length_object);
- size_t byte_offset = NumberToSize(isolate, *byte_offset_object);
- size_t byte_length = NumberToSize(isolate, *byte_length_object);
- ASSERT(byte_length % element_size == 0);
- size_t length = byte_length / element_size;
- Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
- holder->set_length(*length_obj);
- holder->set_weak_next(buffer->weak_first_view());
- buffer->set_weak_first_view(*holder);
- Handle<ExternalArray> elements =
- isolate->factory()->NewExternalArray(
- static_cast<int>(length), array_type,
- static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
- 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(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 4);
- CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
- CONVERT_SMI_ARG_CHECKED(arrayId, 1);
- CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
- CONVERT_ARG_HANDLE_CHECKED(Object, length_obj, 3);
- ASSERT(holder->GetInternalFieldCount() ==
- v8::ArrayBufferView::kInternalFieldCount);
- for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
- holder->SetInternalField(i, Smi::FromInt(0));
- }
- ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
- size_t element_size = 1; // Bogus initialization.
- ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
- Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
- size_t length = NumberToSize(isolate, *length_obj);
- size_t byte_length = length * element_size;
- if (byte_length < length) { // Overflow
- return isolate->Throw(*isolate->factory()->
- NewRangeError("invalid_array_buffer_length",
- HandleVector<Object>(NULL, 0)));
- }
- // We assume that the caller of this function will initialize holder
- // with the loop
- // for(i = 0; i < length; i++) { holder[i] = source[i]; }
- // 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, we do not know (the indexing operation might throw).
- // Hence we require zero initialization unless our source is a typed array.
- bool should_zero_initialize = !source->IsJSTypedArray();
- if (!Runtime::SetupArrayBufferAllocatingData(
- isolate, buffer, byte_length, should_zero_initialize)) {
- return isolate->Throw(*isolate->factory()->
- NewRangeError("invalid_array_buffer_length",
- HandleVector<Object>(NULL, 0)));
- }
- holder->set_buffer(*buffer);
- holder->set_byte_offset(Smi::FromInt(0));
- Handle<Object> 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<ExternalArray> elements =
- isolate->factory()->NewExternalArray(
- static_cast<int>(length), array_type,
- static_cast<uint8_t*>(buffer->backing_store()));
- holder->set_elements(*elements);
- if (source->IsJSTypedArray()) {
- Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
- if (typed_array->type() == holder->type()) {
- uint8_t* backing_store =
- static_cast<uint8_t*>(
- JSArrayBuffer::cast(typed_array->buffer())->backing_store());
- size_t source_byte_offset =
- NumberToSize(isolate, typed_array->byte_offset());
- OS::MemCopy(
- buffer->backing_store(),
- backing_store + source_byte_offset,
- byte_length);
- return *isolate->factory()->true_value();
- } else {
- return *isolate->factory()->false_value();
- }
- }
- return *isolate->factory()->false_value();
- }
- #define TYPED_ARRAY_GETTER(getter, accessor) \
- RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \
- HandleScope scope(isolate); \
- ASSERT(args.length() == 1); \
- CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0); \
- if (!holder->IsJSTypedArray()) \
- return isolate->Throw(*isolate->factory()->NewTypeError( \
- "not_typed_array", HandleVector<Object>(NULL, 0))); \
- Handle<JSTypedArray> typed_array(JSTypedArray::cast(*holder)); \
- return typed_array->accessor(); \
- }
- TYPED_ARRAY_GETTER(Buffer, buffer)
- TYPED_ARRAY_GETTER(ByteLength, byte_length)
- TYPED_ARRAY_GETTER(ByteOffset, byte_offset)
- TYPED_ARRAY_GETTER(Length, length)
- #undef TYPED_ARRAY_GETTER
- // 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(MaybeObject*, Runtime_TypedArraySetFastCases) {
- HandleScope scope(isolate);
- CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0);
- CONVERT_ARG_HANDLE_CHECKED(Object, source_obj, 1);
- CONVERT_ARG_HANDLE_CHECKED(Object, offset_obj, 2);
- if (!target_obj->IsJSTypedArray())
- return isolate->Throw(*isolate->factory()->NewTypeError(
- "not_typed_array", HandleVector<Object>(NULL, 0)));
- if (!source_obj->IsJSTypedArray())
- return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
- Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
- Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
- size_t offset = NumberToSize(isolate, *offset_obj);
- 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
- return isolate->Throw(*isolate->factory()->NewRangeError(
- "typed_array_set_source_too_large", HandleVector<Object>(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<uint8_t*>(
- JSArrayBuffer::cast(target->buffer())->backing_store()) + target_offset;
- uint8_t* source_base =
- static_cast<uint8_t*>(
- JSArrayBuffer::cast(source->buffer())->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
- ASSERT(
- JSArrayBuffer::cast(target->buffer())->backing_store() ==
- JSArrayBuffer::cast(source->buffer())->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(MaybeObject*, Runtime_DataViewInitialize) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 4);
- CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
- CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
- CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset, 2);
- CONVERT_ARG_HANDLE_CHECKED(Object, byte_length, 3);
- ASSERT(holder->GetInternalFieldCount() ==
- v8::ArrayBufferView::kInternalFieldCount);
- for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
- holder->SetInternalField(i, Smi::FromInt(0));
- }
- holder->set_buffer(*buffer);
- ASSERT(byte_offset->IsNumber());
- ASSERT(
- NumberToSize(isolate, buffer->byte_length()) >=
- NumberToSize(isolate, *byte_offset)
- + NumberToSize(isolate, *byte_length));
- holder->set_byte_offset(*byte_offset);
- ASSERT(byte_length->IsNumber());
- 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();
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetBuffer) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
- return data_view->buffer();
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteOffset) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
- return data_view->byte_offset();
- }
- RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteLength) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
- return data_view->byte_length();
- }
- inline static bool NeedToFlipBytes(bool is_little_endian) {
- #ifdef V8_TARGET_LITTLE_ENDIAN
- return !is_little_endian;
- #else
- return is_little_endian;
- #endif
- }
- template<int n>
- inline void CopyBytes(uint8_t* target, uint8_t* source) {
- for (int i = 0; i < n; i++) {
- *(target++) = *(source++);
- }
- }
- template<int n>
- inline void FlipBytes(uint8_t* target, uint8_t* source) {
- source = source + (n-1);
- for (int i = 0; i < n; i++) {
- *(target++) = *(source--);
- }
- }
- template<typename T>
- inline static bool DataViewGetValue(
- Isolate* isolate,
- Handle<JSDataView> data_view,
- Handle<Object> byte_offset_obj,
- bool is_little_endian,
- T* result) {
- size_t byte_offset = NumberToSize(isolate, *byte_offset_obj);
- Handle<JSArrayBuffer> 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;
- ASSERT(
- NumberToSize(isolate, buffer->byte_length())
- >= buffer_offset + sizeof(T));
- uint8_t* source =
- static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
- if (NeedToFlipBytes(is_little_endian)) {
- FlipBytes<sizeof(T)>(value.bytes, source);
- } else {
- CopyBytes<sizeof(T)>(value.bytes, source);
- }
- *result = value.data;
- return true;
- }
- template<typename T>
- static bool DataViewSetValue(
- Isolate* isolate,
- Handle<JSDataView> data_view,
- Handle<Object> byte_offset_obj,
- bool is_little_endian,
- T data) {
- size_t byte_offset = NumberToSize(isolate, *byte_offset_obj);
- Handle<JSArrayBuffer> 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;
- ASSERT(
- NumberToSize(isolate, buffer->byte_length())
- >= buffer_offset + sizeof(T));
- uint8_t* target =
- static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
- if (NeedToFlipBytes(is_little_endian)) {
- FlipBytes<sizeof(T)>(target, value.bytes);
- } else {
- CopyBytes<sizeof(T)>(target, value.bytes);
- }
- return true;
- }
- #define DATA_VIEW_GETTER(TypeName, Type, Converter) \
- RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGet##TypeName) { \
- HandleScope scope(isolate); \
- ASSERT(args.length() == 3); \
- CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
- CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \
- CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \
- Type result; \
- if (DataViewGetValue( \
- isolate, holder, offset, is_little_endian, &result)) { \
- return isolate->heap()->Converter(result); \
- } else { \
- return isolate->Throw(*isolate->factory()->NewRangeError( \
- "invalid_data_view_accessor_offset", \
- HandleVector<Object>(NULL, 0))); \
- } \
- }
- DATA_VIEW_GETTER(Uint8, uint8_t, NumberFromUint32)
- DATA_VIEW_GETTER(Int8, int8_t, NumberFromInt32)
- DATA_VIEW_GETTER(Uint16, uint16_t, NumberFromUint32)
- DATA_VIEW_GETTER(Int16, int16_t, NumberFromInt32)
- DATA_VIEW_GETTER(Uint32, uint32_t, NumberFromUint32)
- DATA_VIEW_GETTER(Int32, int32_t, NumberFromInt32)
- DATA_VIEW_GETTER(Float32, float, NumberFromDouble)
- DATA_VIEW_GETTER(Float64, double, NumberFromDouble)
- #undef DATA_VIEW_GETTER
- template <typename T>
- static T DataViewConvertValue(double value);
- template <>
- int8_t DataViewConvertValue<int8_t>(double value) {
- return static_cast<int8_t>(DoubleToInt32(value));
- }
- template <>
- int16_t DataViewConvertValue<int16_t>(double value) {
- return static_cast<int16_t>(DoubleToInt32(value));
- }
- template <>
- int32_t DataViewConvertValue<int32_t>(double value) {
- return DoubleToInt32(value);
- }
- template <>
- uint8_t DataViewConvertValue<uint8_t>(double value) {
- return static_cast<uint8_t>(DoubleToUint32(value));
- }
- template <>
- uint16_t DataViewConvertValue<uint16_t>(double value) {
- return static_cast<uint16_t>(DoubleToUint32(value));
- }
- template <>
- uint32_t DataViewConvertValue<uint32_t>(double value) {
- return DoubleToUint32(value);
- }
- template <>
- float DataViewConvertValue<float>(double value) {
- return static_cast<float>(value);
- }
- template <>
- double DataViewConvertValue<double>(double value) {
- return value;
- }
- #define DATA_VIEW_SETTER(TypeName, Type) \
- RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewSet##TypeName) { \
- HandleScope scope(isolate); \
- ASSERT(args.length() == 4); \
- CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
- CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \
- CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); \
- CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \
- Type v = DataViewConvertValue<Type>(value->Number()); \
- if (DataViewSetValue( \
- isolate, holder, offset, is_little_endian, v)) { \
- return isolate->heap()->undefined_value(); \
- } else { \
- return isolate->Throw(*isolate->factory()->NewRangeError( \
- …
Large files files are truncated, but you can click here to view the full file