1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/js_function.h"
17
18 #include "ecmascript/base/error_type.h"
19 #include "ecmascript/ecma_macros.h"
20 #include "ecmascript/ecma_runtime_call_info.h"
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/interpreter/interpreter-inl.h"
23 #include "ecmascript/js_tagged_value.h"
24 #include "ecmascript/jspandafile/class_info_extractor.h"
25 #include "ecmascript/js_handle.h"
26 #include "ecmascript/js_promise.h"
27 #include "ecmascript/js_proxy.h"
28 #include "ecmascript/js_tagged_value-inl.h"
29 #include "ecmascript/mem/c_containers.h"
30 #include "ecmascript/module/js_module_source_text.h"
31 #include "ecmascript/object_factory.h"
32 #include "ecmascript/tagged_array.h"
33
34 namespace panda::ecmascript {
InitializeJSFunction(JSThread * thread,const JSHandle<JSFunction> & func,FunctionKind kind)35 void JSFunction::InitializeJSFunction(JSThread *thread, const JSHandle<JSFunction> &func, FunctionKind kind)
36 {
37 func->SetProtoOrHClass(thread, JSTaggedValue::Hole(), SKIP_BARRIER);
38 func->SetHomeObject(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
39 func->SetLexicalEnv(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
40 func->SetModule(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
41 func->SetMethod(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
42
43 auto globalConst = thread->GlobalConstants();
44 if (HasPrototype(kind)) {
45 JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionPrototypeAccessor();
46 if (kind == FunctionKind::BASE_CONSTRUCTOR || kind == FunctionKind::GENERATOR_FUNCTION ||
47 kind == FunctionKind::ASYNC_GENERATOR_FUNCTION) {
48 func->SetPropertyInlinedProps(thread, PROTOTYPE_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
49 accessor = globalConst->GetHandledFunctionNameAccessor();
50 func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
51 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
52 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
53 if (kind == FunctionKind::ASYNC_GENERATOR_FUNCTION) {
54 JSHandle<JSFunction> objFun(env->GetObjectFunction());
55 JSHandle<JSObject> initialGeneratorFuncPrototype = factory->NewJSObjectByConstructor(objFun);
56 JSObject::SetPrototype(thread, initialGeneratorFuncPrototype, env->GetAsyncGeneratorPrototype());
57 func->SetProtoOrHClass(thread, initialGeneratorFuncPrototype);
58 }
59 if (kind == FunctionKind::GENERATOR_FUNCTION) {
60 JSHandle<JSFunction> objFun(env->GetObjectFunction());
61 JSHandle<JSObject> initialGeneratorFuncPrototype = factory->NewJSObjectByConstructor(objFun);
62 JSObject::SetPrototype(thread, initialGeneratorFuncPrototype, env->GetGeneratorPrototype());
63 func->SetProtoOrHClass(thread, initialGeneratorFuncPrototype);
64 }
65 } else if (!JSFunction::IsClassConstructor(kind)) { // class ctor do nothing
66 PropertyDescriptor desc(thread, accessor, kind != FunctionKind::BUILTIN_CONSTRUCTOR, false, false);
67 [[maybe_unused]] bool success = JSObject::DefineOwnProperty(thread, JSHandle<JSObject>(func),
68 globalConst->GetHandledPrototypeString(), desc);
69 ASSERT(success);
70 }
71 } else if (HasAccessor(kind)) {
72 JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionNameAccessor();
73 func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
74 }
75 }
76
NewJSFunctionPrototype(JSThread * thread,ObjectFactory * factory,const JSHandle<JSFunction> & func)77 JSHandle<JSObject> JSFunction::NewJSFunctionPrototype(JSThread *thread, ObjectFactory *factory,
78 const JSHandle<JSFunction> &func)
79 {
80 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
81 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
82 JSHandle<JSFunction> objFun(env->GetObjectFunction());
83 JSHandle<JSObject> funPro = factory->NewJSObjectByConstructor(objFun);
84 func->SetFunctionPrototype(thread, funPro.GetTaggedValue());
85
86 // set "constructor" in prototype
87 JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
88 PropertyDescriptor descriptor(thread, JSHandle<JSTaggedValue>::Cast(func), true, false, true);
89 JSObject::DefineOwnProperty(thread, funPro, constructorKey, descriptor);
90
91 return funPro;
92 }
93
GetOrCreateInitialJSHClass(JSThread * thread,const JSHandle<JSFunction> & fun)94 JSHClass *JSFunction::GetOrCreateInitialJSHClass(JSThread *thread, const JSHandle<JSFunction> &fun)
95 {
96 JSTaggedValue protoOrHClass(fun->GetProtoOrHClass());
97 if (protoOrHClass.IsJSHClass()) {
98 return reinterpret_cast<JSHClass *>(protoOrHClass.GetTaggedObject());
99 }
100
101 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
102 JSHandle<JSTaggedValue> proto;
103 if (!fun->HasFunctionPrototype()) {
104 proto = JSHandle<JSTaggedValue>::Cast(NewJSFunctionPrototype(thread, factory, fun));
105 } else {
106 proto = JSHandle<JSTaggedValue>(thread, fun->GetProtoOrHClass());
107 }
108
109 JSHandle<JSHClass> hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, proto);
110 fun->SetProtoOrHClass(thread, hclass);
111 return *hclass;
112 }
113
PrototypeGetter(JSThread * thread,const JSHandle<JSObject> & self)114 JSTaggedValue JSFunction::PrototypeGetter(JSThread *thread, const JSHandle<JSObject> &self)
115 {
116 JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(self);
117 if (!func->HasFunctionPrototype()) {
118 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
119 NewJSFunctionPrototype(thread, factory, func);
120 }
121 return JSFunction::Cast(*self)->GetFunctionPrototype();
122 }
123
PrototypeSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)124 bool JSFunction::PrototypeSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
125 [[maybe_unused]] bool mayThrow)
126 {
127 JSHandle<JSFunction> func(self);
128 JSTaggedValue protoOrHClass = func->GetProtoOrHClass();
129 if (protoOrHClass.IsJSHClass()) {
130 // need transition
131 JSHandle<JSHClass> hclass(thread, protoOrHClass);
132 JSHandle<JSHClass> newClass = JSHClass::TransitionProto(thread, hclass, value);
133 if (value->IsECMAObject()) {
134 JSObject::Cast(value->GetTaggedObject())->GetJSHClass()->SetIsPrototype(true);
135 }
136 func->SetProtoOrHClass(thread, newClass);
137 } else {
138 func->SetFunctionPrototype(thread, value.GetTaggedValue());
139 }
140 return true;
141 }
142
NameGetter(JSThread * thread,const JSHandle<JSObject> & self)143 JSTaggedValue JSFunction::NameGetter(JSThread *thread, const JSHandle<JSObject> &self)
144 {
145 JSTaggedValue method = JSHandle<JSFunction>::Cast(self)->GetMethod();
146 if (method.IsUndefined()) {
147 return JSTaggedValue::Undefined();
148 }
149 JSHandle<Method> target = JSHandle<Method>(thread, method);
150 if (target->GetPandaFile() == nullptr) {
151 return JSTaggedValue::Undefined();
152 }
153 std::string funcName = target->ParseFunctionName();
154 if (funcName.empty()) {
155 return thread->GlobalConstants()->GetEmptyString();
156 }
157 if (JSHandle<JSFunction>::Cast(self)->GetFunctionKind() == FunctionKind::GETTER_FUNCTION) {
158 funcName.insert(0, "get ");
159 }
160 if (JSHandle<JSFunction>::Cast(self)->GetFunctionKind() == FunctionKind::SETTER_FUNCTION) {
161 funcName.insert(0, "set ");
162 }
163
164 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
165 return factory->NewFromStdString(funcName).GetTaggedValue();
166 }
167
OrdinaryHasInstance(JSThread * thread,const JSHandle<JSTaggedValue> & constructor,const JSHandle<JSTaggedValue> & obj)168 bool JSFunction::OrdinaryHasInstance(JSThread *thread, const JSHandle<JSTaggedValue> &constructor,
169 const JSHandle<JSTaggedValue> &obj)
170 {
171 // 1. If IsCallable(C) is false, return false.
172 if (!constructor->IsCallable()) {
173 return false;
174 }
175
176 // 2. If C has a [[BoundTargetFunction]] internal slot, then
177 // a. Let BC be the value of C's [[BoundTargetFunction]] internal slot.
178 // b. Return InstanceofOperator(O,BC) (see 12.9.4).
179 if (constructor->IsBoundFunction()) {
180 JSHandle<JSBoundFunction> boundFunction(thread, JSBoundFunction::Cast(constructor->GetTaggedObject()));
181 JSTaggedValue boundTarget = boundFunction->GetBoundTarget();
182 return JSObject::InstanceOf(thread, obj, JSHandle<JSTaggedValue>(thread, boundTarget));
183 }
184 // 3. If Type(O) is not Object, return false
185 if (!obj->IsECMAObject()) {
186 return false;
187 }
188
189 // 4. Let P be Get(C, "prototype").
190 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
191 JSHandle<JSTaggedValue> constructorPrototype =
192 JSTaggedValue::GetProperty(thread, constructor, globalConst->GetHandledPrototypeString()).GetValue();
193
194 // 5. ReturnIfAbrupt(P).
195 // no throw exception, so needn't return
196 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
197
198 // 6. If Type(P) is not Object, throw a TypeError exception.
199 if (!constructorPrototype->IsECMAObject()) {
200 THROW_TYPE_ERROR_AND_RETURN(thread, "HasInstance: is not Object", false);
201 }
202
203 // 7. Repeat
204 // a.Let O be O.[[GetPrototypeOf]]().
205 // b.ReturnIfAbrupt(O).
206 // c.If O is null, return false.
207 // d.If SameValue(P, O) is true, return true.
208 JSMutableHandle<JSTaggedValue> object(thread, obj.GetTaggedValue());
209 while (!object->IsNull()) {
210 if (JSTaggedValue::SameValue(object, constructorPrototype)) {
211 return true;
212 }
213 object.Update(JSTaggedValue::GetPrototype(thread, object));
214 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
215 }
216 return false;
217 }
218
MakeConstructor(JSThread * thread,const JSHandle<JSFunction> & func,const JSHandle<JSTaggedValue> & proto,bool writable)219 bool JSFunction::MakeConstructor(JSThread *thread, const JSHandle<JSFunction> &func,
220 const JSHandle<JSTaggedValue> &proto, bool writable)
221 {
222 ASSERT_PRINT(proto->IsHeapObject() || proto->IsUndefined(), "proto must be JSObject or Undefined");
223 ASSERT_PRINT(func->IsConstructor(), "func must be Constructor type");
224 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
225 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
226 JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
227
228 ASSERT_PRINT(func->GetProtoOrHClass().IsHole() && func->IsExtensible(),
229 "function doesn't has proto_type property and is extensible object");
230 ASSERT_PRINT(JSObject::HasProperty(thread, JSHandle<JSObject>(func), constructorKey),
231 "function must have constructor");
232
233 // proto.constructor = func
234 bool status = false;
235 if (proto->IsUndefined()) {
236 // Let prototype be ObjectCreate(%ObjectPrototype%).
237 JSHandle<JSTaggedValue> objPrototype = env->GetObjectFunctionPrototype();
238 PropertyDescriptor constructorDesc(thread, JSHandle<JSTaggedValue>::Cast(func), writable, false, true);
239 status = JSTaggedValue::DefinePropertyOrThrow(thread, objPrototype, constructorKey, constructorDesc);
240 } else {
241 PropertyDescriptor constructorDesc(thread, JSHandle<JSTaggedValue>::Cast(func), writable, false, true);
242 status = JSTaggedValue::DefinePropertyOrThrow(thread, proto, constructorKey, constructorDesc);
243 }
244
245 ASSERT_PRINT(status, "DefineProperty construct failed");
246 // func.prototype = proto
247 // Let status be DefinePropertyOrThrow(F, "prototype", PropertyDescriptor{[[Value]]:
248 // prototype, [[Writable]]: writablePrototype, [[Enumerable]]: false, [[Configurable]]: false}).
249 func->SetFunctionPrototype(thread, proto.GetTaggedValue());
250
251 ASSERT_PRINT(status, "DefineProperty proto_type failed");
252 return status;
253 }
254
Call(EcmaRuntimeCallInfo * info)255 JSTaggedValue JSFunction::Call(EcmaRuntimeCallInfo *info)
256 {
257 if (info == nullptr) {
258 return JSTaggedValue::Exception();
259 }
260
261 JSThread *thread = info->GetThread();
262 // 1. ReturnIfAbrupt(F).
263 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
264 JSHandle<JSTaggedValue> func = info->GetFunction();
265 // 2. If argumentsList was not passed, let argumentsList be a new empty List.
266 // 3. If IsCallable(F) is false, throw a TypeError exception.
267 if (!func->IsCallable()) {
268 THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception());
269 }
270
271 auto *hclass = func->GetTaggedObject()->GetClass();
272 if (hclass->IsClassConstructor()) {
273 THROW_TYPE_ERROR_AND_RETURN(thread, "class constructor cannot call", JSTaggedValue::Exception());
274 }
275 return EcmaInterpreter::Execute(info);
276 }
277
Construct(EcmaRuntimeCallInfo * info)278 JSTaggedValue JSFunction::Construct(EcmaRuntimeCallInfo *info)
279 {
280 if (info == nullptr) {
281 return JSTaggedValue::Exception();
282 }
283
284 JSThread *thread = info->GetThread();
285 JSHandle<JSTaggedValue> func(info->GetFunction());
286 JSHandle<JSTaggedValue> target = info->GetNewTarget();
287 if (target->IsUndefined()) {
288 target = func;
289 info->SetNewTarget(target.GetTaggedValue());
290 }
291 if (!(func->IsConstructor() && target->IsConstructor())) {
292 THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
293 }
294
295 if (func->IsJSFunction()) {
296 return JSFunction::ConstructInternal(info);
297 } else if (func->IsJSProxy()) {
298 return JSProxy::ConstructInternal(info);
299 } else {
300 ASSERT(func->IsBoundFunction());
301 return JSBoundFunction::ConstructInternal(info);
302 }
303 }
304
Invoke(EcmaRuntimeCallInfo * info,const JSHandle<JSTaggedValue> & key)305 JSTaggedValue JSFunction::Invoke(EcmaRuntimeCallInfo *info, const JSHandle<JSTaggedValue> &key)
306 {
307 if (info == nullptr) {
308 return JSTaggedValue::Exception();
309 }
310
311 ASSERT(JSTaggedValue::IsPropertyKey(key));
312 JSThread *thread = info->GetThread();
313 JSHandle<JSTaggedValue> thisArg = info->GetThis();
314 JSHandle<JSTaggedValue> func(JSTaggedValue::GetProperty(thread, thisArg, key).GetValue());
315 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
316 info->SetFunction(func.GetTaggedValue());
317 return JSFunction::Call(info);
318 }
319
320 // [[Construct]]
ConstructInternal(EcmaRuntimeCallInfo * info)321 JSTaggedValue JSFunction::ConstructInternal(EcmaRuntimeCallInfo *info)
322 {
323 if (info == nullptr) {
324 return JSTaggedValue::Exception();
325 }
326
327 JSThread *thread = info->GetThread();
328 JSHandle<JSFunction> func(info->GetFunction());
329 JSHandle<JSTaggedValue> newTarget(info->GetNewTarget());
330 ASSERT(newTarget->IsECMAObject());
331 if (!func->IsConstructor()) {
332 THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
333 }
334
335 JSHandle<JSTaggedValue> obj(thread, JSTaggedValue::Undefined());
336 if (func->IsBase()) {
337 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
338 obj = JSHandle<JSTaggedValue>(factory->NewJSObjectByConstructor(func, newTarget));
339 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
340 }
341
342 JSTaggedValue resultValue;
343 info->SetThis(obj.GetTaggedValue());
344 Method *method = func->GetCallTarget();
345 if (method->IsAotWithCallField()) {
346 const JSTaggedType *prevFp = thread->GetLastLeaveFrame();
347 resultValue = thread->GetEcmaVM()->ExecuteAot(info->GetArgsNumber(), info->GetArgs(), prevFp,
348 OptimizedEntryFrame::CallType::CALL_NEW);
349 const JSTaggedType *curSp = thread->GetCurrentSPFrame();
350 InterpretedEntryFrame *entryState = InterpretedEntryFrame::GetFrameFromSp(curSp);
351 JSTaggedType *prevSp = entryState->base.prev;
352 thread->SetCurrentSPFrame(prevSp);
353 } else {
354 resultValue = EcmaInterpreter::Execute(info);
355 }
356 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
357 // 9.3.2 [[Construct]] (argumentsList, newTarget)
358 if (resultValue.IsECMAObject()) {
359 return resultValue;
360 }
361
362 if (func->IsBase()) {
363 return obj.GetTaggedValue();
364 }
365
366 // derived ctor(sub class) return the obj which created by base ctor(parent class)
367 if (func->IsDerivedConstructor()) {
368 return resultValue;
369 }
370
371 if (!resultValue.IsUndefined()) {
372 THROW_TYPE_ERROR_AND_RETURN(thread, "function is non-constructor", JSTaggedValue::Exception());
373 }
374 return obj.GetTaggedValue();
375 }
376
GetFunctionName(JSThread * thread,const JSHandle<JSFunctionBase> & func)377 JSHandle<JSTaggedValue> JSFunctionBase::GetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func)
378 {
379 JSHandle<JSTaggedValue> nameKey = thread->GlobalConstants()->GetHandledNameString();
380
381 return JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(func), nameKey).GetValue();
382 }
383
SetFunctionName(JSThread * thread,const JSHandle<JSFunctionBase> & func,const JSHandle<JSTaggedValue> & name,const JSHandle<JSTaggedValue> & prefix)384 bool JSFunctionBase::SetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func,
385 const JSHandle<JSTaggedValue> &name, const JSHandle<JSTaggedValue> &prefix)
386 {
387 ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
388 ASSERT_PRINT(name->IsStringOrSymbol(), "name must be string or symbol");
389 bool needPrefix = false;
390 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
391 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
392 if (!prefix->IsUndefined()) {
393 ASSERT_PRINT(prefix->IsString(), "prefix must be string");
394 needPrefix = true;
395 }
396 // If Type(name) is Symbol, then
397 // Let description be name’s [[Description]] value.
398 // If description is undefined, let name be the empty String.
399 // Else, let name be the concatenation of "[", description, and "]".
400 JSHandle<EcmaString> functionName;
401 if (name->IsSymbol()) {
402 JSTaggedValue description = JSHandle<JSSymbol>::Cast(name)->GetDescription();
403 JSHandle<EcmaString> descriptionHandle(thread, description);
404 if (description.IsUndefined()) {
405 functionName = factory->GetEmptyString();
406 } else {
407 JSHandle<EcmaString> leftBrackets = JSHandle<EcmaString>::Cast(globalConst->
408 GetHandledLeftSquareBracketString());
409 JSHandle<EcmaString> rightBrackets = JSHandle<EcmaString>::Cast(globalConst->
410 GetHandledRightSquareBracketString());
411 functionName = factory->ConcatFromString(leftBrackets, descriptionHandle);
412 functionName = factory->ConcatFromString(functionName, rightBrackets);
413 }
414 } else {
415 functionName = JSHandle<EcmaString>::Cast(name);
416 }
417 EcmaString *newString;
418 if (needPrefix) {
419 JSHandle<EcmaString> handlePrefixString = JSTaggedValue::ToString(thread, prefix);
420 JSHandle<EcmaString> spaceString = JSHandle<EcmaString>::Cast(globalConst->GetHandledSpaceString());
421 JSHandle<EcmaString> concatString = factory->ConcatFromString(handlePrefixString, spaceString);
422 newString = *factory->ConcatFromString(concatString, functionName);
423 } else {
424 newString = *functionName;
425 }
426 JSHandle<JSTaggedValue> nameHandle(thread, newString);
427 JSHandle<JSTaggedValue> nameKey = globalConst->GetHandledNameString();
428 PropertyDescriptor nameDesc(thread, nameHandle, false, false, true);
429 JSHandle<JSTaggedValue> funcHandle(func);
430 return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, nameKey, nameDesc);
431 }
432
SetFunctionLength(JSThread * thread,const JSHandle<JSFunction> & func,JSTaggedValue length,bool cfg)433 bool JSFunction::SetFunctionLength(JSThread *thread, const JSHandle<JSFunction> &func, JSTaggedValue length, bool cfg)
434 {
435 ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
436 ASSERT_PRINT(length.IsInteger(), "length must be integer");
437 JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString();
438 ASSERT_PRINT(!JSTaggedValue::Less(thread, JSHandle<JSTaggedValue>(thread, length),
439 JSHandle<JSTaggedValue>(thread, JSTaggedValue(0))),
440 "length must be non negative integer");
441 PropertyDescriptor lengthDesc(thread, JSHandle<JSTaggedValue>(thread, length), false, false, cfg);
442 JSHandle<JSTaggedValue> funcHandle(func);
443 return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, lengthKeyHandle, lengthDesc);
444 }
445
446 // 9.4.1.2[[Construct]](argumentsList, newTarget)
ConstructInternal(EcmaRuntimeCallInfo * info)447 JSTaggedValue JSBoundFunction::ConstructInternal(EcmaRuntimeCallInfo *info)
448 {
449 JSThread *thread = info->GetThread();
450 JSHandle<JSBoundFunction> func(info->GetFunction());
451 JSHandle<JSTaggedValue> target(thread, func->GetBoundTarget());
452 ASSERT(target->IsConstructor());
453 JSHandle<JSTaggedValue> newTarget = info->GetNewTarget();
454 JSMutableHandle<JSTaggedValue> newTargetMutable(thread, newTarget.GetTaggedValue());
455 if (JSTaggedValue::SameValue(func.GetTaggedValue(), newTarget.GetTaggedValue())) {
456 newTargetMutable.Update(target.GetTaggedValue());
457 }
458
459 JSHandle<TaggedArray> boundArgs(thread, func->GetBoundArguments());
460 const uint32_t boundLength = boundArgs->GetLength();
461 const uint32_t argsLength = info->GetArgsNumber() + boundLength;
462 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
463 EcmaRuntimeCallInfo *runtimeInfo =
464 EcmaInterpreter::NewRuntimeCallInfo(thread, target, undefined, newTargetMutable, argsLength);
465 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
466 if (boundLength == 0) {
467 runtimeInfo->SetCallArg(argsLength, 0, info, 0);
468 } else {
469 // 0 ~ boundLength is boundArgs; boundLength ~ argsLength is args of EcmaRuntimeCallInfo.
470 runtimeInfo->SetCallArg(boundLength, boundArgs);
471 runtimeInfo->SetCallArg(argsLength, boundLength, info, 0);
472 }
473 return JSFunction::Construct(runtimeInfo);
474 }
475
ProxyRevocFunctions(const JSThread * thread,const JSHandle<JSProxyRevocFunction> & revoker)476 void JSProxyRevocFunction::ProxyRevocFunctions(const JSThread *thread, const JSHandle<JSProxyRevocFunction> &revoker)
477 {
478 // 1.Let p be the value of F’s [[RevocableProxy]] internal slot.
479 JSTaggedValue proxy = revoker->GetRevocableProxy();
480 // 2.If p is null, return undefined.
481 if (proxy.IsNull()) {
482 return;
483 }
484
485 // 3.Set the value of F’s [[RevocableProxy]] internal slot to null.
486 revoker->SetRevocableProxy(thread, JSTaggedValue::Null());
487
488 // 4.Assert: p is a Proxy object.
489 ASSERT(proxy.IsJSProxy());
490 JSHandle<JSProxy> proxyHandle(thread, proxy);
491
492 // 5 ~ 6 Set internal slot of p to null.
493 proxyHandle->SetTarget(thread, JSTaggedValue::Null());
494 proxyHandle->SetHandler(thread, JSTaggedValue::Null());
495 }
496
AccessCallerArgumentsThrowTypeError(EcmaRuntimeCallInfo * argv)497 JSTaggedValue JSFunction::AccessCallerArgumentsThrowTypeError([[maybe_unused]] EcmaRuntimeCallInfo *argv)
498 {
499 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(),
500 "Under strict mode, 'caller' and 'arguments' properties must not be accessed.",
501 JSTaggedValue::Exception());
502 }
503
IntlNameGetter(JSThread * thread,const JSHandle<JSObject> & self)504 JSTaggedValue JSIntlBoundFunction::IntlNameGetter(JSThread *thread, [[maybe_unused]] const JSHandle<JSObject> &self)
505 {
506 return thread->GlobalConstants()->GetEmptyString();
507 }
508
SetFunctionNameNoPrefix(JSThread * thread,JSFunction * func,JSTaggedValue name)509 void JSFunction::SetFunctionNameNoPrefix(JSThread *thread, JSFunction *func, JSTaggedValue name)
510 {
511 ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
512 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
513 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
514
515 JSHandle<JSTaggedValue> funcHandle(thread, func);
516 {
517 JSMutableHandle<JSTaggedValue> nameHandle(thread, JSTaggedValue::Undefined());
518 if (!name.IsSymbol()) {
519 nameHandle.Update(name);
520 } else {
521 JSHandle<JSTaggedValue> nameBegin(thread, name);
522 JSTaggedValue description = JSSymbol::Cast(name.GetTaggedObject())->GetDescription();
523 if (description.IsUndefined()) {
524 nameHandle.Update(globalConst->GetEmptyString());
525 } else {
526 JSHandle<EcmaString> concatName;
527 JSHandle<EcmaString> leftBrackets = JSHandle<EcmaString>::Cast(globalConst->
528 GetHandledLeftSquareBracketString());
529 JSHandle<EcmaString> rightBrackets = JSHandle<EcmaString>::Cast(globalConst->
530 GetHandledRightSquareBracketString());
531 concatName = factory->ConcatFromString(
532 leftBrackets,
533 JSHandle<EcmaString>(thread, JSSymbol::Cast(nameBegin->GetTaggedObject())->GetDescription()));
534 concatName = factory->ConcatFromString(concatName, rightBrackets);
535 nameHandle.Update(concatName.GetTaggedValue());
536 }
537 }
538 PropertyDescriptor nameDesc(thread, nameHandle, false, false, true);
539 JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, globalConst->GetHandledNameString(), nameDesc);
540 }
541 }
542
GetInstanceJSHClass(JSThread * thread,JSHandle<JSFunction> constructor,JSHandle<JSTaggedValue> newTarget)543 JSHandle<JSHClass> JSFunction::GetInstanceJSHClass(JSThread *thread, JSHandle<JSFunction> constructor,
544 JSHandle<JSTaggedValue> newTarget)
545 {
546 JSHandle<JSHClass> ctorInitialJSHClass(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
547 // newTarget is construct itself
548 if (newTarget.GetTaggedValue() == constructor.GetTaggedValue()) {
549 return ctorInitialJSHClass;
550 }
551
552 // newTarget is derived-class of constructor
553 if (newTarget->IsJSFunction()) {
554 JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
555 if (newTargetFunc->IsDerivedConstructor()) {
556 JSMutableHandle<JSTaggedValue> mutableNewTarget(thread, newTarget.GetTaggedValue());
557 JSMutableHandle<JSTaggedValue> mutableNewTargetProto(thread, JSTaggedValue::Undefined());
558 while (!mutableNewTargetProto->IsNull()) {
559 mutableNewTargetProto.Update(JSTaggedValue::GetPrototype(thread, mutableNewTarget));
560 if (mutableNewTargetProto.GetTaggedValue() == constructor.GetTaggedValue()) {
561 return GetOrCreateDerivedJSHClass(thread, newTargetFunc, ctorInitialJSHClass);
562 }
563 mutableNewTarget.Update(mutableNewTargetProto.GetTaggedValue());
564 }
565 }
566 }
567
568 // ECMA2015 9.1.15 3.Let proto be Get(constructor, "prototype").
569 JSMutableHandle<JSTaggedValue> prototype(thread, JSTaggedValue::Undefined());
570 if (newTarget->IsJSFunction()) {
571 JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
572 FunctionKind kind = newTargetFunc->GetFunctionKind();
573 if (HasPrototype(kind)) {
574 prototype.Update(PrototypeGetter(thread, JSHandle<JSObject>::Cast(newTargetFunc)));
575 }
576 } else {
577 // Such case: bound function and define a "prototype" property.
578 JSHandle<JSTaggedValue> customizePrototype =
579 JSTaggedValue::GetProperty(thread, newTarget, thread->GlobalConstants()->GetHandledPrototypeString())
580 .GetValue();
581 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSHClass, thread);
582 prototype.Update(customizePrototype.GetTaggedValue());
583 // Reload JSHClass of constructor, where the lookup of 'prototype' property may change it.
584 ctorInitialJSHClass = JSHandle<JSHClass>(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
585 }
586
587 if (!prototype->IsECMAObject()) {
588 prototype.Update(constructor->GetFunctionPrototype());
589 }
590
591 JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
592 newJSHClass->SetPrototype(thread, prototype);
593
594 return newJSHClass;
595 }
596
GetOrCreateDerivedJSHClass(JSThread * thread,JSHandle<JSFunction> derived,JSHandle<JSHClass> ctorInitialJSHClass)597 JSHandle<JSHClass> JSFunction::GetOrCreateDerivedJSHClass(JSThread *thread, JSHandle<JSFunction> derived,
598 JSHandle<JSHClass> ctorInitialJSHClass)
599 {
600 JSTaggedValue protoOrHClass(derived->GetProtoOrHClass());
601 // has cached JSHClass, return directly
602 if (protoOrHClass.IsJSHClass()) {
603 return JSHandle<JSHClass>(thread, protoOrHClass);
604 }
605
606 JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
607 // guarante derived has function prototype
608 JSHandle<JSTaggedValue> prototype(thread, derived->GetProtoOrHClass());
609 ASSERT(!prototype->IsHole());
610 newJSHClass->SetPrototype(thread, prototype);
611 derived->SetProtoOrHClass(thread, newJSHClass);
612 return newJSHClass;
613 }
614
615 // Those interface below is discarded
InitializeJSFunction(JSThread * thread,const JSHandle<GlobalEnv> & env,const JSHandle<JSFunction> & func,FunctionKind kind)616 void JSFunction::InitializeJSFunction(JSThread *thread, [[maybe_unused]] const JSHandle<GlobalEnv> &env,
617 const JSHandle<JSFunction> &func, FunctionKind kind)
618 {
619 InitializeJSFunction(thread, func, kind);
620 }
621
NameSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)622 bool JSFunction::NameSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
623 [[maybe_unused]] bool mayThrow)
624 {
625 if (self->IsPropertiesDict()) {
626 // replace setter with value
627 JSHandle<JSTaggedValue> nameString = thread->GlobalConstants()->GetHandledNameString();
628 return self->UpdatePropertyInDictionary(thread, nameString.GetTaggedValue(), value.GetTaggedValue());
629 }
630 self->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, value.GetTaggedValue());
631 return true;
632 }
633
SetFunctionExtraInfo(JSThread * thread,void * nativeFunc,const DeleteEntryPoint & deleter,void * data,size_t nativeBindingsize)634 void JSFunction::SetFunctionExtraInfo(JSThread *thread, void *nativeFunc,
635 const DeleteEntryPoint &deleter, void *data, size_t nativeBindingsize)
636 {
637 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
638 EcmaVM *vm = thread->GetEcmaVM();
639 JSHandle<JSTaggedValue> value(thread, JSTaggedValue(hashField));
640 JSHandle<ECMAObject> obj(thread, this);
641 JSHandle<JSNativePointer> pointer = vm->GetFactory()->NewJSNativePointer(nativeFunc, deleter, data,
642 false, nativeBindingsize);
643 if (!obj->HasHash()) {
644 Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData());
645 return;
646 }
647 if (value->IsHeapObject()) {
648 if (value->IsJSNativePointer()) {
649 Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, pointer.GetTaggedValue().GetRawData());
650 return;
651 }
652 JSHandle<TaggedArray> array(value);
653
654 uint32_t nativeFieldCount = array->GetExtraLength();
655 if (array->GetLength() >= nativeFieldCount + RESOLVED_MAX_SIZE) {
656 array->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer);
657 } else {
658 JSHandle<TaggedArray> newArray =
659 thread->GetEcmaVM()->GetFactory()->NewTaggedArray(nativeFieldCount + RESOLVED_MAX_SIZE);
660 newArray->SetExtraLength(nativeFieldCount);
661 for (uint32_t i = 0; i < nativeFieldCount; i++) {
662 newArray->Set(thread, i, array->Get(i));
663 }
664 newArray->Set(thread, nativeFieldCount + HASH_INDEX, array->Get(nativeFieldCount + HASH_INDEX));
665 newArray->Set(thread, nativeFieldCount + FUNCTION_EXTRA_INDEX, pointer);
666 Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
667 }
668 } else {
669 JSHandle<TaggedArray> newArray =
670 thread->GetEcmaVM()->GetFactory()->NewTaggedArray(RESOLVED_MAX_SIZE);
671 newArray->SetExtraLength(0);
672 newArray->Set(thread, HASH_INDEX, value);
673 newArray->Set(thread, FUNCTION_EXTRA_INDEX, pointer);
674 Barriers::SetObject<true>(thread, *obj, HASH_OFFSET, newArray.GetTaggedValue().GetRawData());
675 }
676 }
677
GetFunctionExtraInfo() const678 JSTaggedValue JSFunction::GetFunctionExtraInfo() const
679 {
680 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
681 JSTaggedValue value(hashField);
682 if (value.IsHeapObject()) {
683 if (value.IsTaggedArray()) {
684 TaggedArray *array = TaggedArray::Cast(value.GetTaggedObject());
685 uint32_t nativeFieldCount = array->GetExtraLength();
686 if (array->GetLength() >= nativeFieldCount + RESOLVED_MAX_SIZE) {
687 return array->Get(nativeFieldCount + FUNCTION_EXTRA_INDEX);
688 }
689 } else if (value.IsJSNativePointer()) {
690 return value;
691 } else {
692 UNREACHABLE();
693 }
694 }
695 return JSTaggedValue::Undefined();
696 }
697
GetNativeFunctionExtraInfo() const698 JSTaggedValue JSFunction::GetNativeFunctionExtraInfo() const
699 {
700 JSTaggedType hashField = Barriers::GetValue<JSTaggedType>(this, HASH_OFFSET);
701 JSTaggedValue value(hashField);
702 if (value.CheckIsJSNativePointer()) {
703 return value;
704 }
705 return JSTaggedValue::Undefined();
706 }
707
GetRecordName() const708 JSTaggedValue JSFunction::GetRecordName() const
709 {
710 JSTaggedValue module = GetModule();
711 if (module.IsSourceTextModule()) {
712 JSTaggedValue recordName = SourceTextModule::Cast(module.GetTaggedObject())->GetEcmaModuleRecordName();
713 if (!recordName.IsString()) {
714 LOG_INTERPRETER(DEBUG) << "module record name is undefined";
715 return JSTaggedValue::Hole();
716 }
717 return recordName;
718 } else if (module.IsString()) {
719 return module;
720 } else {
721 LOG_INTERPRETER(DEBUG) << "record name is undefined";
722 return JSTaggedValue::Hole();
723 }
724 }
725 } // namespace panda::ecmascript
726