[*] 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;
|
bool IsExternalOneByte() const;
|
||||||
|
|
||||||
|
v8::Local<v8::String> GloballyInternalize();
|
||||||
|
|
||||||
|
v8::Local<v8::String> Share(v8::Isolate *pIsolate);
|
||||||
|
|
||||||
class V8_EXPORT ExternalStringResourceBase {
|
class V8_EXPORT ExternalStringResourceBase {
|
||||||
public:
|
public:
|
||||||
virtual ~ExternalStringResourceBase() = default;
|
virtual ~ExternalStringResourceBase() = default;
|
||||||
|
@ -597,6 +597,11 @@ class V8_EXPORT ScriptCompiler {
|
|||||||
CompileOptions options = kNoCompileOptions,
|
CompileOptions options = kNoCompileOptions,
|
||||||
NoCacheReason no_cache_reason = kNoCacheNoReason);
|
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).
|
* Compiles the specified script (bound to current context).
|
||||||
*
|
*
|
||||||
|
@ -165,6 +165,9 @@ class V8_EXPORT Template : public Data {
|
|||||||
using GenericNamedPropertyGetterCallback =
|
using GenericNamedPropertyGetterCallback =
|
||||||
void (*)(Local<Name> property, const PropertyCallbackInfo<Value>& info);
|
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.
|
* Interceptor for set requests on an object.
|
||||||
*
|
*
|
||||||
@ -190,6 +193,11 @@ using GenericNamedPropertySetterCallback =
|
|||||||
void (*)(Local<Name> property, Local<Value> value,
|
void (*)(Local<Name> property, Local<Value> value,
|
||||||
const PropertyCallbackInfo<Value>& info);
|
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
|
* Intercepts all requests that query the attributes of the
|
||||||
* property, e.g., getOwnPropertyDescriptor(), propertyIsEnumerable(), and
|
* property, e.g., getOwnPropertyDescriptor(), propertyIsEnumerable(), and
|
||||||
@ -302,6 +310,10 @@ using GenericNamedPropertyDescriptorCallback =
|
|||||||
using IndexedPropertyGetterCallback =
|
using IndexedPropertyGetterCallback =
|
||||||
void (*)(uint32_t index, const PropertyCallbackInfo<Value>& info);
|
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`.
|
* See `v8::GenericNamedPropertySetterCallback`.
|
||||||
*/
|
*/
|
||||||
@ -309,6 +321,11 @@ using IndexedPropertySetterCallback =
|
|||||||
void (*)(uint32_t index, Local<Value> value,
|
void (*)(uint32_t index, Local<Value> value,
|
||||||
const PropertyCallbackInfo<Value>& info);
|
const PropertyCallbackInfo<Value>& info);
|
||||||
|
|
||||||
|
using IndexedPropertySetterFastCallback = bool (*)(v8::Isolate* pIsolate,
|
||||||
|
Local<Object> that,
|
||||||
|
uint32_t index,
|
||||||
|
v8::Local<Value> value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See `v8::GenericNamedPropertyQueryCallback`.
|
* See `v8::GenericNamedPropertyQueryCallback`.
|
||||||
*/
|
*/
|
||||||
@ -623,6 +640,11 @@ enum class PropertyHandlerFlags {
|
|||||||
* The getter, query, enumerator callbacks do not produce side effects.
|
* The getter, query, enumerator callbacks do not produce side effects.
|
||||||
*/
|
*/
|
||||||
kHasNoSideEffect = 1 << 3,
|
kHasNoSideEffect = 1 << 3,
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
kUseNoProxyNoExternalCallbackInfoFastPath = 1 << 4
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NamedPropertyHandlerConfiguration {
|
struct NamedPropertyHandlerConfiguration {
|
||||||
|
@ -140,6 +140,8 @@
|
|||||||
#include "src/wasm/wasm-serialization.h"
|
#include "src/wasm/wasm-serialization.h"
|
||||||
#endif // V8_ENABLE_WEBASSEMBLY
|
#endif // V8_ENABLE_WEBASSEMBLY
|
||||||
|
|
||||||
|
#include "src/debug/debug-evaluate.h"
|
||||||
|
|
||||||
#if V8_OS_LINUX || V8_OS_DARWIN || V8_OS_FREEBSD
|
#if V8_OS_LINUX || V8_OS_DARWIN || V8_OS_FREEBSD
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
@ -1725,6 +1727,8 @@ i::Handle<i::InterceptorInfo> CreateInterceptorInfo(
|
|||||||
obj->set_has_no_side_effect(
|
obj->set_has_no_side_effect(
|
||||||
static_cast<int>(flags) &
|
static_cast<int>(flags) &
|
||||||
static_cast<int>(PropertyHandlerFlags::kHasNoSideEffect));
|
static_cast<int>(PropertyHandlerFlags::kHasNoSideEffect));
|
||||||
|
obj->set_use_fastpath((static_cast<int>(flags) &
|
||||||
|
static_cast<int>(PropertyHandlerFlags::kUseNoProxyNoExternalCallbackInfoFastPath)) != 0);
|
||||||
|
|
||||||
if (data.IsEmpty()) {
|
if (data.IsEmpty()) {
|
||||||
data = v8::Undefined(reinterpret_cast<v8::Isolate*>(i_isolate));
|
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);
|
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,
|
MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context,
|
||||||
Source* source,
|
Source* source,
|
||||||
CompileOptions options,
|
CompileOptions options,
|
||||||
@ -5871,6 +5891,22 @@ bool v8::String::IsExternalOneByte() const {
|
|||||||
return false;
|
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(
|
void v8::String::VerifyExternalStringResource(
|
||||||
v8::String::ExternalStringResource* value) const {
|
v8::String::ExternalStringResource* value) const {
|
||||||
i::DisallowGarbageCollection no_gc;
|
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.
|
// now we just add the values, thereby over-approximating the peak slightly.
|
||||||
heap_statistics->malloced_memory_ =
|
heap_statistics->malloced_memory_ =
|
||||||
i_isolate->allocator()->GetCurrentMemoryUsage() +
|
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
|
// On 32-bit systems backing_store_bytes() might overflow size_t temporarily
|
||||||
// due to concurrent array buffer sweeping.
|
// due to concurrent array buffer sweeping.
|
||||||
heap_statistics->external_memory_ =
|
heap_statistics->external_memory_ =
|
||||||
|
252
src/ic/ic.cc
252
src/ic/ic.cc
@ -3314,39 +3314,18 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
|
|||||||
return *value;
|
return *value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ASSIGN_RETURN_FAILURE_ON_EXCEPTION2()
|
||||||
|
#define RETURN_FAILURE_IF_SCHEDULED_EXCEPTION_DETECTOR2()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a property with an interceptor performing post interceptor
|
* Loads a property with an interceptor performing post interceptor
|
||||||
* lookup if interceptor failed.
|
* 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);
|
LookupIterator it(isolate, receiver, name, holder);
|
||||||
// Skip any lookup work until we hit the (possibly non-masking) interceptor.
|
// Skip any lookup work until we hit the (possibly non-masking) interceptor.
|
||||||
while (it.state() != LookupIterator::INTERCEPTOR ||
|
while (it.state() != LookupIterator::INTERCEPTOR ||
|
||||||
@ -3376,17 +3355,120 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
|
|||||||
isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
|
isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
|
Address Runtime_LoadPropertyWithInterceptor(int args_length,
|
||||||
HandleScope scope(isolate);
|
Address* args_object,
|
||||||
DCHECK_EQ(3, args.length());
|
Isolate* isolate) {
|
||||||
// Runtime functions don't follow the IC's calling convention.
|
DCHECK(isolate->context().is_null() || isolate->context().IsContext());
|
||||||
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
|
HandleScope scope(isolate);
|
||||||
// for LoadHandler::kInterceptor case.
|
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
InterceptorInfo interceptorInfo;
|
||||||
|
auto handler = holder->map().cached_property_handler();
|
||||||
|
|
||||||
|
if (!handler.is_null()) {
|
||||||
|
interceptorInfo = InterceptorInfo::cast(handler);
|
||||||
|
} else {
|
||||||
|
interceptorInfo = holder->GetNamedInterceptor();
|
||||||
|
holder->map().set_cached_property_handler(interceptorInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
Handle<JSObject> interceptor_holder = receiver;
|
||||||
|
|
||||||
if (receiver->IsJSGlobalProxy() &&
|
if (receiver->IsJSGlobalProxy() &&
|
||||||
(!receiver->HasNamedInterceptor() ||
|
(!receiver->HasNamedInterceptor() ||
|
||||||
receiver->GetNamedInterceptor().non_masking())) {
|
receiver->GetNamedInterceptor().non_masking())) {
|
||||||
@ -3394,20 +3476,56 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
|
|||||||
handle(JSObject::cast(receiver->map().prototype()), isolate);
|
handle(JSObject::cast(receiver->map().prototype()), isolate);
|
||||||
}
|
}
|
||||||
DCHECK(interceptor_holder->HasNamedInterceptor());
|
DCHECK(interceptor_holder->HasNamedInterceptor());
|
||||||
{
|
|
||||||
Handle<InterceptorInfo> interceptor(
|
|
||||||
interceptor_holder->GetNamedInterceptor(), isolate);
|
|
||||||
|
|
||||||
DCHECK(!interceptor->non_masking());
|
interceptorInfo = interceptor_holder->GetNamedInterceptor();
|
||||||
PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
|
receiver->map().set_cached_property_handler(interceptorInfo);
|
||||||
*receiver, Just(kDontThrow));
|
} else {
|
||||||
|
// intentional fallthrough to LookupIterator it [...] without goto
|
||||||
|
bCont = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Handle<Object> result = arguments.CallNamedSetter(interceptor, name, value);
|
if (!bCont) {
|
||||||
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION_DETECTOR(isolate, arguments);
|
DCHECK(!interceptorInfo.non_masking());
|
||||||
if (!result.is_null()) return *value;
|
|
||||||
// If the interceptor didn't handle the request, then there must be no
|
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.
|
// side effects.
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LookupIterator it(isolate, receiver, name, receiver);
|
LookupIterator it(isolate, receiver, name, receiver);
|
||||||
// Skip past any access check on the receiver.
|
// Skip past any access check on the receiver.
|
||||||
@ -3419,10 +3537,12 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
|
|||||||
DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
|
DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
|
||||||
it.Next();
|
it.Next();
|
||||||
|
|
||||||
MAYBE_RETURN(Object::SetProperty(&it, value, StoreOrigin::kNamed),
|
if (Object::SetProperty(&it, value, StoreOrigin::kNamed).IsNothing()) {
|
||||||
ReadOnlyRoots(isolate).exception());
|
return ReadOnlyRoots(isolate).exception().ptr();
|
||||||
return *value;
|
|
||||||
}
|
}
|
||||||
|
return *RT_STPWI_VALUE_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
|
RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
|
||||||
// TODO(verwaest): This should probably get the holder and receiver as input.
|
// TODO(verwaest): This should probably get the holder and receiver as input.
|
||||||
@ -3435,7 +3555,21 @@ RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
|
|||||||
isolate);
|
isolate);
|
||||||
PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
|
PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
|
||||||
*receiver, Just(kDontThrow));
|
*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);
|
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION_DETECTOR(isolate, arguments);
|
||||||
|
|
||||||
@ -3492,7 +3626,23 @@ RUNTIME_FUNCTION(Runtime_HasElementWithInterceptor) {
|
|||||||
return ReadOnlyRoots(isolate).true_value();
|
return ReadOnlyRoots(isolate).true_value();
|
||||||
}
|
}
|
||||||
} else if (!interceptor->getter().IsUndefined(isolate)) {
|
} 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()) {
|
if (!result.is_null()) {
|
||||||
arguments.AcceptSideEffects();
|
arguments.AcceptSideEffects();
|
||||||
return ReadOnlyRoots(isolate).true_value();
|
return ReadOnlyRoots(isolate).true_value();
|
||||||
|
@ -43,6 +43,8 @@ inline uint64_t HashSeed(LocalIsolate* isolate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t HashSeed(ReadOnlyRoots roots) {
|
inline uint64_t HashSeed(ReadOnlyRoots roots) {
|
||||||
|
// eat shit
|
||||||
|
return 0xcbf29ce484222325;
|
||||||
uint64_t seed;
|
uint64_t seed;
|
||||||
roots.hash_seed().copy_out(0, reinterpret_cast<byte*>(&seed), kInt64Size);
|
roots.hash_seed().copy_out(0, reinterpret_cast<byte*>(&seed), kInt64Size);
|
||||||
return seed;
|
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, is_named, NamedBit::kShift)
|
||||||
BOOL_ACCESSORS(InterceptorInfo, flags, has_no_side_effect,
|
BOOL_ACCESSORS(InterceptorInfo, flags, has_no_side_effect,
|
||||||
HasNoSideEffectBit::kShift)
|
HasNoSideEffectBit::kShift)
|
||||||
|
BOOL_ACCESSORS(InterceptorInfo, flags, use_fastpath, UseFastpathBit::kShift)
|
||||||
|
|
||||||
bool CallHandlerInfo::IsSideEffectFreeCallHandlerInfo() const {
|
bool CallHandlerInfo::IsSideEffectFreeCallHandlerInfo() const {
|
||||||
ReadOnlyRoots roots = GetReadOnlyRoots();
|
ReadOnlyRoots roots = GetReadOnlyRoots();
|
||||||
|
@ -110,6 +110,7 @@ class InterceptorInfo
|
|||||||
DECL_BOOLEAN_ACCESSORS(non_masking)
|
DECL_BOOLEAN_ACCESSORS(non_masking)
|
||||||
DECL_BOOLEAN_ACCESSORS(is_named)
|
DECL_BOOLEAN_ACCESSORS(is_named)
|
||||||
DECL_BOOLEAN_ACCESSORS(has_no_side_effect)
|
DECL_BOOLEAN_ACCESSORS(has_no_side_effect)
|
||||||
|
DECL_BOOLEAN_ACCESSORS(use_fastpath)
|
||||||
|
|
||||||
DEFINE_TORQUE_GENERATED_INTERCEPTOR_INFO_FLAGS()
|
DEFINE_TORQUE_GENERATED_INTERCEPTOR_INFO_FLAGS()
|
||||||
|
|
||||||
|
@ -16,6 +16,14 @@ bitfield struct InterceptorInfoFlags extends uint31 {
|
|||||||
non_masking: bool: 1 bit;
|
non_masking: bool: 1 bit;
|
||||||
named: bool: 1 bit;
|
named: bool: 1 bit;
|
||||||
has_no_side_effect: 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 {
|
extern class InterceptorInfo extends Struct {
|
||||||
|
@ -1207,6 +1207,35 @@ MaybeHandle<Object> GetPropertyWithInterceptorInternal(
|
|||||||
ASSIGN_RETURN_ON_EXCEPTION(
|
ASSIGN_RETURN_ON_EXCEPTION(
|
||||||
isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
|
isolate, receiver, Object::ConvertReceiver(isolate, receiver), Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
||||||
*holder, Just(kDontThrow));
|
*holder, Just(kDontThrow));
|
||||||
|
|
||||||
@ -1224,6 +1253,7 @@ MaybeHandle<Object> GetPropertyWithInterceptorInternal(
|
|||||||
// Rebox handle before return
|
// Rebox handle before return
|
||||||
return handle(*result, isolate);
|
return handle(*result, isolate);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
|
Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
|
||||||
LookupIterator* it, Handle<InterceptorInfo> interceptor) {
|
LookupIterator* it, Handle<InterceptorInfo> interceptor) {
|
||||||
@ -1236,21 +1266,28 @@ Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
|
|||||||
Handle<JSObject> holder = it->GetHolder<JSObject>();
|
Handle<JSObject> holder = it->GetHolder<JSObject>();
|
||||||
DCHECK_IMPLIES(!it->IsElement(*holder) && it->name()->IsSymbol(),
|
DCHECK_IMPLIES(!it->IsElement(*holder) && it->name()->IsSymbol(),
|
||||||
interceptor->can_intercept_symbols());
|
interceptor->can_intercept_symbols());
|
||||||
|
|
||||||
Handle<Object> receiver = it->GetReceiver();
|
Handle<Object> receiver = it->GetReceiver();
|
||||||
|
|
||||||
if (!receiver->IsJSReceiver()) {
|
if (!receiver->IsJSReceiver()) {
|
||||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
|
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
|
||||||
Object::ConvertReceiver(isolate, receiver),
|
Object::ConvertReceiver(isolate, receiver),
|
||||||
Nothing<PropertyAttributes>());
|
Nothing<PropertyAttributes>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!interceptor->query().IsUndefined(isolate)) {
|
||||||
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
||||||
*holder, Just(kDontThrow));
|
*holder, Just(kDontThrow));
|
||||||
if (!interceptor->query().IsUndefined(isolate)) {
|
|
||||||
Handle<Object> result;
|
Handle<Object> result;
|
||||||
if (it->IsElement(*holder)) {
|
if (it->IsElement(*holder)) {
|
||||||
result = args.CallIndexedQuery(interceptor, it->array_index());
|
result = args.CallIndexedQuery(interceptor, it->array_index());
|
||||||
} else {
|
} else {
|
||||||
result = args.CallNamedQuery(interceptor, it->name());
|
result = args.CallNamedQuery(interceptor, it->name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RETURN_VALUE_IF_SCHEDULED_EXCEPTION_DETECTOR(isolate, args,
|
||||||
|
Nothing<PropertyAttributes>());
|
||||||
|
|
||||||
if (!result.is_null()) {
|
if (!result.is_null()) {
|
||||||
int32_t value;
|
int32_t value;
|
||||||
CHECK(result->ToInt32(&value));
|
CHECK(result->ToInt32(&value));
|
||||||
@ -1263,27 +1300,16 @@ Maybe<PropertyAttributes> GetPropertyAttributesWithInterceptorInternal(
|
|||||||
return Just(static_cast<PropertyAttributes>(value));
|
return Just(static_cast<PropertyAttributes>(value));
|
||||||
}
|
}
|
||||||
} else if (!interceptor->getter().IsUndefined(isolate)) {
|
} else if (!interceptor->getter().IsUndefined(isolate)) {
|
||||||
// TODO(verwaest): Use GetPropertyWithInterceptor?
|
return Just(NONE);
|
||||||
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_VALUE_IF_SCHEDULED_EXCEPTION_DETECTOR(isolate, args,
|
|
||||||
Nothing<PropertyAttributes>());
|
|
||||||
return Just(ABSENT);
|
return Just(ABSENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<bool> SetPropertyWithInterceptorInternal(
|
Maybe<bool> SetPropertyWithInterceptorInternal(
|
||||||
LookupIterator* it, Handle<InterceptorInfo> interceptor,
|
LookupIterator* it, Handle<InterceptorInfo> interceptor,
|
||||||
Maybe<ShouldThrow> should_throw, Handle<Object> value) {
|
Maybe<ShouldThrow> should_throw, Handle<Object> value) {
|
||||||
|
bool result;
|
||||||
Isolate* isolate = it->isolate();
|
Isolate* isolate = it->isolate();
|
||||||
// Make sure that the top context does not change when doing callbacks or
|
// Make sure that the top context does not change when doing callbacks or
|
||||||
// interceptor calls.
|
// interceptor calls.
|
||||||
@ -1292,11 +1318,28 @@ Maybe<bool> SetPropertyWithInterceptorInternal(
|
|||||||
if (interceptor->setter().IsUndefined(isolate)) return Just(false);
|
if (interceptor->setter().IsUndefined(isolate)) return Just(false);
|
||||||
|
|
||||||
Handle<JSObject> holder = it->GetHolder<JSObject>();
|
Handle<JSObject> holder = it->GetHolder<JSObject>();
|
||||||
bool result;
|
|
||||||
Handle<Object> receiver = it->GetReceiver();
|
Handle<Object> receiver = it->GetReceiver();
|
||||||
|
|
||||||
|
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 {
|
||||||
if (!receiver->IsJSReceiver()) {
|
if (!receiver->IsJSReceiver()) {
|
||||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, receiver,
|
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||||
Object::ConvertReceiver(isolate, receiver),
|
isolate, receiver, Object::ConvertReceiver(isolate, receiver),
|
||||||
Nothing<bool>());
|
Nothing<bool>());
|
||||||
}
|
}
|
||||||
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
||||||
@ -1314,6 +1357,8 @@ Maybe<bool> SetPropertyWithInterceptorInternal(
|
|||||||
RETURN_VALUE_IF_SCHEDULED_EXCEPTION_DETECTOR(it->isolate(), args,
|
RETURN_VALUE_IF_SCHEDULED_EXCEPTION_DETECTOR(it->isolate(), args,
|
||||||
Nothing<bool>());
|
Nothing<bool>());
|
||||||
if (result) args.AcceptSideEffects();
|
if (result) args.AcceptSideEffects();
|
||||||
|
}
|
||||||
|
|
||||||
return Just(result);
|
return Just(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,6 +233,7 @@ class Map : public TorqueGeneratedMap<Map, HeapObject> {
|
|||||||
DECL_GETTER(GetNamedInterceptor, InterceptorInfo)
|
DECL_GETTER(GetNamedInterceptor, InterceptorInfo)
|
||||||
DECL_GETTER(GetIndexedInterceptor, InterceptorInfo)
|
DECL_GETTER(GetIndexedInterceptor, InterceptorInfo)
|
||||||
|
|
||||||
|
DECL_GETTER(GetCachedPropertyHandler, InterceptorInfo)
|
||||||
// Instance type.
|
// Instance type.
|
||||||
DECL_PRIMITIVE_ACCESSORS(instance_type, InstanceType)
|
DECL_PRIMITIVE_ACCESSORS(instance_type, InstanceType)
|
||||||
|
|
||||||
|
@ -68,6 +68,9 @@ extern class Map extends HeapObject {
|
|||||||
@if(TAGGED_SIZE_8_BYTES) optional_padding: uint32;
|
@if(TAGGED_SIZE_8_BYTES) optional_padding: uint32;
|
||||||
@ifnot(TAGGED_SIZE_8_BYTES) optional_padding: void;
|
@ifnot(TAGGED_SIZE_8_BYTES) optional_padding: void;
|
||||||
|
|
||||||
|
cached_property_handler: InterceptorInfo|Undefined;
|
||||||
|
pad: Undefined;
|
||||||
|
|
||||||
prototype: JSReceiver|Null;
|
prototype: JSReceiver|Null;
|
||||||
constructor_or_back_pointer_or_native_context: Object;
|
constructor_or_back_pointer_or_native_context: Object;
|
||||||
instance_descriptors: DescriptorArray;
|
instance_descriptors: DescriptorArray;
|
||||||
|
@ -788,10 +788,8 @@ Handle<String> String::Share(Isolate* isolate, Handle<String> string) {
|
|||||||
case StringTransitionStrategy::kCopy:
|
case StringTransitionStrategy::kCopy:
|
||||||
return SlowShare(isolate, string);
|
return SlowShare(isolate, string);
|
||||||
case StringTransitionStrategy::kInPlace:
|
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());
|
DCHECK(string->InSharedHeap());
|
||||||
string->set_map_no_write_barrier(*new_map.ToHandleChecked());
|
string->set_map(*new_map.ToHandleChecked());
|
||||||
return string;
|
return string;
|
||||||
case StringTransitionStrategy::kAlreadyTransitioned:
|
case StringTransitionStrategy::kAlreadyTransitioned:
|
||||||
return string;
|
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
|
// A relaxed write is sufficient here, because at this point the string
|
||||||
// has not yet escaped the current thread.
|
// has not yet escaped the current thread.
|
||||||
DCHECK(flat->InSharedHeap());
|
DCHECK(flat->InSharedHeap());
|
||||||
flat->set_map_no_write_barrier(*new_map.ToHandleChecked());
|
flat->set_map(*new_map.ToHandleChecked());
|
||||||
return flat;
|
return flat;
|
||||||
case StringTransitionStrategy::kAlreadyTransitioned:
|
case StringTransitionStrategy::kAlreadyTransitioned:
|
||||||
return flat;
|
return flat;
|
||||||
|
Loading…
Reference in New Issue
Block a user