!41 add globalrecord

Merge pull request !41 from clearme777/master
This commit is contained in:
openharmony_ci 2021-09-11 06:36:43 +00:00 committed by Gitee
commit c48bb3a9d6
16 changed files with 275 additions and 22 deletions

View File

@ -562,3 +562,18 @@ groups:
acc: inout:top
prefix: ecma
format: [pref_op_none]
- sig: ecma.stconsttoglobalrecord string_id
acc: in:top
prefix: ecma
format: [pref_op_id_32]
properties: [string_id]
- sig: ecma.stlettoglobalrecord string_id
acc: in:top
prefix: ecma
format: [pref_op_id_32]
properties: [string_id]
- sig: ecma.stclasstoglobalrecord string_id
acc: in:top
prefix: ecma
format: [pref_op_id_32]
properties: [string_id]

View File

@ -33,6 +33,7 @@
#include "ecmascript/js_invoker.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/mem/heap.h"
#include "ecmascript/tagged_dictionary.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/regexp/regexp_parser_cache.h"
#include "ecmascript/runtime_call_id.h"
@ -152,6 +153,7 @@ bool EcmaVM::Initialize()
globalEnv->SetEmptyArray(thread_, factory_->NewEmptyArray());
globalEnv->SetEmptyLayoutInfo(thread_, factory_->CreateLayoutInfo(0));
globalEnv->SetRegisterSymbols(thread_, JSTaggedValue(SymbolTable::Create(thread_)));
globalEnv->SetGlobalRecord(thread_, JSTaggedValue(NameDictionary::Create(thread_)));
JSTaggedValue emptyStr = thread_->GlobalConstants()->GetEmptyString();
stringTable_->InternEmptyString(EcmaString::Cast(emptyStr.GetTaggedObject()));
globalEnv->SetEmptyTaggedQueue(thread_, factory_->NewTaggedQueue(0));

View File

@ -137,7 +137,8 @@ class JSThread;
V(JSTaggedValue, JSIntlBoundFunctionClass, JS_INTL_BOUND_FUNCTION_CLASS) \
V(JSTaggedValue, NumberFormatLocales, NUMBER_FORMAT_LOCALES_INDEX) \
V(JSTaggedValue, DateTimeFormatLocales, DATE_TIMEFORMAT_LOCALES_INDEX) \
V(JSTaggedValue, JSNativeObjectClass, JS_NATIVE_OBJECT_CLASS)
V(JSTaggedValue, JSNativeObjectClass, JS_NATIVE_OBJECT_CLASS) \
V(JSTaggedValue, GlobalRecord, GLOBAL_RECORD)
class GlobalEnv : public TaggedObject {
public:

View File

@ -25,7 +25,7 @@
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/js_typed_array.h"
#include "ecmascript/object_factory-inl.h"
#include "ecmascript/tagged_dictionary.h"
namespace panda::ecmascript {
#define TRACE_IC 0 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
@ -134,12 +134,17 @@ void ICRuntime::TraceIC([[maybe_unused]] JSHandle<JSTaggedValue> receiver,
JSTaggedValue LoadICRuntime::LoadMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
{
if (receiver->IsTypedArray() || !receiver->IsJSObject()) {
return JSTaggedValue::GetProperty(GetThread(), receiver, key).GetValue().GetTaggedValue();
return JSTaggedValue::GetProperty(thread_, receiver, key).GetValue().GetTaggedValue();
}
ObjectOperator op(GetThread(), receiver, key);
auto result = JSHandle<JSTaggedValue>(thread_, JSObject::GetProperty(GetThread(), &op));
if (!op.IsFound() && GetICKind() == ICKind::NamedGlobalLoadIC) {
return SlowRuntimeStub::ThrowReferenceError(GetThread(), key.GetTaggedValue(), " is not defined");
bool found = false;
JSTaggedValue res = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue(), &found);
if (!found) {
return SlowRuntimeStub::ThrowReferenceError(GetThread(), key.GetTaggedValue(), " is not definded");
}
return res;
}
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(GetThread());
// ic-switch

View File

@ -2631,14 +2631,20 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
#endif
bool found = false;
JSTaggedValue result = FastRuntimeStub::GetGlobalOwnProperty(globalObj, prop, &found);
// order: 1. global record 2. global object
JSTaggedValue result = SlowRuntimeStub::LdGlobalRecord(thread, prop, &found);
if (found) {
SET_ACC(result);
} else {
// slow path
JSTaggedValue globalResult = FastRuntimeStub::GetGlobalOwnProperty(globalObj, prop, &found);
if (found) {
SET_ACC(globalResult);
} else {
// slow path
JSTaggedValue res = SlowRuntimeStub::TryLdGlobalByName(thread, globalObj, prop);
INTERPRETER_RETURN_IF_ABRUPT(res);
SET_ACC(res);
}
}
DISPATCH(BytecodeInstruction::Format::PREF_ID32);
@ -2666,12 +2672,21 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
#endif
bool found = false;
FastRuntimeStub::GetGlobalOwnProperty(globalObj, propKey, &found);
if (!found) {
// slow path will throw exception
JSTaggedValue res = SlowRuntimeStub::TryStGlobalByName(thread, propKey);
SlowRuntimeStub::LdGlobalRecord(thread, propKey, &found);
// 1. find from global record
if (found) {
JSTaggedValue value = GET_ACC();
SAVE_ACC();
JSTaggedValue res = SlowRuntimeStub::TryUpdateGlobalRecord(thread, propKey, value);
INTERPRETER_RETURN_IF_ABRUPT(res);
RESTORE_ACC();
} else {
// 2. find from global object
FastRuntimeStub::GetGlobalOwnProperty(globalObj, propKey, &found);
if (!found) {
auto result = SlowRuntimeStub::ThrowReferenceError(thread, propKey, " is not defined");
INTERPRETER_RETURN_IF_ABRUPT(result);
}
JSTaggedValue value = GET_ACC();
SAVE_ACC();
JSTaggedValue res = SlowRuntimeStub::StGlobalVar(thread, propKey, value);
@ -2680,6 +2695,49 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
}
DISPATCH(BytecodeInstruction::Format::PREF_ID32);
}
HANDLE_OPCODE(HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32) {
uint32_t stringId = READ_INST_32_1();
JSTaggedValue propKey = constpool->GetObjectFromCache(stringId);
LOG_INST() << "intrinsics::stconsttoglobalrecord"
<< " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject()));
JSTaggedValue value = GET_ACC();
SAVE_ACC();
JSTaggedValue res = SlowRuntimeStub::StGlobalRecord(thread, propKey, value, true);
INTERPRETER_RETURN_IF_ABRUPT(res);
RESTORE_ACC();
DISPATCH(BytecodeInstruction::Format::PREF_ID32);
}
HANDLE_OPCODE(HANDLE_STLETTOGLOBALRECORD_PREF_ID32) {
uint32_t stringId = READ_INST_32_1();
JSTaggedValue propKey = constpool->GetObjectFromCache(stringId);
LOG_INST() << "intrinsics::stlettoglobalrecord"
<< " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject()));
JSTaggedValue value = GET_ACC();
SAVE_ACC();
JSTaggedValue res = SlowRuntimeStub::StGlobalRecord(thread, propKey, value, false);
INTERPRETER_RETURN_IF_ABRUPT(res);
RESTORE_ACC();
DISPATCH(BytecodeInstruction::Format::PREF_ID32);
}
HANDLE_OPCODE(HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32) {
uint32_t stringId = READ_INST_32_1();
JSTaggedValue propKey = constpool->GetObjectFromCache(stringId);
LOG_INST() << "intrinsics::stclasstoglobalrecord"
<< " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject()));
JSTaggedValue value = GET_ACC();
SAVE_ACC();
JSTaggedValue res = SlowRuntimeStub::StGlobalRecord(thread, propKey, value, false);
INTERPRETER_RETURN_IF_ABRUPT(res);
RESTORE_ACC();
DISPATCH(BytecodeInstruction::Format::PREF_ID32);
}
HANDLE_OPCODE(HANDLE_LDGLOBALVAR_PREF_ID32) {
uint32_t stringId = READ_INST_32_1();
JSTaggedValue propKey = constpool->GetObjectFromCache(stringId);

View File

@ -211,6 +211,9 @@ enum EcmaOpcode {
CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8,
ISTRUE_PREF,
ISFALSE_PREF,
STCONSTTOGLOBALRECORD_PREF_ID32,
STLETTOGLOBALRECORD_PREF_ID32,
STCLASSTOGLOBALRECORD_PREF_ID32,
MOV_DYN_V8_V8,
MOV_DYN_V16_V16,
LDA_STR_ID32,

View File

@ -37,6 +37,7 @@
#include "ecmascript/js_proxy.h"
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/tagged_dictionary.h"
#include "ecmascript/runtime_call_id.h"
#include "ecmascript/template_string.h"
#include "ecmascript/vmstat/runtime_stat.h"
@ -273,8 +274,8 @@ JSTaggedValue SlowRuntimeStub::Div2Dyn(JSThread *thread, JSTaggedValue left, JST
if (dLeft == 0 || std::isnan(dLeft)) {
return JSTaggedValue(base::NAN_VALUE);
}
bool positive = ((bit_cast<uint64_t>(dRight) & base::DOUBLE_SIGN_MASK) ==
(bit_cast<uint64_t>(dLeft) & base::DOUBLE_SIGN_MASK));
bool positive = (((bit_cast<uint64_t>(dRight)) & base::DOUBLE_SIGN_MASK) ==
((bit_cast<uint64_t>(dLeft)) & base::DOUBLE_SIGN_MASK));
return JSTaggedValue(positive ? base::POSITIVE_INFINITY : -base::POSITIVE_INFINITY);
}
return JSTaggedValue(dLeft / dRight);
@ -492,7 +493,7 @@ JSTaggedValue SlowRuntimeStub::ExpDyn(JSThread *thread, JSTaggedValue base, JSTa
return JSTaggedValue(base::NAN_VALUE);
}
if ((doubleBase == 0 && (bit_cast<uint64_t>(doubleBase) & base::DOUBLE_SIGN_MASK) == base::DOUBLE_SIGN_MASK) &&
if (((doubleBase == 0) && ((bit_cast<uint64_t>(doubleBase)) & base::DOUBLE_SIGN_MASK) == base::DOUBLE_SIGN_MASK) &&
std::isfinite(doubleExponent) && base::NumberHelper::TruncateDouble(doubleExponent) == doubleExponent &&
base::NumberHelper::TruncateDouble(doubleExponent / 2) + base::HALF == (doubleExponent / 2)) { // 2: half
if (doubleExponent > 0) {
@ -1283,10 +1284,18 @@ JSTaggedValue SlowRuntimeStub::TryLdGlobalByName(JSThread *thread, JSTaggedValue
JSHandle<JSTaggedValue> obj(thread, global.GetTaggedObject()->GetClass()->GetPrototype());
JSHandle<JSTaggedValue> propHandle(thread, prop);
OperationResult res = JSTaggedValue::GetProperty(thread, obj, propHandle);
if (!res.GetPropertyMetaData().IsFound()) {
if (res.GetPropertyMetaData().IsFound()) {
return res.GetValue().GetTaggedValue();
}
EcmaVM *vm = thread->GetEcmaVM();
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
NameDictionary *dict = NameDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject());
int entry = dict->FindEntry(propHandle.GetTaggedValue());
if (entry == -1) {
return ThrowReferenceError(thread, prop, " is not defined");
}
return res.GetValue().GetTaggedValue();
return dict->GetValue(entry);
}
JSTaggedValue SlowRuntimeStub::TryStGlobalByName(JSThread *thread, JSTaggedValue prop)
@ -1319,6 +1328,59 @@ JSTaggedValue SlowRuntimeStub::StGlobalVar(JSThread *thread, JSTaggedValue prop,
return JSTaggedValue::True();
}
JSTaggedValue SlowRuntimeStub::TryUpdateGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value)
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
EcmaVM *vm = thread->GetEcmaVM();
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
NameDictionary *dict = NameDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject());
int entry = dict->FindEntry(prop);
if (dict->GetAttributes(entry).IsConstProps()) {
return ThrowSyntaxError(thread, " const can not be modified");
}
dict->UpdateValue(thread, entry, value);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return JSTaggedValue::True();
}
JSTaggedValue SlowRuntimeStub::LdGlobalRecord(JSThread *thread, JSTaggedValue key, bool *found)
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
EcmaVM *vm = thread->GetEcmaVM();
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
NameDictionary *dict = NameDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject());
int entry = dict->FindEntry(key);
if (entry != -1) {
*found = true;
return dict->GetValue(entry);
}
return JSTaggedValue::Undefined();
}
JSTaggedValue SlowRuntimeStub::StGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value, bool isConst)
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
EcmaVM *vm = thread->GetEcmaVM();
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
NameDictionary *dict = NameDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject());
int entry = dict->FindEntry(prop);
if (entry != -1) {
return ThrowReferenceError(thread, prop, " is not defined");
}
PropertyAttributes attributes;
attributes.SetIsConstProps(isConst);
JSHandle<JSTaggedValue> propHandle(thread, prop);
JSHandle<JSTaggedValue> valueHandle(thread, value);
JSHandle<NameDictionary> dictHandle(thread, dict);
dict->PutIfAbsent(thread, dictHandle, propHandle, valueHandle, attributes);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return JSTaggedValue::True();
}
JSTaggedValue SlowRuntimeStub::ThrowReferenceError(JSThread *thread, JSTaggedValue prop, const char *desc)
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
@ -1339,6 +1401,13 @@ JSTaggedValue SlowRuntimeStub::ThrowTypeError(JSThread *thread, const char *mess
THROW_TYPE_ERROR_AND_RETURN(thread, message, JSTaggedValue::Exception());
}
JSTaggedValue SlowRuntimeStub::ThrowSyntaxError(JSThread *thread, const char *message)
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
ASSERT_NO_ABRUPT_COMPLETION(thread);
THROW_SYNTAX_ERROR_AND_RETURN(thread, message, JSTaggedValue::Exception());
}
JSTaggedValue SlowRuntimeStub::StArraySpread(JSThread *thread, JSTaggedValue dst, JSTaggedValue index,
JSTaggedValue src)
{

View File

@ -121,6 +121,9 @@ public:
static JSTaggedValue TryStGlobalByName(JSThread *thread, JSTaggedValue prop);
static JSTaggedValue LdGlobalVar(JSThread *thread, JSTaggedValue global, JSTaggedValue prop);
static JSTaggedValue StGlobalVar(JSThread *thread, JSTaggedValue prop, JSTaggedValue value);
static JSTaggedValue StGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value, bool isConst);
static JSTaggedValue LdGlobalRecord(JSThread *thread, JSTaggedValue key, bool *found);
static JSTaggedValue TryUpdateGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value);
static JSTaggedValue StArraySpread(JSThread *thread, JSTaggedValue dst, JSTaggedValue index, JSTaggedValue src);
static JSTaggedValue DefineGeneratorFunc(JSThread *thread, JSFunction *func);
@ -145,6 +148,7 @@ public:
private:
static JSTaggedValue ThrowTypeError(JSThread *thread, const char *message);
static JSTaggedValue ThrowSyntaxError(JSThread *thread, const char *message);
static JSTaggedValue GetCallSpreadArgs(JSThread *thread, JSTaggedValue array);
};
} // namespace panda::ecmascript

View File

@ -141,6 +141,9 @@
&&DEBUG_HANDLE_CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8,
&&DEBUG_HANDLE_ISTRUE_PREF,
&&DEBUG_HANDLE_ISFALSE_PREF,
&&DEBUG_HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32,
&&DEBUG_HANDLE_STLETTOGLOBALRECORD_PREF_ID32,
&&DEBUG_HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32,
&&DEBUG_HANDLE_MOV_DYN_V8_V8,
&&DEBUG_HANDLE_MOV_DYN_V16_V16,
&&DEBUG_HANDLE_LDA_STR_ID32,
@ -266,6 +269,3 @@
&&DEBUG_HANDLE_OVERFLOW,
&&DEBUG_HANDLE_OVERFLOW,
&&DEBUG_HANDLE_OVERFLOW,
&&DEBUG_HANDLE_OVERFLOW,
&&DEBUG_HANDLE_OVERFLOW,
&&DEBUG_HANDLE_OVERFLOW,

View File

@ -653,6 +653,21 @@
NOTIFY_DEBUGGER_EVENT();
REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::ISFALSE_PREF);
}
HANDLE_OPCODE(DEBUG_HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32)
{
NOTIFY_DEBUGGER_EVENT();
REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STCONSTTOGLOBALRECORD_PREF_ID32);
}
HANDLE_OPCODE(DEBUG_HANDLE_STLETTOGLOBALRECORD_PREF_ID32)
{
NOTIFY_DEBUGGER_EVENT();
REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STLETTOGLOBALRECORD_PREF_ID32);
}
HANDLE_OPCODE(DEBUG_HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32)
{
NOTIFY_DEBUGGER_EVENT();
REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STCLASSTOGLOBALRECORD_PREF_ID32);
}
HANDLE_OPCODE(DEBUG_HANDLE_MOV_DYN_V8_V8)
{
NOTIFY_DEBUGGER_EVENT();

View File

@ -141,6 +141,9 @@
&&HANDLE_CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8,
&&HANDLE_ISTRUE_PREF,
&&HANDLE_ISFALSE_PREF,
&&HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32,
&&HANDLE_STLETTOGLOBALRECORD_PREF_ID32,
&&HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32,
&&HANDLE_MOV_DYN_V8_V8,
&&HANDLE_MOV_DYN_V16_V16,
&&HANDLE_LDA_STR_ID32,
@ -266,6 +269,3 @@
&&HANDLE_OVERFLOW,
&&HANDLE_OVERFLOW,
&&HANDLE_OVERFLOW,
&&HANDLE_OVERFLOW,
&&HANDLE_OVERFLOW,
&&HANDLE_OVERFLOW,

View File

@ -76,7 +76,7 @@ public:
static constexpr uint32_t NORMAL_ATTR_BITS = 18;
using NormalAttrField = BitField<int, 0, NORMAL_ATTR_BITS>;
using SortedIndexField = OffsetField::NextField<uint32_t, OFFSET_BITFIELD_NUM>; // 28
using IsConstPropsField = SortedIndexField::NextFlag; // 29
// dictionary mode, include global
using PropertyBoxTypeField = PropertyMetaDataField::NextField<PropertyBoxType, 2>; // 2: 2 bits, 5-6
using DictionaryOrderField = PropertyBoxTypeField::NextField<uint32_t, DICTIONARY_ORDER_NUM>; // 26
@ -217,6 +217,16 @@ public:
return IsInlinedPropsField::Get(value_);
}
inline void SetIsConstProps(bool flag)
{
IsConstPropsField::Set<uint32_t>(flag, &value_);
}
inline bool IsConstProps() const
{
return IsConstPropsField::Get(value_);
}
inline void SetRepresentation(Representation representation)
{
RepresentationField::Set<uint32_t>(representation, &value_);

View File

@ -21,6 +21,7 @@ group("ark_js_moduletest") {
"fortest:fortest_test(${host_toolchain})",
"generator:generator_test(${host_toolchain})",
"getunmappedargs:getunmappedargs_test(${host_toolchain})",
"globalrecord:globalrecord_test(${host_toolchain})",
"helloworld:helloworld_test(${host_toolchain})",
"lexicalenv:lexicalenv_test(${host_toolchain})",

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("//ark/js_runtime/test/test_helper.gni")
host_moduletest_action("globalrecord") {
deps = []
}

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.
Not support function toString() due to Runtime can not obtain Source Code yet.
extends String
a
aa
b

View File

@ -0,0 +1,34 @@
/*
* 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.
*/
"use strict"
class View{}
let a = "a";
const b = "b";
print(View);
class myString extends String{}
var view = new myString("extends String");
print(view);
print(a);
a = "a"
print(a);
print(b);
b = "bb"
print(b);