mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
2. divide CodeBlock into CodeBlock and InterpretedCodeBlock for saving memory 3. expand SCANNER_RESULT_POOL_INITIAL_SIZE to 128 4. connect String -> AtomicString with remaining space of String::m_tag 5. optimize Function.bind Signed-off-by: seonghyun kim <sh8281.kim@samsung.com>
322 lines
16 KiB
C++
322 lines
16 KiB
C++
/*
|
|
* Copyright (c) 2016-present Samsung Electronics 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 "Escargot.h"
|
|
#include "ArgumentsObject.h"
|
|
#include "Context.h"
|
|
#include "EnvironmentRecord.h"
|
|
#include "Environment.h"
|
|
|
|
namespace Escargot {
|
|
|
|
size_t g_argumentsObjectTag;
|
|
|
|
static Value ArgumentsObjectNativeGetter(ExecutionState& state, Object* self, FunctionEnvironmentRecord* targetRecord, InterpretedCodeBlock* codeBlock, AtomicString name)
|
|
{
|
|
InterpretedCodeBlock::IdentifierInfo info = codeBlock->identifierInfos()[codeBlock->findName(name)];
|
|
ASSERT(!info.m_needToAllocateOnStack);
|
|
if (info.m_indexForIndexedStorage == SIZE_MAX) {
|
|
return targetRecord->getBindingValue(state, name).m_value;
|
|
}
|
|
return targetRecord->getHeapValueByIndex(info.m_indexForIndexedStorage);
|
|
}
|
|
|
|
static void ArgumentsObjectNativeSetter(ExecutionState& state, Object* self, const Value& setterInputData, FunctionEnvironmentRecord* targetRecord, InterpretedCodeBlock* codeBlock, AtomicString name)
|
|
{
|
|
InterpretedCodeBlock::IdentifierInfo info = codeBlock->identifierInfos()[codeBlock->findName(name)];
|
|
ASSERT(!info.m_needToAllocateOnStack);
|
|
if (info.m_indexForIndexedStorage == SIZE_MAX) {
|
|
targetRecord->setMutableBinding(state, name, setterInputData);
|
|
return;
|
|
}
|
|
targetRecord->setHeapValueByIndex(info.m_indexForIndexedStorage, setterInputData);
|
|
}
|
|
|
|
void* ArgumentsObject::operator new(size_t size)
|
|
{
|
|
static bool typeInited = false;
|
|
static GC_descr descr;
|
|
if (!typeInited) {
|
|
GC_word obj_bitmap[GC_BITMAP_SIZE(ArgumentsObject)] = { 0 };
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ArgumentsObject, m_structure));
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ArgumentsObject, m_prototype));
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ArgumentsObject, m_values));
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ArgumentsObject, m_targetRecord));
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ArgumentsObject, m_codeBlock));
|
|
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ArgumentsObject, m_argumentPropertyInfo));
|
|
descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(ArgumentsObject));
|
|
typeInited = true;
|
|
}
|
|
return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
|
|
}
|
|
|
|
ArgumentsObject::ArgumentsObject(ExecutionState& state, FunctionEnvironmentRecord* record, ExecutionContext* ec)
|
|
: Object(state, ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 3, true)
|
|
{
|
|
g_argumentsObjectTag = *((size_t*)this);
|
|
|
|
InterpretedCodeBlock* blk = record->functionObject()->codeBlock()->asInterpretedCodeBlock();
|
|
bool isStrict = blk->isStrict();
|
|
|
|
if (isStrict) {
|
|
m_structure = state.context()->defaultStructureForArgumentsObjectInStrictMode();
|
|
} else {
|
|
m_structure = state.context()->defaultStructureForArgumentsObject();
|
|
}
|
|
|
|
// http://www.ecma-international.org/ecma-262/5.1/#sec-10.6
|
|
// Let len be the number of elements in args.
|
|
size_t len = record->argc();
|
|
// Let obj be the result of creating a new ECMAScript object.
|
|
// Set all the internal methods of obj as specified in 8.12.
|
|
// Set the [[Class]] internal property of obj to "Arguments".
|
|
// Let Object be the standard built-in Object constructor (15.2.2).
|
|
// Set the [[Prototype]] internal property of obj to the standard built-in Object prototype object (15.2.4).
|
|
// Object* obj = this;
|
|
|
|
// Call the [[DefineOwnProperty]] internal method on obj passing "length", the Property Descriptor {[[Value]]: len, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}, and false as arguments.
|
|
// obj->defineOwnProperty(state, state.context()->staticStrings().length, ObjectPropertyDescriptor(Value(len), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
|
m_values[ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER] = Value(len);
|
|
|
|
// Let map be the result of creating a new object as if by the expression new Object() where Object is the standard built-in constructor with that name
|
|
// Let mappedNames be an empty List.
|
|
std::vector<AtomicString> mappedNames;
|
|
// Let indx = len - 1.
|
|
int64_t indx = ((int64_t)len - 1);
|
|
// Repeat while indx >= 0,
|
|
|
|
m_argumentPropertyInfo.resizeWithUninitializedValues(len);
|
|
m_targetRecord = record;
|
|
m_codeBlock = blk;
|
|
|
|
while (indx >= 0) {
|
|
// Let val be the element of args at 0-origined list position indx.
|
|
Value val = record->argv()[indx];
|
|
// Call the [[DefineOwnProperty]] internal method on obj passing ToString(indx), the property descriptor {[[Value]]: val, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false as arguments.
|
|
m_argumentPropertyInfo[indx].first = val;
|
|
m_argumentPropertyInfo[indx].second = AtomicString();
|
|
|
|
// If indx is less than the number of elements in names, then
|
|
if ((size_t)indx < blk->parametersInfomation().size()) {
|
|
// Let name be the element of names at 0-origined list position indx.
|
|
AtomicString name = blk->parametersInfomation()[indx].m_name;
|
|
// If strict is false and name is not an element of mappedNames, then
|
|
if (!isStrict && std::find(mappedNames.begin(), mappedNames.end(), name) == mappedNames.end()) {
|
|
// Add name as an element of the list mappedNames.
|
|
mappedNames.push_back(name);
|
|
// Let g be the result of calling the MakeArgGetter abstract operation with arguments name and env.
|
|
// Let p be the result of calling the MakeArgSetter abstract operation with arguments name and env.
|
|
// Set the [[ParameterMap]] internal property of obj to map.
|
|
// Set the [[Get]], [[GetOwnProperty]], [[DefineOwnProperty]], and [[Delete]] internal methods of obj to the definitions provided below.
|
|
// Call the [[DefineOwnProperty]] internal method of map passing ToString(indx), the Property Descriptor {[[Set]]: p, [[Get]]: g, [[Configurable]]: true}, and false as arguments.
|
|
m_argumentPropertyInfo[indx].first = Value();
|
|
m_argumentPropertyInfo[indx].second = name;
|
|
}
|
|
}
|
|
// Let indx = indx - 1
|
|
indx--;
|
|
}
|
|
|
|
// If strict is false, then
|
|
if (!isStrict) {
|
|
// Call the [[DefineOwnProperty]] internal method on obj passing "callee", the property descriptor {[[Value]]: func, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}, and false as arguments.
|
|
// obj->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().callee), ObjectPropertyDescriptor(record->functionObject(), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
|
m_values[ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 1] = Value(record->functionObject());
|
|
|
|
Value caller;
|
|
ExecutionContext* pec = ec->parent();
|
|
while (pec) {
|
|
if (pec->lexicalEnvironment()->record()->isDeclarativeEnvironmentRecord() && pec->lexicalEnvironment()->record()->asDeclarativeEnvironmentRecord()->isFunctionEnvironmentRecord()) {
|
|
caller = pec->lexicalEnvironment()->record()->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord()->functionObject();
|
|
break;
|
|
}
|
|
pec = pec->parent();
|
|
}
|
|
// obj->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().caller), ObjectPropertyDescriptor(caller, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
|
m_values[ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2] = Value(caller);
|
|
} else {
|
|
// Else, strict is true so
|
|
// Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
|
|
auto thrower = state.context()->globalObject()->throwerGetterSetterData();
|
|
// Call the [[DefineOwnProperty]] internal method of obj with arguments "callee", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false.
|
|
// obj->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().callee), ObjectPropertyDescriptor(JSGetterSetter(thrower, thrower), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NonEnumerablePresent | ObjectPropertyDescriptor::NonConfigurablePresent)));
|
|
m_values[ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 1] = Value(thrower);
|
|
// Call the [[DefineOwnProperty]] internal method of obj with arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false.
|
|
// obj->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().caller), ObjectPropertyDescriptor(JSGetterSetter(thrower, thrower), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NonEnumerablePresent | ObjectPropertyDescriptor::NonConfigurablePresent)));
|
|
m_values[ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2] = Value(thrower);
|
|
}
|
|
}
|
|
|
|
ObjectGetResult ArgumentsObject::getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
|
|
{
|
|
uint64_t idx;
|
|
if (LIKELY(P.isUIntType())) {
|
|
idx = P.uintValue();
|
|
} else {
|
|
idx = P.string(state)->tryToUseAsIndex();
|
|
}
|
|
if (LIKELY(idx != Value::InvalidIndexValue)) {
|
|
if (idx < m_argumentPropertyInfo.size()) {
|
|
Value val = m_argumentPropertyInfo[idx].first;
|
|
if (!val.isEmpty()) {
|
|
if (m_argumentPropertyInfo[idx].second.string()->length()) {
|
|
return ObjectGetResult(ArgumentsObjectNativeGetter(state, this, m_targetRecord, m_codeBlock, m_argumentPropertyInfo[idx].second), true, true, true);
|
|
} else {
|
|
return ObjectGetResult(val, true, true, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Object::getOwnProperty(state, P);
|
|
}
|
|
|
|
bool ArgumentsObject::defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
|
|
{
|
|
uint64_t idx;
|
|
if (LIKELY(P.isUIntType())) {
|
|
idx = P.uintValue();
|
|
} else {
|
|
idx = P.string(state)->tryToUseAsIndex();
|
|
}
|
|
if (LIKELY(idx != Value::InvalidIndexValue)) {
|
|
if (idx < m_argumentPropertyInfo.size()) {
|
|
Value val = m_argumentPropertyInfo[idx].first;
|
|
if (!val.isEmpty()) {
|
|
if (desc.isDataWritableEnumerableConfigurable()) {
|
|
if (m_argumentPropertyInfo[idx].second.string()->length()) {
|
|
ArgumentsObjectNativeSetter(state, this, desc.value(), m_targetRecord, m_codeBlock, m_argumentPropertyInfo[idx].second);
|
|
return true;
|
|
} else {
|
|
m_argumentPropertyInfo[idx].first = desc.value();
|
|
return true;
|
|
}
|
|
} else {
|
|
if (m_argumentPropertyInfo[idx].second.string()->length() && desc.isDataDescriptor()) {
|
|
ArgumentsObjectNativeSetter(state, this, desc.value(), m_targetRecord, m_codeBlock, m_argumentPropertyInfo[idx].second);
|
|
}
|
|
m_argumentPropertyInfo[idx].first = Value(Value::EmptyValue);
|
|
ObjectPropertyDescriptor newDesc(desc);
|
|
newDesc.setWritable(true);
|
|
newDesc.setConfigurable(true);
|
|
newDesc.setEnumerable(true);
|
|
|
|
if (desc.isWritablePresent()) {
|
|
newDesc.setWritable(desc.isWritable());
|
|
}
|
|
if (desc.isEnumerablePresent()) {
|
|
newDesc.setEnumerable(desc.isEnumerable());
|
|
}
|
|
if (desc.isConfigurablePresent()) {
|
|
newDesc.setConfigurable(desc.isConfigurable());
|
|
}
|
|
|
|
bool extensibleBefore = isExtensible();
|
|
if (!extensibleBefore) {
|
|
rareData()->m_isExtensible = true;
|
|
}
|
|
bool ret = Object::defineOwnProperty(state, P, newDesc);
|
|
if (!extensibleBefore) {
|
|
preventExtensions();
|
|
}
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Object::defineOwnProperty(state, P, desc);
|
|
}
|
|
|
|
bool ArgumentsObject::deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) ESCARGOT_OBJECT_SUBCLASS_MUST_REDEFINE
|
|
{
|
|
uint64_t idx;
|
|
if (LIKELY(P.isUIntType())) {
|
|
idx = P.uintValue();
|
|
} else {
|
|
idx = P.string(state)->tryToUseAsIndex();
|
|
}
|
|
if (LIKELY(idx != Value::InvalidIndexValue)) {
|
|
if (idx < m_argumentPropertyInfo.size()) {
|
|
Value val = m_argumentPropertyInfo[idx].first;
|
|
if (!val.isEmpty()) {
|
|
m_argumentPropertyInfo[idx].first = Value(Value::EmptyValue);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return Object::deleteOwnProperty(state, P);
|
|
}
|
|
|
|
void ArgumentsObject::enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data)
|
|
{
|
|
for (size_t i = 0; i < m_argumentPropertyInfo.size(); i++) {
|
|
Value v = m_argumentPropertyInfo[i].first;
|
|
if (!v.isEmpty()) {
|
|
if (!callback(state, this, ObjectPropertyName(state, Value(i)), ObjectStructurePropertyDescriptor::createDataDescriptor(ObjectStructurePropertyDescriptor::AllPresent), data)) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
Object::enumeration(state, callback, data);
|
|
}
|
|
|
|
ObjectGetResult ArgumentsObject::getIndexedProperty(ExecutionState& state, const Value& property)
|
|
{
|
|
uint64_t idx;
|
|
if (LIKELY(property.isUInt32())) {
|
|
idx = property.asUInt32();
|
|
} else {
|
|
idx = property.toString(state)->tryToUseAsIndex();
|
|
}
|
|
if (LIKELY(idx != Value::InvalidIndexValue)) {
|
|
if (idx < m_argumentPropertyInfo.size()) {
|
|
Value val = m_argumentPropertyInfo[idx].first;
|
|
if (!val.isEmpty()) {
|
|
if (m_argumentPropertyInfo[idx].second.string()->length()) {
|
|
return ObjectGetResult(ArgumentsObjectNativeGetter(state, this, m_targetRecord, m_codeBlock, m_argumentPropertyInfo[idx].second), true, true, true);
|
|
} else {
|
|
return ObjectGetResult(val, true, true, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return get(state, ObjectPropertyName(state, property));
|
|
}
|
|
|
|
bool ArgumentsObject::setIndexedProperty(ExecutionState& state, const Value& property, const Value& value)
|
|
{
|
|
uint64_t idx;
|
|
if (LIKELY(property.isUInt32())) {
|
|
idx = property.asUInt32();
|
|
} else {
|
|
idx = property.toString(state)->tryToUseAsIndex();
|
|
}
|
|
if (LIKELY(idx != Value::InvalidIndexValue)) {
|
|
if (idx < m_argumentPropertyInfo.size()) {
|
|
Value val = m_argumentPropertyInfo[idx].first;
|
|
if (!val.isEmpty()) {
|
|
if (m_argumentPropertyInfo[idx].second.string()->length()) {
|
|
ArgumentsObjectNativeSetter(state, this, value, m_targetRecord, m_codeBlock, m_argumentPropertyInfo[idx].second);
|
|
return true;
|
|
} else {
|
|
m_argumentPropertyInfo[idx].first = value;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return set(state, ObjectPropertyName(state, property), value, this);
|
|
}
|
|
}
|