Add Instanceof IC

issues:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I647H9

Signed-off-by: lvfuqing <lvfuqing1@huawei.com>
Change-Id: I535da661f62985d7147ab5fd57830011b5c55765
This commit is contained in:
lvfuqing 2022-12-09 11:53:08 +08:00
parent 7f56f31591
commit 4751856dfb
11 changed files with 171 additions and 4 deletions

View File

@ -2037,10 +2037,45 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t
uint16_t v0 = READ_INST_8_1();
LOG_INST() << "intrinsics::instanceof"
<< " v" << v0;
JSTaggedValue obj = GET_VREG_VALUE(v0);
JSTaggedValue object = GET_VREG_VALUE(v0);
JSTaggedValue target = GET_ACC();
#if ECMASCRIPT_ENABLE_IC
// 1. If Type(target) is not Object, throw a TypeError exception.
if (target.IsECMAObject()) {
// 2. Let instOfHandler be GetMethod(target, @@hasInstance).
auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp);
if (!profileTypeInfo.IsUndefined()) {
uint16_t slotId = READ_INST_8_0();
auto profileTypeArray = ProfileTypeInfo::Cast(profileTypeInfo.GetTaggedObject());
JSTaggedValue firstValue = profileTypeArray->Get(slotId);
JSTaggedValue instOfHandler = JSTaggedValue::Hole();
JSTaggedValue res = JSTaggedValue::Hole();
if (LIKELY(firstValue.IsHeapObject())) {
JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1);
instOfHandler = ICRuntimeStub::TryLoadICByName(thread, target, firstValue, secondValue);
}
if (LIKELY(!instOfHandler.IsHole())) {
res = SlowRuntimeStub::InstanceofByHandler(thread, target, object, instOfHandler);
} else if (!firstValue.IsHole()) {
// IC Miss
profileTypeInfo = GetRuntimeProfileTypeInfo(sp);
profileTypeArray = ProfileTypeInfo::Cast(profileTypeInfo.GetTaggedObject());
EcmaVM *vm = thread->GetEcmaVM();
JSTaggedValue key = vm->GetGlobalEnv()->GetHasInstanceSymbol().GetTaggedValue();
instOfHandler = ICRuntimeStub::LoadICByName(thread, profileTypeArray, target, key, slotId);
res = SlowRuntimeStub::InstanceofByHandler(thread, target, object, instOfHandler);
}
if (LIKELY(!res.IsHole())) {
INTERPRETER_RETURN_IF_ABRUPT(res);
SET_ACC(res);
DISPATCH(INSTANCEOF_IMM8_V8);
}
}
}
#endif
SAVE_PC();
JSTaggedValue res = SlowRuntimeStub::Instanceof(thread, obj, target);
JSTaggedValue res = SlowRuntimeStub::Instanceof(thread, object, target);
INTERPRETER_RETURN_IF_ABRUPT(res);
SET_ACC(res);
DISPATCH(INSTANCEOF_IMM8_V8);

View File

@ -388,6 +388,19 @@ JSTaggedValue SlowRuntimeStub::Instanceof(JSThread *thread, JSTaggedValue obj, J
return RuntimeStubs::RuntimeInstanceof(thread, objHandle, targetHandle);
}
JSTaggedValue SlowRuntimeStub::InstanceofByHandler(JSThread *thread, JSTaggedValue target, JSTaggedValue object,
JSTaggedValue instOfHandler)
{
INTERPRETER_TRACE(thread, InstanceofByHandler);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> objectHandle(thread, object);
JSHandle<JSTaggedValue> targetHandle(thread, target);
JSHandle<JSTaggedValue> instOfHandle(thread, instOfHandler);
return RuntimeStubs::RuntimeInstanceofByHandler(thread, targetHandle, objectHandle, instOfHandle);
}
JSTaggedValue SlowRuntimeStub::NewLexicalEnv(JSThread *thread, uint16_t numVars)
{
INTERPRETER_TRACE(thread, Newlexenv);

View File

@ -66,6 +66,8 @@ public:
static JSTaggedValue Exp(JSThread *thread, JSTaggedValue base, JSTaggedValue exponent);
static JSTaggedValue IsIn(JSThread *thread, JSTaggedValue prop, JSTaggedValue obj);
static JSTaggedValue Instanceof(JSThread *thread, JSTaggedValue obj, JSTaggedValue target);
static JSTaggedValue InstanceofByHandler(JSThread *thread, JSTaggedValue target, JSTaggedValue object,
JSTaggedValue instOfHandler);
static JSTaggedValue NewLexicalEnv(JSThread *thread, uint16_t numVars);
static JSTaggedValue NewLexicalEnvWithName(JSThread *thread, uint16_t numVars, uint16_t scopeId);

View File

@ -1391,6 +1391,8 @@ void PandaFileTranslator::UpdateICOffset(MethodLiteral *methodLiteral, uint8_t *
case EcmaOpcode::STGLOBALVAR_IMM16_ID16:
offset = methodLiteral->UpdateSlotSizeWith8Bit(1);
break;
case EcmaOpcode::INSTANCEOF_IMM8_V8:
U_FALLTHROUGH;
case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
U_FALLTHROUGH;
case EcmaOpcode::STOWNBYVALUE_IMM8_V8_V8:

View File

@ -84,6 +84,7 @@ namespace panda::ecmascript {
V(Ldnewobjrange) \
V(IsIn) \
V(Instanceof) \
V(InstanceofByHandler) \
V(NewObjApply) \
V(CallArg0) \
V(CallArg1) \

View File

@ -124,6 +124,34 @@ JSTaggedValue RuntimeStubs::RuntimeInstanceof(JSThread *thread, const JSHandle<J
return JSTaggedValue(ret);
}
JSTaggedValue RuntimeStubs::RuntimeInstanceofByHandler(JSThread *thread, JSHandle<JSTaggedValue> target,
JSHandle<JSTaggedValue> object,
JSHandle<JSTaggedValue> instOfHandler)
{
// 3. ReturnIfAbrupt(instOfHandler).
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue(false));
// 4. If instOfHandler is not undefined, then
if (!instOfHandler->IsUndefined()) {
// a. Return ! ToBoolean(? Call(instOfHandler, target, «object»)).
JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, instOfHandler, target, undefined, 1);
info->SetCallArg(object.GetTaggedValue());
JSTaggedValue tagged = JSFunction::Call(info);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue(false));
return tagged;
}
// 5. If IsCallable(target) is false, throw a TypeError exception.
if (!target->IsCallable()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "InstanceOf error when target is not Callable", JSTaggedValue(false));
}
// 6. Return ? OrdinaryHasInstance(target, object).
bool res = JSFunction::OrdinaryHasInstance(thread, target, object);
return JSTaggedValue(res);
}
JSTaggedValue RuntimeStubs::RuntimeCreateGeneratorObj(JSThread *thread, const JSHandle<JSTaggedValue> &genFunc)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();

View File

@ -352,9 +352,12 @@ private:
static inline JSTaggedValue RuntimeDec(JSThread *thread, const JSHandle<JSTaggedValue> &value);
static inline JSTaggedValue RuntimeExp(JSThread *thread, JSTaggedValue base, JSTaggedValue exponent);
static inline JSTaggedValue RuntimeIsIn(JSThread *thread, const JSHandle<JSTaggedValue> &prop,
const JSHandle<JSTaggedValue> &obj);
const JSHandle<JSTaggedValue> &obj);
static inline JSTaggedValue RuntimeInstanceof(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
const JSHandle<JSTaggedValue> &target);
const JSHandle<JSTaggedValue> &target);
static inline JSTaggedValue RuntimeInstanceofByHandler(JSThread *thread, JSHandle<JSTaggedValue> target,
JSHandle<JSTaggedValue> object,
JSHandle<JSTaggedValue> instOfHandler);
static inline JSTaggedValue RuntimeCreateGeneratorObj(JSThread *thread, const JSHandle<JSTaggedValue> &genFunc);
static inline JSTaggedValue RuntimeCreateAsyncGeneratorObj(JSThread *thread,

View File

@ -38,6 +38,7 @@ group("ark_js_moduletest") {
"globalrecord:globalrecordAction",
"globalthis:globalthisAction",
"helloworld:helloworldAction",
"instanceofic:instanceoficAction",
"ldmodulensbyic:ldmodulensbyicAction",
"lexicalenv:lexicalenvAction",
"linkedhashtable:linkedhashtableAction",
@ -106,6 +107,7 @@ group("ark_asm_test") {
"globalrecord:globalrecordAsmAction",
"globalthis:globalthisAsmAction",
"helloworld:helloworldAsmAction",
"instanceofic:instanceoficAsmAction",
"ldmodulensbyic:ldmodulensbyicAction",
"lexicalenv:lexicalenvAsmAction",
"linkedhashtable:linkedhashtableAsmAction",
@ -166,6 +168,7 @@ group("ark_asm_single_step_test") {
"globalrecord:globalrecordAsmSingleStepAction",
"globalthis:globalthisAsmSingleStepAction",
"helloworld:helloworldAsmSingleStepAction",
"instanceofic:instanceoficAsmSingleStepAction",
"ldmodulensbyic:ldmodulensbyicAction",
"lexicalenv:lexicalenvAsmSingleStepAction",
"loadicbyvalue:loadicbyvalueAsmSingleStepAction",

View File

@ -0,0 +1,18 @@
# Copyright (c) 2021 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_moduletest_action("instanceofic") {
deps = []
}

View File

@ -0,0 +1,15 @@
# Copyright (c) 2021 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.
instanceoficsuccess
instanceoficsuccess

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2021 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.
*/
/*
* @tc.name:instanceofic
* @tc.desc:test instanceofic
* @tc.type: FUNC
* @tc.require: issueI5NO8G
*/
class F {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance);
}
};
let res;
for (let i = 300; i > 0; --i) {
res = [] instanceof F;
if (i == 150) {
if (res) {
print("instanceoficsuccess");
} else {
print("instanceoficfailse");
}
F[Symbol.hasInstance] = function() { return false };
}
if (i == 140) {
if (!res) {
print("instanceoficsuccess");
} else {
print("instanceoficfailse");
}
}
}