diff --git a/ecmascript/ecma_isa.yaml b/ecmascript/ecma_isa.yaml index 3a59436ab3b7b3ce20cf8fa6358a7efb6f6fb073..26a06b0b2fc03230b739a2ec86ffa15d701d3960 100644 --- a/ecmascript/ecma_isa.yaml +++ b/ecmascript/ecma_isa.yaml @@ -577,3 +577,12 @@ groups: prefix: ecma format: [pref_op_id_32] properties: [string_id] + - sig: ecma.stownbyvaluewithnameset v1:in:top, v2:in:top + acc: in:top + prefix: ecma + format: [pref_op_v1_8_v2_8] + - sig: ecma.stownbynamewithnameset string_id, v:in:top + acc: in:top + prefix: ecma + format: [pref_op_id_32_v_8] + properties: [string_id] diff --git a/ecmascript/interpreter/interpreter-inl.h b/ecmascript/interpreter/interpreter-inl.h index 99efe62c898a8b9f80112c357b8041fd98da66a2..f70d136fca7c8a04709d7f98edd2fdebac469d66 100644 --- a/ecmascript/interpreter/interpreter-inl.h +++ b/ecmascript/interpreter/interpreter-inl.h @@ -2303,9 +2303,6 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool value = GET_ACC(); if (!res.IsHole()) { INTERPRETER_RETURN_IF_ABRUPT(res); - if (value.IsJSFunction()) { - JSFunction::SetFunctionNameNoPrefix(thread, JSFunction::Cast(value.GetTaggedObject()), propKey); - } RESTORE_ACC(); DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); } @@ -2745,6 +2742,73 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool DISPATCH(BytecodeInstruction::Format::PREF_ID32); } + HANDLE_OPCODE(HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8) { + uint32_t v0 = READ_INST_8_1(); + uint32_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsics::stownbyvaluewithnameset" + << " v" << v0 << " v" << v1; + JSTaggedValue receiver = GET_VREG_VALUE(v0); + if (receiver.IsHeapObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) { + SAVE_ACC(); + JSTaggedValue propKey = GET_VREG_VALUE(v1); + JSTaggedValue value = GET_ACC(); + // fast path + JSTaggedValue res = FastRuntimeStub::SetPropertyByValue(thread, receiver, propKey, value); + + // SetPropertyByValue maybe gc need update the value + RESTORE_ACC(); + propKey = GET_VREG_VALUE(v1); + value = GET_ACC(); + if (!res.IsHole()) { + INTERPRETER_RETURN_IF_ABRUPT(res); + JSFunction::SetFunctionNameNoPrefix(thread, JSFunction::Cast(value.GetTaggedObject()), propKey); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + } + + // slow path + SAVE_ACC(); + receiver = GET_VREG_VALUE(v0); // Maybe moved by GC + auto propKey = GET_VREG_VALUE(v1); // Maybe moved by GC + auto value = GET_ACC(); // Maybe moved by GC + JSTaggedValue res = SlowRuntimeStub::StOwnByValueWithNameSet(thread, receiver, propKey, value); + RESTORE_ACC(); + INTERPRETER_RETURN_IF_ABRUPT(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8) { + uint32_t stringId = READ_INST_32_1(); + uint32_t v0 = READ_INST_8_5(); + LOG_INST() << "intrinsics::stownbynamewithnameset " + << "v" << v0 << " stringId:" << stringId; + + JSTaggedValue receiver = GET_VREG_VALUE(v0); + if (receiver.IsJSObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) { + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + JSTaggedValue value = GET_ACC(); + // fast path + SAVE_ACC(); + JSTaggedValue res = FastRuntimeStub::SetPropertyByName(thread, receiver, propKey, value); + if (!res.IsHole()) { + INTERPRETER_RETURN_IF_ABRUPT(res); + JSFunction::SetFunctionNameNoPrefix(thread, JSFunction::Cast(value.GetTaggedObject()), propKey); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + RESTORE_ACC(); + } + + SAVE_ACC(); + receiver = GET_VREG_VALUE(v0); // Maybe moved by GC + auto propKey = constpool->GetObjectFromCache(stringId); // Maybe moved by GC + auto value = GET_ACC(); // Maybe moved by GC + JSTaggedValue res = SlowRuntimeStub::StOwnByNameWithNameSet(thread, receiver, propKey, value); + RESTORE_ACC(); + INTERPRETER_RETURN_IF_ABRUPT(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + HANDLE_OPCODE(HANDLE_LDGLOBALVAR_PREF_ID32) { uint32_t stringId = READ_INST_32_1(); JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); diff --git a/ecmascript/interpreter/interpreter.h b/ecmascript/interpreter/interpreter.h index 62964b5a7da72604bcc56228f5b9b2e7ada53de2..cb988f370138aae771da0c4d057671abfa2a8989 100644 --- a/ecmascript/interpreter/interpreter.h +++ b/ecmascript/interpreter/interpreter.h @@ -214,6 +214,8 @@ enum EcmaOpcode { STCONSTTOGLOBALRECORD_PREF_ID32, STLETTOGLOBALRECORD_PREF_ID32, STCLASSTOGLOBALRECORD_PREF_ID32, + STOWNBYVALUEWITHNAMESET_PREF_V8_V8, + STOWNBYNAMEWITHNAMESET_PREF_ID32_V8, MOV_DYN_V8_V8, MOV_DYN_V16_V16, LDA_STR_ID32, diff --git a/ecmascript/interpreter/slow_runtime_stub.cpp b/ecmascript/interpreter/slow_runtime_stub.cpp index 5874bcd6cb94543c838b29b4afb366a02a4967a6..2c08c94165340c862ecee1a520f9a4b10a8dc32f 100644 --- a/ecmascript/interpreter/slow_runtime_stub.cpp +++ b/ecmascript/interpreter/slow_runtime_stub.cpp @@ -740,6 +740,32 @@ JSTaggedValue SlowRuntimeStub::StOwnByName(JSThread *thread, JSTaggedValue obj, return JSTaggedValue::True(); } +JSTaggedValue SlowRuntimeStub::StOwnByNameWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, + JSTaggedValue value) +{ + INTERPRETER_TRACE(thread, StOwnByNameDyn); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + JSHandle objHandle(thread, obj); + JSHandle propHandle(thread, prop); + JSHandle valueHandle(thread, value); + ASSERT(propHandle->IsStringOrSymbol()); + + JSHandle propKey = JSTaggedValue::ToPropertyKey(thread, propHandle); + + // property in class is non-enumerable + bool enumerable = !(objHandle->IsClassPrototype() || objHandle->IsClassConstructor()); + + PropertyDescriptor desc(thread, valueHandle, true, enumerable, true); + bool ret = JSTaggedValue::DefineOwnProperty(thread, objHandle, propHandle, desc); + if (!ret) { + return ThrowTypeError(thread, "SetOwnByNameWithNameSet failed"); + } + JSFunctionBase::SetFunctionName(thread, JSHandle::Cast(valueHandle), propKey, + JSHandle(thread, JSTaggedValue::Undefined())); + return JSTaggedValue::True(); +} + JSTaggedValue SlowRuntimeStub::StOwnByIndex(JSThread *thread, JSTaggedValue obj, uint32_t idx, JSTaggedValue value) { INTERPRETER_TRACE(thread, StOwnByIdDyn); @@ -763,6 +789,7 @@ JSTaggedValue SlowRuntimeStub::StOwnByIndex(JSThread *thread, JSTaggedValue obj, JSTaggedValue SlowRuntimeStub::StOwnByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue value) { [[maybe_unused]] EcmaHandleScope handleScope(thread); + INTERPRETER_TRACE(thread, StOwnByValueDyn); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle objHandle(thread, obj); @@ -783,6 +810,33 @@ JSTaggedValue SlowRuntimeStub::StOwnByValue(JSThread *thread, JSTaggedValue obj, if (!ret) { return ThrowTypeError(thread, "StOwnByValue failed"); } + return JSTaggedValue::True(); +} + +JSTaggedValue SlowRuntimeStub::StOwnByValueWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, + JSTaggedValue value) +{ + [[maybe_unused]] EcmaHandleScope handleScope(thread); + INTERPRETER_TRACE(thread, StOwnByValueDyn); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + JSHandle objHandle(thread, obj); + JSHandle keyHandle(thread, key); + JSHandle valueHandle(thread, value); + + if (objHandle->IsClassConstructor() && + JSTaggedValue::SameValue(keyHandle, globalConst->GetHandledPrototypeString())) { + return ThrowTypeError(thread, "In a class, static property named 'prototype' throw a TypeError"); + } + + // property in class is non-enumerable + bool enumerable = !(objHandle->IsClassPrototype() || objHandle->IsClassConstructor()); + + PropertyDescriptor desc(thread, valueHandle, true, enumerable, true); + JSMutableHandle propKey(JSTaggedValue::ToPropertyKey(thread, keyHandle)); + bool ret = JSTaggedValue::DefineOwnProperty(thread, objHandle, propKey, desc); + if (!ret) { + return ThrowTypeError(thread, "StOwnByValueWithNameSet failed"); + } if (valueHandle->IsJSFunction()) { if (propKey->IsNumber()) { propKey.Update(base::NumberHelper::NumberToString(thread, propKey.GetTaggedValue()).GetTaggedValue()); diff --git a/ecmascript/interpreter/slow_runtime_stub.h b/ecmascript/interpreter/slow_runtime_stub.h index 5523c60564e922c08ed50a2d90c3bb170215671e..afa120f0ce5363cf0377931671767a785f508afd 100644 --- a/ecmascript/interpreter/slow_runtime_stub.h +++ b/ecmascript/interpreter/slow_runtime_stub.h @@ -79,8 +79,12 @@ public: static void ThrowDeleteSuperProperty(JSThread *thread); static JSTaggedValue StOwnByName(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, JSTaggedValue value); + static JSTaggedValue StOwnByNameWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, + JSTaggedValue value); static JSTaggedValue StOwnByIndex(JSThread *thread, JSTaggedValue obj, uint32_t idx, JSTaggedValue value); static JSTaggedValue StOwnByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue value); + static JSTaggedValue StOwnByValueWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, + JSTaggedValue value); static JSTaggedValue CreateEmptyArray(JSThread *thread, ObjectFactory *factory, JSHandle globalEnv); static JSTaggedValue CreateEmptyObject(JSThread *thread, ObjectFactory *factory, JSHandle globalEnv); static JSTaggedValue CreateObjectWithBuffer(JSThread *thread, ObjectFactory *factory, JSObject *literal); diff --git a/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl b/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl index bb5386e842a7b1828d9389d546d363f3dfcfdbdd..5aaacdc93266af639b912df0b1ad5162fc3a554f 100644 --- a/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl +++ b/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl @@ -144,6 +144,8 @@ &&DEBUG_HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32, &&DEBUG_HANDLE_STLETTOGLOBALRECORD_PREF_ID32, &&DEBUG_HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32, + &&DEBUG_HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8, + &&DEBUG_HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8, &&DEBUG_HANDLE_MOV_DYN_V8_V8, &&DEBUG_HANDLE_MOV_DYN_V16_V16, &&DEBUG_HANDLE_LDA_STR_ID32, @@ -266,6 +268,4 @@ &&DEBUG_HANDLE_OVERFLOW, &&DEBUG_HANDLE_OVERFLOW, &&DEBUG_HANDLE_OVERFLOW, - &&DEBUG_HANDLE_OVERFLOW, - &&DEBUG_HANDLE_OVERFLOW, - &&DEBUG_HANDLE_OVERFLOW, + &&DEBUG_HANDLE_OVERFLOW, \ No newline at end of file diff --git a/ecmascript/interpreter/templates/debugger_instruction_handler.inl b/ecmascript/interpreter/templates/debugger_instruction_handler.inl index 60d3cac4a82b366bd14e74e1ef0b85a7bf6e0a19..e578e5cfebc0112b1cc23d32b2a883ac7b3c05a8 100644 --- a/ecmascript/interpreter/templates/debugger_instruction_handler.inl +++ b/ecmascript/interpreter/templates/debugger_instruction_handler.inl @@ -668,6 +668,16 @@ NOTIFY_DEBUGGER_EVENT(); REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STCLASSTOGLOBALRECORD_PREF_ID32); } + HANDLE_OPCODE(DEBUG_HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8) + { + NOTIFY_DEBUGGER_EVENT(); + REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STOWNBYVALUEWITHNAMESET_PREF_V8_V8); + } + HANDLE_OPCODE(DEBUG_HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8) + { + NOTIFY_DEBUGGER_EVENT(); + REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STOWNBYNAMEWITHNAMESET_PREF_ID32_V8); + } HANDLE_OPCODE(DEBUG_HANDLE_MOV_DYN_V8_V8) { NOTIFY_DEBUGGER_EVENT(); diff --git a/ecmascript/interpreter/templates/instruction_dispatch.inl b/ecmascript/interpreter/templates/instruction_dispatch.inl index a9599b0c7a085d7ba8a7a26e8808d2bf800d9b1a..2462b523597738826ddbf06720d5c4543b814e4c 100644 --- a/ecmascript/interpreter/templates/instruction_dispatch.inl +++ b/ecmascript/interpreter/templates/instruction_dispatch.inl @@ -144,6 +144,8 @@ &&HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32, &&HANDLE_STLETTOGLOBALRECORD_PREF_ID32, &&HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32, + &&HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8, + &&HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8, &&HANDLE_MOV_DYN_V8_V8, &&HANDLE_MOV_DYN_V16_V16, &&HANDLE_LDA_STR_ID32, @@ -267,5 +269,4 @@ &&HANDLE_OVERFLOW, &&HANDLE_OVERFLOW, &&HANDLE_OVERFLOW, - &&HANDLE_OVERFLOW, - &&HANDLE_OVERFLOW, +