范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Chrome系列深入理解V8V8如何实现Object?

  JavaScript 对象是一组属性(properties)和元素(elements)。 出于性能和内存的原因,V8 设计了几种不同的属性表示形式,例如对象内(in-object)、慢速属性(slow property)和自字典(self-dict)。 在本章中,让我们更深入地研究 JavaScript 对象。 1.JavaScript 对象布局
  下面的图 1 显示了一个基本的 JavaScript 对象在内存中的样子。
  元素和属性存储在两个独立的数据结构中,这使得添加和访问属性(property)或元素(elements)对于不同的使用模式更加高效。
  元素主要用于各种 Array.prototype 方法,例如 pop 或 slice。 鉴于这些函数访问连续范围内的属性,V8 内部大多数情况下也将它们表示为简单数组。
  命名属性以类似的方式存储在单独的数组中。 然而,与元素不同的是,我们不能简单地使用键来推断它们在属性数组中的位置; 我们需要一些额外的元数据。  在 V8 中,每个 JavaScript 对象都有一个关联的 HiddenClass。 HiddenClass 存储关于对象详情的信息,以及从属性名称到属性值的映射 。
  在图 2 中,有元素(elements)、属性(propertis)和对象内(in-object)属性。 与元素或属性不同,对象内属性存储在对象本身中,这意味着您可以直接访问它们而无需映射。 in-object 的数量是在创建 JavaScript 对象时分配的(不同 V8 版本数量可能不一样)。
  在图 3 中,存在三种不同的命名属性类型:in-object、fast/slow dictionary。 对象内属性直接存储在对象本身并提供最快的访问方式 Fast 属性存在于属性存储中,所有元信息都存储在 HiddenClass 的描述符数组中 慢速属性存在于一个独立的属性字典中,元信息不再通过 HiddenClass 共享
  图 4 显示了 JavaScript 对象内存布局,所有 V8 托管堆对象都必须有一个存储在首地址的映射指针。 当然,也有元素和属性。 描述符是 map 中的一个重要成员,它负责描述一个对象的属性,这个我们以后会讲到。
  在下面的例子中,sayname 是一个等同于 console.log 的函数。这里可以想一个问题:一个对象的函数存储在哪里? 即,sayname 在哪里? 1.  function person(name) { 2.      this.name=name; 3.  	this.sayname=function(){console.log(this.name);} 4.  } 5.  worker = new person("Nicholas"); 6.  worker.sayname(); 7.  //separation........................................ 8.  //separation........................................ 9.  Bytecode Age: 0 10.           000001DAA2FA1E96 @    0 : 13 00             LdaConstant [0] 11.           000001DAA2FA1E98 @    2 : c2                Star1 12.           000001DAA2FA1E99 @    3 : 19 fe f8          Mov , r2 13.      0 E> 000001DAA2FA1E9C @    6 : 64 51 01 f9 02    CallRuntime [DeclareGlobals], r1-r2 14.    100 S> 000001DAA2FA1EA1 @   11 : 21 01 00          LdaGlobal [1], [0] 15.           000001DAA2FA1EA4 @   14 : c2                Star1 16.           000001DAA2FA1EA5 @   15 : 13 02             LdaConstant [2] 17.           000001DAA2FA1EA7 @   17 : c1                Star2 18.           000001DAA2FA1EA8 @   18 : 0b f9             Ldar r1 19.    109 E> 000001DAA2FA1EAA @   20 : 68 f9 f8 01 02    Construct r1, r2-r2, [2] 20.    107 E> 000001DAA2FA1EAF @   25 : 23 03 04          StaGlobal [3], [4] 21.    134 S> 000001DAA2FA1EB2 @   28 : 21 03 06          LdaGlobal [3], [6] 22.           000001DAA2FA1EB5 @   31 : c1                Star2 23.    141 E> 000001DAA2FA1EB6 @   32 : 2d f8 04 08       LdaNamedProperty r2, [4], [8] 24.           000001DAA2FA1EBA @   36 : c2                Star1 25.    141 E> 000001DAA2FA1EBB @   37 : 5c f9 f8 0a       CallProperty0 r1, r2, [10] 26.           000001DAA2FA1EBF @   41 : c3                Star0 27.    151 S> 000001DAA2FA1EC0 @   42 : a8                Return 28.  Constant pool (size = 5) 29.  000001DAA2FA1E29: [FixedArray] in OldSpace 30.   - map: 0x024008ac12c1  31.   - length: 5 32.             0: 0x01daa2fa1d11  33.             1: 0x01daa2fa1c09  34.             2: 0x01daa2fa1c39  35.             3: 0x01daa2fa1c21  36.             4: 0x01daa2fa1c51 
  第一部分是 JavaScript 代码,最后是相应的字节码。第 19-21 行使用 person 对象构造一个名为 worker 的实例,第 23 行加载名称为 sayname 的属性。
  你了解 line23 吗? 它告诉我们 sayname 只是一个属性,与其类型无关。 如果再深入一点,您会发现 console 和 log 也是属性。
  因此, 在 JavaScript 对象中,所有函数都被视为属性(property) 。 2.实例化 一个 JavaScript 对象
  为了调试上述代码,我们将单步执行以下代码: 1.  RUNTIME_FUNCTION(Runtime_NewObject) { 2.    HandleScope scope(isolate); 3.    DCHECK_EQ(2, args.length()); 4.    CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); 5.    CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, 1); 6.    RETURN_RESULT_OR_FAILURE( 7.        isolate, 8.        JSObject::New(target, new_target, Handle::null())); 9.  } 10.  //separation..................................... 11.  MaybeHandle JSObject::New(Handle constructor, 12.                                      Handle new_target, 13.                                      Handle site) { 14.    Isolate* const isolate = constructor->GetIsolate(); 15.    DCHECK(constructor->IsConstructor()); 16.    DCHECK(new_target->IsConstructor()); 17.    DCHECK(!constructor->has_initial_map() || 18.           !InstanceTypeChecker::IsJSFunction( 19.               constructor->initial_map().instance_type())); 20.    Handle initial_map; 21.    ASSIGN_RETURN_ON_EXCEPTION( 22.        isolate, initial_map, 23.        JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject); 24.    int initial_capacity = V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL 25.                               ? SwissNameDictionary::kInitialCapacity 26.                               : NameDictionary::kInitialCapacity; 27.    Handle result = isolate->factory()->NewFastOrSlowJSObjectFromMap( 28.        initial_map, initial_capacity, AllocationType::kYoung, site); 29.    isolate->counters()->constructed_objects()->Increment(); 30.    isolate->counters()->constructed_objects_runtime()->Increment(); 31.    return result; 32.  }
  RUNTIME_FUNCTION(Runtime_NewObject) 是我们在上一章中提到的一个 MACRO。它调用 JSObject::New() 来创建一个新对象, JSObject::New() 调用 JSFunction::GetDerivedMap() 来分配 map,在 JSFunction::GetDerivedMap() 中,将调用以下函数。 1.  void JSFunction::EnsureHasInitialMap(Handle function) { 2.    DCHECK(function->has_prototype_slot()); 3.    DCHECK(function->IsConstructor() || 4.           IsResumableFunction(function->shared().kind())); 5.    if (function->has_initial_map()) return; 6.    Isolate* isolate = function->GetIsolate(); 7.    int expected_nof_properties = 8.        CalculateExpectedNofProperties(isolate, function); 9.    if (function->has_initial_map()) return; 10.    InstanceType instance_type; 11.    if (IsResumableFunction(function->shared().kind())) { 12.      instance_type = IsAsyncGeneratorFunction(function->shared().kind()) 13.                          ? JS_ASYNC_GENERATOR_OBJECT_TYPE 14.                          : JS_GENERATOR_OBJECT_TYPE; 15.    } else { 16.      instance_type = JS_OBJECT_TYPE; 17.    } 18.    int instance_size; 19.    int inobject_properties; 20.    CalculateInstanceSizeHelper(instance_type, false, 0, expected_nof_properties, 21.                                &instance_size, &inobject_properties); 22.    Handle map = isolate->factory()->NewMap(instance_type, instance_size, 23.                                                 TERMINAL_FAST_ELEMENTS_KIND, 24.                                                 inobject_properties); 25.    Handle prototype; 26.    if (function->has_instance_prototype()) { 27.      prototype = handle(function->instance_prototype(), isolate); 28.    } else { 29.      prototype = isolate->factory()->NewFunctionPrototype(function); 30.    } 31.    DCHECK(map->has_fast_object_elements()); 32.    DCHECK(prototype->IsJSReceiver()); 33.    JSFunction::SetInitialMap(isolate, function, map, prototype); 34.    map->StartInobjectSlackTracking(); 35.  }
  第 7 行,返回构造函数期望的属性数,第 26 到 30 行生成原型,关键字 function 是一个构造函数。 在我们的例子中,函数是 person,原型为 null,因为 person 是第一次执行,所以第 29 行被执行。
  生成的原型与构造函数绑定,并为所有实例共享,这就是 V8 实现的原型原则。下面是在第 7 行中调用的 CalculateExpectedNofProperties。  int JSFunction::CalculateExpectedNofProperties(Isolate* isolate, 2.                                                 Handle function) { 3.    int expected_nof_properties = 0; 4.    for (PrototypeIterator iter(isolate, function, kStartAtReceiver); 5.         !iter.IsAtEnd(); iter.Advance()) { 6.      Handle current = 7.          PrototypeIterator::GetCurrent(iter); 8.      if (!current->IsJSFunction()) break; 9.      Handle func = Handle::cast(current); 10.      Handle shared(func->shared(), isolate); 11.      IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate)); 12.      if (is_compiled_scope.is_compiled() || 13.          Compiler::Compile(isolate, func, Compiler::CLEAR_EXCEPTION, 14.                            &is_compiled_scope)) { 15.        DCHECK(shared->is_compiled()); 16.        int count = shared->expected_nof_properties(); 17.        if (expected_nof_properties <= JSObject::kMaxInObjectProperties - count) { 18.          expected_nof_properties += count; 19.        } else { 20.          return JSObject::kMaxInObjectProperties; 21.        } 22.      } else { 23.        continue; 24.      } 25.    } 26.    if (expected_nof_properties > 0) { 27.      expected_nof_properties += 8; 28.      if (expected_nof_properties > JSObject::kMaxInObjectProperties) { 29.        expected_nof_properties = JSObject::kMaxInObjectProperties; 30.      } 31.    } 32.    return expected_nof_properties; 33.  }
  第 28 行, MaxInObject 是 in-object 的最大数量,超过的属性存入 properties 列表 。下面图 5 显示了调用堆栈。
  参考资料
  https://javascript.plainenglish.io/lets-understand-chrome-v8-how-does-v8-implement-a-javascript-object-ddde32120bb5
  https://v8.dev/blog/fast-properties

航空知识发布歼20从首飞到服役节点,意思歼35服役还得2年?最近这两天关于海军新一代隐身舰载机歼35试飞的消息刷爆了军事圈,因为这不光是我国自主研制的第二款五代战机,即将装备服役的大好事,而且更代表了歼35距离正式服役已经很快了。因为从7月死刑巨贪卢万里,住旧屋装廉洁实有8套豪宅,三年贪污6000万死刑巨贪卢万里,住旧屋装廉洁实有8套豪宅,三年贪污6000万贵州省经济委员会和其他7个部门于2003年7月19号在贵阳举行了贵州省反腐与反腐工作的成果展示。在这次的展会上,有一幅奇上下楼蹲起就膝盖疼,走平路没事,是怎么了?骨科主任给您支招陈大爷是一位建筑工人,从事这一行20多年也小有成就,很多的工程都会来找他干,他也很享受这种生活。但就在今年年初,他突然感觉到自己的左膝盖疼,有时候坐下站起来就会听到嘎嘣的一声,但走公务员政审迎来整改,这些岗位还需查三代,报考时需了解清楚现如今,由于疫情的影响,经济形势不景气,而每年需要就业的大学生又居高不下。可谓是就业之难,难于上青天。据调查显示,今年的应届毕业生能达到上千万之多。就业的困难程度可想而知,尤其是想本土新增492717月29日024时,31个省(自治区直辖市)和新疆生产建设兵团报告新增新冠肺炎本土确诊病例49例(甘肃19例,广西15例,四川10例,山东2例,上海1例,河南1例,广东1例),含2失去的时候失去。2020年,新冠肆虐全球,全国实行大封锁,国民惊慌极恐,纷纷配合躲在家里实行自我封锁。而他们却提着脑袋向前冲。现在新冠肆虐,武汉最严重,你不可以去!于星光紧紧抓住夏辰芒的手道落马副市长痛哭流涕我要叩首谢罪我上一次念入党誓词的时候,我就半天没说出来2022年4月26日,在四川省监委留置中心,办案人员带领郭庆重温入党誓词,这名曾经的副市长不禁在党旗前痛哭流涕老泪纵横。7月28日,四川省趁热收下这份防溺水指南吧热1热1热1趁热收下这份防溺水指南吧!预防溺水知识科普随着高温天气的袭来,大家越来越喜欢进行水上活动,溺水事故也进入了高发期,这份防溺水指南,请您收好。家长们预防溺水,这些要做好1讲一味熟地黄,养血虚敛盗汗止烦渴壮腰膝治耳鸣乌须发前些天,有人在评论区留言让远志聊聊大家耳熟能详的熟地黄。行!今天我们就来聊聊熟地黄。熟地黄,即我们常讲的熟地,由生地炮制后而得,性由凉转温,主入肾经,功善滋阴补血,益精填髓,为大补天理何在啊!他来偷鱼被淹死,为何要我赔偿?且看法院如何判吉林松原,家住农村的男子杜某,其所在的村子里,有一块面积达几千亩的沼泽地(东北当地方言称其为水泡子),该沼泽地系天然形成,一直闲置着,无人管理,里面有很多鱼,附近的村民,经常在里面张作霖专列被炸事故现场及遇害的秘密1928年6月4日清晨,一辆装饰华贵,守护森严的列车,从北京开往沈阳。523就在专列经过京奉南满铁路交叉处,皇姑屯火车站的三孔桥时,埋在铁路下的30袋炸药被引爆。一声巨响黑烟滚滚,
天眼查大数据直击,鲶鱼家族割韭菜留下的痕迹是擦不净的近日,网友们被钟老局长的宝贝孙女北极鲶鱼彻底激怒了。事情的缘起也真算是巧合了,本来北极鲶鱼若是单纯在网上炫富,网友们大概率也不会做出如此强烈的反应。这事最让网友们难以下咽的一口气,未来是儿子好还是闺女好?回答从中国人的传统观念和生活习俗上来讲,重男轻女的观念一直大有人在。很多人都会认为,男孩是传宗接代的,有了儿子以后,养老问题就解决了,然而生了女儿,嫁出去的女儿泼出去的水,二十多年一周岁内小宝宝,母乳喂养的话每个月开支是多少?纯母乳喂养省了每个月奶粉钱,孩子衣服基本都是亲戚同事给的,这个费用也省了,可以补充买点袜子和玩具之类的小物件,大头是疫苗(基本选的都是进口的,需要打的就打)和体检(社区有免费的,但新生儿洗澡方法是什么?新生儿洗澡方法是什么?新生儿洗澡方法是提前做好洗澡准备,先洗脸,再洗头,最后洗身体。1。洗澡前准备好洗澡要用的物品,通常包括浴盆纱布巾沐浴露洗发露浴巾等,还有洗澡结束后会用到的婴儿李沁爆火动了谁的奶酪?央视都看不下去了,为她发声真解气年代剧成为了国产剧的标杆,山海情人世间的爆火,让这类题材迅速走红。而最新上线的这部人生之路,更是上线就引来了热播,收视和热度持续上涨。只是从部分网友的反馈来看,人生之路赢在了IP和傻支书的聪明事记新宁县马头桥镇石洞村党支部书记蒋清金红网时刻新闻3月28日讯(通讯员杨坚兰绍华雷良军李京京)3月27日一大早,新宁县马头桥镇石洞村党支部书记蒋清金像往常一样到村部去值班,刚到门口,便迎面碰上一组供养老人蒋松阶。满伢子专访园丰资本盛刚国资机构可为PEVC产业链强链补链21世纪经济报道记者赵娜苏州报道国资成为LP主力军并亲自下场做GP,是否会切走属于市场化PEVC机构的蛋糕?在我们的实践中,更多做的是为园区股权投资和创业投资产业链强链补链。苏州园快收藏!福建发布2023年春季流行性感冒中医药防治方案近日福建省卫健委印发福建省2023年春季流行性感冒中医药防治方案一起来看看福建省2023年春季流行性感冒中医药防治方案(2023年3月)流行性感冒(流感)是由流感病毒引起的一种急性华为自研操作系统与锤子科技有什么关系?我想这之间应该没有任何的关系吧。锤子科技目前的发展遇到了很大的瓶颈,就这两天看的新闻来说,我感觉到锤子科技遇到的压力还是非常巨大的,在这种情况下奢谈什么理想,我觉得都是自作多情。华杜仲粉山楂粉三七粉三者合在一起冲开水喝有什么功效与作用?从中医角度来看,杜仲三七山楂均为药食同源之品,且性温和,分别服用或同服对人体均有一定好处。下面我们分别来分析以下三者的作用杜仲的功效与作用杜仲属于补虚药中的补阳药,其性味甘温,归肝虚拟货币为何越禁越涨?炒作的人是什么心态?历史的车轮滚滚向前,不是因为某个利益集团而停止运动。中华文化上下五千年,每一次进步都阻力重重,但是历史不会止步不前,虚拟货币不要视为洪水猛兽,严格监管是重点,让我们随着历史的脚步一