HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Nougat 7.0
|
7.0.0_r31
下载
查看原文件
收藏
根目录
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 "src/accessors.h" #include "src/allocation-site-scopes.h" #include "src/api.h" #include "src/arguments.h" #include "src/base/bits.h" #include "src/base/utils/random-number-generator.h" #include "src/bootstrapper.h" #include "src/code-stubs.h" #include "src/codegen.h" #include "src/compilation-dependencies.h" #include "src/compiler.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.h" #include "src/field-index-inl.h" #include "src/full-codegen/full-codegen.h" #include "src/ic/ic.h" #include "src/identity-map.h" #include "src/interpreter/bytecodes.h" #include "src/isolate-inl.h" #include "src/key-accumulator.h" #include "src/list.h" #include "src/log.h" #include "src/lookup.h" #include "src/macro-assembler.h" #include "src/messages.h" #include "src/objects-inl.h" #include "src/objects-body-descriptors-inl.h" #include "src/profiler/cpu-profiler.h" #include "src/property-descriptor.h" #include "src/prototype.h" #include "src/regexp/jsregexp.h" #include "src/safepoint-table.h" #include "src/string-builder.h" #include "src/string-search.h" #include "src/string-stream.h" #include "src/utils.h" #include "src/zone.h" #ifdef ENABLE_DISASSEMBLER #include "src/disasm.h" #include "src/disassembler.h" #endif namespace v8 { namespace internal { 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(); return os << "UNKNOWN"; // Keep the compiler happy. } Handle
Object::OptimalType(Isolate* isolate, Representation representation) { if (representation.IsNone()) return HeapType::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 HeapType::Class(map, isolate); } } } return HeapType::Any(isolate); } MaybeHandle
Object::ToObject(Isolate* isolate, Handle
object, Handle
native_context) { 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) { return MaybeHandle
(); } 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; } // static MaybeHandle
Object::ToName(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); } // static MaybeHandle
Object::ToNumber(Handle
input) { while (true) { if (input->IsNumber()) { return input; } if (input->IsString()) { return String::ToNumber(Handle
::cast(input)); } if (input->IsOddball()) { return Oddball::ToNumber(Handle
::cast(input)); } Isolate* const isolate = Handle
::cast(input)->GetIsolate(); if (input->IsSymbol()) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber), Object); } if (input->IsSimd128Value()) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSimdToNumber), Object); } ASSIGN_RETURN_ON_EXCEPTION( isolate, input, JSReceiver::ToPrimitive(Handle
::cast(input), ToPrimitiveHint::kNumber), Object); } } // static MaybeHandle
Object::ToInteger(Isolate* isolate, Handle
input) { ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); return isolate->factory()->NewNumber(DoubleToInteger(input->Number())); } // static MaybeHandle
Object::ToInt32(Isolate* isolate, Handle
input) { ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number())); } // static MaybeHandle
Object::ToUint32(Isolate* isolate, Handle
input) { ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number())); } // static MaybeHandle
Object::ToString(Isolate* isolate, Handle
input) { while (true) { if (input->IsString()) { return Handle
::cast(input); } 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->IsSimd128Value()) { return Simd128Value::ToString(Handle
::cast(input)); } ASSIGN_RETURN_ON_EXCEPTION( isolate, input, JSReceiver::ToPrimitive(Handle
::cast(input), ToPrimitiveHint::kString), String); } } // static MaybeHandle
Object::ToLength(Isolate* isolate, Handle
input) { ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ToNumber(input), Object); double len = DoubleToInteger(input->Number()); if (len <= 0.0) { len = 0.0; } else if (len >= kMaxSafeInteger) { len = kMaxSafeInteger; } return isolate->factory()->NewNumber(len); } bool Object::BooleanValue() { if (IsBoolean()) return IsTrue(); if (IsSmi()) return Smi::cast(this)->value() != 0; if (IsUndefined() || IsNull()) return false; if (IsUndetectableObject()) return false; // Undetectable object is false. if (IsString()) return String::cast(this)->length() != 0; if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue(); 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); } } // namespace // static Maybe
Object::Compare(Handle
x, Handle
y, Strength strength) { if (!is_strong(strength)) { // 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(Handle
::cast(x), Handle
::cast(y))); } // ES6 section 7.2.11 Abstract Relational Comparison step 6. if (!is_strong(strength)) { if (!Object::ToNumber(x).ToHandle(&x) || !Object::ToNumber(y).ToHandle(&y)) { return Nothing
(); } } else { if (!x->IsNumber()) { Isolate* const isolate = Handle
::cast(x)->GetIsolate(); isolate->Throw(*isolate->factory()->NewTypeError( MessageTemplate::kStrongImplicitConversion)); return Nothing
(); } else if (!y->IsNumber()) { Isolate* const isolate = Handle
::cast(y)->GetIsolate(); isolate->Throw(*isolate->factory()->NewTypeError( MessageTemplate::kStrongImplicitConversion)); return Nothing
(); } } return Just(NumberCompare(x->Number(), y->Number())); } // static Maybe
Object::Equals(Handle
x, Handle
y) { 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(Handle
::cast(y)))); } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) { 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(Handle
::cast(x), Handle
::cast(y))); } else if (y->IsNumber()) { x = String::ToNumber(Handle
::cast(x)); return Just(NumberEquals(x, y)); } else if (y->IsBoolean()) { x = String::ToNumber(Handle
::cast(x)); return Just(NumberEquals(*x, Handle
::cast(y)->to_number())); } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) { 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(Handle
::cast(y)); return Just(NumberEquals(Handle
::cast(x)->to_number(), *y)); } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) { if (!JSReceiver::ToPrimitive(Handle
::cast(y)) .ToHandle(&y)) { return Nothing
(); } x = Oddball::ToNumber(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() && !y->IsUndetectableObject()) { if (!JSReceiver::ToPrimitive(Handle
::cast(y)) .ToHandle(&y)) { return Nothing
(); } } else { return Just(false); } } else if (x->IsSimd128Value()) { if (y->IsSimd128Value()) { return Just(Simd128Value::Equals(Handle
::cast(x), Handle
::cast(y))); } else if (y->IsJSReceiver() && !y->IsUndetectableObject()) { if (!JSReceiver::ToPrimitive(Handle
::cast(y)) .ToHandle(&y)) { return Nothing
(); } } else { return Just(false); } } else if (x->IsJSReceiver() && !x->IsUndetectableObject()) { if (y->IsJSReceiver()) { return Just(x.is_identical_to(y)); } else if (y->IsNull() || y->IsUndefined()) { return Just(false); } else if (y->IsBoolean()) { y = Oddball::ToNumber(Handle
::cast(y)); } else if (!JSReceiver::ToPrimitive(Handle
::cast(x)) .ToHandle(&x)) { return Nothing
(); } } else { return Just( (x->IsNull() || x->IsUndefined() || x->IsUndetectableObject()) && (y->IsNull() || y->IsUndefined() || y->IsUndetectableObject())); } } } 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->IsSimd128Value()) { if (!that->IsSimd128Value()) return false; return Simd128Value::cast(this)->Equals(Simd128Value::cast(that)); } return this == that; } // static Handle
Object::TypeOf(Isolate* isolate, Handle
object) { if (object->IsNumber()) return isolate->factory()->number_string(); if (object->IsUndefined() || object->IsUndetectableObject()) { return isolate->factory()->undefined_string(); } if (object->IsBoolean()) return isolate->factory()->boolean_string(); if (object->IsString()) return isolate->factory()->string_string(); if (object->IsSymbol()) return isolate->factory()->symbol_string(); if (object->IsString()) return isolate->factory()->string_string(); #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ if (object->Is##Type()) return isolate->factory()->type##_string(); SIMD128_TYPES(SIMD128_TYPE) #undef SIMD128_TYPE if (object->IsCallable()) return isolate->factory()->function_string(); return isolate->factory()->object_string(); } // static MaybeHandle
Object::Multiply(Isolate* isolate, Handle
lhs, Handle
rhs, Strength strength) { if (!lhs->IsNumber() || !rhs->IsNumber()) { if (is_strong(strength)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kStrongImplicitConversion), Object); } ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); } return isolate->factory()->NewNumber(lhs->Number() * rhs->Number()); } // static MaybeHandle
Object::Divide(Isolate* isolate, Handle
lhs, Handle
rhs, Strength strength) { if (!lhs->IsNumber() || !rhs->IsNumber()) { if (is_strong(strength)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kStrongImplicitConversion), Object); } ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); } return isolate->factory()->NewNumber(lhs->Number() / rhs->Number()); } // static MaybeHandle
Object::Modulus(Isolate* isolate, Handle
lhs, Handle
rhs, Strength strength) { if (!lhs->IsNumber() || !rhs->IsNumber()) { if (is_strong(strength)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kStrongImplicitConversion), Object); } ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); } return isolate->factory()->NewNumber(modulo(lhs->Number(), rhs->Number())); } // static MaybeHandle
Object::Add(Isolate* isolate, Handle
lhs, Handle
rhs, Strength strength) { 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)); } else if (is_strong(strength)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kStrongImplicitConversion), Object); } 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(rhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); return isolate->factory()->NewNumber(lhs->Number() + rhs->Number()); } // static MaybeHandle
Object::Subtract(Isolate* isolate, Handle
lhs, Handle
rhs, Strength strength) { if (!lhs->IsNumber() || !rhs->IsNumber()) { if (is_strong(strength)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kStrongImplicitConversion), Object); } ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); } return isolate->factory()->NewNumber(lhs->Number() - rhs->Number()); } // static MaybeHandle
Object::ShiftLeft(Isolate* isolate, Handle
lhs, Handle
rhs, Strength strength) { if (!lhs->IsNumber() || !rhs->IsNumber()) { if (is_strong(strength)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kStrongImplicitConversion), Object); } ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); } return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) << (NumberToUint32(*rhs) & 0x1F)); } // static MaybeHandle
Object::ShiftRight(Isolate* isolate, Handle
lhs, Handle
rhs, Strength strength) { if (!lhs->IsNumber() || !rhs->IsNumber()) { if (is_strong(strength)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kStrongImplicitConversion), Object); } ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); } return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) >> (NumberToUint32(*rhs) & 0x1F)); } // static MaybeHandle
Object::ShiftRightLogical(Isolate* isolate, Handle
lhs, Handle
rhs, Strength strength) { if (!lhs->IsNumber() || !rhs->IsNumber()) { if (is_strong(strength)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kStrongImplicitConversion), Object); } ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); } return isolate->factory()->NewNumberFromUint(NumberToUint32(*lhs) >> (NumberToUint32(*rhs) & 0x1F)); } // static MaybeHandle
Object::BitwiseAnd(Isolate* isolate, Handle
lhs, Handle
rhs, Strength strength) { if (!lhs->IsNumber() || !rhs->IsNumber()) { if (is_strong(strength)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kStrongImplicitConversion), Object); } ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); } return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) & NumberToInt32(*rhs)); } // static MaybeHandle
Object::BitwiseOr(Isolate* isolate, Handle
lhs, Handle
rhs, Strength strength) { if (!lhs->IsNumber() || !rhs->IsNumber()) { if (is_strong(strength)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kStrongImplicitConversion), Object); } ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); } return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) | NumberToInt32(*rhs)); } // static MaybeHandle
Object::BitwiseXor(Isolate* isolate, Handle
lhs, Handle
rhs, Strength strength) { if (!lhs->IsNumber() || !rhs->IsNumber()) { if (is_strong(strength)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kStrongImplicitConversion), Object); } ASSIGN_RETURN_ON_EXCEPTION(isolate, lhs, Object::ToNumber(lhs), Object); ASSIGN_RETURN_ON_EXCEPTION(isolate, rhs, Object::ToNumber(rhs), Object); } return isolate->factory()->NewNumberFromInt(NumberToInt32(*lhs) ^ NumberToInt32(*rhs)); } Maybe
Object::IsArray(Handle
object) { if (object->IsJSArray()) return Just(true); if (object->IsJSProxy()) { Handle
proxy = Handle
::cast(object); Isolate* isolate = proxy->GetIsolate(); if (proxy->IsRevoked()) { isolate->Throw(*isolate->factory()->NewTypeError( MessageTemplate::kProxyRevoked, isolate->factory()->NewStringFromAsciiChecked("IsArray"))); return Nothing
(); } return Object::IsArray(handle(proxy->target(), isolate)); } return Just(false); } bool Object::IsPromise(Handle
object) { if (!object->IsJSObject()) return false; auto js_object = Handle
::cast(object); // Promises can't have access checks. if (js_object->map()->is_access_check_needed()) return false; auto isolate = js_object->GetIsolate(); // TODO(dcarney): this should just be read from the symbol registry so as not // to be context dependent. auto key = isolate->factory()->promise_status_symbol(); // Shouldn't be possible to throw here. return JSObject::HasRealNamedProperty(js_object, key).FromJust(); } // static MaybeHandle
Object::GetMethod(Handle
receiver, Handle
name) { Handle
func; Isolate* isolate = receiver->GetIsolate(); ASSIGN_RETURN_ON_EXCEPTION(isolate, func, JSReceiver::GetProperty(receiver, name), Object); if (func->IsNull() || func->IsUndefined()) { return isolate->factory()->undefined_value(); } if (!func->IsCallable()) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kPropertyNotFunction, func, name, receiver), Object); } return func; } // static MaybeHandle
Object::CreateListFromArrayLike( Isolate* isolate, Handle
object, ElementTypes element_types) { // 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
raw_length_obj; ASSIGN_RETURN_ON_EXCEPTION( isolate, raw_length_obj, JSReceiver::GetProperty(object, isolate->factory()->length_string()), FixedArray); Handle
raw_length_number; ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number, Object::ToLength(isolate, raw_length_obj), 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, Object::GetElement(isolate, object, 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 Maybe
JSReceiver::HasProperty(LookupIterator* it) { for (; it->IsFound(); it->Next()) { switch (it->state()) { case LookupIterator::NOT_FOUND: case LookupIterator::TRANSITION: UNREACHABLE(); case LookupIterator::JSPROXY: // Call the "has" trap on proxies. return JSProxy::HasProperty(it->isolate(), it->GetHolder
(), it->GetName()); case LookupIterator::INTERCEPTOR: { Maybe
result = JSObject::GetPropertyAttributesWithInterceptor(it); if (!result.IsJust()) 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.IsJust()) 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 MaybeHandle
Object::GetProperty(LookupIterator* it, LanguageMode language_mode) { for (; it->IsFound(); it->Next()) { switch (it->state()) { case LookupIterator::NOT_FOUND: case LookupIterator::TRANSITION: UNREACHABLE(); case LookupIterator::JSPROXY: return JSProxy::GetProperty(it->isolate(), it->GetHolder
(), it->GetName(), it->GetReceiver(), language_mode); 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, language_mode); case LookupIterator::INTEGER_INDEXED_EXOTIC: return ReadAbsentProperty(it, language_mode); case LookupIterator::DATA: return it->GetDataValue(); } } return ReadAbsentProperty(it, language_mode); } #define STACK_CHECK(result_value) \ do { \ StackLimitCheck stack_check(isolate); \ if (stack_check.HasOverflowed()) { \ isolate->Throw(*isolate->factory()->NewRangeError( \ MessageTemplate::kStackOverflow)); \ return result_value; \ } \ } while (false) // static MaybeHandle
JSProxy::GetProperty(Isolate* isolate, Handle
proxy, Handle
name, Handle
receiver, LanguageMode language_mode) { if (receiver->IsJSGlobalObject()) { THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kReadGlobalReferenceThroughProxy, name), Object); } DCHECK(!name->IsPrivate()); STACK_CHECK(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(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()) { // 7.a Return target.[[Get]](P, Receiver). LookupIterator it = LookupIterator::PropertyOrElement(isolate, receiver, name, target); return Object::GetProperty(&it, language_mode); } // 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); // 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) { THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, name, target_desc.value(), trap_result), Object); } // 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. inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) && !target_desc.configurable() && target_desc.get()->IsUndefined() && !trap_result->IsUndefined(); if (inconsistent) { THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name, trap_result), Object); } } // 11. Return trap_result return trap_result; } Handle
JSReceiver::GetDataProperty(Handle
object, Handle
name) { LookupIterator it(object, name, LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); return GetDataProperty(&it); } 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; // Fall through. case LookupIterator::JSPROXY: it->NotFound(); return it->isolate()->factory()->undefined_value(); case LookupIterator::ACCESSOR: // TODO(verwaest): For now this doesn't call into // ExecutableAccessorInfo, 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::cast(this)->value(); return true; } if (IsHeapNumber()) { double num = HeapNumber::cast(this)->value(); if (FastI2D(FastD2I(num)) == num) { *value = FastD2I(num); return true; } } return false; } bool Object::ToUint32(uint32_t* value) { if (IsSmi()) { int num = Smi::cast(this)->value(); if (num < 0) return false; *value = static_cast
(num); return true; } if (IsHeapNumber()) { double num = HeapNumber::cast(this)->value(); if (num < 0) return false; uint32_t uint_value = FastD2UI(num); if (FastUI2D(uint_value) == num) { *value = uint_value; return true; } } return false; } bool FunctionTemplateInfo::IsTemplateFor(Object* object) { if (!object->IsHeapObject()) return false; return IsTemplateFor(HeapObject::cast(object)->map()); } 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(); if (!cons_obj->IsJSFunction()) return false; JSFunction* fun = JSFunction::cast(cons_obj); // Iterate through the chain of inheriting function templates to // see if the required one occurs. for (Object* type = fun->shared()->function_data(); type->IsFunctionTemplateInfo(); type = FunctionTemplateInfo::cast(type)->parent_template()) { if (type == this) return true; } // Didn't find the required type in the inheritance chain. return false; } // TODO(dcarney): CallOptimization duplicates this logic, merge. Object* FunctionTemplateInfo::GetCompatibleReceiver(Isolate* isolate, Object* receiver) { // API calls are only supported with JSObject receivers. if (!receiver->IsJSObject()) return isolate->heap()->null_value(); Object* recv_type = this->signature(); // No signature, return holder. if (recv_type->IsUndefined()) return receiver; FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type); // Check the receiver. for (PrototypeIterator iter(isolate, receiver, PrototypeIterator::START_AT_RECEIVER); !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) { if (signature->IsTemplateFor(iter.GetCurrent())) return iter.GetCurrent(); } return isolate->heap()->null_value(); } // 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); isolate->counters()->constructed_objects()->Increment(); isolate->counters()->constructed_objects_runtime()->Increment(); return result; } Handle
JSObject::EnsureWritableFastElements( Handle
object) { DCHECK(object->HasFastSmiOrObjectElements()); Isolate* isolate = object->GetIsolate(); Handle
elems(FixedArray::cast(object->elements()), isolate); if (elems->map() != isolate->heap()->fixed_cow_array_map()) return elems; Handle
writable_elems = isolate->factory()->CopyFixedArrayWithMap( elems, isolate->factory()->fixed_array_map()); object->set_elements(*writable_elems); isolate->counters()->cow_arrays_converted()->Increment(); return writable_elems; } // ES6 9.5.1 // static MaybeHandle
JSProxy::GetPrototype(Handle
proxy) { Isolate* isolate = proxy->GetIsolate(); Handle
trap_name = isolate->factory()->getPrototypeOf_string(); STACK_CHECK(MaybeHandle
()); // 1. Let handler be the value of the [[ProxyHandler]] internal slot. // 2. If handler is null, throw a TypeError exception. // 3. Assert: Type(handler) is Object. // 4. Let target be the value of the [[ProxyTarget]] internal slot. if (proxy->IsRevoked()) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyRevoked, trap_name), Object); } Handle
target(proxy->target(), isolate); Handle
handler(JSReceiver::cast(proxy->handler()), isolate); // 5. Let trap be ? GetMethod(handler, "getPrototypeOf"). Handle
trap; ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name), Object); // 6. If trap is undefined, then return target.[[GetPrototypeOf]](). if (trap->IsUndefined()) { return Object::GetPrototype(isolate, target); } // 7. Let handlerProto be ? Call(trap, handler, «target»). Handle
argv[] = {target}; Handle
handler_proto; ASSIGN_RETURN_ON_EXCEPTION( isolate, handler_proto, Execution::Call(isolate, trap, handler, arraysize(argv), argv), Object); // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError. if (!(handler_proto->IsJSReceiver() || handler_proto->IsNull())) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyGetPrototypeOfInvalid), Object); } // 9. Let extensibleTarget be ? IsExtensible(target). Maybe
is_extensible = JSReceiver::IsExtensible(target); MAYBE_RETURN_NULL(is_extensible); // 10. If extensibleTarget is true, return handlerProto. if (is_extensible.FromJust()) return handler_proto; // 11. Let targetProto be ? target.[[GetPrototypeOf]](). Handle
target_proto; ASSIGN_RETURN_ON_EXCEPTION(isolate, target_proto, Object::GetPrototype(isolate, target), Object); // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError. if (!handler_proto->SameValue(*target_proto)) { THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kProxyGetPrototypeOfNonExtensible), Object); } // 13. Return handlerProto. return handler_proto; } MaybeHandle
Object::GetPropertyWithAccessor( LookupIterator* it, LanguageMode language_mode) { Isolate* isolate = it->isolate(); Handle
structure = it->GetAccessors(); Handle
receiver = it->GetReceiver(); // We should never get here to initialize a const with the hole value since a // const declaration would conflict with the getter. DCHECK(!structure->IsForeign()); // API style callbacks. if (structure->IsAccessorInfo()) { Handle
holder = it->GetHolder
(); Handle
name = it->GetName(); Handle
info = Handle
::cast(structure); if (!info->IsCompatibleReceiver(*receiver)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, name, receiver), Object); } v8::AccessorNameGetterCallback call_fun = v8::ToCData
(info->getter()); if (call_fun == nullptr) return isolate->factory()->undefined_value(); LOG(isolate, ApiNamedPropertyAccess("load", *holder, *name)); PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder); v8::Local
result = args.Call(call_fun, v8::Utils::ToLocal(name)); RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); if (result.IsEmpty()) { return ReadAbsentProperty(isolate, receiver, name, language_mode); } Handle
return_value = v8::Utils::OpenHandle(*result); return_value->VerifyApiCallResultType(); // Rebox handle before return. return handle(*return_value, isolate); } // Regular accessor. Handle
getter(AccessorPair::cast(*structure)->getter(), isolate); if (getter->IsCallable()) { // TODO(rossberg): nicer would be to cast to some JSCallable here... return Object::GetPropertyWithDefinedGetter( receiver, Handle
::cast(getter)); } // Getter is not a function. return ReadAbsentProperty(isolate, receiver, it->GetName(), language_mode); } bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate, Handle
info, Handle
map) { if (!info->HasExpectedReceiverType()) return true; if (!map->IsJSObjectMap()) return false; return FunctionTemplateInfo::cast(info->expected_receiver_type()) ->IsTemplateFor(*map); } Maybe
Object::SetPropertyWithAccessor(LookupIterator* it, Handle
value, ShouldThrow should_throw) { Isolate* isolate = it->isolate(); Handle
structure = it->GetAccessors(); Handle
receiver = it->GetReceiver(); // We should never get here to initialize a const with the hole value since a // const declaration would conflict with the setter. DCHECK(!structure->IsForeign()); // API style callbacks. if (structure->IsExecutableAccessorInfo()) { Handle
holder = it->GetHolder
(); Handle
name = it->GetName(); Handle
info = Handle
::cast(structure); if (!info->IsCompatibleReceiver(*receiver)) { isolate->Throw(*isolate->factory()->NewTypeError( MessageTemplate::kIncompatibleMethodReceiver, name, receiver)); return Nothing
(); } v8::AccessorNameSetterCallback call_fun = v8::ToCData
(info->setter()); if (call_fun == nullptr) return Just(true); // TODO(verwaest): Shouldn't this case be unreachable (at least in the // long run?) Should we have ExecutableAccessorPairs with missing setter // that are "writable"? If they aren't writable, shouldn't we have bailed // out already earlier? LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name)); PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder); args.Call(call_fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value)); RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing
()); return Just(true); } // Regular accessor. Handle
setter(AccessorPair::cast(*structure)->setter(), isolate); if (setter->IsCallable()) { // TODO(rossberg): nicer would be to cast to some JSCallable here... return SetPropertyWithDefinedSetter( receiver, Handle
::cast(setter), value, should_throw); } RETURN_FAILURE(isolate, should_throw, NewTypeError(MessageTemplate::kNoSetterInCallback, it->GetName(), it->GetHolder
())); } MaybeHandle
Object::GetPropertyWithDefinedGetter( Handle
receiver, Handle
getter) { Isolate* isolate = getter->GetIsolate(); // Platforms with simulators like arm/arm64 expose a funny issue. If the // simulator has a separate JS stack pointer from the C++ stack pointer, it // can miss C++ stack overflows in the stack guard at the start of JavaScript // functions. It would be very expensive to check the C++ stack pointer at // that location. The best solution seems to be to break the impasse by // adding checks at possible recursion points. What's more, we don't put // this stack check behind the USE_SIMULATOR define in order to keep // behavior the same between hardware and simulators. StackLimitCheck check(isolate); if (check.JsHasOverflowed()) { isolate->StackOverflow(); return MaybeHandle
(); } return Execution::Call(isolate, getter, receiver, 0, NULL); } Maybe
Object::SetPropertyWithDefinedSetter(Handle
receiver, Handle
setter, Handle
value, ShouldThrow should_throw) { Isolate* isolate = setter->GetIsolate(); Handle
argv[] = { value }; RETURN_ON_EXCEPTION_VALUE(isolate, Execution::Call(isolate, setter, receiver, arraysize(argv), argv), Nothing
()); return Just(true); } // static bool Object::IsErrorObject(Isolate* isolate, Handle
object) { if (!object->IsJSObject()) return false; // Use stack_trace_symbol as proxy for [[ErrorData]]. Handle
symbol = isolate->factory()->stack_trace_symbol(); Maybe
has_stack_trace = JSReceiver::HasOwnProperty(Handle
::cast(object), symbol); DCHECK(!has_stack_trace.IsNothing()); return has_stack_trace.FromJust(); } // static bool JSObject::AllCanRead(LookupIterator* it) { // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of // which have already been checked. DCHECK(it->state() == LookupIterator::ACCESS_CHECK || it->state() == LookupIterator::INTERCEPTOR); for (it->Next(); it->IsFound(); it->Next()) { if (it->state() == LookupIterator::ACCESSOR) { auto accessors = it->GetAccessors(); if (accessors->IsAccessorInfo()) { if (AccessorInfo::cast(*accessors)->all_can_read()) return true; } } else if (it->state() == LookupIterator::INTERCEPTOR) { if (it->GetInterceptor()->all_can_read()) return true; } else if (it->state() == LookupIterator::JSPROXY) { // Stop lookupiterating. And no, AllCanNotRead. return false; } } return false; } MaybeHandle
JSObject::GetPropertyWithFailedAccessCheck( LookupIterator* it) { Handle
checked = it->GetHolder
(); while (AllCanRead(it)) { if (it->state() == LookupIterator::ACCESSOR) { return GetPropertyWithAccessor(it, SLOPPY); } DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); bool done; Handle
result; ASSIGN_RETURN_ON_EXCEPTION(it->isolate(), result, GetPropertyWithInterceptor(it, &done), Object); if (done) return result; } // Cross-Origin [[Get]] of Well-Known Symbols does not throw, and returns // undefined. Handle
name = it->GetName(); if (name->IsSymbol() && Symbol::cast(*name)->is_well_known_symbol()) { return it->factory()->undefined_value(); } it->isolate()->ReportFailedAccessCheck(checked); RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); return it->factory()->undefined_value(); } Maybe
JSObject::GetPropertyAttributesWithFailedAccessCheck( LookupIterator* it) { Handle
checked = it->GetHolder
(); while (AllCanRead(it)) { if (it->state() == LookupIterator::ACCESSOR) { return Just(it->property_details().attributes()); } DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); auto result = GetPropertyAttributesWithInterceptor(it); if (it->isolate()->has_scheduled_exception()) break; if (result.IsJust() && result.FromJust() != ABSENT) return result; } it->isolate()->ReportFailedAccessCheck(checked); RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing
()); return Just(ABSENT); } // static bool JSObject::AllCanWrite(LookupIterator* it) { for (; it->IsFound() && it->state() != LookupIterator::JSPROXY; it->Next()) { if (it->state() == LookupIterator::ACCESSOR) { Handle
accessors = it->GetAccessors(); if (accessors->IsAccessorInfo()) { if (AccessorInfo::cast(*accessors)->all_can_write()) return true; } } } return false; } Maybe
JSObject::SetPropertyWithFailedAccessCheck( LookupIterator* it, Handle
value, ShouldThrow should_throw) { Handle
checked = it->GetHolder
(); if (AllCanWrite(it)) { return SetPropertyWithAccessor(it, value, should_throw); } it->isolate()->ReportFailedAccessCheck(checked); RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(), Nothing
()); return Just(true); } void JSObject::SetNormalizedProperty(Handle
object, Handle
name, Handle
value, PropertyDetails details) { DCHECK(!object->HasFastProperties()); if (!name->IsUniqueName()) { name = object->GetIsolate()->factory()->InternalizeString( Handle
::cast(name)); } if (object->IsJSGlobalObject()) { Handle
property_dictionary(object->global_dictionary()); int entry = property_dictionary->FindEntry(name); if (entry == GlobalDictionary::kNotFound) { auto cell = object->GetIsolate()->factory()->NewPropertyCell(); cell->set_value(*value); auto cell_type = value->IsUndefined() ? PropertyCellType::kUndefined : PropertyCellType::kConstant; details = details.set_cell_type(cell_type); value = cell; property_dictionary = GlobalDictionary::Add(property_dictionary, name, value, details); object->set_properties(*property_dictionary); } else { PropertyCell::UpdateCell(property_dictionary, entry, value, details); } } else { Handle
property_dictionary(object->property_dictionary()); int entry = property_dictionary->FindEntry(name); if (entry == NameDictionary::kNotFound) { property_dictionary = NameDictionary::Add(property_dictionary, name, value, details); object->set_properties(*property_dictionary); } else { PropertyDetails original_details = property_dictionary->DetailsAt(entry); int enumeration_index = original_details.dictionary_index(); DCHECK(enumeration_index > 0); details = details.set_index(enumeration_index); property_dictionary->SetEntry(entry, name, value, details); } } } Maybe
Object::HasInPrototypeChain(Isolate* isolate, Handle
object, Handle
proto) { PrototypeIterator iter(isolate, object, PrototypeIterator::START_AT_RECEIVER); while (true) { if (!iter.AdvanceFollowingProxies()) return Nothing