Revert "AllocationSites for all literals"
This reverts commit r17219 due to WebKit failures. R=mstarzinger@chromium.org TBR=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/26539010 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17222 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
ea4e0a3d28
commit
f4edc076d8
@ -1,108 +0,0 @@
|
||||
// Copyright 2013 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "allocation-site-scopes.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
Handle<AllocationSite> AllocationSiteCreationContext::EnterNewScope() {
|
||||
Handle<AllocationSite> scope_site;
|
||||
if (top().is_null()) {
|
||||
// We are creating the top level AllocationSite as opposed to a nested
|
||||
// AllocationSite.
|
||||
InitializeTraversal(isolate()->factory()->NewAllocationSite());
|
||||
scope_site = Handle<AllocationSite>(*top(), isolate());
|
||||
if (FLAG_trace_creation_allocation_sites) {
|
||||
PrintF("*** Creating top level AllocationSite %p\n",
|
||||
static_cast<void*>(*scope_site));
|
||||
}
|
||||
} else {
|
||||
ASSERT(!current().is_null());
|
||||
scope_site = isolate()->factory()->NewAllocationSite();
|
||||
if (FLAG_trace_creation_allocation_sites) {
|
||||
PrintF("Creating nested site (top, current, new) (%p, %p, %p)\n",
|
||||
static_cast<void*>(*top()),
|
||||
static_cast<void*>(*current()),
|
||||
static_cast<void*>(*scope_site));
|
||||
}
|
||||
current()->set_nested_site(*scope_site);
|
||||
update_current_site(*scope_site);
|
||||
}
|
||||
ASSERT(!scope_site.is_null());
|
||||
return scope_site;
|
||||
}
|
||||
|
||||
|
||||
void AllocationSiteCreationContext::ExitScope(
|
||||
Handle<AllocationSite> scope_site,
|
||||
Handle<JSObject> object) {
|
||||
if (!object.is_null() && !object->IsFailure()) {
|
||||
bool top_level = !scope_site.is_null() &&
|
||||
top().is_identical_to(scope_site);
|
||||
|
||||
scope_site->set_transition_info(*object);
|
||||
if (FLAG_trace_creation_allocation_sites) {
|
||||
if (top_level) {
|
||||
PrintF("*** Setting AllocationSite %p transition_info %p\n",
|
||||
static_cast<void*>(*scope_site),
|
||||
static_cast<void*>(*object));
|
||||
} else {
|
||||
PrintF("Setting AllocationSite (%p, %p) transition_info %p\n",
|
||||
static_cast<void*>(*top()),
|
||||
static_cast<void*>(*scope_site),
|
||||
static_cast<void*>(*object));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Handle<AllocationSite> AllocationSiteUsageContext::EnterNewScope() {
|
||||
if (top().is_null()) {
|
||||
InitializeTraversal(top_site_);
|
||||
} else {
|
||||
// Advance current site
|
||||
Object* nested_site = current()->nested_site();
|
||||
// Something is wrong if we advance to the end of the list here.
|
||||
ASSERT(nested_site->IsAllocationSite());
|
||||
update_current_site(AllocationSite::cast(nested_site));
|
||||
}
|
||||
return Handle<AllocationSite>(*current(), isolate());
|
||||
}
|
||||
|
||||
|
||||
void AllocationSiteUsageContext::ExitScope(
|
||||
Handle<AllocationSite> scope_site,
|
||||
Handle<JSObject> object) {
|
||||
// This assert ensures that we are pointing at the right sub-object in a
|
||||
// recursive walk of a nested literal.
|
||||
ASSERT(*object == scope_site->transition_info());
|
||||
}
|
||||
|
||||
} } // namespace v8::internal
|
@ -1,115 +0,0 @@
|
||||
// Copyright 2013 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef V8_ALLOCATION_SITE_SCOPES_H_
|
||||
#define V8_ALLOCATION_SITE_SCOPES_H_
|
||||
|
||||
#include "ast.h"
|
||||
#include "handles.h"
|
||||
#include "objects.h"
|
||||
#include "zone.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// AllocationSiteContext is the base class for walking and copying a nested
|
||||
// boilerplate with AllocationSite and AllocationMemento support.
|
||||
class AllocationSiteContext {
|
||||
public:
|
||||
AllocationSiteContext(Isolate* isolate, bool activated) {
|
||||
isolate_ = isolate;
|
||||
activated_ = activated;
|
||||
};
|
||||
virtual ~AllocationSiteContext() {}
|
||||
|
||||
Handle<AllocationSite> top() { return top_; }
|
||||
Handle<AllocationSite> current() { return current_; }
|
||||
|
||||
// If activated, then recursively create mementos
|
||||
bool activated() const { return activated_; }
|
||||
|
||||
// Returns the AllocationSite that matches this scope.
|
||||
virtual Handle<AllocationSite> EnterNewScope() = 0;
|
||||
|
||||
// scope_site should be the handle returned by the matching EnterNewScope()
|
||||
virtual void ExitScope(Handle<AllocationSite> scope_site,
|
||||
Handle<JSObject> object) = 0;
|
||||
|
||||
protected:
|
||||
void update_current_site(AllocationSite* site) {
|
||||
*(current_.location()) = site;
|
||||
}
|
||||
|
||||
Isolate* isolate() { return isolate_; }
|
||||
void InitializeTraversal(Handle<AllocationSite> site) {
|
||||
top_ = site;
|
||||
current_ = Handle<AllocationSite>(*top_, isolate());
|
||||
}
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
Handle<AllocationSite> top_;
|
||||
Handle<AllocationSite> current_;
|
||||
bool activated_;
|
||||
};
|
||||
|
||||
|
||||
// AllocationSiteCreationContext aids in the creation of AllocationSites to
|
||||
// accompany object literals.
|
||||
class AllocationSiteCreationContext : public AllocationSiteContext {
|
||||
public:
|
||||
explicit AllocationSiteCreationContext(Isolate* isolate)
|
||||
: AllocationSiteContext(isolate, true) { }
|
||||
|
||||
virtual Handle<AllocationSite> EnterNewScope() V8_OVERRIDE;
|
||||
virtual void ExitScope(Handle<AllocationSite> site,
|
||||
Handle<JSObject> object) V8_OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
// AllocationSiteUsageContext aids in the creation of AllocationMementos placed
|
||||
// behind some/all components of a copied object literal.
|
||||
class AllocationSiteUsageContext : public AllocationSiteContext {
|
||||
public:
|
||||
AllocationSiteUsageContext(Isolate* isolate, Handle<AllocationSite> site,
|
||||
bool activated)
|
||||
: AllocationSiteContext(isolate, activated),
|
||||
top_site_(site) { }
|
||||
|
||||
virtual Handle<AllocationSite> EnterNewScope() V8_OVERRIDE;
|
||||
virtual void ExitScope(Handle<AllocationSite> site,
|
||||
Handle<JSObject> object) V8_OVERRIDE;
|
||||
|
||||
private:
|
||||
Handle<AllocationSite> top_site_;
|
||||
};
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_ALLOCATION_SITE_SCOPES_H_
|
@ -806,9 +806,6 @@ DEFINE_implication(log_internal_timer_events, prof)
|
||||
// elements.cc
|
||||
DEFINE_bool(trace_elements_transitions, false, "trace elements transitions")
|
||||
|
||||
DEFINE_bool(trace_creation_allocation_sites, false,
|
||||
"trace the creation of allocation sites")
|
||||
|
||||
// code-stubs.cc
|
||||
DEFINE_bool(print_code_stubs, false, "print code stubs")
|
||||
DEFINE_bool(test_secondary_stub_cache,
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "v8.h"
|
||||
#include "allocation-site-scopes.h"
|
||||
#include "codegen.h"
|
||||
#include "full-codegen.h"
|
||||
#include "hashmap.h"
|
||||
@ -4299,10 +4298,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
|
||||
if (!boilerplate.is_null() &&
|
||||
IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
|
||||
AllocationSiteUsageContext usage_context(isolate(), site, false);
|
||||
usage_context.EnterNewScope();
|
||||
literal = BuildFastLiteral(boilerplate, &usage_context);
|
||||
usage_context.ExitScope(site, boilerplate);
|
||||
literal = BuildFastLiteral(boilerplate);
|
||||
} else {
|
||||
NoObservableSideEffectsScope no_effects(this);
|
||||
Handle<FixedArray> closure_literals(closure->literals(), isolate());
|
||||
@ -4318,9 +4314,6 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
Add<HPushArgument>(Add<HConstant>(constant_properties));
|
||||
Add<HPushArgument>(Add<HConstant>(flags));
|
||||
|
||||
// TODO(mvstanton): Add a flag to turn off creation of any
|
||||
// AllocationMementos for this call: we are in crankshaft and should have
|
||||
// learned enough about transition behavior to stop emitting mementos.
|
||||
Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral;
|
||||
literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
|
||||
Runtime::FunctionForId(function_id),
|
||||
@ -4411,48 +4404,45 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
bool uninitialized = false;
|
||||
Handle<Object> literals_cell(literals->get(expr->literal_index()),
|
||||
isolate());
|
||||
Handle<JSObject> boilerplate_object;
|
||||
Handle<Object> raw_boilerplate;
|
||||
if (literals_cell->IsUndefined()) {
|
||||
uninitialized = true;
|
||||
Handle<Object> raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
|
||||
raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
|
||||
isolate(), literals, expr->constant_elements());
|
||||
if (raw_boilerplate.is_null()) {
|
||||
return Bailout(kArrayBoilerplateCreationFailed);
|
||||
}
|
||||
|
||||
boilerplate_object = Handle<JSObject>::cast(raw_boilerplate);
|
||||
AllocationSiteCreationContext creation_context(isolate());
|
||||
site = creation_context.EnterNewScope();
|
||||
JSObject::DeepWalk(boilerplate_object, &creation_context);
|
||||
creation_context.ExitScope(site, boilerplate_object);
|
||||
site = isolate()->factory()->NewAllocationSite();
|
||||
site->set_transition_info(*raw_boilerplate);
|
||||
literals->set(expr->literal_index(), *site);
|
||||
|
||||
if (boilerplate_object->elements()->map() ==
|
||||
if (JSObject::cast(*raw_boilerplate)->elements()->map() ==
|
||||
isolate()->heap()->fixed_cow_array_map()) {
|
||||
isolate()->counters()->cow_arrays_created_runtime()->Increment();
|
||||
}
|
||||
} else {
|
||||
ASSERT(literals_cell->IsAllocationSite());
|
||||
site = Handle<AllocationSite>::cast(literals_cell);
|
||||
boilerplate_object = Handle<JSObject>(
|
||||
JSObject::cast(site->transition_info()), isolate());
|
||||
raw_boilerplate = Handle<Object>(site->transition_info(), isolate());
|
||||
}
|
||||
|
||||
ASSERT(!boilerplate_object.is_null());
|
||||
ASSERT(site->SitePointsToLiteral());
|
||||
ASSERT(!raw_boilerplate.is_null());
|
||||
ASSERT(site->IsLiteralSite());
|
||||
|
||||
Handle<JSObject> boilerplate_object =
|
||||
Handle<JSObject>::cast(raw_boilerplate);
|
||||
ElementsKind boilerplate_elements_kind =
|
||||
boilerplate_object->GetElementsKind();
|
||||
Handle<JSObject>::cast(boilerplate_object)->GetElementsKind();
|
||||
|
||||
ASSERT(AllocationSite::CanTrack(boilerplate_object->map()->instance_type()));
|
||||
|
||||
// Check whether to use fast or slow deep-copying for boilerplate.
|
||||
int max_properties = kMaxFastLiteralProperties;
|
||||
if (IsFastLiteral(boilerplate_object,
|
||||
kMaxFastLiteralDepth,
|
||||
&max_properties)) {
|
||||
AllocationSiteUsageContext usage_context(isolate(), site, false);
|
||||
usage_context.EnterNewScope();
|
||||
literal = BuildFastLiteral(boilerplate_object, &usage_context);
|
||||
usage_context.ExitScope(site, boilerplate_object);
|
||||
literal = BuildFastLiteral(boilerplate_object);
|
||||
} else {
|
||||
NoObservableSideEffectsScope no_effects(this);
|
||||
// Boilerplate already exists and constant elements are never accessed,
|
||||
@ -4464,9 +4454,6 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
Add<HPushArgument>(Add<HConstant>(literal_index));
|
||||
Add<HPushArgument>(Add<HConstant>(constants));
|
||||
|
||||
// TODO(mvstanton): Consider a flag to turn off creation of any
|
||||
// AllocationMementos for this call: we are in crankshaft and should have
|
||||
// learned enough about transition behavior to stop emitting mementos.
|
||||
Runtime::FunctionId function_id = (expr->depth() > 1)
|
||||
? Runtime::kCreateArrayLiteral : Runtime::kCreateArrayLiteralShallow;
|
||||
literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
|
||||
@ -8355,8 +8342,7 @@ HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
|
||||
|
||||
|
||||
HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
|
||||
Handle<JSObject> boilerplate_object,
|
||||
AllocationSiteContext* site_context) {
|
||||
Handle<JSObject> boilerplate_object) {
|
||||
NoObservableSideEffectsScope no_effects(this);
|
||||
InstanceType instance_type = boilerplate_object->map()->instance_type();
|
||||
ASSERT(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE);
|
||||
@ -8388,15 +8374,15 @@ HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
|
||||
}
|
||||
BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements);
|
||||
|
||||
|
||||
// Copy object elements if non-COW.
|
||||
if (object_elements != NULL) {
|
||||
BuildEmitElements(boilerplate_object, elements, object_elements,
|
||||
site_context);
|
||||
BuildEmitElements(boilerplate_object, elements, object_elements);
|
||||
}
|
||||
|
||||
// Copy in-object properties.
|
||||
if (boilerplate_object->map()->NumberOfFields() != 0) {
|
||||
BuildEmitInObjectProperties(boilerplate_object, object, site_context);
|
||||
BuildEmitInObjectProperties(boilerplate_object, object);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
@ -8448,8 +8434,7 @@ void HOptimizedGraphBuilder::BuildInitElementsInObjectHeader(
|
||||
|
||||
void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
|
||||
Handle<JSObject> boilerplate_object,
|
||||
HInstruction* object,
|
||||
AllocationSiteContext* site_context) {
|
||||
HInstruction* object) {
|
||||
Handle<DescriptorArray> descriptors(
|
||||
boilerplate_object->map()->instance_descriptors());
|
||||
int limit = boilerplate_object->map()->NumberOfOwnDescriptors();
|
||||
@ -8473,10 +8458,7 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
|
||||
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
Handle<AllocationSite> current_site = site_context->EnterNewScope();
|
||||
HInstruction* result =
|
||||
BuildFastLiteral(value_object, site_context);
|
||||
site_context->ExitScope(current_site, value_object);
|
||||
HInstruction* result = BuildFastLiteral(value_object);
|
||||
Add<HStoreNamedField>(object, access, result);
|
||||
} else {
|
||||
Representation representation = details.representation();
|
||||
@ -8485,12 +8467,6 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
|
||||
if (representation.IsDouble()) {
|
||||
// Allocate a HeapNumber box and store the value into it.
|
||||
HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize);
|
||||
// TODO(mvstanton): This heap number alloc does not have a corresponding
|
||||
// AllocationSite. That is okay because
|
||||
// 1) it's a child object of another object with a valid allocation site
|
||||
// 2) we can just use the mode of the parent object for pretenuring
|
||||
// The todo is replace GetPretenureMode() with
|
||||
// site_context->top()->GetPretenureMode().
|
||||
HInstruction* double_box =
|
||||
Add<HAllocate>(heap_number_constant, HType::HeapNumber(),
|
||||
isolate()->heap()->GetPretenureMode(), HEAP_NUMBER_TYPE);
|
||||
@ -8520,8 +8496,7 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
|
||||
void HOptimizedGraphBuilder::BuildEmitElements(
|
||||
Handle<JSObject> boilerplate_object,
|
||||
Handle<FixedArrayBase> elements,
|
||||
HValue* object_elements,
|
||||
AllocationSiteContext* site_context) {
|
||||
HValue* object_elements) {
|
||||
ElementsKind kind = boilerplate_object->map()->elements_kind();
|
||||
int elements_length = elements->length();
|
||||
HValue* object_elements_length = Add<HConstant>(elements_length);
|
||||
@ -8531,8 +8506,7 @@ void HOptimizedGraphBuilder::BuildEmitElements(
|
||||
if (elements->IsFixedDoubleArray()) {
|
||||
BuildEmitFixedDoubleArray(elements, kind, object_elements);
|
||||
} else if (elements->IsFixedArray()) {
|
||||
BuildEmitFixedArray(elements, kind, object_elements,
|
||||
site_context);
|
||||
BuildEmitFixedArray(elements, kind, object_elements);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -8561,8 +8535,7 @@ void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray(
|
||||
void HOptimizedGraphBuilder::BuildEmitFixedArray(
|
||||
Handle<FixedArrayBase> elements,
|
||||
ElementsKind kind,
|
||||
HValue* object_elements,
|
||||
AllocationSiteContext* site_context) {
|
||||
HValue* object_elements) {
|
||||
HInstruction* boilerplate_elements = Add<HConstant>(elements);
|
||||
int elements_length = elements->length();
|
||||
Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
|
||||
@ -8571,10 +8544,7 @@ void HOptimizedGraphBuilder::BuildEmitFixedArray(
|
||||
HValue* key_constant = Add<HConstant>(i);
|
||||
if (value->IsJSObject()) {
|
||||
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
||||
Handle<AllocationSite> current_site = site_context->EnterNewScope();
|
||||
HInstruction* result =
|
||||
BuildFastLiteral(value_object, site_context);
|
||||
site_context->ExitScope(current_site, value_object);
|
||||
HInstruction* result = BuildFastLiteral(value_object);
|
||||
Add<HStoreKeyed>(object_elements, key_constant, result, kind);
|
||||
} else {
|
||||
HInstruction* value_instruction =
|
||||
|
@ -2248,8 +2248,7 @@ class HOptimizedGraphBuilder V8_FINAL
|
||||
|
||||
HInstruction* BuildThisFunction();
|
||||
|
||||
HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object,
|
||||
AllocationSiteContext* site_context);
|
||||
HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object);
|
||||
|
||||
void BuildEmitObjectHeader(Handle<JSObject> boilerplate_object,
|
||||
HInstruction* object);
|
||||
@ -2259,13 +2258,11 @@ class HOptimizedGraphBuilder V8_FINAL
|
||||
HInstruction* object_elements);
|
||||
|
||||
void BuildEmitInObjectProperties(Handle<JSObject> boilerplate_object,
|
||||
HInstruction* object,
|
||||
AllocationSiteContext* site_context);
|
||||
HInstruction* object);
|
||||
|
||||
void BuildEmitElements(Handle<JSObject> boilerplate_object,
|
||||
Handle<FixedArrayBase> elements,
|
||||
HValue* object_elements,
|
||||
AllocationSiteContext* site_context);
|
||||
HValue* object_elements);
|
||||
|
||||
void BuildEmitFixedDoubleArray(Handle<FixedArrayBase> elements,
|
||||
ElementsKind kind,
|
||||
@ -2273,8 +2270,7 @@ class HOptimizedGraphBuilder V8_FINAL
|
||||
|
||||
void BuildEmitFixedArray(Handle<FixedArrayBase> elements,
|
||||
ElementsKind kind,
|
||||
HValue* object_elements,
|
||||
AllocationSiteContext* site_context);
|
||||
HValue* object_elements);
|
||||
|
||||
void AddCheckPrototypeMaps(Handle<JSObject> holder,
|
||||
Handle<Map> receiver_map);
|
||||
|
114
src/objects.cc
114
src/objects.cc
@ -28,7 +28,6 @@
|
||||
#include "v8.h"
|
||||
|
||||
#include "accessors.h"
|
||||
#include "allocation-site-scopes.h"
|
||||
#include "api.h"
|
||||
#include "arguments.h"
|
||||
#include "bootstrapper.h"
|
||||
@ -5616,14 +5615,6 @@ MUST_USE_RESULT MaybeObject* JSObject::SetObserved(Isolate* isolate) {
|
||||
}
|
||||
|
||||
|
||||
Handle<JSObject> JSObject::Copy(Handle<JSObject> object,
|
||||
Handle<AllocationSite> site) {
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
CALL_HEAP_FUNCTION(isolate,
|
||||
isolate->heap()->CopyJSObject(*object, *site), JSObject);
|
||||
}
|
||||
|
||||
|
||||
Handle<JSObject> JSObject::Copy(Handle<JSObject> object) {
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
CALL_HEAP_FUNCTION(isolate,
|
||||
@ -5633,93 +5624,45 @@ Handle<JSObject> JSObject::Copy(Handle<JSObject> object) {
|
||||
|
||||
class JSObjectWalkVisitor {
|
||||
public:
|
||||
explicit JSObjectWalkVisitor(AllocationSiteContext* site_context) :
|
||||
site_context_(site_context) {}
|
||||
explicit JSObjectWalkVisitor() {}
|
||||
virtual ~JSObjectWalkVisitor() {}
|
||||
|
||||
Handle<JSObject> Visit(Handle<JSObject> object) {
|
||||
return StructureWalk(object);
|
||||
}
|
||||
|
||||
// Returns true if the visitor is a copying visitor.
|
||||
virtual bool is_copying() = 0;
|
||||
|
||||
protected:
|
||||
Handle<JSObject> StructureWalk(Handle<JSObject> object);
|
||||
|
||||
// The returned handle will be used for the object in all subsequent usages.
|
||||
// This allows VisitObject to make a copy of the object if desired.
|
||||
// The returned handle should point to a new object if the visitor is a
|
||||
// copying visitor, otherwise it should be the same as the input object.
|
||||
virtual Handle<JSObject> VisitObject(Handle<JSObject> object) = 0;
|
||||
|
||||
// The returned handle should point to a new value if the visitor is a
|
||||
// copying visitor, otherwise it should be the same as the input value.
|
||||
virtual Handle<JSObject> VisitElementOrProperty(Handle<JSObject> object,
|
||||
Handle<JSObject> value) = 0;
|
||||
|
||||
AllocationSiteContext* site_context() { return site_context_; }
|
||||
|
||||
private:
|
||||
AllocationSiteContext* site_context_;
|
||||
};
|
||||
|
||||
|
||||
class JSObjectCopyVisitor: public JSObjectWalkVisitor {
|
||||
public:
|
||||
explicit JSObjectCopyVisitor(AllocationSiteContext* site_context)
|
||||
: JSObjectWalkVisitor(site_context) {}
|
||||
explicit JSObjectCopyVisitor() {}
|
||||
|
||||
virtual bool is_copying() V8_OVERRIDE { return true; }
|
||||
|
||||
// The returned handle will be used for the object in all
|
||||
// subsequent usages. This allows VisitObject to make a copy
|
||||
// of the object if desired.
|
||||
protected:
|
||||
virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE {
|
||||
// Only create a memento if
|
||||
// 1) we have a JSArray, and
|
||||
// 2) the elements kind is palatable
|
||||
// 3) allow_mementos is true
|
||||
Handle<JSObject> copy;
|
||||
if (site_context()->activated() &&
|
||||
AllocationSite::CanTrack(object->map()->instance_type()) &&
|
||||
AllocationSite::GetMode(object->GetElementsKind()) ==
|
||||
TRACK_ALLOCATION_SITE) {
|
||||
copy = JSObject::Copy(object, site_context()->current());
|
||||
} else {
|
||||
copy = JSObject::Copy(object);
|
||||
}
|
||||
|
||||
return copy;
|
||||
return JSObject::Copy(object);
|
||||
}
|
||||
|
||||
virtual Handle<JSObject> VisitElementOrProperty(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> value) V8_OVERRIDE {
|
||||
Handle<AllocationSite> current_site = site_context()->EnterNewScope();
|
||||
Handle<JSObject> copy_of_value = StructureWalk(value);
|
||||
site_context()->ExitScope(current_site, value);
|
||||
return copy_of_value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class JSObjectCreateAllocationSitesVisitor: public JSObjectWalkVisitor {
|
||||
public:
|
||||
explicit JSObjectCreateAllocationSitesVisitor(
|
||||
AllocationSiteContext* site_context)
|
||||
: JSObjectWalkVisitor(site_context) {}
|
||||
|
||||
virtual bool is_copying() V8_OVERRIDE { return false; }
|
||||
|
||||
// The returned handle will be used for the object in all
|
||||
// subsequent usages. This allows VisitObject to make a copy
|
||||
// of the object if desired.
|
||||
virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE {
|
||||
return object;
|
||||
}
|
||||
|
||||
virtual Handle<JSObject> VisitElementOrProperty(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> value) V8_OVERRIDE {
|
||||
Handle<AllocationSite> current_site = site_context()->EnterNewScope();
|
||||
value = StructureWalk(value);
|
||||
site_context()->ExitScope(current_site, value);
|
||||
return value;
|
||||
return StructureWalk(value);
|
||||
}
|
||||
};
|
||||
|
||||
@ -5866,18 +5809,8 @@ Handle<JSObject> JSObjectWalkVisitor::StructureWalk(Handle<JSObject> object) {
|
||||
}
|
||||
|
||||
|
||||
Handle<JSObject> JSObject::DeepWalk(Handle<JSObject> object,
|
||||
AllocationSiteContext* site_context) {
|
||||
JSObjectCreateAllocationSitesVisitor v(site_context);
|
||||
Handle<JSObject> copy = v.Visit(object);
|
||||
ASSERT(!v.is_copying() && copy.is_identical_to(object));
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object,
|
||||
AllocationSiteContext* site_context) {
|
||||
JSObjectCopyVisitor v(site_context);
|
||||
Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
|
||||
JSObjectCopyVisitor v;
|
||||
Handle<JSObject> copy = v.Visit(object);
|
||||
ASSERT(v.is_copying() && !copy.is_identical_to(object));
|
||||
return copy;
|
||||
@ -12640,20 +12573,6 @@ void JSObject::TransitionElementsKind(Handle<JSObject> object,
|
||||
}
|
||||
|
||||
|
||||
bool AllocationSite::IsNestedSite() {
|
||||
ASSERT(FLAG_trace_track_allocation_sites);
|
||||
Object* current = GetHeap()->allocation_sites_list();
|
||||
while (current != NULL && current->IsAllocationSite()) {
|
||||
AllocationSite* current_site = AllocationSite::cast(current);
|
||||
if (current_site->nested_site() == this) {
|
||||
return true;
|
||||
}
|
||||
current = current_site->weak_next();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) {
|
||||
if (!FLAG_track_allocation_sites || !IsJSArray()) {
|
||||
return this;
|
||||
@ -12666,8 +12585,7 @@ MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) {
|
||||
|
||||
// Walk through to the Allocation Site
|
||||
AllocationSite* site = memento->GetAllocationSite();
|
||||
if (site->SitePointsToLiteral() &&
|
||||
site->transition_info()->IsJSArray()) {
|
||||
if (site->IsLiteralSite()) {
|
||||
JSArray* transition_info = JSArray::cast(site->transition_info());
|
||||
ElementsKind kind = transition_info->GetElementsKind();
|
||||
// if kind is holey ensure that to_kind is as well.
|
||||
@ -12681,11 +12599,9 @@ MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) {
|
||||
CHECK(transition_info->length()->ToArrayIndex(&length));
|
||||
if (length <= AllocationSite::kMaximumArrayBytesToPretransition) {
|
||||
if (FLAG_trace_track_allocation_sites) {
|
||||
bool is_nested = site->IsNestedSite();
|
||||
PrintF(
|
||||
"AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
|
||||
"AllocationSite: JSArray %p boilerplate updated %s->%s\n",
|
||||
reinterpret_cast<void*>(this),
|
||||
is_nested ? "(nested)" : "",
|
||||
ElementsKindToString(kind),
|
||||
ElementsKindToString(to_kind));
|
||||
}
|
||||
|
@ -865,9 +865,8 @@ enum CompareResult {
|
||||
inline void set_##name(type* value, \
|
||||
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \
|
||||
|
||||
|
||||
class AccessorPair;
|
||||
class AllocationSite;
|
||||
class AllocationSiteContext;
|
||||
class DictionaryElementsAccessor;
|
||||
class ElementsAccessor;
|
||||
class Failure;
|
||||
@ -2545,13 +2544,8 @@ class JSObject: public JSReceiver {
|
||||
MUST_USE_RESULT MaybeObject* SetObserved(Isolate* isolate);
|
||||
|
||||
// Copy object.
|
||||
static Handle<JSObject> Copy(Handle<JSObject> object,
|
||||
Handle<AllocationSite> site);
|
||||
static Handle<JSObject> Copy(Handle<JSObject> object);
|
||||
static Handle<JSObject> DeepCopy(Handle<JSObject> object,
|
||||
AllocationSiteContext* site_context);
|
||||
static Handle<JSObject> DeepWalk(Handle<JSObject> object,
|
||||
AllocationSiteContext* site_context);
|
||||
static Handle<JSObject> DeepCopy(Handle<JSObject> object);
|
||||
|
||||
// Casting.
|
||||
static inline JSObject* cast(Object* obj);
|
||||
@ -8011,15 +8005,8 @@ class AllocationSite: public Struct {
|
||||
|
||||
inline void Initialize();
|
||||
|
||||
bool HasNestedSites() {
|
||||
return nested_site()->IsAllocationSite();
|
||||
}
|
||||
|
||||
// This method is expensive, it should only be called for reporting.
|
||||
bool IsNestedSite();
|
||||
|
||||
ElementsKind GetElementsKind() {
|
||||
ASSERT(!SitePointsToLiteral());
|
||||
ASSERT(!IsLiteralSite());
|
||||
return static_cast<ElementsKind>(Smi::cast(transition_info())->value());
|
||||
}
|
||||
|
||||
@ -8027,11 +8014,11 @@ class AllocationSite: public Struct {
|
||||
set_transition_info(Smi::FromInt(static_cast<int>(kind)));
|
||||
}
|
||||
|
||||
bool SitePointsToLiteral() {
|
||||
bool IsLiteralSite() {
|
||||
// If transition_info is a smi, then it represents an ElementsKind
|
||||
// for a constructed array. Otherwise, it must be a boilerplate
|
||||
// for an object or array literal.
|
||||
return transition_info()->IsJSArray() || transition_info()->IsJSObject();
|
||||
// for an array literal
|
||||
return transition_info()->IsJSArray();
|
||||
}
|
||||
|
||||
DECLARE_PRINTER(AllocationSite)
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include "v8.h"
|
||||
|
||||
#include "accessors.h"
|
||||
#include "allocation-site-scopes.h"
|
||||
#include "api.h"
|
||||
#include "arguments.h"
|
||||
#include "bootstrapper.h"
|
||||
@ -489,34 +488,25 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
|
||||
// Check if boilerplate exists. If not, create it first.
|
||||
Handle<Object> literal_site(literals->get(literals_index), isolate);
|
||||
Handle<AllocationSite> site;
|
||||
Handle<JSObject> boilerplate;
|
||||
Handle<Object> boilerplate;
|
||||
if (*literal_site == isolate->heap()->undefined_value()) {
|
||||
Handle<Object> raw_boilerplate = CreateObjectLiteralBoilerplate(
|
||||
isolate,
|
||||
literals,
|
||||
constant_properties,
|
||||
should_have_fast_elements,
|
||||
has_function_literal);
|
||||
RETURN_IF_EMPTY_HANDLE(isolate, raw_boilerplate);
|
||||
boilerplate = Handle<JSObject>::cast(raw_boilerplate);
|
||||
|
||||
AllocationSiteCreationContext creation_context(isolate);
|
||||
site = creation_context.EnterNewScope();
|
||||
JSObject::DeepWalk(boilerplate, &creation_context);
|
||||
creation_context.ExitScope(site, boilerplate);
|
||||
boilerplate = CreateObjectLiteralBoilerplate(isolate,
|
||||
literals,
|
||||
constant_properties,
|
||||
should_have_fast_elements,
|
||||
has_function_literal);
|
||||
RETURN_IF_EMPTY_HANDLE(isolate, boilerplate);
|
||||
site = isolate->factory()->NewAllocationSite();
|
||||
site->set_transition_info(*boilerplate);
|
||||
|
||||
// Update the functions literal and return the boilerplate.
|
||||
literals->set(literals_index, *site);
|
||||
} else {
|
||||
site = Handle<AllocationSite>::cast(literal_site);
|
||||
boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
|
||||
isolate);
|
||||
boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()));
|
||||
}
|
||||
|
||||
AllocationSiteUsageContext usage_context(isolate, site, true);
|
||||
usage_context.EnterNewScope();
|
||||
Handle<Object> copy = JSObject::DeepCopy(boilerplate, &usage_context);
|
||||
usage_context.ExitScope(site, boilerplate);
|
||||
Handle<Object> copy = JSObject::DeepCopy(Handle<JSObject>::cast(boilerplate));
|
||||
RETURN_IF_EMPTY_HANDLE(isolate, copy);
|
||||
return *copy;
|
||||
}
|
||||
@ -534,13 +524,12 @@ static Handle<AllocationSite> GetLiteralAllocationSite(
|
||||
ASSERT(*elements != isolate->heap()->empty_fixed_array());
|
||||
Handle<Object> boilerplate =
|
||||
Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
|
||||
if (boilerplate.is_null()) return Handle<AllocationSite>::null();
|
||||
|
||||
AllocationSiteCreationContext creation_context(isolate);
|
||||
site = creation_context.EnterNewScope();
|
||||
JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate), &creation_context);
|
||||
creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate));
|
||||
|
||||
if (boilerplate.is_null()) {
|
||||
ASSERT(site.is_null());
|
||||
return site;
|
||||
}
|
||||
site = isolate->factory()->NewAllocationSite();
|
||||
site->set_transition_info(*boilerplate);
|
||||
literals->set(literals_index, *site);
|
||||
} else {
|
||||
site = Handle<AllocationSite>::cast(literal_site);
|
||||
@ -562,10 +551,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
|
||||
RETURN_IF_EMPTY_HANDLE(isolate, site);
|
||||
|
||||
Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
|
||||
AllocationSiteUsageContext usage_context(isolate, site, true);
|
||||
usage_context.EnterNewScope();
|
||||
Handle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context);
|
||||
usage_context.ExitScope(site, boilerplate);
|
||||
Handle<JSObject> copy = JSObject::DeepCopy(boilerplate);
|
||||
RETURN_IF_EMPTY_HANDLE(isolate, copy);
|
||||
return *copy;
|
||||
}
|
||||
@ -588,8 +574,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
|
||||
isolate->counters()->cow_arrays_created_runtime()->Increment();
|
||||
}
|
||||
|
||||
if (AllocationSite::GetMode(boilerplate->GetElementsKind()) ==
|
||||
TRACK_ALLOCATION_SITE) {
|
||||
AllocationSiteMode mode = AllocationSite::GetMode(
|
||||
boilerplate->GetElementsKind());
|
||||
if (mode == TRACK_ALLOCATION_SITE) {
|
||||
return isolate->heap()->CopyJSObject(boilerplate, *site);
|
||||
}
|
||||
|
||||
@ -14698,7 +14685,7 @@ static MaybeObject* ArrayConstructorCommon(Isolate* isolate,
|
||||
Handle<Cell> cell = Handle<Cell>::cast(type_info);
|
||||
Handle<AllocationSite> site = Handle<AllocationSite>(
|
||||
AllocationSite::cast(cell->value()), isolate);
|
||||
ASSERT(!site->SitePointsToLiteral());
|
||||
ASSERT(!site->IsLiteralSite());
|
||||
ElementsKind to_kind = site->GetElementsKind();
|
||||
if (holey && !IsFastHoleyElementsKind(to_kind)) {
|
||||
to_kind = GetHoleyElementsKind(to_kind);
|
||||
|
@ -383,114 +383,4 @@ if (support_smi_only_arrays) {
|
||||
|
||||
instanceof_check(realmBArray);
|
||||
assertUnoptimized(instanceof_check);
|
||||
|
||||
// Case: make sure nested arrays benefit from allocation site feedback as
|
||||
// well.
|
||||
(function() {
|
||||
// Make sure we handle nested arrays
|
||||
function get_nested_literal() {
|
||||
var literal = [[1,2,3,4], [2], [3]];
|
||||
return literal;
|
||||
}
|
||||
|
||||
obj = get_nested_literal();
|
||||
assertKind(elements_kind.fast, obj);
|
||||
obj[0][0] = 3.5;
|
||||
obj[2][0] = "hello";
|
||||
obj = get_nested_literal();
|
||||
assertKind(elements_kind.fast_double, obj[0]);
|
||||
assertKind(elements_kind.fast_smi_only, obj[1]);
|
||||
assertKind(elements_kind.fast, obj[2]);
|
||||
|
||||
// A more complex nested literal case.
|
||||
function get_deep_nested_literal() {
|
||||
var literal = [[1], [[2], "hello"], 3, [4]];
|
||||
return literal;
|
||||
}
|
||||
|
||||
obj = get_deep_nested_literal();
|
||||
assertKind(elements_kind.fast_smi_only, obj[1][0]);
|
||||
obj[0][0] = 3.5;
|
||||
obj[1][0][0] = "goodbye";
|
||||
assertKind(elements_kind.fast_double, obj[0]);
|
||||
assertKind(elements_kind.fast, obj[1][0]);
|
||||
|
||||
obj = get_deep_nested_literal();
|
||||
assertKind(elements_kind.fast_double, obj[0]);
|
||||
assertKind(elements_kind.fast, obj[1][0]);
|
||||
})();
|
||||
|
||||
|
||||
// Make sure object literals with array fields benefit from the type feedback
|
||||
// that allocation mementos provide.
|
||||
(function() {
|
||||
// A literal in an object
|
||||
function get_object_literal() {
|
||||
var literal = {
|
||||
array: [1,2,3],
|
||||
data: 3.5
|
||||
};
|
||||
return literal;
|
||||
}
|
||||
|
||||
obj = get_object_literal();
|
||||
assertKind(elements_kind.fast_smi_only, obj.array);
|
||||
obj.array[1] = 3.5;
|
||||
assertKind(elements_kind.fast_double, obj.array);
|
||||
obj = get_object_literal();
|
||||
assertKind(elements_kind.fast_double, obj.array);
|
||||
|
||||
function get_nested_object_literal() {
|
||||
var literal = {
|
||||
array: [[1],[2],[3]],
|
||||
data: 3.5
|
||||
};
|
||||
return literal;
|
||||
}
|
||||
|
||||
obj = get_nested_object_literal();
|
||||
assertKind(elements_kind.fast, obj.array);
|
||||
assertKind(elements_kind.fast_smi_only, obj.array[1]);
|
||||
obj.array[1][0] = 3.5;
|
||||
assertKind(elements_kind.fast_double, obj.array[1]);
|
||||
obj = get_nested_object_literal();
|
||||
assertKind(elements_kind.fast_double, obj.array[1]);
|
||||
|
||||
%OptimizeFunctionOnNextCall(get_nested_object_literal);
|
||||
get_nested_object_literal();
|
||||
obj = get_nested_object_literal();
|
||||
assertKind(elements_kind.fast_double, obj.array[1]);
|
||||
|
||||
// Make sure we handle nested arrays
|
||||
function get_nested_literal() {
|
||||
var literal = [[1,2,3,4], [2], [3]];
|
||||
return literal;
|
||||
}
|
||||
|
||||
obj = get_nested_literal();
|
||||
assertKind(elements_kind.fast, obj);
|
||||
obj[0][0] = 3.5;
|
||||
obj[2][0] = "hello";
|
||||
obj = get_nested_literal();
|
||||
assertKind(elements_kind.fast_double, obj[0]);
|
||||
assertKind(elements_kind.fast_smi_only, obj[1]);
|
||||
assertKind(elements_kind.fast, obj[2]);
|
||||
|
||||
// A more complex nested literal case.
|
||||
function get_deep_nested_literal() {
|
||||
var literal = [[1], [[2], "hello"], 3, [4]];
|
||||
return literal;
|
||||
}
|
||||
|
||||
obj = get_deep_nested_literal();
|
||||
assertKind(elements_kind.fast_smi_only, obj[1][0]);
|
||||
obj[0][0] = 3.5;
|
||||
obj[1][0][0] = "goodbye";
|
||||
assertKind(elements_kind.fast_double, obj[0]);
|
||||
assertKind(elements_kind.fast, obj[1][0]);
|
||||
|
||||
obj = get_deep_nested_literal();
|
||||
assertKind(elements_kind.fast_double, obj[0]);
|
||||
assertKind(elements_kind.fast, obj[1][0]);
|
||||
})();
|
||||
}
|
||||
|
@ -209,8 +209,6 @@
|
||||
'../../src/accessors.h',
|
||||
'../../src/allocation.cc',
|
||||
'../../src/allocation.h',
|
||||
'../../src/allocation-site-scopes.cc',
|
||||
'../../src/allocation-site-scopes.h',
|
||||
'../../src/api.cc',
|
||||
'../../src/api.h',
|
||||
'../../src/apiutils.h',
|
||||
|
Loading…
Reference in New Issue
Block a user