• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "js_function.h"
17 
18 #include "ecmascript/base/error_type.h"
19 #include "ecmascript/class_info_extractor.h"
20 #include "ecmascript/ecma_macros.h"
21 #include "ecmascript/ecma_runtime_call_info.h"
22 #include "ecmascript/global_env.h"
23 #include "ecmascript/internal_call_params.h"
24 #include "ecmascript/interpreter/interpreter-inl.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/object_factory.h"
31 #include "ecmascript/tagged_array.h"
32 
33 namespace panda::ecmascript {
InitializeJSFunction(JSThread * thread,const JSHandle<JSFunction> & func,FunctionKind kind,bool strict)34 void JSFunction::InitializeJSFunction(JSThread *thread, const JSHandle<JSFunction> &func, FunctionKind kind,
35                                       bool strict)
36 {
37     FunctionMode thisMode;
38     if (IsArrowFunction(kind)) {
39         thisMode = FunctionMode::LEXICAL;
40     } else if (strict) {
41         thisMode = FunctionMode::STRICT;
42     } else {
43         thisMode = FunctionMode::GLOBAL;
44     }
45 
46     func->SetProtoOrDynClass(thread, JSTaggedValue::Hole(), SKIP_BARRIER);
47     func->SetHomeObject(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
48     func->SetLexicalEnv(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
49     func->SetConstantPool(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
50     func->SetProfileTypeInfo(thread, JSTaggedValue::Undefined(), SKIP_BARRIER);
51     func->SetFunctionExtraInfo(thread, JSTaggedValue::Undefined());
52     func->SetFunctionKind(kind);
53     func->SetStrict(strict);
54     func->SetThisMode(thisMode);
55     func->SetResolved(false);
56 
57     auto globalConst = thread->GlobalConstants();
58     if (HasPrototype(kind)) {
59         JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionPrototypeAccessor();
60         if (kind == FunctionKind::BASE_CONSTRUCTOR || kind == FunctionKind::GENERATOR_FUNCTION) {
61             func->SetPropertyInlinedProps(thread, PROTOTYPE_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
62             accessor = globalConst->GetHandledFunctionNameAccessor();
63             func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
64         } else if (!JSFunction::IsClassConstructor(kind)) {  // class ctor do nothing
65             PropertyDescriptor desc(thread, accessor, kind != FunctionKind::BUILTIN_CONSTRUCTOR, false, false);
66             [[maybe_unused]] bool success = JSObject::DefineOwnProperty(thread, JSHandle<JSObject>(func),
67                                                                         globalConst->GetHandledPrototypeString(), desc);
68             ASSERT(success);
69         }
70     } else if (HasAccessor(kind)) {
71         JSHandle<JSTaggedValue> accessor = globalConst->GetHandledFunctionNameAccessor();
72         func->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue());
73     }
74 }
75 
NewJSFunctionPrototype(JSThread * thread,ObjectFactory * factory,const JSHandle<JSFunction> & func)76 JSHandle<JSObject> JSFunction::NewJSFunctionPrototype(JSThread *thread, ObjectFactory *factory,
77                                                       const JSHandle<JSFunction> &func)
78 {
79     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
80     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
81     JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
82     JSHandle<JSObject> funPro = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
83     func->SetFunctionPrototype(thread, funPro.GetTaggedValue());
84 
85     // set "constructor" in prototype
86     JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
87     PropertyDescriptor descriptor(thread, JSHandle<JSTaggedValue>::Cast(func), true, false, true);
88     JSObject::DefineOwnProperty(thread, funPro, constructorKey, descriptor);
89 
90     return funPro;
91 }
92 
GetOrCreateInitialJSHClass(JSThread * thread,const JSHandle<JSFunction> & fun)93 JSHClass *JSFunction::GetOrCreateInitialJSHClass(JSThread *thread, const JSHandle<JSFunction> &fun)
94 {
95     JSTaggedValue protoOrDyn(fun->GetProtoOrDynClass());
96     if (protoOrDyn.IsJSHClass()) {
97         return reinterpret_cast<JSHClass *>(protoOrDyn.GetTaggedObject());
98     }
99 
100     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
101     JSHandle<JSTaggedValue> proto;
102     if (!fun->HasFunctionPrototype()) {
103         proto = JSHandle<JSTaggedValue>::Cast(NewJSFunctionPrototype(thread, factory, fun));
104     } else {
105         proto = JSHandle<JSTaggedValue>(thread, fun->GetProtoOrDynClass());
106     }
107 
108     JSHandle<JSHClass> dynclass = factory->NewEcmaDynClass(JSObject::SIZE, JSType::JS_OBJECT, proto);
109     fun->SetProtoOrDynClass(thread, dynclass);
110     return *dynclass;
111 }
112 
PrototypeGetter(JSThread * thread,const JSHandle<JSObject> & self)113 JSTaggedValue JSFunction::PrototypeGetter(JSThread *thread, const JSHandle<JSObject> &self)
114 {
115     JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(self);
116     if (!func->HasFunctionPrototype()) {
117         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
118         NewJSFunctionPrototype(thread, factory, func);
119     }
120     return JSFunction::Cast(*self)->GetFunctionPrototype();
121 }
122 
PrototypeSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)123 bool JSFunction::PrototypeSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
124                                  [[maybe_unused]] bool mayThrow)
125 {
126     JSHandle<JSFunction> func(self);
127     JSTaggedValue protoOrDyn = func->GetProtoOrDynClass();
128     if (protoOrDyn.IsJSHClass()) {
129         // need transtion
130         JSHandle<JSHClass> dynclass(thread, protoOrDyn);
131         JSHandle<JSHClass> newDynclass = JSHClass::TransitionProto(thread, dynclass, value);
132         if (value->IsECMAObject()) {
133             JSObject::Cast(value->GetTaggedObject())->GetJSHClass()->SetIsPrototype(true);
134         }
135         func->SetProtoOrDynClass(thread, newDynclass);
136     } else {
137         func->SetFunctionPrototype(thread, value.GetTaggedValue());
138     }
139     return true;
140 }
141 
NameGetter(JSThread * thread,const JSHandle<JSObject> & self)142 JSTaggedValue JSFunction::NameGetter(JSThread *thread, const JSHandle<JSObject> &self)
143 {
144     JSMethod *target = JSHandle<JSFunction>::Cast(self)->GetCallTarget();
145     if (target->GetPandaFile() == nullptr) {
146         return JSTaggedValue::Undefined();
147     }
148     std::string funcName = target->ParseFunctionName();
149     if (funcName.empty()) {
150         return thread->GlobalConstants()->GetEmptyString();
151     }
152     if (JSHandle<JSFunction>::Cast(self)->GetFunctionKind() == FunctionKind::GETTER_FUNCTION) {
153         funcName.insert(0, "get ");
154     }
155     if (JSHandle<JSFunction>::Cast(self)->GetFunctionKind() == FunctionKind::SETTER_FUNCTION) {
156         funcName.insert(0, "set ");
157     }
158 
159     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
160     return factory->NewFromStdString(funcName).GetTaggedValue();
161 }
162 
OrdinaryHasInstance(JSThread * thread,const JSHandle<JSTaggedValue> & constructor,const JSHandle<JSTaggedValue> & obj)163 bool JSFunction::OrdinaryHasInstance(JSThread *thread, const JSHandle<JSTaggedValue> &constructor,
164                                      const JSHandle<JSTaggedValue> &obj)
165 {
166     // 1. If IsCallable(C) is false, return false.
167     if (!constructor->IsCallable()) {
168         return false;
169     }
170 
171     // 2. If C has a [[BoundTargetFunction]] internal slot, then
172     //    a. Let BC be the value of C's [[BoundTargetFunction]] internal slot.
173     //    b. Return InstanceofOperator(O,BC)  (see 12.9.4).
174     if (constructor->IsBoundFunction()) {
175         JSHandle<JSBoundFunction> boundFunction(thread, JSBoundFunction::Cast(constructor->GetTaggedObject()));
176         JSTaggedValue boundTarget = boundFunction->GetBoundTarget();
177         return JSObject::InstanceOf(thread, obj, JSHandle<JSTaggedValue>(thread, boundTarget));
178     }
179     // 3. If Type(O) is not Object, return false
180     if (!obj->IsECMAObject()) {
181         return false;
182     }
183 
184     // 4. Let P be Get(C, "prototype").
185     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
186     JSHandle<JSTaggedValue> constructorPrototype =
187         JSTaggedValue::GetProperty(thread, constructor, globalConst->GetHandledPrototypeString()).GetValue();
188 
189     // 5. ReturnIfAbrupt(P).
190     // no throw exception, so needn't return
191     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
192 
193     // 6. If Type(P) is not Object, throw a TypeError exception.
194     if (!constructorPrototype->IsECMAObject()) {
195         THROW_TYPE_ERROR_AND_RETURN(thread, "HasInstance: is not Object", false);
196     }
197 
198     // 7. Repeat
199     //    a.Let O be O.[[GetPrototypeOf]]().
200     //    b.ReturnIfAbrupt(O).
201     //    c.If O is null, return false.
202     //    d.If SameValue(P, O) is true, return true.
203     JSTaggedValue objPrototype = obj.GetTaggedValue();
204     while (!objPrototype.IsNull()) {
205         if (JSTaggedValue::SameValue(objPrototype, constructorPrototype.GetTaggedValue())) {
206             return true;
207         }
208         objPrototype = JSObject::Cast(objPrototype)->GetPrototype(thread);
209         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
210     }
211     return false;
212 }
213 
MakeConstructor(JSThread * thread,const JSHandle<JSFunction> & func,const JSHandle<JSTaggedValue> & proto,bool writable)214 bool JSFunction::MakeConstructor(JSThread *thread, const JSHandle<JSFunction> &func,
215                                  const JSHandle<JSTaggedValue> &proto, bool writable)
216 {
217     ASSERT_PRINT(proto->IsHeapObject() || proto->IsUndefined(), "proto must be JSObject or Undefined");
218     ASSERT_PRINT(func->IsConstructor(), "func must be Constructor type");
219     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
220     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
221     JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
222 
223     ASSERT_PRINT(func->GetProtoOrDynClass().IsHole() && func->IsExtensible(),
224                  "function doesn't has proto_type property and is extensible object");
225     ASSERT_PRINT(JSObject::HasProperty(thread, JSHandle<JSObject>(func), constructorKey),
226                  "function must have constructor");
227 
228     // proto.constructor = func
229     bool status = false;
230     if (proto->IsUndefined()) {
231         // Let prototype be ObjectCreate(%ObjectPrototype%).
232         JSHandle<JSTaggedValue> objPrototype = env->GetObjectFunctionPrototype();
233         PropertyDescriptor constructorDesc(thread, JSHandle<JSTaggedValue>::Cast(func), writable, false, true);
234         status = JSTaggedValue::DefinePropertyOrThrow(thread, objPrototype, constructorKey, constructorDesc);
235     } else {
236         PropertyDescriptor constructorDesc(thread, JSHandle<JSTaggedValue>::Cast(func), writable, false, true);
237         status = JSTaggedValue::DefinePropertyOrThrow(thread, proto, constructorKey, constructorDesc);
238     }
239 
240     ASSERT_PRINT(status, "DefineProperty construct failed");
241     // func.prototype = proto
242     // Let status be DefinePropertyOrThrow(F, "prototype", PropertyDescriptor{[[Value]]:
243     // prototype, [[Writable]]: writablePrototype, [[Enumerable]]: false, [[Configurable]]: false}).
244     func->SetFunctionPrototype(thread, proto.GetTaggedValue());
245 
246     ASSERT_PRINT(status, "DefineProperty proto_type failed");
247     return status;
248 }
249 
Call(JSThread * thread,const JSHandle<JSTaggedValue> & func,const JSHandle<JSTaggedValue> & thisArg,uint32_t argc,const JSTaggedType argv[])250 JSTaggedValue JSFunction::Call(JSThread *thread, const JSHandle<JSTaggedValue> &func,
251                                const JSHandle<JSTaggedValue> &thisArg, uint32_t argc, const JSTaggedType argv[])
252 {
253     // 1. ReturnIfAbrupt(F).
254     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
255     // 2. If argumentsList was not passed, let argumentsList be a new empty List.
256     // 3. If IsCallable(F) is false, throw a TypeError exception.
257     if (!func->IsCallable()) {
258         THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception());
259     }
260 
261     if (func->IsJSFunction()) {
262         return JSFunction::CallInternal(thread, JSHandle<JSFunction>(func), thisArg, argc, argv);
263     }
264 
265     if (func->IsBoundFunction()) {
266         return JSBoundFunction::CallInternal(thread, JSHandle<JSBoundFunction>(func));
267     }
268 
269     if (func->IsJSProxy()) {
270         return JSProxy::CallInternal(thread, JSHandle<JSProxy>(func), thisArg, argc, argv);
271     }
272     THROW_TYPE_ERROR_AND_RETURN(thread, "Call NonCallable", JSTaggedValue::Exception());
273 }
274 
Construct(JSThread * thread,const JSHandle<JSTaggedValue> & func,uint32_t argc,const JSTaggedType argv[],const JSHandle<JSTaggedValue> & newTarget)275 JSTaggedValue JSFunction::Construct(JSThread *thread, const JSHandle<JSTaggedValue> &func, uint32_t argc,
276                                     const JSTaggedType argv[], const JSHandle<JSTaggedValue> &newTarget)
277 {
278     JSMutableHandle<JSTaggedValue> target(thread, newTarget.GetTaggedValue());
279     if (target->IsUndefined()) {
280         target.Update(func.GetTaggedValue());
281     }
282     if (!(func->IsConstructor() && target->IsConstructor())) {
283         THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
284     }
285     if (func->IsJSFunction()) {
286         return JSFunction::ConstructInternal(thread, JSHandle<JSFunction>(func), argc, argv, target);
287     }
288     if (func->IsBoundFunction()) {
289         return JSBoundFunction::ConstructInternal(thread, JSHandle<JSBoundFunction>(func), target);
290     }
291     if (func->IsJSProxy()) {
292         return JSProxy::ConstructInternal(thread, JSHandle<JSProxy>(func), argc, argv, target);
293     }
294     THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor NonConstructor", JSTaggedValue::Exception());
295 }
296 
Invoke(JSThread * thread,const JSHandle<JSTaggedValue> & thisArg,const JSHandle<JSTaggedValue> & key,uint32_t argc,const JSTaggedType argv[])297 JSTaggedValue JSFunction::Invoke(JSThread *thread, const JSHandle<JSTaggedValue> &thisArg,
298                                  const JSHandle<JSTaggedValue> &key, uint32_t argc, const JSTaggedType argv[])
299 {
300     ASSERT(JSTaggedValue::IsPropertyKey(key));
301     JSHandle<JSTaggedValue> func(JSTaggedValue::GetProperty(thread, thisArg, key).GetValue());
302     return JSFunction::Call(thread, func, thisArg, argc, argv);
303 }
304 
305 // [[Call]]
CallInternal(JSThread * thread,const JSHandle<JSFunction> & func,const JSHandle<JSTaggedValue> & thisArg,uint32_t argc,const JSTaggedType argv[])306 JSTaggedValue JSFunction::CallInternal(JSThread *thread, const JSHandle<JSFunction> &func,
307                                        const JSHandle<JSTaggedValue> &thisArg, uint32_t argc, const JSTaggedType argv[])
308 {
309     if (!func->IsBuiltinsConstructor() && func->IsClassConstructor()) {
310         THROW_TYPE_ERROR_AND_RETURN(thread, "class constructor cannot call", JSTaggedValue::Exception());
311     }
312     CallParams params;
313     params.callTarget = ECMAObject::Cast(*func);
314     params.newTarget = JSTaggedValue::VALUE_UNDEFINED;
315     params.thisArg = thisArg.GetTaggedType();
316     params.argc = argc;
317     params.argv = argv;
318     return EcmaInterpreter::Execute(thread, params);
319 }
320 
321 // [[Construct]]
ConstructInternal(JSThread * thread,const JSHandle<JSFunction> & func,uint32_t argc,const JSTaggedType argv[],const JSHandle<JSTaggedValue> & newTarget)322 JSTaggedValue JSFunction::ConstructInternal(JSThread *thread, const JSHandle<JSFunction> &func, uint32_t argc,
323                                             const JSTaggedType argv[], const JSHandle<JSTaggedValue> &newTarget)
324 {
325     ASSERT(newTarget->IsECMAObject());
326     if (!func->IsConstructor()) {
327         THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception());
328     }
329 
330     JSHandle<JSTaggedValue> obj(thread, JSTaggedValue::Undefined());
331     if (!func->IsBuiltinsConstructor() && func->IsBase()) {
332         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
333         obj = JSHandle<JSTaggedValue>(factory->NewJSObjectByConstructor(func, newTarget));
334     }
335 
336     CallParams params;
337     params.callTarget = ECMAObject::Cast(*func);
338     params.newTarget = newTarget.GetTaggedType();
339     params.thisArg = obj.GetTaggedType();
340     params.argc = argc;
341     params.argv = argv;
342 
343     JSTaggedValue resultValue = EcmaInterpreter::Execute(thread, params);
344     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
345     // 9.3.2 [[Construct]] (argumentsList, newTarget)
346     if (func->IsBuiltinsConstructor() || resultValue.IsECMAObject()) {
347         return resultValue;
348     }
349 
350     if (func->IsBase()) {
351         return obj.GetTaggedValue();
352     }
353 
354     // derived ctor(sub class) return the obj which created by base ctor(parent class)
355     if (func->IsDerivedConstructor()) {
356         return resultValue;
357     }
358 
359     if (!resultValue.IsUndefined()) {
360         THROW_TYPE_ERROR_AND_RETURN(thread, "function is non-constructor", JSTaggedValue::Exception());
361     }
362     return obj.GetTaggedValue();
363 }
364 
GetFunctionName(JSThread * thread,const JSHandle<JSFunctionBase> & func)365 JSHandle<JSTaggedValue> JSFunctionBase::GetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func)
366 {
367     JSHandle<JSTaggedValue> nameKey = thread->GlobalConstants()->GetHandledNameString();
368 
369     return JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(func), nameKey).GetValue();
370 }
371 
SetFunctionName(JSThread * thread,const JSHandle<JSFunctionBase> & func,const JSHandle<JSTaggedValue> & name,const JSHandle<JSTaggedValue> & prefix)372 bool JSFunctionBase::SetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func,
373                                      const JSHandle<JSTaggedValue> &name, const JSHandle<JSTaggedValue> &prefix)
374 {
375     ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
376     ASSERT_PRINT(name->IsStringOrSymbol(), "name must be string or symbol");
377     bool needPrefix = false;
378     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
379     if (!prefix->IsUndefined()) {
380         ASSERT_PRINT(prefix->IsString(), "prefix must be string");
381         needPrefix = true;
382     }
383     // If Type(name) is Symbol, then
384     // Let description be name’s [[Description]] value.
385     // If description is undefined, let name be the empty String.
386     // Else, let name be the concatenation of "[", description, and "]".
387     JSHandle<EcmaString> functionName;
388     if (name->IsSymbol()) {
389         JSTaggedValue description = JSHandle<JSSymbol>::Cast(name)->GetDescription();
390         JSHandle<EcmaString> descriptionHandle(thread, description);
391         if (description.IsUndefined()) {
392             functionName = factory->GetEmptyString();
393         } else {
394             JSHandle<EcmaString> leftBrackets = factory->NewFromCanBeCompressString("[");
395             JSHandle<EcmaString> rightBrackets = factory->NewFromCanBeCompressString("]");
396             functionName = factory->ConcatFromString(leftBrackets, descriptionHandle);
397             functionName = factory->ConcatFromString(functionName, rightBrackets);
398         }
399     } else {
400         functionName = JSHandle<EcmaString>::Cast(name);
401     }
402     EcmaString *newString;
403     if (needPrefix) {
404         JSHandle<EcmaString> handlePrefixString = JSTaggedValue::ToString(thread, prefix);
405         JSHandle<EcmaString> spaceString(factory->NewFromCanBeCompressString(" "));
406         JSHandle<EcmaString> concatString = factory->ConcatFromString(handlePrefixString, spaceString);
407         newString = *factory->ConcatFromString(concatString, functionName);
408     } else {
409         newString = *functionName;
410     }
411     JSHandle<JSTaggedValue> nameHandle(thread, newString);
412     JSHandle<JSTaggedValue> nameKey = thread->GlobalConstants()->GetHandledNameString();
413     PropertyDescriptor nameDesc(thread, nameHandle, false, false, true);
414     JSHandle<JSTaggedValue> funcHandle(func);
415     return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, nameKey, nameDesc);
416 }
417 
SetFunctionLength(JSThread * thread,const JSHandle<JSFunction> & func,JSTaggedValue length,bool cfg)418 bool JSFunction::SetFunctionLength(JSThread *thread, const JSHandle<JSFunction> &func, JSTaggedValue length, bool cfg)
419 {
420     ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
421     ASSERT_PRINT(length.IsInteger(), "length must be integer");
422     JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString();
423     ASSERT_PRINT(!JSTaggedValue::Less(thread, JSHandle<JSTaggedValue>(thread, length),
424                                       JSHandle<JSTaggedValue>(thread, JSTaggedValue(0))),
425                  "length must be non negtive integer");
426     PropertyDescriptor lengthDesc(thread, JSHandle<JSTaggedValue>(thread, length), false, false, cfg);
427     JSHandle<JSTaggedValue> funcHandle(func);
428     return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, lengthKeyHandle, lengthDesc);
429 }
430 
CallInternal(JSThread * thread,const JSHandle<JSBoundFunction> & func)431 JSTaggedValue JSBoundFunction::CallInternal(JSThread *thread, const JSHandle<JSBoundFunction> &func)
432 {
433     JSHandle<JSTaggedValue> target(thread, func->GetBoundTarget());
434     JSHandle<JSTaggedValue> boundThis(thread, func->GetBoundThis());
435 
436     InternalCallParams *params = thread->GetInternalCallParams();
437     params->MakeBoundArgv(thread, func);
438     return JSFunction::Call(thread, target, boundThis, params->GetLength(), params->GetArgv());
439 }
440 
441 // 9.4.1.2[[Construct]](argumentsList, newTarget)
ConstructInternal(JSThread * thread,const JSHandle<JSBoundFunction> & func,const JSHandle<JSTaggedValue> & newTarget)442 JSTaggedValue JSBoundFunction::ConstructInternal(JSThread *thread, const JSHandle<JSBoundFunction> &func,
443                                                  const JSHandle<JSTaggedValue> &newTarget)
444 {
445     JSHandle<JSTaggedValue> target(thread, func->GetBoundTarget());
446     ASSERT(target->IsConstructor());
447     JSMutableHandle<JSTaggedValue> newTargetMutable(thread, newTarget.GetTaggedValue());
448     if (JSTaggedValue::SameValue(func.GetTaggedValue(), newTarget.GetTaggedValue())) {
449         newTargetMutable.Update(target.GetTaggedValue());
450     }
451     InternalCallParams *params = thread->GetInternalCallParams();
452     params->MakeBoundArgv(thread, func);
453     return JSFunction::Construct(thread, target, params->GetLength(), params->GetArgv(), newTargetMutable);
454 }
455 
ProxyRevocFunctions(const JSThread * thread,const JSHandle<JSProxyRevocFunction> & revoker)456 void JSProxyRevocFunction::ProxyRevocFunctions(const JSThread *thread, const JSHandle<JSProxyRevocFunction> &revoker)
457 {
458     // 1.Let p be the value of F’s [[RevocableProxy]] internal slot.
459     JSTaggedValue proxy = revoker->GetRevocableProxy();
460     // 2.If p is null, return undefined.
461     if (proxy.IsNull()) {
462         return;
463     }
464 
465     // 3.Set the value of F’s [[RevocableProxy]] internal slot to null.
466     revoker->SetRevocableProxy(thread, JSTaggedValue::Null());
467 
468     // 4.Assert: p is a Proxy object.
469     ASSERT(proxy.IsJSProxy());
470     JSHandle<JSProxy> proxyHandle(thread, proxy);
471 
472     // 5 ~ 6 Set internal slot of p to null.
473     proxyHandle->SetTarget(thread, JSTaggedValue::Null());
474     proxyHandle->SetHandler(thread, JSTaggedValue::Null());
475 }
476 
AccessCallerArgumentsThrowTypeError(EcmaRuntimeCallInfo * argv)477 JSTaggedValue JSFunction::AccessCallerArgumentsThrowTypeError([[maybe_unused]] EcmaRuntimeCallInfo *argv)
478 {
479     THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(),
480                                 "Under strict mode, 'caller' and 'arguments' properties must not be accessed.",
481                                 JSTaggedValue::Exception());
482 }
483 
IntlNameGetter(JSThread * thread,const JSHandle<JSObject> & self)484 JSTaggedValue JSIntlBoundFunction::IntlNameGetter(JSThread *thread, [[maybe_unused]] const JSHandle<JSObject> &self)
485 {
486     return thread->GlobalConstants()->GetEmptyString();
487 }
488 
SetFunctionNameNoPrefix(JSThread * thread,JSFunction * func,JSTaggedValue name)489 void JSFunction::SetFunctionNameNoPrefix(JSThread *thread, JSFunction *func, JSTaggedValue name)
490 {
491     ASSERT_PRINT(func->IsExtensible(), "Function must be extensible");
492     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
493 
494     JSHandle<JSTaggedValue> funcHandle(thread, func);
495     {
496         JSMutableHandle<JSTaggedValue> nameHandle(thread, JSTaggedValue::Undefined());
497         if (!name.IsSymbol()) {
498             nameHandle.Update(name);
499         } else {
500             JSHandle<JSTaggedValue> nameBegin(thread, name);
501             JSTaggedValue description = JSSymbol::Cast(name.GetTaggedObject())->GetDescription();
502             if (description.IsUndefined()) {
503                 nameHandle.Update(thread->GlobalConstants()->GetEmptyString());
504             } else {
505                 JSHandle<EcmaString> concatName;
506                 JSHandle<EcmaString> leftBrackets = factory->NewFromCanBeCompressString("[");
507                 JSHandle<EcmaString> rightBrackets = factory->NewFromCanBeCompressString("]");
508                 concatName = factory->ConcatFromString(
509                     leftBrackets,
510                     JSHandle<EcmaString>(thread, JSSymbol::Cast(nameBegin->GetHeapObject())->GetDescription()));
511                 concatName = factory->ConcatFromString(concatName, rightBrackets);
512                 nameHandle.Update(concatName.GetTaggedValue());
513             }
514         }
515         PropertyDescriptor nameDesc(thread, nameHandle, false, false, true);
516         JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, thread->GlobalConstants()->GetHandledNameString(),
517                                              nameDesc);
518     }
519 }
520 
GetInstanceJSHClass(JSThread * thread,JSHandle<JSFunction> constructor,JSHandle<JSTaggedValue> newTarget)521 JSHandle<JSHClass> JSFunction::GetInstanceJSHClass(JSThread *thread, JSHandle<JSFunction> constructor,
522                                                    JSHandle<JSTaggedValue> newTarget)
523 {
524     JSHandle<JSHClass> ctorInitialJSHClass(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
525     // newTarget is construct itself
526     if (newTarget.GetTaggedValue() == constructor.GetTaggedValue()) {
527         return ctorInitialJSHClass;
528     }
529 
530     // newTarget is derived-class of constructor
531     if (newTarget->IsJSFunction()) {
532         JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
533         if (newTargetFunc->IsDerivedConstructor()) {
534             JSTaggedValue newTargetProto = JSHandle<JSObject>::Cast(newTarget)->GetPrototype(thread);
535             if (newTargetProto == constructor.GetTaggedValue()) {
536                 return GetOrCreateDerivedJSHClass(thread, newTargetFunc, constructor, ctorInitialJSHClass);
537             }
538         }
539     }
540 
541     // ECMA2015 9.1.15 3.Let proto be Get(constructor, "prototype").
542     JSMutableHandle<JSTaggedValue> prototype(thread, JSTaggedValue::Undefined());
543     if (newTarget->IsJSFunction()) {
544         JSHandle<JSFunction> newTargetFunc = JSHandle<JSFunction>::Cast(newTarget);
545         FunctionKind kind = newTargetFunc->GetFunctionKind();
546         if (HasPrototype(kind)) {
547             prototype.Update(PrototypeGetter(thread, JSHandle<JSObject>::Cast(newTargetFunc)));
548         }
549     } else {
550         // Such case: bound function and define a "prototype" property.
551         JSHandle<JSTaggedValue> customizePrototype =
552             JSTaggedValue::GetProperty(thread, newTarget, thread->GlobalConstants()->GetHandledPrototypeString())
553                 .GetValue();
554         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSHClass, thread);
555         prototype.Update(customizePrototype.GetTaggedValue());
556         // Reload JSHClass of constructor, where the lookup of 'prototype' property may change it.
557         ctorInitialJSHClass = JSHandle<JSHClass>(thread, JSFunction::GetOrCreateInitialJSHClass(thread, constructor));
558     }
559 
560     if (!prototype->IsECMAObject()) {
561         prototype.Update(constructor->GetFunctionPrototype());
562     }
563 
564     JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
565     newJSHClass->SetPrototype(thread, prototype);
566 
567     return newJSHClass;
568 }
569 
GetOrCreateDerivedJSHClass(JSThread * thread,JSHandle<JSFunction> derived,JSHandle<JSFunction> constructor,JSHandle<JSHClass> ctorInitialJSHClass)570 JSHandle<JSHClass> JSFunction::GetOrCreateDerivedJSHClass(JSThread *thread, JSHandle<JSFunction> derived,
571                                                           JSHandle<JSFunction> constructor,
572                                                           JSHandle<JSHClass> ctorInitialJSHClass)
573 {
574     JSTaggedValue protoOrDyn(derived->GetProtoOrDynClass());
575     // has cached JSHClass, return directly
576     if (protoOrDyn.IsJSHClass()) {
577         return JSHandle<JSHClass>(thread, protoOrDyn);
578     }
579 
580     JSHandle<JSHClass> newJSHClass = JSHClass::Clone(thread, ctorInitialJSHClass);
581     // guarante derived has function prototype
582     JSHandle<JSTaggedValue> prototype(thread, derived->GetProtoOrDynClass());
583     ASSERT(!prototype->IsHole());
584     newJSHClass->SetPrototype(thread, prototype);
585     derived->SetProtoOrDynClass(thread, newJSHClass);
586     return newJSHClass;
587 }
588 
589 // Those interface below is discarded
InitializeJSFunction(JSThread * thread,const JSHandle<GlobalEnv> & env,const JSHandle<JSFunction> & func,FunctionKind kind,bool strict)590 void JSFunction::InitializeJSFunction(JSThread *thread, [[maybe_unused]] const JSHandle<GlobalEnv> &env,
591                                       const JSHandle<JSFunction> &func, FunctionKind kind, bool strict)
592 {
593     InitializeJSFunction(thread, func, kind, strict);
594 }
595 
IsDynClass(JSTaggedValue object)596 bool JSFunction::IsDynClass(JSTaggedValue object)
597 {
598     return object.IsJSHClass();
599 }
600 
GetOrCreateInitialDynClass(JSThread * thread,const JSHandle<JSFunction> & fun)601 DynClass *JSFunction::GetOrCreateInitialDynClass(JSThread *thread, const JSHandle<JSFunction> &fun)
602 {
603     return reinterpret_cast<DynClass *>(JSFunction::GetOrCreateInitialJSHClass(thread, fun));
604 }
605 
GetInstanceDynClass(JSThread * thread,JSHandle<JSFunction> constructor,JSHandle<JSTaggedValue> newTarget)606 JSHandle<DynClass> JSFunction::GetInstanceDynClass(JSThread *thread, JSHandle<JSFunction> constructor,
607                                                    JSHandle<JSTaggedValue> newTarget)
608 {
609     return JSHandle<DynClass>(JSFunction::GetInstanceJSHClass(thread, constructor, newTarget));
610 }
611 
NameSetter(JSThread * thread,const JSHandle<JSObject> & self,const JSHandle<JSTaggedValue> & value,bool mayThrow)612 bool JSFunction::NameSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
613                             [[maybe_unused]] bool mayThrow)
614 {
615     if (self->IsPropertiesDict()) {
616         // replace setter with value
617         JSHandle<JSTaggedValue> nameString = thread->GlobalConstants()->GetHandledNameString();
618         return self->UpdatePropertyInDictionary(thread, nameString.GetTaggedValue(), value.GetTaggedValue());
619     }
620     self->SetPropertyInlinedProps(thread, NAME_INLINE_PROPERTY_INDEX, value.GetTaggedValue());
621     return true;
622 }
623 }  // namespace panda::ecmascript
624