[*] Speed glorious speed
[+] Removed isolate entropy from the AstXXX hash seed bases, string inls, and string hash to ensure v8::Names deterministic across instances. Hashes are expected to colloid. Doubt anything depends on isolate entropy. [+] v8::String::GloballyInternalize(...) [+] v8::String::Share(...) [+] ScriptCompiler::EvaluateGlobal Previous aurora commits:4c7c7d1a24
,c9b547e373
,97450cb8d1
,07e2139b4f
, ...
This commit is contained in:
parent
4c7c7d1a24
commit
f86bf4d785
@ -223,6 +223,10 @@ class V8_EXPORT String : public Name {
|
||||
*/
|
||||
bool IsExternalOneByte() const;
|
||||
|
||||
v8::Local<v8::String> GloballyInternalize();
|
||||
|
||||
v8::Local<v8::String> Share(v8::Isolate *pIsolate);
|
||||
|
||||
class V8_EXPORT ExternalStringResourceBase {
|
||||
public:
|
||||
virtual ~ExternalStringResourceBase() = default;
|
||||
|
@ -597,6 +597,11 @@ class V8_EXPORT ScriptCompiler {
|
||||
CompileOptions options = kNoCompileOptions,
|
||||
NoCacheReason no_cache_reason = kNoCacheNoReason);
|
||||
|
||||
static MaybeLocal<v8::Value> EvaluateGlobal(v8::Isolate* isolate,
|
||||
v8::Local<v8::String> source,
|
||||
bool repl);
|
||||
|
||||
|
||||
/**
|
||||
* Compiles the specified script (bound to current context).
|
||||
*
|
||||
|
@ -165,6 +165,9 @@ class V8_EXPORT Template : public Data {
|
||||
using GenericNamedPropertyGetterCallback =
|
||||
void (*)(Local<Name> property, const PropertyCallbackInfo<Value>& info);
|
||||
|
||||
using GenericNamedPropertyGetterFastCallback = v8::Local<Value> (*)(
|
||||
v8::Isolate* pIsolate, Local<Object> that, Local<Name> property, bool *pShouldCheckBase);
|
||||
|
||||
/**
|
||||
* Interceptor for set requests on an object.
|
||||
*
|
||||
@ -190,6 +193,11 @@ using GenericNamedPropertySetterCallback =
|
||||
void (*)(Local<Name> property, Local<Value> value,
|
||||
const PropertyCallbackInfo<Value>& info);
|
||||
|
||||
using GenericNamedPropertySetterFastCallback = bool (*)(v8::Isolate *pIsolate,
|
||||
Local<Object> that,
|
||||
Local<Name> property,
|
||||
Local<Value> &value);
|
||||
|
||||
/**
|
||||
* Intercepts all requests that query the attributes of the
|
||||
* property, e.g., getOwnPropertyDescriptor(), propertyIsEnumerable(), and
|
||||
@ -302,6 +310,10 @@ using GenericNamedPropertyDescriptorCallback =
|
||||
using IndexedPropertyGetterCallback =
|
||||
void (*)(uint32_t index, const PropertyCallbackInfo<Value>& info);
|
||||
|
||||
using IndexedPropertyGetterFastCallback =
|
||||
v8::Local<Value> (*)(v8::Isolate* pIsolate,
|
||||
Local<Object> that,
|
||||
uint32_t index);
|
||||
/**
|
||||
* See `v8::GenericNamedPropertySetterCallback`.
|
||||
*/
|
||||
@ -309,6 +321,11 @@ using IndexedPropertySetterCallback =
|
||||
void (*)(uint32_t index, Local<Value> value,
|
||||
const PropertyCallbackInfo<Value>& info);
|
||||
|
||||
using IndexedPropertySetterFastCallback = bool (*)(v8::Isolate* pIsolate,
|
||||
Local<Object> that,
|
||||
uint32_t index,
|
||||
v8::Local<Value> value);
|
||||
|
||||
/**
|
||||
* See `v8::GenericNamedPropertyQueryCallback`.
|
||||
*/
|
||||
@ -623,6 +640,11 @@ enum class PropertyHandlerFlags {
|
||||
* The getter, query, enumerator callbacks do not produce side effects.
|
||||
*/
|
||||
kHasNoSideEffect = 1 << 3,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
kUseNoProxyNoExternalCallbackInfoFastPath = 1 << 4
|
||||
};
|
||||
|
||||
struct NamedPropertyHandlerConfiguration {
|
||||
|
@ -140,6 +140,8 @@
|
||||
#include "src/wasm/wasm-serialization.h"
|
||||
#endif // V8_ENABLE_WEBASSEMBLY
|
||||
|
||||
#include "src/debug/debug-evaluate.h"
|
||||
|
||||
#if V8_OS_LINUX || V8_OS_DARWIN || V8_OS_FREEBSD
|
||||
#include <signal.h>
|
||||
|
||||
@ -1725,6 +1727,8 @@ i::Handle<i::InterceptorInfo> CreateInterceptorInfo(
|
||||
obj->set_has_no_side_effect(
|
||||
static_cast<int>(flags) &
|
||||
static_cast<int>(PropertyHandlerFlags::kHasNoSideEffect));
|
||||
obj->set_use_fastpath((static_cast<int>(flags) &
|
||||
static_cast<int>(PropertyHandlerFlags::kUseNoProxyNoExternalCallbackInfoFastPath)) != 0);
|
||||
|
||||
if (data.IsEmpty()) {
|
||||
data = v8::Undefined(reinterpret_cast<v8::Isolate*>(i_isolate));
|
||||
@ -2555,6 +2559,22 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundScript(
|
||||
return CompileUnboundInternal(v8_isolate, source, options, no_cache_reason);
|
||||
}
|
||||
|
||||
MaybeLocal<v8::Value> ScriptCompiler::EvaluateGlobal(
|
||||
v8::Isolate* isolate, v8::Local<v8::String> source,
|
||||
bool repl) {
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE(i_isolate, Value);
|
||||
i::REPLMode repl_mode = repl ? i::REPLMode::kYes : i::REPLMode::kNo;
|
||||
Local<Value> result;
|
||||
has_pending_exception = !ToLocal<Value>(
|
||||
i::DebugEvaluate::Global(i_isolate, Utils::OpenHandle(*source),
|
||||
debug::EvaluateGlobalMode::kDefault,
|
||||
repl_mode),
|
||||
&result);
|
||||
RETURN_ON_FAILED_EXECUTION(Value);
|
||||
RETURN_ESCAPED(result)
|
||||
}
|
||||
|
||||
MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context,
|
||||
Source* source,
|
||||
CompileOptions options,
|
||||
@ -5871,6 +5891,22 @@ bool v8::String::IsExternalOneByte() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
v8::Local<v8::String> v8::String::GloballyInternalize() {
|
||||
i::DisallowGarbageCollection no_gc;
|
||||
i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
i::Isolate* i_isolate = i::GetIsolateFromWritableObject(*str);
|
||||
if (!str->IsUniqueName()) {
|
||||
return Utils::ToLocal(i_isolate->factory()->InternalizeString(str));
|
||||
} else {
|
||||
return Utils::ToLocal(str);
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::String> v8::String::Share(v8::Isolate* pIsolate) {
|
||||
i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
return Utils::ToLocal(i::String::Share(reinterpret_cast<i::Isolate*>(pIsolate), str));
|
||||
}
|
||||
|
||||
void v8::String::VerifyExternalStringResource(
|
||||
v8::String::ExternalStringResource* value) const {
|
||||
i::DisallowGarbageCollection no_gc;
|
||||
@ -9048,7 +9084,9 @@ void Isolate::GetHeapStatistics(HeapStatistics* heap_statistics) {
|
||||
// now we just add the values, thereby over-approximating the peak slightly.
|
||||
heap_statistics->malloced_memory_ =
|
||||
i_isolate->allocator()->GetCurrentMemoryUsage() +
|
||||
i_isolate->string_table()->GetCurrentMemoryUsage();
|
||||
0;
|
||||
|
||||
//i_isolate->string_table()->GetCurrentMemoryUsage();
|
||||
// On 32-bit systems backing_store_bytes() might overflow size_t temporarily
|
||||
// due to concurrent array buffer sweeping.
|
||||
heap_statistics->external_memory_ =
|
||||
|
264
src/ic/ic.cc
264
src/ic/ic.cc
@ -3314,39 +3314,18 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
|
||||
return *value;
|
||||
}
|
||||
|
||||
#define ASSIGN_RETURN_FAILURE_ON_EXCEPTION2()
|
||||
#define RETURN_FAILURE_IF_SCHEDULED_EXCEPTION_DETECTOR2()
|
||||
|
||||
/**
|
||||
* Loads a property with an interceptor performing post interceptor
|
||||
* lookup if interceptor failed.
|
||||
*/
|
||||
RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(5, args.length());
|
||||
Handle<Name> name = args.at<Name>(0);
|
||||
Handle<Object> receiver = args.at(1);
|
||||
Handle<JSObject> holder = args.at<JSObject>(2);
|
||||
|
||||
if (!receiver->IsJSReceiver()) {
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, receiver, Object::ConvertReceiver(isolate, receiver));
|
||||
}
|
||||
|
||||
{
|
||||
Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate);
|
||||
PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
|
||||
*holder, Just(kDontThrow));
|
||||
|
||||
Handle<Object> result = arguments.CallNamedGetter(interceptor, name);
|
||||
|
||||
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION_DETECTOR(isolate, arguments);
|
||||
|
||||
if (!result.is_null()) {
|
||||
arguments.AcceptSideEffects();
|
||||
return *result;
|
||||
}
|
||||
// If the interceptor didn't handle the request, then there must be no
|
||||
// side effects.
|
||||
}
|
||||
|
||||
static V8_INLINE Object Runtime_LoadPropertyWithInterceptor_Slow(
|
||||
RuntimeArguments args, Isolate* isolate, Handle<Object> receiver,
|
||||
Handle<Name> name, Handle<JSObject> holder) {
|
||||
LookupIterator it(isolate, receiver, name, holder);
|
||||
// Skip any lookup work until we hit the (possibly non-masking) interceptor.
|
||||
while (it.state() != LookupIterator::INTERCEPTOR ||
|
||||
@ -3376,37 +3355,176 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
|
||||
isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
|
||||
Address Runtime_LoadPropertyWithInterceptor(int args_length,
|
||||
Address* args_object,
|
||||
Isolate* isolate) {
|
||||
DCHECK(isolate->context().is_null() || isolate->context().IsContext());
|
||||
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(3, args.length());
|
||||
// Runtime functions don't follow the IC's calling convention.
|
||||
Handle<Object> value = args.at(0);
|
||||
Handle<JSObject> receiver = args.at<JSObject>(1);
|
||||
Handle<Name> name = args.at<Name>(2);
|
||||
|
||||
// TODO(ishell): Cache interceptor_holder in the store handler like we do
|
||||
// for LoadHandler::kInterceptor case.
|
||||
Handle<JSObject> interceptor_holder = receiver;
|
||||
if (receiver->IsJSGlobalProxy() &&
|
||||
(!receiver->HasNamedInterceptor() ||
|
||||
receiver->GetNamedInterceptor().non_masking())) {
|
||||
interceptor_holder =
|
||||
handle(JSObject::cast(receiver->map().prototype()), isolate);
|
||||
#define RT_STPWI_HOLDER_ADDRESS \
|
||||
(reinterpret_cast<Address*>(reinterpret_cast<Address>(args_object) - \
|
||||
(2 * kSystemPointerSize)))
|
||||
|
||||
#define RT_STPWI_NAME_ADDRESS \
|
||||
(reinterpret_cast<Address*>(reinterpret_cast<Address>(args_object) - \
|
||||
(0 * kSystemPointerSize)))
|
||||
|
||||
#define RT_STPWI_RECV_ADDRESS \
|
||||
(reinterpret_cast<Address*>(reinterpret_cast<Address>(args_object) - \
|
||||
(1 * kSystemPointerSize)))
|
||||
|
||||
Handle<Object> receiver = Handle<JSObject>(RT_STPWI_RECV_ADDRESS);
|
||||
Handle<Name> name = Handle<Name>(RT_STPWI_NAME_ADDRESS);
|
||||
Handle<JSObject> holder = Handle<JSObject>(RT_STPWI_HOLDER_ADDRESS);
|
||||
|
||||
if (!receiver->IsJSReceiver()) {
|
||||
if (!Object::ConvertReceiver(isolate, receiver).ToHandle(&receiver)) {
|
||||
return ReadOnlyRoots(isolate).exception().ptr();
|
||||
}
|
||||
}
|
||||
DCHECK(interceptor_holder->HasNamedInterceptor());
|
||||
|
||||
{
|
||||
Handle<InterceptorInfo> interceptor(
|
||||
interceptor_holder->GetNamedInterceptor(), isolate);
|
||||
InterceptorInfo interceptorInfo;
|
||||
auto handler = holder->map().cached_property_handler();
|
||||
|
||||
DCHECK(!interceptor->non_masking());
|
||||
PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
|
||||
*receiver, Just(kDontThrow));
|
||||
if (!handler.is_null()) {
|
||||
interceptorInfo = InterceptorInfo::cast(handler);
|
||||
} else {
|
||||
interceptorInfo = holder->GetNamedInterceptor();
|
||||
holder->map().set_cached_property_handler(interceptorInfo);
|
||||
}
|
||||
|
||||
Handle<Object> result = arguments.CallNamedSetter(interceptor, name, value);
|
||||
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION_DETECTOR(isolate, arguments);
|
||||
if (!result.is_null()) return *value;
|
||||
// If the interceptor didn't handle the request, then there must be no
|
||||
// side effects.
|
||||
if (interceptorInfo.use_fastpath()) {
|
||||
bool bScan{};
|
||||
auto ret = reinterpret_cast<GenericNamedPropertyGetterFastCallback>(
|
||||
v8::internal::Foreign::cast(interceptorInfo.getter())
|
||||
.foreign_address())((v8::Isolate*)(isolate),
|
||||
v8::Utils::ToLocal(receiver).As<v8::Object>(),
|
||||
v8::Utils::ToLocal(name), &bScan);
|
||||
if (!ret.IsEmpty()) {
|
||||
return (*(v8::internal::Object*)(*ret)).ptr();
|
||||
} else if (!bScan) {
|
||||
return (*isolate->factory()->undefined_value()).ptr();
|
||||
}
|
||||
} else {
|
||||
PropertyCallbackArguments arguments(isolate, interceptorInfo.data(),
|
||||
*receiver, *holder, Just(kDontThrow));
|
||||
|
||||
Handle<Object> result = arguments.CallNamedGetter(
|
||||
Handle<InterceptorInfo>(interceptorInfo, isolate), name);
|
||||
if (isolate->has_pending_exception())
|
||||
{
|
||||
return ReadOnlyRoots(isolate).exception().ptr();
|
||||
}
|
||||
|
||||
if (!result.is_null()) {
|
||||
arguments.AcceptSideEffects();
|
||||
return (*result).ptr();
|
||||
}
|
||||
// If the interceptor didn't handle the request, then there must be no
|
||||
// side effects.
|
||||
}
|
||||
}
|
||||
|
||||
RuntimeArguments args(args_length, args_object);
|
||||
return BUILTIN_CONVERT_RESULT(Runtime_LoadPropertyWithInterceptor_Slow(
|
||||
args, isolate, receiver, name, holder));
|
||||
}
|
||||
|
||||
#undef RT_STPWI_HOLDER_ADDRESS
|
||||
#undef RT_STPWI_NAME_ADDRESS
|
||||
#undef RT_STPWI_RECV_ADDRESS
|
||||
|
||||
Address Runtime_StorePropertyWithInterceptor(int args_length,
|
||||
Address* args_object,
|
||||
Isolate* isolate) {
|
||||
DCHECK_EQ(3, args_length);
|
||||
HandleScope scope(isolate);
|
||||
|
||||
#define RT_STPWI_VALUE_ADDRESS \
|
||||
(reinterpret_cast<Address*>(reinterpret_cast<Address>(args_object) - \
|
||||
(0 * kSystemPointerSize)))
|
||||
|
||||
#define RT_STPWI_NAME_ADDRESS \
|
||||
(reinterpret_cast<Address*>(reinterpret_cast<Address>(args_object) - \
|
||||
(2 * kSystemPointerSize)))
|
||||
|
||||
#define RT_STPWI_RECV_ADDRESS \
|
||||
(reinterpret_cast<Address*>(reinterpret_cast<Address>(args_object) - \
|
||||
(1 * kSystemPointerSize)))
|
||||
|
||||
Handle<JSObject> receiver = Handle<JSObject>(RT_STPWI_RECV_ADDRESS);
|
||||
Handle<Name> name = Handle<Name>(RT_STPWI_NAME_ADDRESS);
|
||||
Handle<Object> value = Handle<Object>(RT_STPWI_VALUE_ADDRESS);
|
||||
|
||||
{
|
||||
bool bCont{};
|
||||
InterceptorInfo interceptorInfo;
|
||||
auto handler = receiver->map().cached_property_handler();
|
||||
|
||||
if (!handler.is_null()) {
|
||||
interceptorInfo = InterceptorInfo::cast(handler);
|
||||
} else {
|
||||
if (receiver->HasNamedInterceptor()) {
|
||||
Handle<JSObject> interceptor_holder = receiver;
|
||||
|
||||
if (receiver->IsJSGlobalProxy() &&
|
||||
(!receiver->HasNamedInterceptor() ||
|
||||
receiver->GetNamedInterceptor().non_masking())) {
|
||||
interceptor_holder =
|
||||
handle(JSObject::cast(receiver->map().prototype()), isolate);
|
||||
}
|
||||
DCHECK(interceptor_holder->HasNamedInterceptor());
|
||||
|
||||
interceptorInfo = interceptor_holder->GetNamedInterceptor();
|
||||
receiver->map().set_cached_property_handler(interceptorInfo);
|
||||
} else {
|
||||
// intentional fallthrough to LookupIterator it [...] without goto
|
||||
bCont = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bCont) {
|
||||
DCHECK(!interceptorInfo.non_masking());
|
||||
|
||||
if (interceptorInfo.use_fastpath()) {
|
||||
AssertNoContextChange ncc(isolate);
|
||||
auto val = v8::Utils::ToLocal(value);
|
||||
bool bStatus = reinterpret_cast<GenericNamedPropertySetterFastCallback>(
|
||||
v8::internal::Foreign::cast(interceptorInfo.setter())
|
||||
.foreign_address())((v8::Isolate*)(isolate),
|
||||
v8::Utils::ToLocal(receiver),
|
||||
v8::Utils::ToLocal(name), val);
|
||||
if (bStatus) {
|
||||
return v8::Utils::OpenHandle(*val).address(); // 1:
|
||||
}
|
||||
|
||||
if (isolate->has_scheduled_exception()) {
|
||||
return isolate->PromoteScheduledException().ptr();
|
||||
}
|
||||
} else {
|
||||
PropertyCallbackArguments arguments(isolate, interceptorInfo.data(),
|
||||
*receiver, *receiver,
|
||||
Just(kDontThrow));
|
||||
|
||||
if (isolate->has_scheduled_exception()) {
|
||||
arguments.AcceptSideEffects();
|
||||
return isolate->PromoteScheduledException().ptr();
|
||||
}
|
||||
|
||||
if (!arguments
|
||||
.CallNamedSetter(
|
||||
Handle<InterceptorInfo>(interceptorInfo, isolate), name,
|
||||
value)
|
||||
.is_null()) {
|
||||
return *RT_STPWI_VALUE_ADDRESS; // 1:
|
||||
}
|
||||
}
|
||||
|
||||
// 1: If the interceptor didn't handle the request, then there must be no
|
||||
// side effects.
|
||||
}
|
||||
}
|
||||
|
||||
LookupIterator it(isolate, receiver, name, receiver);
|
||||
@ -3419,11 +3537,13 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
|
||||
DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
|
||||
it.Next();
|
||||
|
||||
MAYBE_RETURN(Object::SetProperty(&it, value, StoreOrigin::kNamed),
|
||||
ReadOnlyRoots(isolate).exception());
|
||||
return *value;
|
||||
if (Object::SetProperty(&it, value, StoreOrigin::kNamed).IsNothing()) {
|
||||
return ReadOnlyRoots(isolate).exception().ptr();
|
||||
}
|
||||
return *RT_STPWI_VALUE_ADDRESS;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
|
||||
// TODO(verwaest): This should probably get the holder and receiver as input.
|
||||
HandleScope scope(isolate);
|
||||
@ -3435,7 +3555,21 @@ RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
|
||||
isolate);
|
||||
PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
|
||||
*receiver, Just(kDontThrow));
|
||||
Handle<Object> result = arguments.CallIndexedGetter(interceptor, index);
|
||||
|
||||
Handle<Object> result;
|
||||
if (interceptor->use_fastpath()) {
|
||||
auto ret = reinterpret_cast<IndexedPropertyGetterFastCallback>(
|
||||
v8::internal::Foreign::cast(interceptor->getter()).foreign_address())(
|
||||
(v8::Isolate*)(isolate), v8::Utils::ToLocal(receiver).As<v8::Object>(),
|
||||
index);
|
||||
if (!ret.IsEmpty()) {
|
||||
result = v8::Utils::OpenHandle(*ret);
|
||||
} else {
|
||||
result = isolate->factory()->undefined_value();
|
||||
}
|
||||
} else {
|
||||
result = arguments.CallIndexedGetter(interceptor, index);
|
||||
}
|
||||
|
||||
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION_DETECTOR(isolate, arguments);
|
||||
|
||||
@ -3492,7 +3626,23 @@ RUNTIME_FUNCTION(Runtime_HasElementWithInterceptor) {
|
||||
return ReadOnlyRoots(isolate).true_value();
|
||||
}
|
||||
} else if (!interceptor->getter().IsUndefined(isolate)) {
|
||||
Handle<Object> result = arguments.CallIndexedGetter(interceptor, index);
|
||||
Handle<Object> result;
|
||||
|
||||
if (interceptor->use_fastpath()) {
|
||||
auto ret = reinterpret_cast<IndexedPropertyGetterFastCallback>(
|
||||
v8::internal::Foreign::cast(interceptor->getter())
|
||||
.foreign_address())(
|
||||
(v8::Isolate*)(isolate),
|
||||
v8::Utils::ToLocal(receiver).As<v8::Object>(), index);
|
||||
if (!ret.IsEmpty()) {
|
||||
result = v8::Utils::OpenHandle(*ret);
|
||||
} else {
|
||||
result = isolate->factory()->undefined_value();
|
||||
}
|
||||
} else {
|
||||
result = arguments.CallIndexedGetter(interceptor, index);
|
||||
}
|
||||
|
||||
if (!result.is_null()) {
|
||||
arguments.AcceptSideEffects();
|
||||
return ReadOnlyRoots(isolate).true_value();
|
||||
|
@ -43,6 +43,8 @@ inline uint64_t HashSeed(LocalIsolate* isolate) {
|
||||
}
|
||||
|
||||
inline uint64_t HashSeed(ReadOnlyRoots roots) {
|
||||
// eat shit
|
||||
return 0xcbf29ce484222325;
|
||||
uint64_t seed;
|
||||
roots.hash_seed().copy_out(0, reinterpret_cast<byte*>(&seed), kInt64Size);
|
||||
return seed;
|
||||
|
@ -121,6 +121,7 @@ BOOL_ACCESSORS(InterceptorInfo, flags, non_masking, NonMaskingBit::kShift)
|
||||
BOOL_ACCESSORS(InterceptorInfo, flags, is_named, NamedBit::kShift)
|
||||
BOOL_ACCESSORS(InterceptorInfo, flags, has_no_side_effect,
|
||||
HasNoSideEffectBit::kShift)
|
||||
BOOL_ACCESSORS(InterceptorInfo, flags, use_fastpath, UseFastpathBit::kShift)
|
||||
|
||||
bool CallHandlerInfo::IsSideEffectFreeCallHandlerInfo() const {
|
||||
ReadOnlyRoots roots = GetReadOnlyRoots();
|
||||
|
@ -110,7 +110,8 @@ class InterceptorInfo
|
||||
DECL_BOOLEAN_ACCESSORS(non_masking)
|
||||
DECL_BOOLEAN_ACCESSORS(is_named)
|
||||
DECL_BOOLEAN_ACCESSORS(has_no_side_effect)
|
||||
|
||||
DECL_BOOLEAN_ACCESSORS(use_fastpath)
|
||||
|
||||
DEFINE_TORQUE_GENERATED_INTERCEPTOR_INFO_FLAGS()
|
||||
|
||||
using BodyDescriptor = StructBodyDescriptor;
|
||||
|
@ -16,6 +16,14 @@ bitfield struct InterceptorInfoFlags extends uint31 {
|
||||
non_masking: bool: 1 bit;
|
||||
named: bool: 1 bit;
|
||||
has_no_side_effect: bool: 1 bit;
|
||||
|
||||
// Hidden prototype and indexer interceptor semantics are responsible for
|
||||
// significantly slowing down named property accessors. For named accessors
|
||||
// on non-proxy objects, an order of magnitude of difference can be observed.
|
||||
// For a frame of reference, Object insertion @ 100k/ops * 8 members was taking
|
||||
// ~2ms as opposed to 20-30ms on a stubbed out name setter.
|
||||
// warning: also bypasses set_external_callback_scope [!!!]
|
||||
use_fastpath: bool: 1 bit;
|
||||
}
|
||||
|
||||
extern class InterceptorInfo extends Struct {
|
||||
|
@ -1207,22 +1207,52 @@ MaybeHandle<Object> GetPropertyWithInterceptorInternal(
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
|
||||
}
|
||||
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
||||
*holder, Just(kDontThrow));
|
||||
|
||||
if (it->IsElement(*holder)) {
|
||||
result = args.CallIndexedGetter(interceptor, it->array_index());
|
||||
if (interceptor->use_fastpath()) {
|
||||
bool bScanBase{};
|
||||
|
||||
if (it->IsElement(*holder)) {
|
||||
auto ret = reinterpret_cast<IndexedPropertyGetterFastCallback>(
|
||||
v8::internal::Foreign::cast(interceptor->getter()).foreign_address())(
|
||||
(v8::Isolate*)(isolate),
|
||||
v8::Utils::ToLocal(receiver).As<v8::Object>(), it->array_index());
|
||||
if (!ret.IsEmpty()) {
|
||||
*done = true;
|
||||
return handle(*(internal::Object*)(*ret), isolate);
|
||||
}
|
||||
} else {
|
||||
auto ret = reinterpret_cast<GenericNamedPropertyGetterFastCallback>(
|
||||
v8::internal::Foreign::cast(interceptor->getter()).foreign_address())(
|
||||
(v8::Isolate*)(isolate),
|
||||
v8::Utils::ToLocal(receiver).As<v8::Object>(),
|
||||
v8::Utils::ToLocal(Handle<Name>(it->name())), &bScanBase);
|
||||
if (!ret.IsEmpty()) {
|
||||
*done = true;
|
||||
return handle(*(internal::Object*)(*ret), isolate);
|
||||
}
|
||||
}
|
||||
|
||||
if (!bScanBase) {
|
||||
return isolate->factory()->undefined_value();
|
||||
}
|
||||
} else {
|
||||
result = args.CallNamedGetter(interceptor, it->name());
|
||||
}
|
||||
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
||||
*holder, Just(kDontThrow));
|
||||
|
||||
RETURN_VALUE_IF_SCHEDULED_EXCEPTION_DETECTOR(isolate, args,
|
||||
MaybeHandle<Object>());
|
||||
if (result.is_null()) return isolate->factory()->undefined_value();
|
||||
*done = true;
|
||||
args.AcceptSideEffects();
|
||||
// Rebox handle before return
|
||||
return handle(*result, isolate);
|
||||
if (it->IsElement(*holder)) {
|
||||
result = args.CallIndexedGetter(interceptor, it->array_index());
|
||||
} else {
|
||||
result = args.CallNamedGetter(interceptor, it->name());
|
||||
}
|
||||
|
||||
RETURN_VALUE_IF_SCHEDULED_EXCEPTION_DETECTOR(isolate, args,
|
||||
MaybeHandle<Object>());
|
||||
if (result.is_null()) return isolate->factory()->undefined_value();
|
||||
*done = true;
|
||||
args.AcceptSideEffects();
|
||||
// Rebox handle before return
|
||||
return handle(*result, isolate);
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
|
||||
@ -1236,21 +1266,28 @@ Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
|
||||
Handle<JSObject> holder = it->GetHolder<JSObject>();
|
||||
DCHECK_IMPLIES(!it->IsElement(*holder) && it->name()->IsSymbol(),
|
||||
interceptor->can_intercept_symbols());
|
||||
|
||||
Handle<Object> receiver = it->GetReceiver();
|
||||
|
||||
if (!receiver->IsJSReceiver()) {
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
|
||||
Object::ConvertReceiver(isolate, receiver),
|
||||
Nothing<PropertyAttributes>());
|
||||
}
|
||||
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
||||
*holder, Just(kDontThrow));
|
||||
|
||||
if (!interceptor->query().IsUndefined(isolate)) {
|
||||
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
||||
*holder, Just(kDontThrow));
|
||||
Handle<Object> result;
|
||||
if (it->IsElement(*holder)) {
|
||||
result = args.CallIndexedQuery(interceptor, it->array_index());
|
||||
} else {
|
||||
result = args.CallNamedQuery(interceptor, it->name());
|
||||
}
|
||||
|
||||
RETURN_VALUE_IF_SCHEDULED_EXCEPTION_DETECTOR(isolate, args,
|
||||
Nothing<PropertyAttributes>());
|
||||
|
||||
if (!result.is_null()) {
|
||||
int32_t value;
|
||||
CHECK(result->ToInt32(&value));
|
||||
@ -1263,27 +1300,16 @@ Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
|
||||
return Just(static_cast<PropertyAttributes>(value));
|
||||
}
|
||||
} else if (!interceptor->getter().IsUndefined(isolate)) {
|
||||
// TODO(verwaest): Use GetPropertyWithInterceptor?
|
||||
Handle<Object> result;
|
||||
if (it->IsElement(*holder)) {
|
||||
result = args.CallIndexedGetter(interceptor, it->array_index());
|
||||
} else {
|
||||
result = args.CallNamedGetter(interceptor, it->name());
|
||||
}
|
||||
if (!result.is_null()) {
|
||||
args.AcceptSideEffects();
|
||||
return Just(DONT_ENUM);
|
||||
}
|
||||
return Just(NONE);
|
||||
}
|
||||
|
||||
RETURN_VALUE_IF_SCHEDULED_EXCEPTION_DETECTOR(isolate, args,
|
||||
Nothing<PropertyAttributes>());
|
||||
return Just(ABSENT);
|
||||
}
|
||||
|
||||
Maybe<bool> SetPropertyWithInterceptorInternal(
|
||||
LookupIterator* it, Handle<InterceptorInfo> interceptor,
|
||||
Maybe<ShouldThrow> should_throw, Handle<Object> value) {
|
||||
bool result;
|
||||
Isolate* isolate = it->isolate();
|
||||
// Make sure that the top context does not change when doing callbacks or
|
||||
// interceptor calls.
|
||||
@ -1292,28 +1318,47 @@ Maybe<bool> SetPropertyWithInterceptorInternal(
|
||||
if (interceptor->setter().IsUndefined(isolate)) return Just(false);
|
||||
|
||||
Handle<JSObject> holder = it->GetHolder<JSObject>();
|
||||
bool result;
|
||||
Handle<Object> receiver = it->GetReceiver();
|
||||
if (!receiver->IsJSReceiver()) {
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
|
||||
Object::ConvertReceiver(isolate, receiver),
|
||||
Nothing<bool>());
|
||||
}
|
||||
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
||||
*holder, should_throw);
|
||||
|
||||
if (it->IsElement(*holder)) {
|
||||
// TODO(neis): In the future, we may want to actually return the
|
||||
// interceptor's result, which then should be a boolean.
|
||||
result = !args.CallIndexedSetter(interceptor, it->array_index(), value)
|
||||
.is_null();
|
||||
if (interceptor->use_fastpath()) {
|
||||
if (it->IsElement(*holder)) {
|
||||
result = reinterpret_cast<IndexedPropertySetterFastCallback>(
|
||||
v8::internal::Foreign::cast(interceptor->setter()).foreign_address())(
|
||||
(v8::Isolate*)(isolate),
|
||||
v8::Utils::ToLocal(receiver).As<v8::Object>(), it->array_index(),
|
||||
v8::Utils::ToLocal(value));
|
||||
} else {
|
||||
auto val = v8::Utils::ToLocal(value);
|
||||
result = reinterpret_cast<GenericNamedPropertySetterFastCallback>(
|
||||
v8::internal::Foreign::cast(interceptor->setter()).foreign_address())(
|
||||
(v8::Isolate*)(isolate),
|
||||
v8::Utils::ToLocal(receiver).As<v8::Object>(),
|
||||
v8::Utils::ToLocal(it->name()), val);
|
||||
value = v8::Utils::OpenHandle(*val);
|
||||
}
|
||||
} else {
|
||||
result = !args.CallNamedSetter(interceptor, it->name(), value).is_null();
|
||||
if (!receiver->IsJSReceiver()) {
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, receiver, Object::ConvertReceiver(isolate, receiver),
|
||||
Nothing<bool>());
|
||||
}
|
||||
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
||||
*holder, should_throw);
|
||||
|
||||
if (it->IsElement(*holder)) {
|
||||
// TODO(neis): In the future, we may want to actually return the
|
||||
// interceptor's result, which then should be a boolean.
|
||||
result = !args.CallIndexedSetter(interceptor, it->array_index(), value)
|
||||
.is_null();
|
||||
} else {
|
||||
result = !args.CallNamedSetter(interceptor, it->name(), value).is_null();
|
||||
}
|
||||
|
||||
RETURN_VALUE_IF_SCHEDULED_EXCEPTION_DETECTOR(it->isolate(), args,
|
||||
Nothing<bool>());
|
||||
if (result) args.AcceptSideEffects();
|
||||
}
|
||||
|
||||
RETURN_VALUE_IF_SCHEDULED_EXCEPTION_DETECTOR(it->isolate(), args,
|
||||
Nothing<bool>());
|
||||
if (result) args.AcceptSideEffects();
|
||||
return Just(result);
|
||||
}
|
||||
|
||||
|
@ -233,6 +233,7 @@ class Map : public TorqueGeneratedMap<Map, HeapObject> {
|
||||
DECL_GETTER(GetNamedInterceptor, InterceptorInfo)
|
||||
DECL_GETTER(GetIndexedInterceptor, InterceptorInfo)
|
||||
|
||||
DECL_GETTER(GetCachedPropertyHandler, InterceptorInfo)
|
||||
// Instance type.
|
||||
DECL_PRIMITIVE_ACCESSORS(instance_type, InstanceType)
|
||||
|
||||
|
@ -68,6 +68,9 @@ extern class Map extends HeapObject {
|
||||
@if(TAGGED_SIZE_8_BYTES) optional_padding: uint32;
|
||||
@ifnot(TAGGED_SIZE_8_BYTES) optional_padding: void;
|
||||
|
||||
cached_property_handler: InterceptorInfo|Undefined;
|
||||
pad: Undefined;
|
||||
|
||||
prototype: JSReceiver|Null;
|
||||
constructor_or_back_pointer_or_native_context: Object;
|
||||
instance_descriptors: DescriptorArray;
|
||||
|
@ -788,10 +788,8 @@ Handle<String> String::Share(Isolate* isolate, Handle<String> string) {
|
||||
case StringTransitionStrategy::kCopy:
|
||||
return SlowShare(isolate, string);
|
||||
case StringTransitionStrategy::kInPlace:
|
||||
// A relaxed write is sufficient here, because at this point the string
|
||||
// has not yet escaped the current thread.
|
||||
DCHECK(string->InSharedHeap());
|
||||
string->set_map_no_write_barrier(*new_map.ToHandleChecked());
|
||||
string->set_map(*new_map.ToHandleChecked());
|
||||
return string;
|
||||
case StringTransitionStrategy::kAlreadyTransitioned:
|
||||
return string;
|
||||
|
@ -114,7 +114,7 @@ Handle<String> String::SlowShare(Isolate* isolate, Handle<String> source) {
|
||||
// A relaxed write is sufficient here, because at this point the string
|
||||
// has not yet escaped the current thread.
|
||||
DCHECK(flat->InSharedHeap());
|
||||
flat->set_map_no_write_barrier(*new_map.ToHandleChecked());
|
||||
flat->set_map(*new_map.ToHandleChecked());
|
||||
return flat;
|
||||
case StringTransitionStrategy::kAlreadyTransitioned:
|
||||
return flat;
|
||||
|
Loading…
Reference in New Issue
Block a user