* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/compiler/access_object_stub_builder.h"
#include "ecmascript/compiler/ic_stub_builder.h"
#include "ecmascript/compiler/interpreter_stub-inl.h"
#include "ecmascript/compiler/profiler_operation.h"
#include "ecmascript/compiler/share_gate_meta_data.h"
namespace panda::ecmascript::kungfu {
GateRef AccessObjectStubBuilder::LoadObjByName(GateRef glue, GateRef receiver, GateRef prop, const StringIdInfo &info,
GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
Label tryPreDump(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
GateRef value = 0;
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
StartTraceLoadDetail(glue, receiver, profileTypeInfo, IntToTaggedInt(slotId));
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, prop, info, jsFunc_);
#else
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
#endif
builder.LoadICByName(&result, &tryFastPath, &tryPreDump, &exit, callback);
Bind(&tryFastPath);
{
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
result = GetPropertyByName(glue, receiver, propKey, Circuit::NullGate(), callback);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&tryPreDump);
{
callback.TryPreDump();
Jump(&slowPath);
}
Bind(&slowPath);
{
EndTraceLoad(glue);
StartTraceLoadSlowPath(glue);
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
result =
CallRuntime(glue, RTSTUB_ID(LoadICByName), {profileTypeInfo, receiver, propKey, IntToTaggedInt(slotId)});
Jump(&exit);
}
Bind(&exit);
EndTraceLoad(glue);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::LoadObjByNameWithMega(GateRef glue, GateRef receiver, GateRef megaStubCache,
GateRef propKey, GateRef jsFunc, GateRef slotId,
ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label slowPath(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
GateRef value = 0;
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
builder.SetParameters(glue, receiver, 0, value, slotId, megaStubCache, propKey, ProfileOperation());
builder.LoadICByNameWithMega(&result, nullptr, &slowPath, &exit, callback);
Bind(&slowPath);
{
GateRef profileTypeInfo = GetProfileTypeInfo(glue, jsFunc);
result =
CallRuntime(glue, RTSTUB_ID(LoadICByName), {profileTypeInfo, receiver, propKey, IntToTaggedInt(slotId)});
callback.TryPreDump();
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::StoreObjByNameWithMega(GateRef glue, GateRef receiver, GateRef value,
GateRef megaStubCache, GateRef propKey, GateRef jsFunc,
GateRef slotId, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
builder.SetParameters(glue, receiver, 0, value, slotId, megaStubCache, propKey, ProfileOperation());
builder.StoreICByNameWithMega(&result, nullptr, &slowPath, &exit);
Bind(&slowPath);
{
GateRef profileTypeInfo = GetProfileTypeInfo(glue, jsFunc);
result = CallRuntime(glue, RTSTUB_ID(StoreICByName),
{profileTypeInfo, receiver, propKey, value, IntToTaggedInt(slotId)});
callback.TryPreDump();
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::LoadPrivatePropertyByName(
GateRef glue, GateRef receiver, GateRef key, GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
Label tryPreDump(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
GateRef value = 0;
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
builder.LoadICByName(&result, &tryFastPath, &tryPreDump, &exit, callback);
Bind(&tryFastPath);
{
result = GetPropertyByName(glue, receiver, key, Circuit::NullGate(), callback);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&tryPreDump);
{
callback.TryPreDump();
Jump(&slowPath);
}
Bind(&slowPath);
{
result = CallRuntime(glue, RTSTUB_ID(LoadICByName), {profileTypeInfo, receiver, key, IntToTaggedInt(slotId)});
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::DeprecatedLoadObjByName(GateRef glue, GateRef receiver, GateRef propKey)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label fastPath(env);
Label slowPath(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
BRANCH(TaggedIsHeapObject(receiver), &fastPath, &slowPath);
Bind(&fastPath);
{
result = GetPropertyByName(glue, receiver, propKey);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&slowPath);
{
result = CallRuntime(glue, RTSTUB_ID(LoadICByName),
{ Undefined(), receiver, propKey, IntToTaggedInt(Int32(0xFF)) });
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::StoreObjByName(GateRef glue, GateRef receiver, GateRef prop, const StringIdInfo &info,
GateRef value, GateRef profileTypeInfo, GateRef slotId,
ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
Label tryPreDump(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
StartTraceStoreDetail(glue, receiver, profileTypeInfo, IntToTaggedInt(slotId));
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, callback);
builder.StoreICByName(&result, &tryFastPath, &tryPreDump, &exit);
Bind(&tryFastPath);
{
EndTraceStore(glue);
StartTraceStoreFastPath(glue);
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
result = SetPropertyByName(glue, receiver, propKey, value, false, True(), callback);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&tryPreDump);
{
callback.TryPreDump();
Jump(&slowPath);
}
Bind(&slowPath);
{
EndTraceStore(glue);
StartTraceStoreSlowPath(glue);
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
result = CallRuntime(
glue, RTSTUB_ID(StoreICByName), {profileTypeInfo, receiver, propKey, value, IntToTaggedInt(slotId)});
Jump(&exit);
}
Bind(&exit);
EndTraceStore(glue);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::StOwnICByName(GateRef glue, GateRef receiver, GateRef prop, const StringIdInfo &info,
GateRef value, GateRef profileTypeInfo, GateRef slotId,
ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
Label tryPreDump(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, callback);
builder.StoreICByName(&result, &tryFastPath, &tryPreDump, &exit);
Bind(&tryFastPath);
{
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
result = SetPropertyByName(glue, receiver, propKey, value, true, True(), callback);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&tryPreDump);
{
callback.TryPreDump();
Jump(&slowPath);
}
Bind(&slowPath);
{
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
result = CallRuntime(glue, RTSTUB_ID(StoreOwnICByName),
{profileTypeInfo, receiver, propKey, value, IntToTaggedInt(slotId)});
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::StorePrivatePropertyByName(GateRef glue,
GateRef receiver,
GateRef key,
GateRef value,
GateRef profileTypeInfo,
GateRef slotId,
ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
Label tryPreDump(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, callback);
builder.StoreICByName(&result, &tryFastPath, &tryPreDump, &exit);
Bind(&tryFastPath);
{
result = SetPropertyByName(glue, receiver, key, value, false, True(), callback);
Branch(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&tryPreDump);
{
callback.TryPreDump();
Jump(&slowPath);
}
Bind(&slowPath);
{
result = CallRuntime(
glue, RTSTUB_ID(StoreICByName), {profileTypeInfo, receiver, key, value, IntToTaggedInt(slotId)});
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
#if !ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef AccessObjectStubBuilder::ResolvePropKey(GateRef glue, GateRef prop, const StringIdInfo &info)
{
if (jsFunc_ != Circuit::NullGate()) {
GateRef constpool = GetConstPoolFromFunction(glue, jsFunc_);
return GetStringFromConstPool(glue, constpool, ChangeIntPtrToInt32(prop));
}
if (!info.IsValid()) {
return prop;
}
ASSERT(info.IsValid());
InterpreterToolsStubBuilder builder(GetCallSignature(), GetEnvironment());
GateRef stringId = builder.GetStringId(info);
return GetStringFromConstPool(glue, info.GetConstantPool(), stringId);
}
#endif
GateRef AccessObjectStubBuilder::LoadObjByValue(GateRef glue, GateRef receiver, GateRef key, GateRef profileTypeInfo,
GateRef slotId, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
Label tryPreDump(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
GateRef value = 0;
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
StartTraceLoadValueDetail(glue, receiver, profileTypeInfo, IntToTaggedInt(slotId), key);
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, key);
builder.LoadICByValue(&result, &tryFastPath, &tryPreDump, &exit, callback);
Bind(&tryFastPath);
{
result = GetPropertyByValue(glue, receiver, key, Circuit::NullGate(), callback);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&tryPreDump);
{
callback.TryPreDump();
Jump(&slowPath);
}
Bind(&slowPath);
{
EndTraceLoadValue(glue);
StartTraceLoadValueSlowPath(glue);
result = CallRuntime(glue, RTSTUB_ID(LoadICByValue), {profileTypeInfo, receiver, key, IntToTaggedInt(slotId)});
Jump(&exit);
}
Bind(&exit);
EndTraceLoadValue(glue);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::DeprecatedLoadObjByValue(GateRef glue, GateRef receiver, GateRef key)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label fastPath(env);
Label slowPath(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
BRANCH(TaggedIsHeapObject(receiver), &fastPath, &slowPath);
Bind(&fastPath);
{
result = GetPropertyByValue(glue, receiver, key);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&slowPath);
{
result = CallRuntime(glue, RTSTUB_ID(LoadICByValue),
{ Undefined(), receiver, key, IntToTaggedInt(Int32(0xFF)) });
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::StoreOwnByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value,
GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, IntToTaggedPtr(index), callback);
builder.StoreICByValue(&result, &tryFastPath, &slowPath, &exit);
Bind(&tryFastPath);
{
Label isHeapObject(env);
BRANCH(TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
Bind(&isHeapObject);
Label notClassConstructor(env);
BRANCH(IsClassConstructor(glue, receiver), &slowPath, ¬ClassConstructor);
Bind(¬ClassConstructor);
Label notClassPrototype(env);
BRANCH(IsClassPrototype(glue, receiver), &slowPath, ¬ClassPrototype);
Bind(¬ClassPrototype);
result = SetPropertyByIndex(glue, receiver, index, value, true);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&slowPath);
{
result = CallRuntime(glue, RTSTUB_ID(StoreOwnICByValue),
{ profileTypeInfo, receiver, IntToTaggedInt(index), value, IntToTaggedInt(slotId) });
callback.TryPreDump();
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::StoreObjByValue(GateRef glue, GateRef receiver, GateRef key, GateRef value,
GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
Label tryPreDump(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, key, callback);
builder.StoreICByValue(&result, &tryFastPath, &tryPreDump, &exit);
Bind(&tryFastPath);
{
result = SetPropertyByValue(glue, receiver, key, value, false, callback);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&tryPreDump);
{
callback.TryPreDump();
Jump(&slowPath);
}
Bind(&slowPath);
{
result = CallRuntime(
glue, RTSTUB_ID(StoreICByValue), {profileTypeInfo, receiver, key, value, IntToTaggedInt(slotId)});
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::TryLoadGlobalByName(GateRef glue, GateRef prop, const StringIdInfo &info,
GateRef profileTypeInfo, GateRef slotId,
ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
GateRef receiver = 0;
GateRef value = 0;
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
builder.TryLoadGlobalICByName(&result, &tryFastPath, &slowPath, &exit);
Bind(&tryFastPath);
{
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
#if ENABLE_V70_OPTIMIZATION
GlobalEnvScope scope(this);
#endif
GateRef record = LdGlobalRecord(glue, propKey);
Label foundInRecord(env);
Label notFoundInRecord(env);
BRANCH(TaggedIsUndefined(record), ¬FoundInRecord, &foundInRecord);
Bind(&foundInRecord);
{
result = Load(VariableType::JS_ANY(), glue, record, IntPtr(PropertyBox::VALUE_OFFSET));
Jump(&exit);
}
Bind(¬FoundInRecord);
{
GateRef globalObject = GetGlobalObject(glue, GetCurrentGlobalEnv());
result = GetGlobalOwnProperty(glue, globalObject, propKey, callback);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
}
Bind(&slowPath);
{
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
#if ENABLE_V70_OPTIMIZATION
GlobalEnvScope scope(this);
#endif
result = CallRuntimeWithGlobalEnv(glue,
GetCurrentGlobalEnv(),
RTSTUB_ID(TryLdGlobalICByName),
{profileTypeInfo, propKey, IntToTaggedInt(slotId)});
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::TryStoreGlobalByName(GateRef glue, GateRef prop, const StringIdInfo &info,
GateRef value, GateRef profileTypeInfo, GateRef slotId,
ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
GateRef receiver = 0;
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
builder.TryStoreGlobalICByName(&result, &tryFastPath, &slowPath, &exit);
Bind(&tryFastPath);
{
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
#if ENABLE_V70_OPTIMIZATION
GlobalEnvScope scope(this);
#endif
GateRef record = LdGlobalRecord(glue, propKey);
Label foundInRecord(env);
Label notFoundInRecord(env);
BRANCH(TaggedIsUndefined(record), ¬FoundInRecord, &foundInRecord);
Bind(&foundInRecord);
{
result = CallRuntimeWithGlobalEnv(
glue, GetCurrentGlobalEnv(), RTSTUB_ID(TryUpdateGlobalRecord), {propKey, value});
Jump(&exit);
}
Bind(¬FoundInRecord);
{
GateRef globalEnv = GetCurrentGlobalEnv();
GateRef globalObject = GetGlobalObject(glue, globalEnv);
result = GetGlobalOwnProperty(glue, globalObject, propKey, callback);
Label isFoundInGlobal(env);
Label notFoundInGlobal(env);
BRANCH(TaggedIsHole(*result), ¬FoundInGlobal, &isFoundInGlobal);
Bind(&isFoundInGlobal);
{
result = CallRuntimeWithGlobalEnv(glue, globalEnv, RTSTUB_ID(StGlobalVar), { propKey, value });
Jump(&exit);
}
Bind(¬FoundInGlobal);
{
result = CallRuntimeWithGlobalEnv(glue, globalEnv, RTSTUB_ID(ThrowReferenceError), { propKey });
Jump(&exit);
}
}
}
Bind(&slowPath);
{
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
#if ENABLE_V70_OPTIMIZATION
GlobalEnvScope scope(this);
#endif
GateRef globalEnv = GetCurrentGlobalEnv();
GateRef globalObject = GetGlobalObject(glue, globalEnv);
result = CallRuntimeWithGlobalEnv(glue, globalEnv, RTSTUB_ID(StoreMiss),
{ profileTypeInfo, globalObject, propKey, value, IntToTaggedInt(slotId),
IntToTaggedInt(Int32(static_cast<int>(ICKind::NamedGlobalTryStoreIC))) });
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::LoadGlobalVar(GateRef glue, GateRef prop, const StringIdInfo &info,
GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
GateRef receiver = 0;
GateRef value = 0;
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
builder.TryLoadGlobalICByName(&result, &tryFastPath, &slowPath, &exit);
Bind(&tryFastPath);
{
#if ENABLE_V70_OPTIMIZATION
GlobalEnvScope scope(this);
#endif
GateRef globalObject = GetGlobalObject(glue, GetCurrentGlobalEnv());
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
result = GetGlobalOwnProperty(glue, globalObject, propKey, callback);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&slowPath);
{
#if ENABLE_V70_OPTIMIZATION
GlobalEnvScope scope(this);
#endif
GateRef globalEnv = GetCurrentGlobalEnv();
GateRef globalObject = GetGlobalObject(glue, globalEnv);
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
result = CallRuntimeWithGlobalEnv(glue, globalEnv, RTSTUB_ID(LdGlobalICVar),
{ globalObject, propKey, profileTypeInfo, IntToTaggedInt(slotId) });
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::StoreGlobalVar(GateRef glue, GateRef prop, const StringIdInfo &info,
GateRef value, GateRef profileTypeInfo, GateRef slotId)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label tryFastPath(env);
Label slowPath(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
GateRef receiver = 0;
ICStubBuilder builder(this);
PropagateGlobalEnvTo(&builder);
builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
builder.TryStoreGlobalICByName(&result, &tryFastPath, &slowPath, &exit);
Bind(&tryFastPath);
{
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
#if ENABLE_V70_OPTIMIZATION
GlobalEnvScope scope(this);
#endif
GateRef globalEnv = GetCurrentGlobalEnv();
result = CallRuntimeWithGlobalEnv(glue, globalEnv, RTSTUB_ID(StGlobalVar), { propKey, value });
Jump(&exit);
}
Bind(&slowPath);
{
#if ECMASCRIPT_ENABLE_NOT_FOUND_IC_CHECK
GateRef propKey = ResolvePropKey(glue, prop, info, jsFunc_);
#else
GateRef propKey = ResolvePropKey(glue, prop, info);
#endif
#if ENABLE_V70_OPTIMIZATION
GlobalEnvScope scope(this);
#endif
GateRef globalEnv = GetCurrentGlobalEnv();
GateRef globalObject = GetGlobalObject(glue, globalEnv);
result = CallRuntimeWithGlobalEnv(glue, globalEnv, RTSTUB_ID(StoreMiss),
{ profileTypeInfo, globalObject, propKey, value, IntToTaggedInt(slotId),
IntToTaggedInt(Int32(static_cast<int>(ICKind::NamedGlobalStoreIC))) });
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::StOwnByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
Label isHeapObject(env);
Label slowPath(env);
Label exit(env);
BRANCH(TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
Bind(&isHeapObject);
Label notClassConstructor(env);
BRANCH(IsClassConstructor(glue, receiver), &slowPath, ¬ClassConstructor);
Bind(¬ClassConstructor);
Label notClassPrototype(env);
BRANCH(IsClassPrototype(glue, receiver), &slowPath, ¬ClassPrototype);
Bind(¬ClassPrototype);
{
result = SetPropertyByIndex(glue, receiver, TruncInt64ToInt32(index), value, true);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&slowPath);
{
result = CallRuntime(glue, RTSTUB_ID(StOwnByIndex), {receiver, IntToTaggedInt(index), value });
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::StOwnByValue(GateRef glue, GateRef receiver, GateRef key, GateRef value)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
Label isHeapObject(env);
Label slowPath(env);
Label exit(env);
BRANCH(TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
Bind(&isHeapObject);
Label notClassConstructor(env);
BRANCH(IsClassConstructor(glue, receiver), &slowPath, ¬ClassConstructor);
Bind(¬ClassConstructor);
Label notClassPrototype(env);
BRANCH(IsClassPrototype(glue, receiver), &slowPath, ¬ClassPrototype);
Bind(¬ClassPrototype);
{
result = SetPropertyByValue(glue, receiver, key, value, true);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&slowPath);
{
result = CallRuntime(glue, RTSTUB_ID(StOwnByValue), { receiver, key, value });
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::StOwnByName(GateRef glue, GateRef receiver, GateRef key, GateRef value)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
Label isJSObject(env);
Label slowPath(env);
Label exit(env);
BRANCH(IsJSObject(glue, receiver), &isJSObject, &slowPath);
Bind(&isJSObject);
Label notClassConstructor(env);
BRANCH(IsClassConstructor(glue, receiver), &slowPath, ¬ClassConstructor);
Bind(¬ClassConstructor);
Label notClassPrototype(env);
BRANCH(IsClassPrototype(glue, receiver), &slowPath, ¬ClassPrototype);
Bind(¬ClassPrototype);
{
result = SetPropertyByName(glue, receiver, key, value, true, True());
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&slowPath);
{
result = CallRuntime(glue, RTSTUB_ID(StOwnByName), { receiver, key, value });
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::StOwnByValueWithNameSet(GateRef glue, GateRef receiver, GateRef key, GateRef value)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
Label isHeapObject(env);
Label slowPath(env);
Label notClassConstructor(env);
Label notClassPrototype(env);
Label notHole(env);
Label exit(env);
BRANCH(TaggedIsHeapObject(receiver), &isHeapObject, &slowPath);
Bind(&isHeapObject);
{
BRANCH(IsClassConstructor(glue, receiver), &slowPath, ¬ClassConstructor);
Bind(¬ClassConstructor);
{
BRANCH(IsClassPrototype(glue, receiver), &slowPath, ¬ClassPrototype);
Bind(¬ClassPrototype);
{
result = SetPropertyByValue(glue, receiver, key, value, true, ProfileOperation(), true);
BRANCH(TaggedIsHole(*result), &slowPath, ¬Hole);
Bind(¬Hole);
{
Label notexception(env);
BRANCH(TaggedIsException(*result), &exit, ¬exception);
Bind(¬exception);
CallRuntime(glue, RTSTUB_ID(SetFunctionNameNoPrefix), { value, key });
Jump(&exit);
}
}
}
}
Bind(&slowPath);
{
result = CallRuntime(glue, RTSTUB_ID(StOwnByValueWithNameSet), { receiver, key, value });
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::StOwnByNameWithNameSet(GateRef glue, GateRef receiver, GateRef key, GateRef value)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
Label isJSObject(env);
Label notJSObject(env);
Label notClassConstructor(env);
Label notClassPrototype(env);
Label notHole(env);
Label exit(env);
BRANCH(IsJSObject(glue, receiver), &isJSObject, ¬JSObject);
Bind(&isJSObject);
{
BRANCH(IsClassConstructor(glue, receiver), ¬JSObject, ¬ClassConstructor);
Bind(¬ClassConstructor);
{
BRANCH(IsClassPrototype(glue, receiver), ¬JSObject, ¬ClassPrototype);
Bind(¬ClassPrototype);
{
result = SetPropertyByName(glue, receiver, key, value, true, True(), ProfileOperation(), false, true);
BRANCH(TaggedIsHole(*result), ¬JSObject, ¬Hole);
Bind(¬Hole);
{
Label notException(env);
BRANCH(TaggedIsException(*result), &exit, ¬Exception);
Bind(¬Exception);
CallRuntime(glue, RTSTUB_ID(SetFunctionNameNoPrefix), {value, key});
Jump(&exit);
}
}
}
}
Bind(¬JSObject);
{
result = CallRuntime(glue, RTSTUB_ID(StOwnByNameWithNameSet), { receiver, key, value });
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::StObjByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
Label exit(env);
Label fastPath(env);
Label slowPath(env);
BRANCH(TaggedIsHeapObject(receiver), &fastPath, &slowPath);
Bind(&fastPath);
{
result = SetPropertyByIndex(glue, receiver, TruncInt64ToInt32(index), value, false);
BRANCH(TaggedIsHole(*result), &slowPath, &exit);
}
Bind(&slowPath);
{
result = CallRuntime(glue, RTSTUB_ID(StObjByIndex), {receiver, IntToTaggedInt(index), value});
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef AccessObjectStubBuilder::LdObjByIndex(GateRef glue, GateRef receiver, GateRef index)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
DEFVARIABLE(varAcc, VariableType::JS_ANY(), Hole());
Label fastPath(env);
Label slowPath(env);
Label exit(env);
BRANCH(TaggedIsHeapObject(receiver), &fastPath, &slowPath);
Bind(&fastPath);
{
varAcc = GetPropertyByIndex(glue, receiver, TruncInt64ToInt32(index), ProfileOperation());
BRANCH(TaggedIsHole(*varAcc), &slowPath, &exit);
}
Bind(&slowPath);
{
GateRef undefined = Undefined();
auto args = { receiver, IntToTaggedInt(index), TaggedFalse(), undefined };
varAcc = CallRuntime(glue, RTSTUB_ID(LdObjByIndex), args);
Jump(&exit);
}
Bind(&exit);
auto ret = *varAcc;
env->SubCfgExit();
return ret;
}
}