HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Android 10
|
10.0.0_r6
下载
查看原文件
收藏
根目录
external
v8
src
objects.cc
// Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/objects.h" #include
#include
#include
#include
#include
#include "src/objects-inl.h" #include "src/accessors.h" #include "src/allocation-site-scopes.h" #include "src/api-arguments-inl.h" #include "src/api-natives.h" #include "src/api.h" #include "src/arguments.h" #include "src/ast/ast.h" #include "src/ast/scopes.h" #include "src/base/bits.h" #include "src/base/utils/random-number-generator.h" #include "src/bootstrapper.h" #include "src/builtins/builtins.h" #include "src/code-stubs.h" #include "src/compiler.h" #include "src/counters-inl.h" #include "src/counters.h" #include "src/date.h" #include "src/debug/debug.h" #include "src/deoptimizer.h" #include "src/elements.h" #include "src/execution.h" #include "src/field-index-inl.h" #include "src/field-index.h" #include "src/field-type.h" #include "src/frames-inl.h" #include "src/globals.h" #include "src/ic/ic.h" #include "src/identity-map.h" #include "src/interpreter/bytecode-array-iterator.h" #include "src/interpreter/bytecode-decoder.h" #include "src/interpreter/interpreter.h" #include "src/isolate-inl.h" #include "src/keys.h" #include "src/log.h" #include "src/lookup-inl.h" #include "src/macro-assembler.h" #include "src/map-updater.h" #include "src/messages.h" #include "src/objects-body-descriptors-inl.h" #include "src/objects/api-callbacks.h" #include "src/objects/arguments-inl.h" #include "src/objects/bigint.h" #include "src/objects/code-inl.h" #include "src/objects/compilation-cache-inl.h" #include "src/objects/debug-objects-inl.h" #include "src/objects/frame-array-inl.h" #include "src/objects/hash-table-inl.h" #include "src/objects/js-array-inl.h" #ifdef V8_INTL_SUPPORT #include "src/objects/js-collator.h" #endif // V8_INTL_SUPPORT #include "src/objects/js-collection-inl.h" #include "src/objects/js-generator-inl.h" #ifdef V8_INTL_SUPPORT #include "src/objects/js-list-format.h" #include "src/objects/js-locale.h" #endif // V8_INTL_SUPPORT #include "src/objects/js-regexp-inl.h" #include "src/objects/js-regexp-string-iterator.h" #ifdef V8_INTL_SUPPORT #include "src/objects/js-plural-rules.h" #include "src/objects/js-relative-time-format.h" #endif // V8_INTL_SUPPORT #include "src/objects/literal-objects-inl.h" #include "src/objects/map.h" #include "src/objects/microtask-inl.h" #include "src/objects/module-inl.h" #include "src/objects/promise-inl.h" #include "src/parsing/preparsed-scope-data.h" #include "src/property-descriptor.h" #include "src/prototype.h" #include "src/regexp/jsregexp.h" #include "src/safepoint-table.h" #include "src/snapshot/code-serializer.h" #include "src/snapshot/snapshot.h" #include "src/source-position-table.h" #include "src/string-builder-inl.h" #include "src/string-search.h" #include "src/string-stream.h" #include "src/unicode-cache-inl.h" #include "src/unicode-decoder.h" #include "src/utils-inl.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-objects.h" #include "src/zone/zone.h" #ifdef ENABLE_DISASSEMBLER #include "src/disasm.h" #include "src/disassembler.h" #include "src/eh-frame.h" #endif namespace v8 { namespace internal { bool ComparisonResultToBool(Operation op, ComparisonResult result) { switch (op) { case Operation::kLessThan: return result == ComparisonResult::kLessThan; case Operation::kLessThanOrEqual: return result == ComparisonResult::kLessThan || result == ComparisonResult::kEqual; case Operation::kGreaterThan: return result == ComparisonResult::kGreaterThan; case Operation::kGreaterThanOrEqual: return result == ComparisonResult::kGreaterThan || result == ComparisonResult::kEqual; default: break; } UNREACHABLE(); } std::ostream& operator<<(std::ostream& os, InstanceType instance_type) { switch (instance_type) { #define WRITE_TYPE(TYPE) \ case TYPE: \ return os << #TYPE; INSTANCE_TYPE_LIST(WRITE_TYPE) #undef WRITE_TYPE } UNREACHABLE(); } Handle
Object::OptimalType(Isolate* isolate, Representation representation) { if (representation.IsNone()) return FieldType::None(isolate); if (FLAG_track_field_types) { if (representation.IsHeapObject() && IsHeapObject()) { // We can track only JavaScript objects with stable maps. Handle
map(HeapObject::cast(this)->map(), isolate); if (map->is_stable() && map->IsJSReceiverMap()) { return FieldType::Class(map, isolate); } } } return FieldType::Any(isolate); } MaybeHandle
Object::ToObject(Isolate* isolate, Handle
object, Handle
native_context, const char* method_name) { if (object->IsJSReceiver()) return Handle
::cast(object); Handle
constructor; if (object->IsSmi()) { constructor = handle(native_context->number_function(), isolate); } else { int constructor_function_index = Handle
::cast(object)->map()->GetConstructorFunctionIndex(); if (constructor_function_index == Map::kNoConstructorFunctionIndex) { if (method_name != nullptr) { THROW_NEW_ERROR( isolate, NewTypeError( MessageTemplate::kCalledOnNullOrUndefined, isolate->factory()->NewStringFromAsciiChecked(method_name)), JSReceiver); } THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject), JSReceiver); } constructor = handle( JSFunction::cast(native_context->get(constructor_function_index)), isolate); } Handle
result = isolate->factory()->NewJSObject(constructor); Handle
::cast(result)->set_value(*object); return result; } // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee. // static MaybeHandle
Object::ConvertReceiver(Isolate* isolate, Handle
object) { if (object->IsJSReceiver()) return Handle
::cast(object); if (object->IsNullOrUndefined(isolate)) { return isolate->global_proxy(); } return Object::ToObject(isolate, object); } // static MaybeHandle
Object::ConvertToNumberOrNumeric(Isolate* isolate, Handle
input, Conversion mode) { while (true) { if (input->IsNumber()) { return input; } if (input->IsString()) { return String::ToNumber(isolate, Handle
::cast(input)); } if (input->IsOddball()) { return Oddball::ToNumber(isolate, Handle
::cast(input)); } if (input->IsSymbol()) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber), Object); } if (input->IsBigInt()) { if (mode == Conversion::kToNumeric) return input; DCHECK_EQ(mode, Conversion::kToNumber); THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kBigIntToNumber), Object); } ASSIGN_RETURN_ON_EXCEPTION( isolate, input, JSReceiver::ToPrimitive(Handle
::cast(input), ToPrimitiveHint::kNumber), Object); } } // static MaybeHandle
Object::ConvertToInteger(Isolate* isolate, Handle
input) { ASSIGN_RETURN_ON_EXCEPTION( isolate, input, ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object); if (input->IsSmi()) return input; return isolate->factory()->NewNumber(DoubleToInteger(input->Number())); } // static MaybeHandle
Object::ConvertToInt32(Isolate* isolate, Handle
input) { ASSIGN_RETURN_ON_EXCEPTION( isolate, input, ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object); if (input->IsSmi()) return input; return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number())); } // static MaybeHandle
Object::ConvertToUint32(Isolate* isolate, Handle
input) { ASSIGN_RETURN_ON_EXCEPTION( isolate, input, ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object); if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate); return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number())); } // static MaybeHandle
Object::ConvertToName(Isolate* isolate, Handle
input) { ASSIGN_RETURN_ON_EXCEPTION( isolate, input, Object::ToPrimitive(input, ToPrimitiveHint::kString), Name); if (input->IsName()) return Handle
::cast(input); return ToString(isolate, input); } // ES6 7.1.14 // static MaybeHandle
Object::ConvertToPropertyKey(Isolate* isolate, Handle
value) { // 1. Let key be ToPrimitive(argument, hint String). MaybeHandle
maybe_key = Object::ToPrimitive(value, ToPrimitiveHint::kString); // 2. ReturnIfAbrupt(key). Handle
key; if (!maybe_key.ToHandle(&key)) return key; // 3. If Type(key) is Symbol, then return key. if (key->IsSymbol()) return key; // 4. Return ToString(key). // Extending spec'ed behavior, we'd be happy to return an element index. if (key->IsSmi()) return key; if (key->IsHeapNumber()) { uint32_t uint_value; if (value->ToArrayLength(&uint_value) && uint_value <= static_cast
(Smi::kMaxValue)) { return handle(Smi::FromInt(static_cast
(uint_value)), isolate); } } return Object::ToString(isolate, key); } // static MaybeHandle
Object::ConvertToString(Isolate* isolate, Handle
input) { while (true) { if (input->IsOddball()) { return handle(Handle
::cast(input)->to_string(), isolate); } if (input->IsNumber()) { return isolate->factory()->NumberToString(input); } if (input->IsSymbol()) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToString), String); } if (input->IsBigInt()) { return BigInt::ToString(isolate, Handle
::cast(input)); } ASSIGN_RETURN_ON_EXCEPTION( isolate, input, JSReceiver::ToPrimitive(Handle
::cast(input), ToPrimitiveHint::kString), String); // The previous isString() check happened in Object::ToString and thus we // put it at the end of the loop in this helper. if (input->IsString()) { return Handle
::cast(input); } } } namespace { bool IsErrorObject(Isolate* isolate, Handle
object) { if (!object->IsJSReceiver()) return false; Handle
symbol = isolate->factory()->stack_trace_symbol(); return JSReceiver::HasOwnProperty(Handle
::cast(object), symbol) .FromMaybe(false); } Handle
AsStringOrEmpty(Isolate* isolate, Handle
object) { return object->IsString() ? Handle
::cast(object) : isolate->factory()->empty_string(); } Handle
NoSideEffectsErrorToString(Isolate* isolate, Handle
input) { Handle
receiver = Handle
::cast(input); Handle
name_key = isolate->factory()->name_string(); Handle
name = JSReceiver::GetDataProperty(receiver, name_key); Handle
name_str = AsStringOrEmpty(isolate, name); Handle
msg_key = isolate->factory()->message_string(); Handle
msg = JSReceiver::GetDataProperty(receiver, msg_key); Handle
msg_str = AsStringOrEmpty(isolate, msg); if (name_str->length() == 0) return msg_str; if (msg_str->length() == 0) return name_str; IncrementalStringBuilder builder(isolate); builder.AppendString(name_str); builder.AppendCString(": "); builder.AppendString(msg_str); return builder.Finish().ToHandleChecked(); } } // namespace // static Handle
Object::NoSideEffectsToString(Isolate* isolate, Handle
input) { DisallowJavascriptExecution no_js(isolate); if (input->IsString() || input->IsNumeric() || input->IsOddball()) { return Object::ToString(isolate, input).ToHandleChecked(); } else if (input->IsFunction()) { // -- F u n c t i o n Handle
fun_str; if (input->IsJSBoundFunction()) { fun_str = JSBoundFunction::ToString(Handle
::cast(input)); } else { DCHECK(input->IsJSFunction()); fun_str = JSFunction::ToString(Handle
::cast(input)); } if (fun_str->length() > 128) { IncrementalStringBuilder builder(isolate); builder.AppendString(isolate->factory()->NewSubString(fun_str, 0, 111)); builder.AppendCString("...
..."); builder.AppendString(isolate->factory()->NewSubString( fun_str, fun_str->length() - 2, fun_str->length())); return builder.Finish().ToHandleChecked(); } return fun_str; } else if (input->IsSymbol()) { // -- S y m b o l Handle
symbol = Handle
::cast(input); IncrementalStringBuilder builder(isolate); builder.AppendCString("Symbol("); if (symbol->name()->IsString()) { builder.AppendString(handle(String::cast(symbol->name()), isolate)); } builder.AppendCharacter(')'); return builder.Finish().ToHandleChecked(); } else if (input->IsJSReceiver()) { // -- J S R e c e i v e r Handle
receiver = Handle
::cast(input); Handle
to_string = JSReceiver::GetDataProperty( receiver, isolate->factory()->toString_string()); if (IsErrorObject(isolate, input) || *to_string == *isolate->error_to_string()) { // When internally formatting error objects, use a side-effects-free // version of Error.prototype.toString independent of the actually // installed toString method. return NoSideEffectsErrorToString(isolate, input); } else if (*to_string == *isolate->object_to_string()) { Handle
ctor = JSReceiver::GetDataProperty( receiver, isolate->factory()->constructor_string()); if (ctor->IsFunction()) { Handle
ctor_name; if (ctor->IsJSBoundFunction()) { ctor_name = JSBoundFunction::GetName( isolate, Handle
::cast(ctor)) .ToHandleChecked(); } else if (ctor->IsJSFunction()) { Handle
ctor_name_obj = JSFunction::GetName(isolate, Handle
::cast(ctor)); ctor_name = AsStringOrEmpty(isolate, ctor_name_obj); } if (ctor_name->length() != 0) { IncrementalStringBuilder builder(isolate); builder.AppendCString("#<"); builder.AppendString(ctor_name); builder.AppendCString(">"); return builder.Finish().ToHandleChecked(); } } } } // At this point, input is either none of the above or a JSReceiver. Handle
receiver; if (input->IsJSReceiver()) { receiver = Handle
::cast(input); } else { // This is the only case where Object::ToObject throws. DCHECK(!input->IsSmi()); int constructor_function_index = Handle
::cast(input)->map()->GetConstructorFunctionIndex(); if (constructor_function_index == Map::kNoConstructorFunctionIndex) { return isolate->factory()->NewStringFromAsciiChecked("[object Unknown]"); } receiver = Object::ToObject(isolate, input, isolate->native_context()) .ToHandleChecked(); } Handle
builtin_tag = handle(receiver->class_name(), isolate); Handle
tag_obj = JSReceiver::GetDataProperty( receiver, isolate->factory()->to_string_tag_symbol()); Handle
tag = tag_obj->IsString() ? Handle
::cast(tag_obj) : builtin_tag; IncrementalStringBuilder builder(isolate); builder.AppendCString("[object "); builder.AppendString(tag); builder.AppendCString("]"); return builder.Finish().ToHandleChecked(); } // static MaybeHandle
Object::ConvertToLength(Isolate* isolate, Handle
input) { ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object); if (input->IsSmi()) { int value = std::max(Smi::ToInt(*input), 0); return handle(Smi::FromInt(value), isolate); } double len = DoubleToInteger(input->Number()); if (len <= 0.0) { return handle(Smi::kZero, isolate); } else if (len >= kMaxSafeInteger) { len = kMaxSafeInteger; } return isolate->factory()->NewNumber(len); } // static MaybeHandle
Object::ConvertToIndex( Isolate* isolate, Handle
input, MessageTemplate::Template error_index) { if (input->IsUndefined(isolate)) return handle(Smi::kZero, isolate); ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(isolate, input), Object); if (input->IsSmi() && Smi::ToInt(*input) >= 0) return input; double len = DoubleToInteger(input->Number()) + 0.0; auto js_len = isolate->factory()->NewNumber(len); if (len < 0.0 || len > kMaxSafeInteger) { THROW_NEW_ERROR(isolate, NewRangeError(error_index, js_len), Object); } return js_len; } bool Object::BooleanValue(Isolate* isolate) { if (IsSmi()) return Smi::ToInt(this) != 0; DCHECK(IsHeapObject()); if (IsBoolean()) return IsTrue(isolate); if (IsNullOrUndefined(isolate)) return false; if (IsUndetectable()) return false; // Undetectable object is false. if (IsString()) return String::cast(this)->length() != 0; if (IsHeapNumber()) return DoubleToBoolean(HeapNumber::cast(this)->value()); if (IsBigInt()) return BigInt::cast(this)->ToBoolean(); return true; } namespace { // TODO(bmeurer): Maybe we should introduce a marker interface Number, // where we put all these methods at some point? ComparisonResult NumberCompare(double x, double y) { if (std::isnan(x) || std::isnan(y)) { return ComparisonResult::kUndefined; } else if (x < y) { return ComparisonResult::kLessThan; } else if (x > y) { return ComparisonResult::kGreaterThan; } else { return ComparisonResult::kEqual; } } bool NumberEquals(double x, double y) { // Must check explicitly for NaN's on Windows, but -0 works fine. if (std::isnan(x)) return false; if (std::isnan(y)) return false; return x == y; } bool NumberEquals(const Object* x, const Object* y) { return NumberEquals(x->Number(), y->Number()); } bool NumberEquals(Handle
x, Handle
y) { return NumberEquals(*x, *y); } ComparisonResult Reverse(ComparisonResult result) { if (result == ComparisonResult::kLessThan) { return ComparisonResult::kGreaterThan; } if (result == ComparisonResult::kGreaterThan) { return ComparisonResult::kLessThan; } return result; } } // anonymous namespace // static Maybe
Object::Compare(Isolate* isolate, Handle
x, Handle
y) { // ES6 section 7.2.11 Abstract Relational Comparison step 3 and 4. if (!Object::ToPrimitive(x, ToPrimitiveHint::kNumber).ToHandle(&x) || !Object::ToPrimitive(y, ToPrimitiveHint::kNumber).ToHandle(&y)) { return Nothing
(); } if (x->IsString() && y->IsString()) { // ES6 section 7.2.11 Abstract Relational Comparison step 5. return Just(String::Compare(isolate, Handle
::cast(x), Handle
::cast(y))); } if (x->IsBigInt() && y->IsString()) { return Just(BigInt::CompareToString(isolate, Handle
::cast(x), Handle
::cast(y))); } if (x->IsString() && y->IsBigInt()) { return Just(Reverse(BigInt::CompareToString( isolate, Handle
::cast(y), Handle
::cast(x)))); } // ES6 section 7.2.11 Abstract Relational Comparison step 6. if (!Object::ToNumeric(isolate, x).ToHandle(&x) || !Object::ToNumeric(isolate, y).ToHandle(&y)) { return Nothing
(); } bool x_is_number = x->IsNumber(); bool y_is_number = y->IsNumber(); if (x_is_number && y_is_number) { return Just(NumberCompare(x->Number(), y->Number())); } else if (!x_is_number && !y_is_number) { return Just(BigInt::CompareToBigInt(Handle
::cast(x), Handle
::cast(y))); } else if (x_is_number) { return Just(Reverse(BigInt::CompareToNumber(Handle
::cast(y), x))); } else { return Just(BigInt::CompareToNumber(Handle
::cast(x), y)); } } // static Maybe
Object::Equals(Isolate* isolate, Handle
x, Handle
y) { // This is the generic version of Abstract Equality Comparison. Must be in // sync with CodeStubAssembler::Equal. while (true) { if (x->IsNumber()) { if (y->IsNumber()) { return Just(NumberEquals(x, y)); } else if (y->IsBoolean()) { return Just(NumberEquals(*x, Handle
::cast(y)->to_number())); } else if (y->IsString()) { return Just(NumberEquals( x, String::ToNumber(isolate, Handle
::cast(y)))); } else if (y->IsBigInt()) { return Just(BigInt::EqualToNumber(Handle
::cast(y), x)); } else if (y->IsJSReceiver()) { if (!JSReceiver::ToPrimitive(Handle
::cast(y)) .ToHandle(&y)) { return Nothing
(); } } else { return Just(false); } } else if (x->IsString()) { if (y->IsString()) { return Just(String::Equals(isolate, Handle
::cast(x), Handle
::cast(y))); } else if (y->IsNumber()) { x = String::ToNumber(isolate, Handle
::cast(x)); return Just(NumberEquals(x, y)); } else if (y->IsBoolean()) { x = String::ToNumber(isolate, Handle
::cast(x)); return Just(NumberEquals(*x, Handle
::cast(y)->to_number())); } else if (y->IsBigInt()) { return Just(BigInt::EqualToString(isolate, Handle
::cast(y), Handle
::cast(x))); } else if (y->IsJSReceiver()) { if (!JSReceiver::ToPrimitive(Handle
::cast(y)) .ToHandle(&y)) { return Nothing
(); } } else { return Just(false); } } else if (x->IsBoolean()) { if (y->IsOddball()) { return Just(x.is_identical_to(y)); } else if (y->IsNumber()) { return Just(NumberEquals(Handle
::cast(x)->to_number(), *y)); } else if (y->IsString()) { y = String::ToNumber(isolate, Handle
::cast(y)); return Just(NumberEquals(Handle
::cast(x)->to_number(), *y)); } else if (y->IsBigInt()) { x = Oddball::ToNumber(isolate, Handle
::cast(x)); return Just(BigInt::EqualToNumber(Handle
::cast(y), x)); } else if (y->IsJSReceiver()) { if (!JSReceiver::ToPrimitive(Handle
::cast(y)) .ToHandle(&y)) { return Nothing
(); } x = Oddball::ToNumber(isolate, Handle
::cast(x)); } else { return Just(false); } } else if (x->IsSymbol()) { if (y->IsSymbol()) { return Just(x.is_identical_to(y)); } else if (y->IsJSReceiver()) { if (!JSReceiver::ToPrimitive(Handle
::cast(y)) .ToHandle(&y)) { return Nothing
(); } } else { return Just(false); } } else if (x->IsBigInt()) { if (y->IsBigInt()) { return Just(BigInt::EqualToBigInt(BigInt::cast(*x), BigInt::cast(*y))); } return Equals(isolate, y, x); } else if (x->IsJSReceiver()) { if (y->IsJSReceiver()) { return Just(x.is_identical_to(y)); } else if (y->IsUndetectable()) { return Just(x->IsUndetectable()); } else if (y->IsBoolean()) { y = Oddball::ToNumber(isolate, Handle
::cast(y)); } else if (!JSReceiver::ToPrimitive(Handle
::cast(x)) .ToHandle(&x)) { return Nothing
(); } } else { return Just(x->IsUndetectable() && y->IsUndetectable()); } } } bool Object::StrictEquals(Object* that) { if (this->IsNumber()) { if (!that->IsNumber()) return false; return NumberEquals(this, that); } else if (this->IsString()) { if (!that->IsString()) return false; return String::cast(this)->Equals(String::cast(that)); } else if (this->IsBigInt()) { if (!that->IsBigInt()) return false; return BigInt::EqualToBigInt(BigInt::cast(this), BigInt::cast(that)); } return this == that; } // static Handle
Object::TypeOf(Isolate* isolate, Handle
object) { if (object->IsNumber()) return isolate->factory()->number_string(); if (object->IsOddball()) return handle(Oddball::cast(*object)->type_of(), isolate); if (object->IsUndetectable()) { return isolate->factory()->undefined_string(); } if (object->IsString()) return isolate->factory()->string_string(); if (object->IsSymbol()) return isolate->factory()->symbol_string(); if (object->IsBigInt()) return isolate->factory()->bigint_string(); if (object->IsCallable()) return isolate->factory()->function_string(); return isolate->factory()->object_string(); } // static MaybeHandle
Object::Add(Isolate* isolate, Handle
lhs, Handle
rhs) { if (lhs->IsNumber() && rhs->IsNumber()) { return isolate->factory()->NewNumber(lhs->Number() + rhs->Number()); } else if (lhs->IsString() && rhs->IsString()) { return isolate->factory()->NewConsString(Handle
::cast(lhs), Handle
::cast(rhs)); } ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToPrimitive(lhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToPrimitive(rhs), Object); if (lhs->IsString() || rhs->IsString()) { ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToString(isolate, rhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToString(isolate, lhs), Object); return isolate->factory()->NewConsString(Handle
::cast(lhs), Handle
::cast(rhs)); } ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(isolate, rhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(isolate, lhs), Object); return isolate->factory()->NewNumber(lhs->Number() + rhs->Number()); } // static MaybeHandle
Object::OrdinaryHasInstance(Isolate* isolate, Handle
callable, Handle
object) { // The {callable} must have a [[Call]] internal method. if (!callable->IsCallable()) return isolate->factory()->false_value(); // Check if {callable} is a bound function, and if so retrieve its // [[BoundTargetFunction]] and use that instead of {callable}. if (callable->IsJSBoundFunction()) { Handle
bound_callable( Handle
::cast(callable)->bound_target_function(), isolate); return Object::InstanceOf(isolate, object, bound_callable); } // If {object} is not a receiver, return false. if (!object->IsJSReceiver()) return isolate->factory()->false_value(); // Get the "prototype" of {callable}; raise an error if it's not a receiver. Handle
prototype; ASSIGN_RETURN_ON_EXCEPTION( isolate, prototype, Object::GetProperty(isolate, callable, isolate->factory()->prototype_string()), Object); if (!prototype->IsJSReceiver()) { THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kInstanceofNonobjectProto, prototype), Object); } // Return whether or not {prototype} is in the prototype chain of {object}. Maybe
result = JSReceiver::HasInPrototypeChain( isolate, Handle
::cast(object), prototype); if (result.IsNothing()) return MaybeHandle
(); return isolate->factory()->ToBoolean(result.FromJust()); } // static MaybeHandle
Object::InstanceOf(Isolate* isolate, Handle
object, Handle
callable) { // The {callable} must be a receiver. if (!callable->IsJSReceiver()) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kNonObjectInInstanceOfCheck), Object); } // Lookup the @@hasInstance method on {callable}. Handle
inst_of_handler; ASSIGN_RETURN_ON_EXCEPTION( isolate, inst_of_handler, JSReceiver::GetMethod(Handle
::cast(callable), isolate->factory()->has_instance_symbol()), Object); if (!inst_of_handler->IsUndefined(isolate)) { // Call the {inst_of_handler} on the {callable}. Handle
result; ASSIGN_RETURN_ON_EXCEPTION( isolate, result, Execution::Call(isolate, inst_of_handler, callable, 1, &object), Object); return isolate->factory()->ToBoolean(result->BooleanValue(isolate)); } // The {callable} must have a [[Call]] internal method. if (!callable->IsCallable()) { THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kNonCallableInInstanceOfCheck), Object); } // Fall back to OrdinaryHasInstance with {callable} and {object}. Handle
result; ASSIGN_RETURN_ON_EXCEPTION( isolate, result, JSReceiver::OrdinaryHasInstance(isolate, callable, object), Object); return result; } // static MaybeHandle
Object::GetMethod(Handle
receiver, Handle
name) { Handle
func; Isolate* isolate = receiver->GetIsolate(); ASSIGN_RETURN_ON_EXCEPTION( isolate, func, JSReceiver::GetProperty(isolate, receiver, name), Object); if (func->IsNullOrUndefined(isolate)) { return isolate->factory()->undefined_value(); } if (!func->IsCallable()) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction, func, name, receiver), Object); } return func; } namespace { MaybeHandle
CreateListFromArrayLikeFastPath( Isolate* isolate, Handle
object, ElementTypes element_types) { if (element_types == ElementTypes::kAll) { if (object->IsJSArray()) { Handle
array = Handle
::cast(object); uint32_t length; if (!array->HasArrayPrototype(isolate) || !array->length()->ToUint32(&length) || !array->HasFastElements() || !JSObject::PrototypeHasNoElements(isolate, *array)) { return MaybeHandle
(); } return array->GetElementsAccessor()->CreateListFromArrayLike( isolate, array, length); } else if (object->IsJSTypedArray()) { Handle
array = Handle
::cast(object); size_t length = array->length_value(); if (array->WasNeutered() || length > static_cast
(FixedArray::kMaxLength)) { return MaybeHandle
(); } return array->GetElementsAccessor()->CreateListFromArrayLike( isolate, array, static_cast
(length)); } } return MaybeHandle
(); } } // namespace // static MaybeHandle
Object::CreateListFromArrayLike( Isolate* isolate, Handle
object, ElementTypes element_types) { // Fast-path for JSArray and JSTypedArray. MaybeHandle
fast_result = CreateListFromArrayLikeFastPath(isolate, object, element_types); if (!fast_result.is_null()) return fast_result; // 1. ReturnIfAbrupt(object). // 2. (default elementTypes -- not applicable.) // 3. If Type(obj) is not Object, throw a TypeError exception. if (!object->IsJSReceiver()) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, isolate->factory()->NewStringFromAsciiChecked( "CreateListFromArrayLike")), FixedArray); } // 4. Let len be ? ToLength(? Get(obj, "length")). Handle
receiver = Handle
::cast(object); Handle
raw_length_number; ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number, Object::GetLengthFromArrayLike(isolate, receiver), FixedArray); uint32_t len; if (!raw_length_number->ToUint32(&len) || len > static_cast
(FixedArray::kMaxLength)) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength), FixedArray); } // 5. Let list be an empty List. Handle
list = isolate->factory()->NewFixedArray(len); // 6. Let index be 0. // 7. Repeat while index < len: for (uint32_t index = 0; index < len; ++index) { // 7a. Let indexName be ToString(index). // 7b. Let next be ? Get(obj, indexName). Handle
next; ASSIGN_RETURN_ON_EXCEPTION(isolate, next, JSReceiver::GetElement(isolate, receiver, index), FixedArray); switch (element_types) { case ElementTypes::kAll: // Nothing to do. break; case ElementTypes::kStringAndSymbol: { // 7c. If Type(next) is not an element of elementTypes, throw a // TypeError exception. if (!next->IsName()) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kNotPropertyName, next), FixedArray); } // 7d. Append next as the last element of list. // Internalize on the fly so we can use pointer identity later. next = isolate->factory()->InternalizeName(Handle
::cast(next)); break; } } list->set(index, *next); // 7e. Set index to index + 1. (See loop header.) } // 8. Return list. return list; } // static MaybeHandle
Object::GetLengthFromArrayLike(Isolate* isolate, Handle
object) { Handle
val; Handle
key = isolate->factory()->length_string(); ASSIGN_RETURN_ON_EXCEPTION( isolate, val, JSReceiver::GetProperty(isolate, object, key), Object); return Object::ToLength(isolate, val); } // static Maybe
JSReceiver::HasProperty(LookupIterator* it) { for (; it->IsFound(); it->Next()) { switch (it->state()) { case LookupIterator::NOT_FOUND: case LookupIterator::TRANSITION: UNREACHABLE(); case LookupIterator::JSPROXY: return JSProxy::HasProperty(it->isolate(), it->GetHolder
(), it->GetName()); case LookupIterator::INTERCEPTOR: { Maybe
result = JSObject::GetPropertyAttributesWithInterceptor(it); if (result.IsNothing()) return Nothing
(); if (result.FromJust() != ABSENT) return Just(true); break; } case LookupIterator::ACCESS_CHECK: { if (it->HasAccess()) break; Maybe
result = JSObject::GetPropertyAttributesWithFailedAccessCheck(it); if (result.IsNothing()) return Nothing
(); return Just(result.FromJust() != ABSENT); } case LookupIterator::INTEGER_INDEXED_EXOTIC: // TypedArray out-of-bounds access. return Just(false); case LookupIterator::ACCESSOR: case LookupIterator::DATA: return Just(true); } } return Just(false); } // static Maybe
JSReceiver::HasOwnProperty(Handle
object, Handle
name) { if (object->IsJSModuleNamespace()) { PropertyDescriptor desc; return JSReceiver::GetOwnPropertyDescriptor(object->GetIsolate(), object, name, &desc); } if (object->IsJSObject()) { // Shortcut. LookupIterator it = LookupIterator::PropertyOrElement( object->GetIsolate(), object, name, object, LookupIterator::OWN); return HasProperty(&it); } Maybe
attributes = JSReceiver::GetOwnPropertyAttributes(object, name); MAYBE_RETURN(attributes, Nothing
()); return Just(attributes.FromJust() != ABSENT); } // static MaybeHandle
Object::GetProperty(LookupIterator* it, OnNonExistent on_non_existent) { for (; it->IsFound(); it->Next()) { switch (it->state()) { case LookupIterator::NOT_FOUND: case LookupIterator::TRANSITION: UNREACHABLE(); case LookupIterator::JSPROXY: { bool was_found; MaybeHandle
result = JSProxy::GetProperty(it->isolate(), it->GetHolder
(), it->GetName(), it->GetReceiver(), &was_found); if (!was_found) it->NotFound(); return result; } case LookupIterator::INTERCEPTOR: { bool done; Handle
result; ASSIGN_RETURN_ON_EXCEPTION( it->isolate(), result, JSObject::GetPropertyWithInterceptor(it, &done), Object); if (done) return result; break; } case LookupIterator::ACCESS_CHECK: if (it->HasAccess()) break; return JSObject::GetPropertyWithFailedAccessCheck(it); case LookupIterator::ACCESSOR: return GetPropertyWithAccessor(it); case LookupIterator::INTEGER_INDEXED_EXOTIC: return it->isolate()->factory()->undefined_value(); case LookupIterator::DATA: return it->GetDataValue(); } } if (on_non_existent == OnNonExistent::kThrowReferenceError) { THROW_NEW_ERROR(it->isolate(), NewReferenceError(MessageTemplate::kNotDefined, it->name()), Object); } return it->isolate()->factory()->undefined_value(); } // static MaybeHandle
JSProxy::GetProperty(Isolate* isolate, Handle
proxy, Handle
name, Handle
receiver, bool* was_found) { *was_found = true; DCHECK(!name->IsPrivate()); STACK_CHECK(isolate, MaybeHandle
()); Handle
trap_name = isolate->factory()->get_string(); // 1. Assert: IsPropertyKey(P) is true. // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. Handle
handler(proxy->handler(), isolate); // 3. If handler is null, throw a TypeError exception. // 4. Assert: Type(handler) is Object. if (proxy->IsRevoked()) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyRevoked, trap_name), Object); } // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. Handle
target(JSReceiver::cast(proxy->target()), isolate); // 6. Let trap be ? GetMethod(handler, "get"). Handle
trap; ASSIGN_RETURN_ON_EXCEPTION( isolate, trap, Object::GetMethod(Handle
::cast(handler), trap_name), Object); // 7. If trap is undefined, then if (trap->IsUndefined(isolate)) { // 7.a Return target.[[Get]](P, Receiver). LookupIterator it = LookupIterator::PropertyOrElement(isolate, receiver, name, target); MaybeHandle
result = Object::GetProperty(&it); *was_found = it.IsFound(); return result; } // 8. Let trapResult be ? Call(trap, handler, «target, P, Receiver»). Handle
trap_result; Handle
args[] = {target, name, receiver}; ASSIGN_RETURN_ON_EXCEPTION( isolate, trap_result, Execution::Call(isolate, trap, handler, arraysize(args), args), Object); MaybeHandle
result = JSProxy::CheckGetSetTrapResult(isolate, name, target, trap_result, kGet); if (result.is_null()) { return result; } // 11. Return trap_result return trap_result; } // static MaybeHandle
JSProxy::CheckGetSetTrapResult(Isolate* isolate, Handle
name, Handle
target, Handle
trap_result, AccessKind access_kind) { // 9. Let targetDesc be ? target.[[GetOwnProperty]](P). PropertyDescriptor target_desc; Maybe
target_found = JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); MAYBE_RETURN_NULL(target_found); // 10. If targetDesc is not undefined, then if (target_found.FromJust()) { // 10.a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is // false and targetDesc.[[Writable]] is false, then // 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false, // throw a TypeError exception. bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) && !target_desc.configurable() && !target_desc.writable() && !trap_result->SameValue(*target_desc.value()); if (inconsistent) { if (access_kind == kGet) { THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, name, target_desc.value(), trap_result), Object); } else { isolate->Throw(*isolate->factory()->NewTypeError( MessageTemplate::kProxySetFrozenData, name)); return MaybeHandle
(); } } // 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]] // is false and targetDesc.[[Get]] is undefined, then // 10.b.i. If trapResult is not undefined, throw a TypeError exception. if (access_kind == kGet) { inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) && !target_desc.configurable() && target_desc.get()->IsUndefined(isolate) && !trap_result->IsUndefined(isolate); } else { inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) && !target_desc.configurable() && target_desc.set()->IsUndefined(isolate); } if (inconsistent) { if (access_kind == kGet) { THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name, trap_result), Object); } else { isolate->Throw(*isolate->factory()->NewTypeError( MessageTemplate::kProxySetFrozenAccessor, name)); return MaybeHandle
(); } } } return isolate->factory()->undefined_value(); } Handle
JSReceiver::GetDataProperty(LookupIterator* it) { for (; it->IsFound(); it->Next()) { switch (it->state()) { case LookupIterator::INTERCEPTOR: case LookupIterator::NOT_FOUND: case LookupIterator::TRANSITION: UNREACHABLE(); case LookupIterator::ACCESS_CHECK: // Support calling this method without an active context, but refuse // access to access-checked objects in that case. if (it->isolate()->context() != nullptr && it->HasAccess()) continue; V8_FALLTHROUGH; case LookupIterator::JSPROXY: it->NotFound(); return it->isolate()->factory()->undefined_value(); case LookupIterator::ACCESSOR: // TODO(verwaest): For now this doesn't call into AccessorInfo, since // clients don't need it. Update once relevant. it->NotFound(); return it->isolate()->factory()->undefined_value(); case LookupIterator::INTEGER_INDEXED_EXOTIC: return it->isolate()->factory()->undefined_value(); case LookupIterator::DATA: return it->GetDataValue(); } } return it->isolate()->factory()->undefined_value(); } bool Object::ToInt32(int32_t* value) { if (IsSmi()) { *value = Smi::ToInt(this); return true; } if (IsHeapNumber()) { double num = HeapNumber::cast(this)->value(); // Check range before conversion to avoid undefined behavior. if (num >= kMinInt && num <= kMaxInt && FastI2D(FastD2I(num)) == num) { *value = FastD2I(num); return true; } } return false; } Handle
FunctionTemplateInfo::GetOrCreateSharedFunctionInfo( Isolate* isolate, Handle
info, MaybeHandle
maybe_name) { Object* current_info = info->shared_function_info(); if (current_info->IsSharedFunctionInfo()) { return handle(SharedFunctionInfo::cast(current_info), isolate); } Handle
name; Handle
name_string; if (maybe_name.ToHandle(&name) && name->IsString()) { name_string = Handle
::cast(name); } else if (info->class_name()->IsString()) { name_string = handle(String::cast(info->class_name()), isolate); } else { name_string = isolate->factory()->empty_string(); } FunctionKind function_kind; if (info->remove_prototype()) { function_kind = kConciseMethod; } else { function_kind = kNormalFunction; } Handle
result = isolate->factory()->NewSharedFunctionInfoForApiFunction(name_string, info, function_kind); result->set_length(info->length()); result->DontAdaptArguments(); DCHECK(result->IsApiFunction()); info->set_shared_function_info(*result); return result; } bool FunctionTemplateInfo::IsTemplateFor(Map* map) { // There is a constraint on the object; check. if (!map->IsJSObjectMap()) return false; // Fetch the constructor function of the object. Object* cons_obj = map->GetConstructor(); Object* type; if (cons_obj->IsJSFunction()) { JSFunction* fun = JSFunction::cast(cons_obj); type = fun->shared()->function_data(); } else if (cons_obj->IsFunctionTemplateInfo()) { type = FunctionTemplateInfo::cast(cons_obj); } else { return false; } // Iterate through the chain of inheriting function templates to // see if the required one occurs. while (type->IsFunctionTemplateInfo()) { if (type == this) return true; type = FunctionTemplateInfo::cast(type)->parent_template(); } // Didn't find the required type in the inheritance chain. return false; } // static Handle
TemplateList::New(Isolate* isolate, int size) { Handle
list = isolate->factory()->NewFixedArray(kLengthIndex + size); list->set(kLengthIndex, Smi::kZero); return Handle
::cast(list); } // static Handle
TemplateList::Add(Isolate* isolate, Handle
list, Handle
value) { STATIC_ASSERT(kFirstElementIndex == 1); int index = list->length() + 1; Handle
fixed_array = Handle
::cast(list); fixed_array = FixedArray::SetAndGrow(isolate, fixed_array, index, value); fixed_array->set(kLengthIndex, Smi::FromInt(index)); return Handle
::cast(fixed_array); } // static MaybeHandle
JSObject::New(Handle
constructor, Handle
new_target, Handle
site) { // If called through new, new.target can be: // - a subclass of constructor, // - a proxy wrapper around constructor, or // - the constructor itself. // If called through Reflect.construct, it's guaranteed to be a constructor. Isolate* const isolate = constructor->GetIsolate(); DCHECK(constructor->IsConstructor()); DCHECK(new_target->IsConstructor()); DCHECK(!constructor->has_initial_map() || constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE); Handle
initial_map; ASSIGN_RETURN_ON_EXCEPTION( isolate, initial_map, JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject); Handle
result = isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site); if (initial_map->is_dictionary_map()) { Handle
dictionary = NameDictionary::New(isolate, NameDictionary::kInitialCapacity); result->SetProperties(*dictionary); } isolate->counters()->constructed_objects()->Increment(); isolate->counters()->constructed_objects_runtime()->Increment(); return result; } // 9.1.12 ObjectCreate ( proto [ , internalSlotsList ] ) // Notice: This is NOT 19.1.2.2 Object.create ( O, Properties ) MaybeHandle
JSObject::ObjectCreate(Isolate* isolate, Handle
prototype) { // Generate the map with the specified {prototype} based on the Object // function's initial map from the current native context. // TODO(bmeurer): Use a dedicated cache for Object.create; think about // slack tracking for Object.create. Handle
map = Map::GetObjectCreateMap(isolate, Handle
::cast(prototype)); // Actually allocate the object. Handle
object; if (map->is_dictionary_map()) { object = isolate->factory()->NewSlowJSObjectFromMap(map); } else { object = isolate->factory()->NewJSObjectFromMap(map); } return object; } void JSObject::EnsureWritableFastElements(Handle