Sau một số thử nghiệm gửi lại, tôi thấy rằng việc triển khai của tôi không thể xử lý nhiều đệ quy. Mặc dù sau khi tôi chạy một vài thử nghiệm trong Firefox, tôi thấy rằng điều này có thể phổ biến hơn tôi nghĩ ban đầu. Tôi tin rằng vấn đề cơ bản là việc triển khai của tôi yêu cầu 3 cuộc gọi để thực hiện cuộc gọi hàm. Cuộc gọi đầu tiên được thực hiện với một phương thức có tên là Call
đảm bảo cuộc gọi đang được thực hiện cho đối tượng có thể gọi và nhận giá trị của bất kỳ đối số nào là tham chiếu. Cuộc gọi thứ hai được thực hiện theo phương thức có tên Call
được xác định trong giao diện ICallable
. Phương thức này tạo ra bối cảnh thực thi mới và xây dựng biểu thức lambda nếu nó chưa được tạo ra. Cuộc gọi cuối cùng được thực hiện cho lambda mà đối tượng hàm đóng gói. Rõ ràng thực hiện một cuộc gọi chức năng là khá nặng nhưng tôi chắc chắn rằng với một chút tinh chỉnh tôi có thể làm cho đệ quy một công cụ khả thi khi sử dụng thực hiện này.Làm cách nào để cải thiện khả năng đệ quy của việc triển khai ECMAScript?
public static object Call(ExecutionContext context, object value, object[] args)
{
var func = Reference.GetValue(value) as ICallable;
if (func == null)
{
throw new TypeException();
}
if (args != null && args.Length > 0)
{
for (int i = 0; i < args.Length; i++)
{
args[i] = Reference.GetValue(args[i]);
}
}
var reference = value as Reference;
if (reference != null)
{
if (reference.IsProperty)
{
return func.Call(reference.Value, args);
}
else
{
return func.Call(((EnviromentRecord)reference.Value).ImplicitThisValue(), args);
}
}
return func.Call(Undefined.Value, args);
}
public object Call(object thisObject, object[] arguments)
{
var lexicalEnviroment = Scope.NewDeclarativeEnviroment();
var variableEnviroment = Scope.NewDeclarativeEnviroment();
var thisBinding = thisObject ?? Engine.GlobalEnviroment.GlobalObject;
var newContext = new ExecutionContext(Engine, lexicalEnviroment, variableEnviroment, thisBinding);
Engine.EnterContext(newContext);
var result = Function.Value(newContext, arguments);
Engine.LeaveContext();
return result;
}
Tôi cho rằng việc chuyển đổi đệ quy đuôi thành vòng lặp nằm ngoài phạm vi hiện tại? Bằng cách đó bạn có thể tránh gọi hoàn toàn. –
@DrJokepu - Tôi đã giữ ý tưởng sử dụng đệ quy đuôi trong tâm trí của mình nhưng tôi cũng đang tìm kiếm các gợi ý về cách làm cho các cuộc gọi trở nên kém nặng nề như cải thiện hiệu suất chung. Ngoài ra tôi không tin rằng đệ quy đuôi có thể được thực hiện đúng trong trường hợp độ phức tạp của hàm quá lớn. – ChaosPandion
Vâng, nó không giống như nó làm bất cứ điều gì không cần thiết, bạn đã thử chạy nó với một hồ sơ? Tôi có nghĩa là, các cuộc gọi chức năng (trong chế độ phát hành) không phải là rất tốn kém trong CLR (tiếc là cuộc gọi thứ hai là một chút quá béo để được inlined bởi JIT) vì vậy tôi nghi ngờ rằng đó là lý do tại sao nó nặng. Có lẽ một cái gì đó trong Reference.GetValue() hoặc một cái gì đó? Một profiler chắc chắn sẽ rất hữu ích. –