• 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 "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