blob: 1f52a225de9ceee3a4cefc1d0e1d1e8b785da2e4 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000109MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
110 JSObject* boilerplate) {
111 StackLimitCheck check(isolate);
112 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000115 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000116 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000117 if (!maybe_result->ToObject(&result)) return maybe_result;
118 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119 JSObject* copy = JSObject::cast(result);
120
121 // Deep copy local properties.
122 if (copy->HasFastProperties()) {
123 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000124 for (int i = 0; i < properties->length(); i++) {
125 Object* value = properties->get(i);
126 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000127 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000128 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000129 if (!maybe_result->ToObject(&result)) return maybe_result;
130 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000131 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000132 }
133 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000134 int nof = copy->map()->inobject_properties();
135 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000136 Object* value = copy->InObjectPropertyAt(i);
137 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000138 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000140 if (!maybe_result->ToObject(&result)) return maybe_result;
141 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000142 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000143 }
144 }
145 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000147 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000148 if (!maybe_result->ToObject(&result)) return maybe_result;
149 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 FixedArray* names = FixedArray::cast(result);
151 copy->GetLocalPropertyNames(names, 0);
152 for (int i = 0; i < names->length(); i++) {
153 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000154 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000155 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000156 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 // Only deep copy fields from the object literal expression.
158 // In particular, don't try to copy the length attribute of
159 // an array.
160 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 Object* value =
162 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000163 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000164 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000165 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000166 if (!maybe_result->ToObject(&result)) return maybe_result;
167 }
168 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000169 // Creating object copy for literals. No strict mode needed.
170 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000171 if (!maybe_result->ToObject(&result)) return maybe_result;
172 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 }
174 }
175 }
176
177 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000178 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000179 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000180 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000181 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000182 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000183 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000184 if (elements->map() == heap->fixed_cow_array_map()) {
185 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000186#ifdef DEBUG
187 for (int i = 0; i < elements->length(); i++) {
188 ASSERT(!elements->get(i)->IsJSObject());
189 }
190#endif
191 } else {
192 for (int i = 0; i < elements->length(); i++) {
193 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000194 ASSERT(value->IsSmi() ||
195 value->IsTheHole() ||
196 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000197 if (value->IsJSObject()) {
198 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000199 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
200 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000201 if (!maybe_result->ToObject(&result)) return maybe_result;
202 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000203 elements->set(i, result);
204 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000205 }
206 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000207 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000208 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000209 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000210 NumberDictionary* element_dictionary = copy->element_dictionary();
211 int capacity = element_dictionary->Capacity();
212 for (int i = 0; i < capacity; i++) {
213 Object* k = element_dictionary->KeyAt(i);
214 if (element_dictionary->IsKey(k)) {
215 Object* value = element_dictionary->ValueAt(i);
216 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000217 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000218 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
219 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000220 if (!maybe_result->ToObject(&result)) return maybe_result;
221 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000222 element_dictionary->ValueAtPut(i, result);
223 }
224 }
225 }
226 break;
227 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000228 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000229 UNIMPLEMENTED();
230 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000231 case EXTERNAL_PIXEL_ELEMENTS:
232 case EXTERNAL_BYTE_ELEMENTS:
233 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
234 case EXTERNAL_SHORT_ELEMENTS:
235 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
236 case EXTERNAL_INT_ELEMENTS:
237 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
238 case EXTERNAL_FLOAT_ELEMENTS:
239 case EXTERNAL_DOUBLE_ELEMENTS:
240 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000241 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000242 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000243 }
244 return copy;
245}
246
247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000248RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000249 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000250 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000251}
252
253
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000254RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000256 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000257}
258
259
ager@chromium.org236ad962008-09-25 09:45:57 +0000260static Handle<Map> ComputeObjectLiteralMap(
261 Handle<Context> context,
262 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000263 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000264 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 int properties_length = constant_properties->length();
266 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000268 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000270 for (int p = 0; p != properties_length; p += 2) {
271 Object* key = constant_properties->get(p);
272 uint32_t element_index = 0;
273 if (key->IsSymbol()) {
274 number_of_symbol_keys++;
275 } else if (key->ToArrayIndex(&element_index)) {
276 // An index key does not require space in the property backing store.
277 number_of_properties--;
278 } else {
279 // Bail out as a non-symbol non-index key makes caching impossible.
280 // ASSERT to make sure that the if condition after the loop is false.
281 ASSERT(number_of_symbol_keys != number_of_properties);
282 break;
283 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000285 // If we only have symbols and array indices among keys then we can
286 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000287 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000288 if ((number_of_symbol_keys == number_of_properties) &&
289 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000290 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000291 Handle<FixedArray> keys =
292 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000293 if (number_of_symbol_keys > 0) {
294 int index = 0;
295 for (int p = 0; p < properties_length; p += 2) {
296 Object* key = constant_properties->get(p);
297 if (key->IsSymbol()) {
298 keys->set(index++, key);
299 }
300 }
301 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000302 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000303 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000305 }
306 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000307 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000308 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000309 Handle<Map>(context->object_function()->initial_map()),
310 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000311}
312
313
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000314static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000316 Handle<FixedArray> literals,
317 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000318
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000319
320static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000321 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000322 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000323 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 bool should_have_fast_elements,
325 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000326 // Get the global context from the literals array. This is the
327 // context in which the function was created and we use the object
328 // function from this context to create the object literal. We do
329 // not use the object function from the current global context
330 // because this might be the object function from another context
331 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000332 Handle<Context> context =
333 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
334
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000335 // In case we have function literals, we want the object to be in
336 // slow properties mode for now. We don't go in the map cache because
337 // maps with constant functions can't be shared if the functions are
338 // not the same (which is the common case).
339 bool is_result_from_cache = false;
340 Handle<Map> map = has_function_literal
341 ? Handle<Map>(context->object_function()->initial_map())
342 : ComputeObjectLiteralMap(context,
343 constant_properties,
344 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000346 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000347
348 // Normalize the elements of the boilerplate to save space if needed.
349 if (!should_have_fast_elements) NormalizeElements(boilerplate);
350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000351 // Add the constant properties to the boilerplate.
352 int length = constant_properties->length();
353 bool should_transform =
354 !is_result_from_cache && boilerplate->HasFastProperties();
355 if (should_transform || has_function_literal) {
356 // Normalize the properties of object to avoid n^2 behavior
357 // when extending the object multiple properties. Indicate the number of
358 // properties to be added.
359 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
360 }
361
362 for (int index = 0; index < length; index +=2) {
363 Handle<Object> key(constant_properties->get(index+0), isolate);
364 Handle<Object> value(constant_properties->get(index+1), isolate);
365 if (value->IsFixedArray()) {
366 // The value contains the constant_properties of a
367 // simple object or array literal.
368 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
369 value = CreateLiteralBoilerplate(isolate, literals, array);
370 if (value.is_null()) return value;
371 }
372 Handle<Object> result;
373 uint32_t element_index = 0;
374 if (key->IsSymbol()) {
375 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
376 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000377 result = SetOwnElement(boilerplate,
378 element_index,
379 value,
380 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000382 Handle<String> name(String::cast(*key));
383 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000384 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
385 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000387 } else if (key->ToArrayIndex(&element_index)) {
388 // Array index (uint32).
389 result = SetOwnElement(boilerplate,
390 element_index,
391 value,
392 kNonStrictMode);
393 } else {
394 // Non-uint32 number.
395 ASSERT(key->IsNumber());
396 double num = key->Number();
397 char arr[100];
398 Vector<char> buffer(arr, ARRAY_SIZE(arr));
399 const char* str = DoubleToCString(num, buffer);
400 Handle<String> name =
401 isolate->factory()->NewStringFromAscii(CStrVector(str));
402 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
403 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 // If setting the property on the boilerplate throws an
406 // exception, the exception is converted to an empty handle in
407 // the handle based operations. In that case, we need to
408 // convert back to an exception.
409 if (result.is_null()) return result;
410 }
411
412 // Transform to fast properties if necessary. For object literals with
413 // containing function literals we defer this operation until after all
414 // computed properties have been assigned so that we can generate
415 // constant function properties.
416 if (should_transform && !has_function_literal) {
417 TransformToFastProperties(boilerplate,
418 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000419 }
420
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000421 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000422}
423
424
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000425static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000426 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000427 Handle<FixedArray> literals,
428 Handle<FixedArray> elements) {
429 // Create the JSArray.
430 Handle<JSFunction> constructor(
431 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000433
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000434 const bool is_cow =
435 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000436 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000437 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438
439 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000440 bool has_non_smi = false;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000441 if (is_cow) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000442 // Copy-on-write arrays must be shallow (and simple).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000443 if (FLAG_smi_only_arrays) {
444 for (int i = 0; i < content->length(); i++) {
445 Object* current = content->get(i);
446 ASSERT(!current->IsFixedArray());
447 if (!current->IsSmi() && !current->IsTheHole()) {
448 has_non_smi = true;
449 }
450 }
451 } else {
452#if DEBUG
453 for (int i = 0; i < content->length(); i++) {
454 ASSERT(!content->get(i)->IsFixedArray());
455 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000456#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000457 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000458 } else {
459 for (int i = 0; i < content->length(); i++) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000460 Object* current = content->get(i);
461 if (current->IsFixedArray()) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000462 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000463 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000464 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
465 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000467 if (result.is_null()) return result;
468 content->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000469 has_non_smi = true;
470 } else {
471 if (!current->IsSmi() && !current->IsTheHole()) {
472 has_non_smi = true;
473 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000474 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000475 }
476 }
477
478 // Set the elements.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000479 Handle<JSArray> js_object(Handle<JSArray>::cast(object));
480 isolate->factory()->SetContent(js_object, content);
481
482 if (FLAG_smi_only_arrays) {
483 if (has_non_smi && js_object->HasFastSmiOnlyElements()) {
484 isolate->factory()->EnsureCanContainNonSmiElements(js_object);
485 }
486 }
487
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000488 return object;
489}
490
491
492static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000493 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000494 Handle<FixedArray> literals,
495 Handle<FixedArray> array) {
496 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000497 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000498 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000499 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000500 return CreateObjectLiteralBoilerplate(isolate,
501 literals,
502 elements,
503 true,
504 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000505 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000506 return CreateObjectLiteralBoilerplate(isolate,
507 literals,
508 elements,
509 false,
510 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000511 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000513 default:
514 UNREACHABLE();
515 return Handle<Object>::null();
516 }
517}
518
519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000520RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000521 // Takes a FixedArray of elements containing the literal elements of
522 // the array literal and produces JSArray with those elements.
523 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000524 // which contains the context from which to get the Array function
525 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000526 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000527 ASSERT(args.length() == 3);
528 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000529 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000530 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000532 Handle<Object> object =
533 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000534 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000535
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000536 // Update the functions literal and return the boilerplate.
537 literals->set(literals_index, *object);
538 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000539}
540
541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000542RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000543 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000544 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000545 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000546 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000548 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
550 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000551
552 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000553 Handle<Object> boilerplate(literals->get(literals_index), isolate);
554 if (*boilerplate == isolate->heap()->undefined_value()) {
555 boilerplate = CreateObjectLiteralBoilerplate(isolate,
556 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000557 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 should_have_fast_elements,
559 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000560 if (boilerplate.is_null()) return Failure::Exception();
561 // Update the functions literal and return the boilerplate.
562 literals->set(literals_index, *boilerplate);
563 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565}
566
567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000568RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000570 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000571 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000572 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000573 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000574 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000575 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
576 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000577
578 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 Handle<Object> boilerplate(literals->get(literals_index), isolate);
580 if (*boilerplate == isolate->heap()->undefined_value()) {
581 boilerplate = CreateObjectLiteralBoilerplate(isolate,
582 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000583 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 should_have_fast_elements,
585 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000586 if (boilerplate.is_null()) return Failure::Exception();
587 // Update the functions literal and return the boilerplate.
588 literals->set(literals_index, *boilerplate);
589 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000590 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000591}
592
593
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000594RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000595 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000596 ASSERT(args.length() == 3);
597 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000598 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000599 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
600
601 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 Handle<Object> boilerplate(literals->get(literals_index), isolate);
603 if (*boilerplate == isolate->heap()->undefined_value()) {
604 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000605 if (boilerplate.is_null()) return Failure::Exception();
606 // Update the functions literal and return the boilerplate.
607 literals->set(literals_index, *boilerplate);
608 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000610}
611
612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000613RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000615 ASSERT(args.length() == 3);
616 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000617 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000618 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
619
620 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000621 Handle<Object> boilerplate(literals->get(literals_index), isolate);
622 if (*boilerplate == isolate->heap()->undefined_value()) {
623 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000624 if (boilerplate.is_null()) return Failure::Exception();
625 // Update the functions literal and return the boilerplate.
626 literals->set(literals_index, *boilerplate);
627 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000628 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000629 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000630 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000631 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000633}
634
635
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000636RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
637 ASSERT(args.length() == 2);
638 Object* handler = args[0];
639 Object* prototype = args[1];
640 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000641 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000642 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
643}
644
645
lrn@chromium.org34e60782011-09-15 07:25:40 +0000646RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
647 ASSERT(args.length() == 4);
648 Object* handler = args[0];
649 Object* call_trap = args[1];
650 Object* construct_trap = args[2];
651 Object* prototype = args[3];
652 Object* used_prototype =
653 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
654 return isolate->heap()->AllocateJSFunctionProxy(
655 handler, call_trap, construct_trap, used_prototype);
656}
657
658
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000659RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
660 ASSERT(args.length() == 1);
661 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000662 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000663}
664
665
lrn@chromium.org34e60782011-09-15 07:25:40 +0000666RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
667 ASSERT(args.length() == 1);
668 Object* obj = args[0];
669 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
670}
671
672
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000673RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
674 ASSERT(args.length() == 1);
675 CONVERT_CHECKED(JSProxy, proxy, args[0]);
676 return proxy->handler();
677}
678
679
lrn@chromium.org34e60782011-09-15 07:25:40 +0000680RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
681 ASSERT(args.length() == 1);
682 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
683 return proxy->call_trap();
684}
685
686
687RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
688 ASSERT(args.length() == 1);
689 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
690 return proxy->construct_trap();
691}
692
693
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
695 ASSERT(args.length() == 1);
696 CONVERT_CHECKED(JSProxy, proxy, args[0]);
697 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000698 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000699}
700
701
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000702RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
703 HandleScope scope(isolate);
704 ASSERT(args.length() == 1);
705 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
706 ASSERT(weakmap->map()->inobject_properties() == 0);
707 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
708 weakmap->set_table(*table);
709 weakmap->set_next(Smi::FromInt(0));
710 return *weakmap;
711}
712
713
714RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
715 NoHandleAllocation ha;
716 ASSERT(args.length() == 2);
717 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000718 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
719 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000720}
721
722
723RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
724 HandleScope scope(isolate);
725 ASSERT(args.length() == 3);
726 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000727 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000728 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000729 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000730 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
731 weakmap->set_table(*new_table);
732 return *value;
733}
734
735
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000736RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000737 NoHandleAllocation ha;
738 ASSERT(args.length() == 1);
739 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000740 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000741 return JSObject::cast(obj)->class_name();
742}
743
ager@chromium.org7c537e22008-10-16 08:43:32 +0000744
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000745RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
746 NoHandleAllocation ha;
747 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000748 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
749 Object* obj = input_obj;
750 // We don't expect access checks to be needed on JSProxy objects.
751 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000752 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000753 if (obj->IsAccessCheckNeeded() &&
754 !isolate->MayNamedAccess(JSObject::cast(obj),
755 isolate->heap()->Proto_symbol(),
756 v8::ACCESS_GET)) {
757 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
758 return isolate->heap()->undefined_value();
759 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000760 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000761 } while (obj->IsJSObject() &&
762 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000763 return obj;
764}
765
766
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000767RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000768 NoHandleAllocation ha;
769 ASSERT(args.length() == 2);
770 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
771 Object* O = args[0];
772 Object* V = args[1];
773 while (true) {
774 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000775 if (prototype->IsNull()) return isolate->heap()->false_value();
776 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777 V = prototype;
778 }
779}
780
781
ager@chromium.org9085a012009-05-11 19:22:57 +0000782// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000783RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000784 NoHandleAllocation ha;
785 ASSERT(args.length() == 2);
786 CONVERT_CHECKED(JSObject, jsobject, args[0]);
787 CONVERT_CHECKED(JSObject, proto, args[1]);
788
789 // Sanity checks. The old prototype (that we are replacing) could
790 // theoretically be null, but if it is not null then check that we
791 // didn't already install a hidden prototype here.
792 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
793 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
794 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
795
796 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000797 Object* map_or_failure;
798 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
799 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
800 return maybe_map_or_failure;
801 }
802 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000803 Map* new_proto_map = Map::cast(map_or_failure);
804
lrn@chromium.org303ada72010-10-27 09:33:13 +0000805 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
806 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
807 return maybe_map_or_failure;
808 }
809 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000810 Map* new_map = Map::cast(map_or_failure);
811
812 // Set proto's prototype to be the old prototype of the object.
813 new_proto_map->set_prototype(jsobject->GetPrototype());
814 proto->set_map(new_proto_map);
815 new_proto_map->set_is_hidden_prototype();
816
817 // Set the object's prototype to proto.
818 new_map->set_prototype(proto);
819 jsobject->set_map(new_map);
820
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000821 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000822}
823
824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000825RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000826 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000827 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000828 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000829 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000830}
831
832
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000833// Recursively traverses hidden prototypes if property is not found
834static void GetOwnPropertyImplementation(JSObject* obj,
835 String* name,
836 LookupResult* result) {
837 obj->LocalLookupRealNamedProperty(name, result);
838
839 if (!result->IsProperty()) {
840 Object* proto = obj->GetPrototype();
841 if (proto->IsJSObject() &&
842 JSObject::cast(proto)->map()->is_hidden_prototype())
843 GetOwnPropertyImplementation(JSObject::cast(proto),
844 name, result);
845 }
846}
847
848
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000849static bool CheckAccessException(LookupResult* result,
850 v8::AccessType access_type) {
851 if (result->type() == CALLBACKS) {
852 Object* callback = result->GetCallbackObject();
853 if (callback->IsAccessorInfo()) {
854 AccessorInfo* info = AccessorInfo::cast(callback);
855 bool can_access =
856 (access_type == v8::ACCESS_HAS &&
857 (info->all_can_read() || info->all_can_write())) ||
858 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
859 (access_type == v8::ACCESS_SET && info->all_can_write());
860 return can_access;
861 }
862 }
863
864 return false;
865}
866
867
868static bool CheckAccess(JSObject* obj,
869 String* name,
870 LookupResult* result,
871 v8::AccessType access_type) {
872 ASSERT(result->IsProperty());
873
874 JSObject* holder = result->holder();
875 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000876 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000877 while (true) {
878 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000880 // Access check callback denied the access, but some properties
881 // can have a special permissions which override callbacks descision
882 // (currently see v8::AccessControl).
883 break;
884 }
885
886 if (current == holder) {
887 return true;
888 }
889
890 current = JSObject::cast(current->GetPrototype());
891 }
892
893 // API callbacks can have per callback access exceptions.
894 switch (result->type()) {
895 case CALLBACKS: {
896 if (CheckAccessException(result, access_type)) {
897 return true;
898 }
899 break;
900 }
901 case INTERCEPTOR: {
902 // If the object has an interceptor, try real named properties.
903 // Overwrite the result to fetch the correct property later.
904 holder->LookupRealNamedProperty(name, result);
905 if (result->IsProperty()) {
906 if (CheckAccessException(result, access_type)) {
907 return true;
908 }
909 }
910 break;
911 }
912 default:
913 break;
914 }
915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000916 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000917 return false;
918}
919
920
921// TODO(1095): we should traverse hidden prototype hierachy as well.
922static bool CheckElementAccess(JSObject* obj,
923 uint32_t index,
924 v8::AccessType access_type) {
925 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000926 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000927 return false;
928 }
929
930 return true;
931}
932
933
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000934// Enumerator used as indices into the array returned from GetOwnProperty
935enum PropertyDescriptorIndices {
936 IS_ACCESSOR_INDEX,
937 VALUE_INDEX,
938 GETTER_INDEX,
939 SETTER_INDEX,
940 WRITABLE_INDEX,
941 ENUMERABLE_INDEX,
942 CONFIGURABLE_INDEX,
943 DESCRIPTOR_SIZE
944};
945
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000946// Returns an array with the property description:
947// if args[1] is not a property on args[0]
948// returns undefined
949// if args[1] is a data property on args[0]
950// [false, value, Writeable, Enumerable, Configurable]
951// if args[1] is an accessor on args[0]
952// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000953RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000954 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000955 Heap* heap = isolate->heap();
956 HandleScope scope(isolate);
957 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
958 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000959 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000960 CONVERT_ARG_CHECKED(JSObject, obj, 0);
961 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000962
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000963 // This could be an element.
964 uint32_t index;
965 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000966 switch (obj->HasLocalElement(index)) {
967 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000969
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000970 case JSObject::STRING_CHARACTER_ELEMENT: {
971 // Special handling of string objects according to ECMAScript 5
972 // 15.5.5.2. Note that this might be a string object with elements
973 // other than the actual string value. This is covered by the
974 // subsequent cases.
975 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
976 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000977 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000978
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000979 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000980 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000981 elms->set(WRITABLE_INDEX, heap->false_value());
982 elms->set(ENUMERABLE_INDEX, heap->false_value());
983 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000984 return *desc;
985 }
986
987 case JSObject::INTERCEPTED_ELEMENT:
988 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000989 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000990 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000991 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000992 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000993 elms->set(WRITABLE_INDEX, heap->true_value());
994 elms->set(ENUMERABLE_INDEX, heap->true_value());
995 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000996 return *desc;
997 }
998
999 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001000 Handle<JSObject> holder = obj;
1001 if (obj->IsJSGlobalProxy()) {
1002 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001004 ASSERT(proto->IsJSGlobalObject());
1005 holder = Handle<JSObject>(JSObject::cast(proto));
1006 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001007 FixedArray* elements = FixedArray::cast(holder->elements());
1008 NumberDictionary* dictionary = NULL;
1009 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1010 dictionary = NumberDictionary::cast(elements->get(1));
1011 } else {
1012 dictionary = NumberDictionary::cast(elements);
1013 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001014 int entry = dictionary->FindEntry(index);
1015 ASSERT(entry != NumberDictionary::kNotFound);
1016 PropertyDetails details = dictionary->DetailsAt(entry);
1017 switch (details.type()) {
1018 case CALLBACKS: {
1019 // This is an accessor property with getter and/or setter.
1020 FixedArray* callbacks =
1021 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001022 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001023 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1024 elms->set(GETTER_INDEX, callbacks->get(0));
1025 }
1026 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1027 elms->set(SETTER_INDEX, callbacks->get(1));
1028 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001029 break;
1030 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001031 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001032 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001034 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001035 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001036 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001037 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001038 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001039 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001040 default:
1041 UNREACHABLE();
1042 break;
1043 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001044 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1045 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001046 return *desc;
1047 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001048 }
1049 }
1050
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001051 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001052 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001053
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001054 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001055 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001056 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001057
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001058 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001059 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001060 }
1061
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001062 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1063 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001064
1065 bool is_js_accessor = (result.type() == CALLBACKS) &&
1066 (result.GetCallbackObject()->IsFixedArray());
1067
1068 if (is_js_accessor) {
1069 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001070 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001071
1072 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1073 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1074 elms->set(GETTER_INDEX, structure->get(0));
1075 }
1076 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1077 elms->set(SETTER_INDEX, structure->get(1));
1078 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001079 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001080 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1081 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001082
1083 PropertyAttributes attrs;
1084 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001085 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001086 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1087 if (!maybe_value->ToObject(&value)) return maybe_value;
1088 }
1089 elms->set(VALUE_INDEX, value);
1090 }
1091
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001092 return *desc;
1093}
1094
1095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001096RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001097 ASSERT(args.length() == 1);
1098 CONVERT_CHECKED(JSObject, obj, args[0]);
1099 return obj->PreventExtensions();
1100}
1101
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001103RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001104 ASSERT(args.length() == 1);
1105 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001106 if (obj->IsJSGlobalProxy()) {
1107 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001108 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001109 ASSERT(proto->IsJSGlobalObject());
1110 obj = JSObject::cast(proto);
1111 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001112 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001113}
1114
1115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001116RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001117 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001119 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1120 CONVERT_ARG_CHECKED(String, pattern, 1);
1121 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001122 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1123 if (result.is_null()) return Failure::Exception();
1124 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001125}
1126
1127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001128RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001129 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001130 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001131 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001132 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001133}
1134
1135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001136RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 ASSERT(args.length() == 1);
1138 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001139 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001140 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141}
1142
1143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001144RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001145 ASSERT(args.length() == 2);
1146 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001148 int index = field->value();
1149 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1150 InstanceType type = templ->map()->instance_type();
1151 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1152 type == OBJECT_TEMPLATE_INFO_TYPE);
1153 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001154 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001155 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1156 } else {
1157 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1158 }
1159 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001160}
1161
1162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001163RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001164 ASSERT(args.length() == 1);
1165 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001166 Map* old_map = object->map();
1167 bool needs_access_checks = old_map->is_access_check_needed();
1168 if (needs_access_checks) {
1169 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001170 Object* new_map;
1171 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1172 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1173 }
ager@chromium.org32912102009-01-16 10:38:43 +00001174
1175 Map::cast(new_map)->set_is_access_check_needed(false);
1176 object->set_map(Map::cast(new_map));
1177 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001178 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001179}
1180
1181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001182RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001183 ASSERT(args.length() == 1);
1184 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001185 Map* old_map = object->map();
1186 if (!old_map->is_access_check_needed()) {
1187 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001188 Object* new_map;
1189 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1190 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1191 }
ager@chromium.org32912102009-01-16 10:38:43 +00001192
1193 Map::cast(new_map)->set_is_access_check_needed(true);
1194 object->set_map(Map::cast(new_map));
1195 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001196 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001197}
1198
1199
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200static Failure* ThrowRedeclarationError(Isolate* isolate,
1201 const char* type,
1202 Handle<String> name) {
1203 HandleScope scope(isolate);
1204 Handle<Object> type_handle =
1205 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001206 Handle<Object> args[2] = { type_handle, name };
1207 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001208 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1209 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001210}
1211
1212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001213RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001214 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001215 HandleScope scope(isolate);
1216 Handle<GlobalObject> global = Handle<GlobalObject>(
1217 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218
ager@chromium.org3811b432009-10-28 14:53:37 +00001219 Handle<Context> context = args.at<Context>(0);
1220 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001221 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223 // Traverse the name/value pairs and set the properties.
1224 int length = pairs->length();
1225 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001226 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001227 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001228 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001229
1230 // We have to declare a global const property. To capture we only
1231 // assign to it when evaluating the assignment for "const x =
1232 // <expr>" the initial value is the hole.
1233 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001234 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001235 if (value->IsUndefined() || is_const_property) {
1236 // Lookup the property in the global object, and don't set the
1237 // value of the variable if the property is already there.
1238 LookupResult lookup;
1239 global->Lookup(*name, &lookup);
1240 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001241 // We found an existing property. Unless it was an interceptor
1242 // that claims the property is absent, skip this declaration.
1243 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244 continue;
1245 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001246 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1247 if (attributes != ABSENT) {
1248 continue;
1249 }
1250 // Fall-through and introduce the absent property by using
1251 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252 }
1253 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001254 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001256 Handle<SharedFunctionInfo> shared =
1257 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001259 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1260 context,
1261 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262 value = function;
1263 }
1264
1265 LookupResult lookup;
1266 global->LocalLookup(*name, &lookup);
1267
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001268 // Compute the property attributes. According to ECMA-262, section
1269 // 13, page 71, the property must be read-only and
1270 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1271 // property as read-only, so we don't either.
1272 int attr = NONE;
1273 if ((flags & kDeclareGlobalsEvalFlag) == 0) {
1274 attr |= DONT_DELETE;
1275 }
1276 bool is_native = (flags & kDeclareGlobalsNativeFlag) != 0;
1277 if (is_const_property || (is_native && is_function_declaration)) {
1278 attr |= READ_ONLY;
1279 }
1280
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001281 // Safari does not allow the invocation of callback setters for
1282 // function declarations. To mimic this behavior, we do not allow
1283 // the invocation of setters for function values. This makes a
1284 // difference for global functions with the same names as event
1285 // handlers such as "function onload() {}". Firefox does call the
1286 // onload setter in those case and Safari does not. We follow
1287 // Safari for compatibility.
1288 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001289 // Do not change DONT_DELETE to false from true.
1290 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001291 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001292 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001293 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1294
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001295 RETURN_IF_EMPTY_HANDLE(isolate,
1296 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001297 name,
1298 value,
1299 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001301 StrictModeFlag strict_mode =
1302 ((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode
1303 : kNonStrictMode;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001304 RETURN_IF_EMPTY_HANDLE(isolate,
1305 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001306 name,
1307 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001308 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001309 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 }
1311 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001312
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001313 ASSERT(!isolate->has_pending_exception());
1314 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315}
1316
1317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001318RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001319 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001320 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001322 // Declarations are always made in a function or global context. In the
1323 // case of eval code, the context passed is the context of the caller,
1324 // which may be some nested context and not the declaration context.
1325 RUNTIME_ASSERT(args[0]->IsContext());
1326 Handle<Context> context(Context::cast(args[0])->declaration_context());
1327
ager@chromium.org7c537e22008-10-16 08:43:32 +00001328 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001329 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001330 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001331 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333 int index;
1334 PropertyAttributes attributes;
1335 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001336 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001337 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001338 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339
1340 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001341 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001342 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1343 // Functions are not read-only.
1344 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1345 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001346 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347 }
1348
1349 // Initialize it if necessary.
1350 if (*initial_value != NULL) {
1351 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001352 ASSERT(holder.is_identical_to(context));
1353 if (((attributes & READ_ONLY) == 0) ||
1354 context->get(index)->IsTheHole()) {
1355 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 }
1357 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001358 // Slow case: The property is in the context extension object of a
1359 // function context or the global object of a global context.
1360 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001361 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001362 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001363 SetProperty(object, name, initial_value, mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364 }
1365 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001366
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001368 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001369 // "declared" in the function context's extension context or as a
1370 // property of the the global object.
1371 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001372 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001373 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001374 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001375 // Context extension objects are allocated lazily.
1376 ASSERT(context->IsFunctionContext());
1377 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001378 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001379 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001380 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001381 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001382
ager@chromium.org7c537e22008-10-16 08:43:32 +00001383 // Declare the property by setting it to the initial value if provided,
1384 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1385 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001386 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001387 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001388 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001389 // Declaring a const context slot is a conflicting declaration if
1390 // there is a callback with that name in a prototype. It is
1391 // allowed to introduce const variables in
1392 // JSContextExtensionObjects. They are treated specially in
1393 // SetProperty and no setters are invoked for those since they are
1394 // not real JSObjects.
1395 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001396 !object->IsJSContextExtensionObject()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001397 LookupResult lookup;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001398 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001399 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001400 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001401 }
1402 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001403 RETURN_IF_EMPTY_HANDLE(isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001404 SetProperty(object, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001405 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001406 }
1407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001408 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409}
1410
1411
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001412RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001414 // args[0] == name
1415 // args[1] == strict_mode
1416 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417
1418 // Determine if we need to assign to the variable if it already
1419 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001420 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1421 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422
1423 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001424 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001425 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001426 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001427 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001428
1429 // According to ECMA-262, section 12.2, page 62, the property must
1430 // not be deletable.
1431 PropertyAttributes attributes = DONT_DELETE;
1432
1433 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001434 // there, there is a property with this name in the prototype chain.
1435 // We follow Safari and Firefox behavior and only set the property
1436 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001437 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001438 // Note that objects can have hidden prototypes, so we need to traverse
1439 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001440 Object* object = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441 LookupResult lookup;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001442 while (object->IsJSObject() &&
1443 JSObject::cast(object)->map()->is_hidden_prototype()) {
1444 JSObject* raw_holder = JSObject::cast(object);
1445 raw_holder->LocalLookup(*name, &lookup);
1446 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1447 HandleScope handle_scope(isolate);
1448 Handle<JSObject> holder(raw_holder);
1449 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1450 // Update the raw pointer in case it's changed due to GC.
1451 raw_holder = *holder;
1452 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1453 // Found an interceptor that's not read only.
1454 if (assign) {
1455 return raw_holder->SetProperty(
1456 &lookup, *name, args[2], attributes, strict_mode);
1457 } else {
1458 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001459 }
1460 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001461 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001462 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463 }
1464
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001465 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001466 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001467 if (assign) {
1468 return global->SetProperty(*name, args[2], attributes, strict_mode);
1469 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001470 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471}
1472
1473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001474RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475 // All constants are declared with an initial value. The name
1476 // of the constant is the first argument and the initial value
1477 // is the second.
1478 RUNTIME_ASSERT(args.length() == 2);
1479 CONVERT_ARG_CHECKED(String, name, 0);
1480 Handle<Object> value = args.at<Object>(1);
1481
1482 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001483 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484
1485 // According to ECMA-262, section 12.2, page 62, the property must
1486 // not be deletable. Since it's a const, it must be READ_ONLY too.
1487 PropertyAttributes attributes =
1488 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1489
1490 // Lookup the property locally in the global object. If it isn't
1491 // there, we add the property and take special precautions to always
1492 // add it as a local property even in case of callbacks in the
1493 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001494 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001495 LookupResult lookup;
1496 global->LocalLookup(*name, &lookup);
1497 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001498 return global->SetLocalPropertyIgnoreAttributes(*name,
1499 *value,
1500 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 }
1502
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001503 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001505 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001506 HandleScope handle_scope(isolate);
1507 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001508
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001509 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510 // property through an interceptor and only do it if it's
1511 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001512 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001513 RETURN_IF_EMPTY_HANDLE(isolate,
1514 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001515 name,
1516 value,
1517 attributes,
1518 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001519 return *value;
1520 }
1521
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001522 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001523 // constant. For now, we determine this by checking if the
1524 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001525 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001526 PropertyType type = lookup.type();
1527 if (type == FIELD) {
1528 FixedArray* properties = global->properties();
1529 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001530 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 properties->set(index, *value);
1532 }
1533 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001534 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1535 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001536 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001537 }
1538 } else {
1539 // Ignore re-initialization of constants that have already been
1540 // assigned a function value.
1541 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1542 }
1543
1544 // Use the set value as the result of the operation.
1545 return *value;
1546}
1547
1548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001549RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001550 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001551 ASSERT(args.length() == 3);
1552
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001553 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001556 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001557 RUNTIME_ASSERT(args[1]->IsContext());
1558 Handle<Context> context(Context::cast(args[1])->declaration_context());
1559
1560 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561
1562 int index;
1563 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001564 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001565 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001566 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001567 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001570 ASSERT(holder->IsContext());
1571 // Property was found in a context. Perform the assignment if we
1572 // found some non-constant or an uninitialized constant.
1573 Handle<Context> context = Handle<Context>::cast(holder);
1574 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1575 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576 }
1577 return *value;
1578 }
1579
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001580 // The property could not be found, we introduce it as a property of the
1581 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001582 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001583 Handle<JSObject> global = Handle<JSObject>(
1584 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001585 // Strict mode not needed (const disallowed in strict mode).
1586 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001587 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001588 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001589 return *value;
1590 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001592 // The property was present in some function's context extension object,
1593 // as a property on the subject of a with, or as a property of the global
1594 // object.
1595 //
1596 // In most situations, eval-introduced consts should still be present in
1597 // the context extension object. However, because declaration and
1598 // initialization are separate, the property might have been deleted
1599 // before we reach the initialization point.
1600 //
1601 // Example:
1602 //
1603 // function f() { eval("delete x; const x;"); }
1604 //
1605 // In that case, the initialization behaves like a normal assignment.
1606 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001608 if (*object == context->extension()) {
1609 // This is the property that was introduced by the const declaration.
1610 // Set it if it hasn't been set before. NOTE: We cannot use
1611 // GetProperty() to get the current value as it 'unholes' the value.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001612 LookupResult lookup;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001613 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001614 ASSERT(lookup.IsProperty()); // the property was declared
1615 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1616
1617 PropertyType type = lookup.type();
1618 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001619 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001620 int index = lookup.GetFieldIndex();
1621 if (properties->get(index)->IsTheHole()) {
1622 properties->set(index, *value);
1623 }
1624 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001625 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1626 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001627 }
1628 } else {
1629 // We should not reach here. Any real, named property should be
1630 // either a field or a dictionary slot.
1631 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632 }
1633 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001634 // The property was found on some other object. Set it if it is not a
1635 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001636 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001637 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001638 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001639 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001640 SetProperty(object, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001641 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001642 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001643
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001644 return *value;
1645}
1646
1647
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001648RUNTIME_FUNCTION(MaybeObject*,
1649 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001650 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001651 ASSERT(args.length() == 2);
1652 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001653 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001654 if (object->HasFastProperties()) {
1655 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1656 }
1657 return *object;
1658}
1659
1660
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001661RUNTIME_FUNCTION(MaybeObject*, Runtime_NonSmiElementStored) {
1662 ASSERT(args.length() == 1);
1663 CONVERT_ARG_CHECKED(JSObject, object, 0);
1664 if (FLAG_smi_only_arrays && object->HasFastSmiOnlyElements()) {
1665 MaybeObject* maybe_map = object->GetElementsTransitionMap(FAST_ELEMENTS);
1666 Map* map;
1667 if (!maybe_map->To<Map>(&map)) return maybe_map;
1668 object->set_map(Map::cast(map));
1669 }
1670 return *object;
1671}
1672
1673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001674RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001675 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001676 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001677 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1678 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001679 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001680 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001681 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001682 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001683 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001684 RUNTIME_ASSERT(index >= 0);
1685 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001686 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001687 Handle<Object> result = RegExpImpl::Exec(regexp,
1688 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001689 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001690 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001691 if (result.is_null()) return Failure::Exception();
1692 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001693}
1694
1695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001696RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001697 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001698 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001699 if (elements_count < 0 ||
1700 elements_count > FixedArray::kMaxLength ||
1701 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001702 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001703 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001704 Object* new_object;
1705 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001706 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001707 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1708 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001709 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001710 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1711 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001712 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1713 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001714 {
1715 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001716 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001717 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001718 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001719 }
1720 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001721 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001722 array->set_elements(elements);
1723 array->set_length(Smi::FromInt(elements_count));
1724 // Write in-object properties after the length of the array.
1725 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1726 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1727 return array;
1728}
1729
1730
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001731RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001732 AssertNoAllocation no_alloc;
1733 ASSERT(args.length() == 5);
1734 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1735 CONVERT_CHECKED(String, source, args[1]);
1736
1737 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001738 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001739
1740 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001742
1743 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001744 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001745
1746 Map* map = regexp->map();
1747 Object* constructor = map->constructor();
1748 if (constructor->IsJSFunction() &&
1749 JSFunction::cast(constructor)->initial_map() == map) {
1750 // If we still have the original map, set in-object properties directly.
1751 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1752 // TODO(lrn): Consider skipping write barrier on booleans as well.
1753 // Both true and false should be in oldspace at all times.
1754 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1755 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1756 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1757 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1758 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001759 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001760 return regexp;
1761 }
1762
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001764 PropertyAttributes final =
1765 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1766 PropertyAttributes writable =
1767 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001768 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001769 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001771 source,
1772 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001773 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001774 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001775 global,
1776 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001777 ASSERT(!result->IsFailure());
1778 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001779 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001780 ignoreCase,
1781 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001782 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001783 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001784 multiline,
1785 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001786 ASSERT(!result->IsFailure());
1787 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001789 Smi::FromInt(0),
1790 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001791 ASSERT(!result->IsFailure());
1792 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001793 return regexp;
1794}
1795
1796
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001797RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001799 ASSERT(args.length() == 1);
1800 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1801 // This is necessary to enable fast checks for absence of elements
1802 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001803 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001804 return Smi::FromInt(0);
1805}
1806
1807
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1809 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001810 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001811 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001812 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1813 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1814 Handle<JSFunction> optimized =
1815 isolate->factory()->NewFunction(key,
1816 JS_OBJECT_TYPE,
1817 JSObject::kHeaderSize,
1818 code,
1819 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001820 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001821 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001822 return optimized;
1823}
1824
1825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001826RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001828 ASSERT(args.length() == 1);
1829 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1830
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001831 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1832 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1833 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1834 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1835 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1836 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1837 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001838
1839 return *holder;
1840}
1841
1842
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001843RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1844 NoHandleAllocation handle_free;
1845 ASSERT(args.length() == 1);
1846 CONVERT_CHECKED(JSFunction, function, args[0]);
1847 SharedFunctionInfo* shared = function->shared();
1848 if (shared->native() || shared->strict_mode()) {
1849 return isolate->heap()->undefined_value();
1850 }
1851 // Returns undefined for strict or native functions, or
1852 // the associated global receiver for "normal" functions.
1853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001854 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001855 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001856 return global_context->global()->global_receiver();
1857}
1858
1859
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001860RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001862 ASSERT(args.length() == 4);
1863 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001864 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001865 Handle<String> pattern = args.at<String>(2);
1866 Handle<String> flags = args.at<String>(3);
1867
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001868 // Get the RegExp function from the context in the literals array.
1869 // This is the RegExp function from the context in which the
1870 // function was created. We do not use the RegExp function from the
1871 // current global context because this might be the RegExp function
1872 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001873 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001874 Handle<JSFunction>(
1875 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001876 // Compute the regular expression literal.
1877 bool has_pending_exception;
1878 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001879 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1880 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001881 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001882 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001883 return Failure::Exception();
1884 }
1885 literals->set(index, *regexp);
1886 return *regexp;
1887}
1888
1889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001890RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001891 NoHandleAllocation ha;
1892 ASSERT(args.length() == 1);
1893
1894 CONVERT_CHECKED(JSFunction, f, args[0]);
1895 return f->shared()->name();
1896}
1897
1898
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001899RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001900 NoHandleAllocation ha;
1901 ASSERT(args.length() == 2);
1902
1903 CONVERT_CHECKED(JSFunction, f, args[0]);
1904 CONVERT_CHECKED(String, name, args[1]);
1905 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001906 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001907}
1908
1909
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001910RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1911 NoHandleAllocation ha;
1912 ASSERT(args.length() == 1);
1913 CONVERT_CHECKED(JSFunction, f, args[0]);
1914 return isolate->heap()->ToBoolean(
1915 f->shared()->name_should_print_as_anonymous());
1916}
1917
1918
1919RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1920 NoHandleAllocation ha;
1921 ASSERT(args.length() == 1);
1922 CONVERT_CHECKED(JSFunction, f, args[0]);
1923 f->shared()->set_name_should_print_as_anonymous(true);
1924 return isolate->heap()->undefined_value();
1925}
1926
1927
whesse@chromium.org7b260152011-06-20 15:33:18 +00001928RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1929 HandleScope scope(isolate);
1930 ASSERT(args.length() == 1);
1931
1932 CONVERT_CHECKED(JSFunction, fun, args[0]);
1933 fun->shared()->set_bound(true);
1934 return isolate->heap()->undefined_value();
1935}
1936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001937RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001938 NoHandleAllocation ha;
1939 ASSERT(args.length() == 1);
1940
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001942 Object* obj = f->RemovePrototype();
1943 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001944
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001945 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001946}
1947
1948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001949RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001950 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001951 ASSERT(args.length() == 1);
1952
1953 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001954 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1955 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956
1957 return *GetScriptWrapper(Handle<Script>::cast(script));
1958}
1959
1960
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001961RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 NoHandleAllocation ha;
1963 ASSERT(args.length() == 1);
1964
1965 CONVERT_CHECKED(JSFunction, f, args[0]);
1966 return f->shared()->GetSourceCode();
1967}
1968
1969
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001970RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001971 NoHandleAllocation ha;
1972 ASSERT(args.length() == 1);
1973
1974 CONVERT_CHECKED(JSFunction, fun, args[0]);
1975 int pos = fun->shared()->start_position();
1976 return Smi::FromInt(pos);
1977}
1978
1979
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001980RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001981 ASSERT(args.length() == 2);
1982
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001983 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001984 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1985
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001986 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1987
1988 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001989 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001990}
1991
1992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001993RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001994 NoHandleAllocation ha;
1995 ASSERT(args.length() == 2);
1996
1997 CONVERT_CHECKED(JSFunction, fun, args[0]);
1998 CONVERT_CHECKED(String, name, args[1]);
1999 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002000 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002001}
2002
2003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002004RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002005 NoHandleAllocation ha;
2006 ASSERT(args.length() == 2);
2007
2008 CONVERT_CHECKED(JSFunction, fun, args[0]);
2009 CONVERT_CHECKED(Smi, length, args[1]);
2010 fun->shared()->set_length(length->value());
2011 return length;
2012}
2013
2014
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002015// Creates a local, readonly, property called length with the correct
2016// length (when read by the user). This effectively overwrites the
2017// interceptor used to normally provide the length.
2018RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2019 NoHandleAllocation ha;
2020 ASSERT(args.length() == 2);
2021 CONVERT_CHECKED(JSFunction, fun, args[0]);
2022 CONVERT_CHECKED(Smi, length, args[1]);
2023 MaybeObject* maybe_name =
2024 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2025 String* name;
2026 if (!maybe_name->To(&name)) return maybe_name;
2027 PropertyAttributes attr =
2028 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2029 return fun->AddProperty(name, length, attr, kNonStrictMode);
2030}
2031
2032
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002033RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002034 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002035 ASSERT(args.length() == 2);
2036
2037 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002038 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002039 Object* obj;
2040 { MaybeObject* maybe_obj =
2041 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2042 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2043 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 return args[0]; // return TOS
2045}
2046
2047
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002048RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2049 NoHandleAllocation ha;
2050 RUNTIME_ASSERT(args.length() == 1);
2051 CONVERT_CHECKED(JSFunction, function, args[0]);
2052
2053 MaybeObject* maybe_name =
2054 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2055 String* name;
2056 if (!maybe_name->To(&name)) return maybe_name;
2057
2058 if (function->HasFastProperties()) {
2059 // Construct a new field descriptor with updated attributes.
2060 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2061 int index = instance_desc->Search(name);
2062 ASSERT(index != DescriptorArray::kNotFound);
2063 PropertyDetails details(instance_desc->GetDetails(index));
2064 CallbacksDescriptor new_desc(name,
2065 instance_desc->GetValue(index),
2066 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2067 details.index());
2068 // Construct a new field descriptors array containing the new descriptor.
2069 Object* descriptors_unchecked;
2070 { MaybeObject* maybe_descriptors_unchecked =
2071 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2072 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2073 return maybe_descriptors_unchecked;
2074 }
2075 }
2076 DescriptorArray* new_descriptors =
2077 DescriptorArray::cast(descriptors_unchecked);
2078 // Create a new map featuring the new field descriptors array.
2079 Object* map_unchecked;
2080 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2081 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2082 return maybe_map_unchecked;
2083 }
2084 }
2085 Map* new_map = Map::cast(map_unchecked);
2086 new_map->set_instance_descriptors(new_descriptors);
2087 function->set_map(new_map);
2088 } else { // Dictionary properties.
2089 // Directly manipulate the property details.
2090 int entry = function->property_dictionary()->FindEntry(name);
2091 ASSERT(entry != StringDictionary::kNotFound);
2092 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2093 PropertyDetails new_details(
2094 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2095 details.type(),
2096 details.index());
2097 function->property_dictionary()->DetailsAtPut(entry, new_details);
2098 }
2099 return function;
2100}
2101
2102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002103RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002104 NoHandleAllocation ha;
2105 ASSERT(args.length() == 1);
2106
2107 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002108 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002109}
2110
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002111
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002112RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002113 NoHandleAllocation ha;
2114 ASSERT(args.length() == 1);
2115
2116 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002117 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002118}
2119
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002121RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002122 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002123 ASSERT(args.length() == 2);
2124
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002125 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002126 Handle<Object> code = args.at<Object>(1);
2127
2128 Handle<Context> context(target->context());
2129
2130 if (!code->IsNull()) {
2131 RUNTIME_ASSERT(code->IsJSFunction());
2132 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002133 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002134
2135 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002136 return Failure::Exception();
2137 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002138 // Since we don't store the source for this we should never
2139 // optimize this.
2140 shared->code()->set_optimizable(false);
2141
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002142 // Set the code, scope info, formal parameter count,
2143 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002144 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002145 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002146 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002147 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002148 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002149 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002150 // Set the source code of the target function to undefined.
2151 // SetCode is only used for built-in constructors like String,
2152 // Array, and Object, and some web code
2153 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002154 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002155 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002156 // Clear the optimization hints related to the compiled code as these are no
2157 // longer valid when the code is overwritten.
2158 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002159 context = Handle<Context>(fun->context());
2160
2161 // Make sure we get a fresh copy of the literal vector to avoid
2162 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002163 int number_of_literals = fun->NumberOfLiterals();
2164 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002165 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002166 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002167 // Insert the object, regexp and array functions in the literals
2168 // array prefix. These are the functions that will be used when
2169 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002170 literals->set(JSFunction::kLiteralGlobalContextIndex,
2171 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002173 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002174 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002175
2176 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2177 isolate->logger()->LogExistingFunction(
2178 shared, Handle<Code>(shared->code()));
2179 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002180 }
2181
2182 target->set_context(*context);
2183 return *target;
2184}
2185
2186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002187RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002188 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002189 ASSERT(args.length() == 2);
2190 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002191 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002192 RUNTIME_ASSERT(num >= 0);
2193 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002194 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002195}
2196
2197
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002198MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2199 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002200 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002201 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002202 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002203 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002204 }
2205 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002206 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002207}
2208
2209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002210RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002211 NoHandleAllocation ha;
2212 ASSERT(args.length() == 2);
2213
2214 CONVERT_CHECKED(String, subject, args[0]);
2215 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002216 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002217
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002218 uint32_t i = 0;
2219 if (index->IsSmi()) {
2220 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002221 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002222 i = value;
2223 } else {
2224 ASSERT(index->IsHeapNumber());
2225 double value = HeapNumber::cast(index)->value();
2226 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002227 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002228
2229 // Flatten the string. If someone wants to get a char at an index
2230 // in a cons string, it is likely that more indices will be
2231 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002232 Object* flat;
2233 { MaybeObject* maybe_flat = subject->TryFlatten();
2234 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2235 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002236 subject = String::cast(flat);
2237
2238 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002239 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002240 }
2241
2242 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002243}
2244
2245
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002246RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002247 NoHandleAllocation ha;
2248 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002249 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002250}
2251
lrn@chromium.org25156de2010-04-06 13:10:27 +00002252
2253class FixedArrayBuilder {
2254 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002255 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2256 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002257 length_(0),
2258 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002259 // Require a non-zero initial size. Ensures that doubling the size to
2260 // extend the array will work.
2261 ASSERT(initial_capacity > 0);
2262 }
2263
2264 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2265 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002266 length_(0),
2267 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002268 // Require a non-zero initial size. Ensures that doubling the size to
2269 // extend the array will work.
2270 ASSERT(backing_store->length() > 0);
2271 }
2272
2273 bool HasCapacity(int elements) {
2274 int length = array_->length();
2275 int required_length = length_ + elements;
2276 return (length >= required_length);
2277 }
2278
2279 void EnsureCapacity(int elements) {
2280 int length = array_->length();
2281 int required_length = length_ + elements;
2282 if (length < required_length) {
2283 int new_length = length;
2284 do {
2285 new_length *= 2;
2286 } while (new_length < required_length);
2287 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002288 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002289 array_->CopyTo(0, *extended_array, 0, length_);
2290 array_ = extended_array;
2291 }
2292 }
2293
2294 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002295 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002296 ASSERT(length_ < capacity());
2297 array_->set(length_, value);
2298 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002299 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002300 }
2301
2302 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002303 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002304 ASSERT(length_ < capacity());
2305 array_->set(length_, value);
2306 length_++;
2307 }
2308
2309 Handle<FixedArray> array() {
2310 return array_;
2311 }
2312
2313 int length() {
2314 return length_;
2315 }
2316
2317 int capacity() {
2318 return array_->length();
2319 }
2320
2321 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002322 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002323 result_array->set_length(Smi::FromInt(length_));
2324 return result_array;
2325 }
2326
2327 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002328 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 target_array->set_length(Smi::FromInt(length_));
2330 return target_array;
2331 }
2332
2333 private:
2334 Handle<FixedArray> array_;
2335 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002336 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002337};
2338
2339
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002340// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002341const int kStringBuilderConcatHelperLengthBits = 11;
2342const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002343
2344template <typename schar>
2345static inline void StringBuilderConcatHelper(String*,
2346 schar*,
2347 FixedArray*,
2348 int);
2349
lrn@chromium.org25156de2010-04-06 13:10:27 +00002350typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2351 StringBuilderSubstringLength;
2352typedef BitField<int,
2353 kStringBuilderConcatHelperLengthBits,
2354 kStringBuilderConcatHelperPositionBits>
2355 StringBuilderSubstringPosition;
2356
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002357
2358class ReplacementStringBuilder {
2359 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002360 ReplacementStringBuilder(Heap* heap,
2361 Handle<String> subject,
2362 int estimated_part_count)
2363 : heap_(heap),
2364 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002365 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002366 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002367 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002368 // Require a non-zero initial size. Ensures that doubling the size to
2369 // extend the array will work.
2370 ASSERT(estimated_part_count > 0);
2371 }
2372
lrn@chromium.org25156de2010-04-06 13:10:27 +00002373 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2374 int from,
2375 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002376 ASSERT(from >= 0);
2377 int length = to - from;
2378 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002379 if (StringBuilderSubstringLength::is_valid(length) &&
2380 StringBuilderSubstringPosition::is_valid(from)) {
2381 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2382 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002383 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002384 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002385 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002386 builder->Add(Smi::FromInt(-length));
2387 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002388 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002389 }
2390
2391
2392 void EnsureCapacity(int elements) {
2393 array_builder_.EnsureCapacity(elements);
2394 }
2395
2396
2397 void AddSubjectSlice(int from, int to) {
2398 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002399 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002400 }
2401
2402
2403 void AddString(Handle<String> string) {
2404 int length = string->length();
2405 ASSERT(length > 0);
2406 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002407 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002408 is_ascii_ = false;
2409 }
2410 IncrementCharacterCount(length);
2411 }
2412
2413
2414 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002415 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002416 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002417 }
2418
2419 Handle<String> joined_string;
2420 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002421 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002422 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002423 char* char_buffer = seq->GetChars();
2424 StringBuilderConcatHelper(*subject_,
2425 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002426 *array_builder_.array(),
2427 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002428 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002429 } else {
2430 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002431 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002432 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002433 uc16* char_buffer = seq->GetChars();
2434 StringBuilderConcatHelper(*subject_,
2435 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002436 *array_builder_.array(),
2437 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002438 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 }
2440 return joined_string;
2441 }
2442
2443
2444 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002445 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002446 V8::FatalProcessOutOfMemory("String.replace result too large.");
2447 }
2448 character_count_ += by;
2449 }
2450
lrn@chromium.org25156de2010-04-06 13:10:27 +00002451 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002452 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002453 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002454
lrn@chromium.org25156de2010-04-06 13:10:27 +00002455 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002456 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2457 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002458 }
2459
2460
ager@chromium.org04921a82011-06-27 13:21:41 +00002461 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2462 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 }
2464
2465
2466 void AddElement(Object* element) {
2467 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002468 ASSERT(array_builder_.capacity() > array_builder_.length());
2469 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002470 }
2471
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002472 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002473 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002474 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002475 int character_count_;
2476 bool is_ascii_;
2477};
2478
2479
2480class CompiledReplacement {
2481 public:
2482 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002483 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002484
2485 void Compile(Handle<String> replacement,
2486 int capture_count,
2487 int subject_length);
2488
2489 void Apply(ReplacementStringBuilder* builder,
2490 int match_from,
2491 int match_to,
2492 Handle<JSArray> last_match_info);
2493
2494 // Number of distinct parts of the replacement pattern.
2495 int parts() {
2496 return parts_.length();
2497 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002498
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002499 bool simple_hint() {
2500 return simple_hint_;
2501 }
2502
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002503 private:
2504 enum PartType {
2505 SUBJECT_PREFIX = 1,
2506 SUBJECT_SUFFIX,
2507 SUBJECT_CAPTURE,
2508 REPLACEMENT_SUBSTRING,
2509 REPLACEMENT_STRING,
2510
2511 NUMBER_OF_PART_TYPES
2512 };
2513
2514 struct ReplacementPart {
2515 static inline ReplacementPart SubjectMatch() {
2516 return ReplacementPart(SUBJECT_CAPTURE, 0);
2517 }
2518 static inline ReplacementPart SubjectCapture(int capture_index) {
2519 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2520 }
2521 static inline ReplacementPart SubjectPrefix() {
2522 return ReplacementPart(SUBJECT_PREFIX, 0);
2523 }
2524 static inline ReplacementPart SubjectSuffix(int subject_length) {
2525 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2526 }
2527 static inline ReplacementPart ReplacementString() {
2528 return ReplacementPart(REPLACEMENT_STRING, 0);
2529 }
2530 static inline ReplacementPart ReplacementSubString(int from, int to) {
2531 ASSERT(from >= 0);
2532 ASSERT(to > from);
2533 return ReplacementPart(-from, to);
2534 }
2535
2536 // If tag <= 0 then it is the negation of a start index of a substring of
2537 // the replacement pattern, otherwise it's a value from PartType.
2538 ReplacementPart(int tag, int data)
2539 : tag(tag), data(data) {
2540 // Must be non-positive or a PartType value.
2541 ASSERT(tag < NUMBER_OF_PART_TYPES);
2542 }
2543 // Either a value of PartType or a non-positive number that is
2544 // the negation of an index into the replacement string.
2545 int tag;
2546 // The data value's interpretation depends on the value of tag:
2547 // tag == SUBJECT_PREFIX ||
2548 // tag == SUBJECT_SUFFIX: data is unused.
2549 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2550 // tag == REPLACEMENT_SUBSTRING ||
2551 // tag == REPLACEMENT_STRING: data is index into array of substrings
2552 // of the replacement string.
2553 // tag <= 0: Temporary representation of the substring of the replacement
2554 // string ranging over -tag .. data.
2555 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2556 // substring objects.
2557 int data;
2558 };
2559
2560 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002561 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002562 Vector<Char> characters,
2563 int capture_count,
2564 int subject_length) {
2565 int length = characters.length();
2566 int last = 0;
2567 for (int i = 0; i < length; i++) {
2568 Char c = characters[i];
2569 if (c == '$') {
2570 int next_index = i + 1;
2571 if (next_index == length) { // No next character!
2572 break;
2573 }
2574 Char c2 = characters[next_index];
2575 switch (c2) {
2576 case '$':
2577 if (i > last) {
2578 // There is a substring before. Include the first "$".
2579 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2580 last = next_index + 1; // Continue after the second "$".
2581 } else {
2582 // Let the next substring start with the second "$".
2583 last = next_index;
2584 }
2585 i = next_index;
2586 break;
2587 case '`':
2588 if (i > last) {
2589 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2590 }
2591 parts->Add(ReplacementPart::SubjectPrefix());
2592 i = next_index;
2593 last = i + 1;
2594 break;
2595 case '\'':
2596 if (i > last) {
2597 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2598 }
2599 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2600 i = next_index;
2601 last = i + 1;
2602 break;
2603 case '&':
2604 if (i > last) {
2605 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2606 }
2607 parts->Add(ReplacementPart::SubjectMatch());
2608 i = next_index;
2609 last = i + 1;
2610 break;
2611 case '0':
2612 case '1':
2613 case '2':
2614 case '3':
2615 case '4':
2616 case '5':
2617 case '6':
2618 case '7':
2619 case '8':
2620 case '9': {
2621 int capture_ref = c2 - '0';
2622 if (capture_ref > capture_count) {
2623 i = next_index;
2624 continue;
2625 }
2626 int second_digit_index = next_index + 1;
2627 if (second_digit_index < length) {
2628 // Peek ahead to see if we have two digits.
2629 Char c3 = characters[second_digit_index];
2630 if ('0' <= c3 && c3 <= '9') { // Double digits.
2631 int double_digit_ref = capture_ref * 10 + c3 - '0';
2632 if (double_digit_ref <= capture_count) {
2633 next_index = second_digit_index;
2634 capture_ref = double_digit_ref;
2635 }
2636 }
2637 }
2638 if (capture_ref > 0) {
2639 if (i > last) {
2640 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2641 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002642 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002643 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2644 last = next_index + 1;
2645 }
2646 i = next_index;
2647 break;
2648 }
2649 default:
2650 i = next_index;
2651 break;
2652 }
2653 }
2654 }
2655 if (length > last) {
2656 if (last == 0) {
2657 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002658 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002659 } else {
2660 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2661 }
2662 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002663 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002664 }
2665
2666 ZoneList<ReplacementPart> parts_;
2667 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002668 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002669};
2670
2671
2672void CompiledReplacement::Compile(Handle<String> replacement,
2673 int capture_count,
2674 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002675 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002676 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002677 String::FlatContent content = replacement->GetFlatContent();
2678 ASSERT(content.IsFlat());
2679 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002680 simple_hint_ = ParseReplacementPattern(&parts_,
2681 content.ToAsciiVector(),
2682 capture_count,
2683 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002684 } else {
2685 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002686 simple_hint_ = ParseReplacementPattern(&parts_,
2687 content.ToUC16Vector(),
2688 capture_count,
2689 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002690 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002691 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002692 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002693 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002694 int substring_index = 0;
2695 for (int i = 0, n = parts_.length(); i < n; i++) {
2696 int tag = parts_[i].tag;
2697 if (tag <= 0) { // A replacement string slice.
2698 int from = -tag;
2699 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002700 replacement_substrings_.Add(
2701 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002702 parts_[i].tag = REPLACEMENT_SUBSTRING;
2703 parts_[i].data = substring_index;
2704 substring_index++;
2705 } else if (tag == REPLACEMENT_STRING) {
2706 replacement_substrings_.Add(replacement);
2707 parts_[i].data = substring_index;
2708 substring_index++;
2709 }
2710 }
2711}
2712
2713
2714void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2715 int match_from,
2716 int match_to,
2717 Handle<JSArray> last_match_info) {
2718 for (int i = 0, n = parts_.length(); i < n; i++) {
2719 ReplacementPart part = parts_[i];
2720 switch (part.tag) {
2721 case SUBJECT_PREFIX:
2722 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2723 break;
2724 case SUBJECT_SUFFIX: {
2725 int subject_length = part.data;
2726 if (match_to < subject_length) {
2727 builder->AddSubjectSlice(match_to, subject_length);
2728 }
2729 break;
2730 }
2731 case SUBJECT_CAPTURE: {
2732 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002733 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002734 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2735 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2736 if (from >= 0 && to > from) {
2737 builder->AddSubjectSlice(from, to);
2738 }
2739 break;
2740 }
2741 case REPLACEMENT_SUBSTRING:
2742 case REPLACEMENT_STRING:
2743 builder->AddString(replacement_substrings_[part.data]);
2744 break;
2745 default:
2746 UNREACHABLE();
2747 }
2748 }
2749}
2750
2751
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002752void FindAsciiStringIndices(Vector<const char> subject,
2753 char pattern,
2754 ZoneList<int>* indices,
2755 unsigned int limit) {
2756 ASSERT(limit > 0);
2757 // Collect indices of pattern in subject using memchr.
2758 // Stop after finding at most limit values.
2759 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2760 const char* subject_end = subject_start + subject.length();
2761 const char* pos = subject_start;
2762 while (limit > 0) {
2763 pos = reinterpret_cast<const char*>(
2764 memchr(pos, pattern, subject_end - pos));
2765 if (pos == NULL) return;
2766 indices->Add(static_cast<int>(pos - subject_start));
2767 pos++;
2768 limit--;
2769 }
2770}
2771
2772
2773template <typename SubjectChar, typename PatternChar>
2774void FindStringIndices(Isolate* isolate,
2775 Vector<const SubjectChar> subject,
2776 Vector<const PatternChar> pattern,
2777 ZoneList<int>* indices,
2778 unsigned int limit) {
2779 ASSERT(limit > 0);
2780 // Collect indices of pattern in subject.
2781 // Stop after finding at most limit values.
2782 int pattern_length = pattern.length();
2783 int index = 0;
2784 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2785 while (limit > 0) {
2786 index = search.Search(subject, index);
2787 if (index < 0) return;
2788 indices->Add(index);
2789 index += pattern_length;
2790 limit--;
2791 }
2792}
2793
2794
2795void FindStringIndicesDispatch(Isolate* isolate,
2796 String* subject,
2797 String* pattern,
2798 ZoneList<int>* indices,
2799 unsigned int limit) {
2800 {
2801 AssertNoAllocation no_gc;
2802 String::FlatContent subject_content = subject->GetFlatContent();
2803 String::FlatContent pattern_content = pattern->GetFlatContent();
2804 ASSERT(subject_content.IsFlat());
2805 ASSERT(pattern_content.IsFlat());
2806 if (subject_content.IsAscii()) {
2807 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2808 if (pattern_content.IsAscii()) {
2809 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2810 if (pattern_vector.length() == 1) {
2811 FindAsciiStringIndices(subject_vector,
2812 pattern_vector[0],
2813 indices,
2814 limit);
2815 } else {
2816 FindStringIndices(isolate,
2817 subject_vector,
2818 pattern_vector,
2819 indices,
2820 limit);
2821 }
2822 } else {
2823 FindStringIndices(isolate,
2824 subject_vector,
2825 pattern_content.ToUC16Vector(),
2826 indices,
2827 limit);
2828 }
2829 } else {
2830 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002831 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002832 FindStringIndices(isolate,
2833 subject_vector,
2834 pattern_content.ToAsciiVector(),
2835 indices,
2836 limit);
2837 } else {
2838 FindStringIndices(isolate,
2839 subject_vector,
2840 pattern_content.ToUC16Vector(),
2841 indices,
2842 limit);
2843 }
2844 }
2845 }
2846}
2847
2848
2849template<typename ResultSeqString>
2850MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2851 Isolate* isolate,
2852 Handle<String> subject,
2853 Handle<JSRegExp> pattern_regexp,
2854 Handle<String> replacement) {
2855 ASSERT(subject->IsFlat());
2856 ASSERT(replacement->IsFlat());
2857
2858 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2859 ZoneList<int> indices(8);
2860 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2861 String* pattern =
2862 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2863 int subject_len = subject->length();
2864 int pattern_len = pattern->length();
2865 int replacement_len = replacement->length();
2866
2867 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2868
2869 int matches = indices.length();
2870 if (matches == 0) return *subject;
2871
2872 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2873 int subject_pos = 0;
2874 int result_pos = 0;
2875
2876 Handle<ResultSeqString> result;
2877 if (ResultSeqString::kHasAsciiEncoding) {
2878 result = Handle<ResultSeqString>::cast(
2879 isolate->factory()->NewRawAsciiString(result_len));
2880 } else {
2881 result = Handle<ResultSeqString>::cast(
2882 isolate->factory()->NewRawTwoByteString(result_len));
2883 }
2884
2885 for (int i = 0; i < matches; i++) {
2886 // Copy non-matched subject content.
2887 if (subject_pos < indices.at(i)) {
2888 String::WriteToFlat(*subject,
2889 result->GetChars() + result_pos,
2890 subject_pos,
2891 indices.at(i));
2892 result_pos += indices.at(i) - subject_pos;
2893 }
2894
2895 // Replace match.
2896 if (replacement_len > 0) {
2897 String::WriteToFlat(*replacement,
2898 result->GetChars() + result_pos,
2899 0,
2900 replacement_len);
2901 result_pos += replacement_len;
2902 }
2903
2904 subject_pos = indices.at(i) + pattern_len;
2905 }
2906 // Add remaining subject content at the end.
2907 if (subject_pos < subject_len) {
2908 String::WriteToFlat(*subject,
2909 result->GetChars() + result_pos,
2910 subject_pos,
2911 subject_len);
2912 }
2913 return *result;
2914}
2915
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002916
lrn@chromium.org303ada72010-10-27 09:33:13 +00002917MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002918 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002919 String* subject,
2920 JSRegExp* regexp,
2921 String* replacement,
2922 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002923 ASSERT(subject->IsFlat());
2924 ASSERT(replacement->IsFlat());
2925
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002926 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002927
2928 int length = subject->length();
2929 Handle<String> subject_handle(subject);
2930 Handle<JSRegExp> regexp_handle(regexp);
2931 Handle<String> replacement_handle(replacement);
2932 Handle<JSArray> last_match_info_handle(last_match_info);
2933 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2934 subject_handle,
2935 0,
2936 last_match_info_handle);
2937 if (match.is_null()) {
2938 return Failure::Exception();
2939 }
2940 if (match->IsNull()) {
2941 return *subject_handle;
2942 }
2943
2944 int capture_count = regexp_handle->CaptureCount();
2945
2946 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002947 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002948 CompiledReplacement compiled_replacement;
2949 compiled_replacement.Compile(replacement_handle,
2950 capture_count,
2951 length);
2952
2953 bool is_global = regexp_handle->GetFlags().is_global();
2954
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002955 // Shortcut for simple non-regexp global replacements
2956 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002957 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002958 compiled_replacement.simple_hint()) {
2959 if (subject_handle->HasOnlyAsciiChars() &&
2960 replacement_handle->HasOnlyAsciiChars()) {
2961 return StringReplaceStringWithString<SeqAsciiString>(
2962 isolate, subject_handle, regexp_handle, replacement_handle);
2963 } else {
2964 return StringReplaceStringWithString<SeqTwoByteString>(
2965 isolate, subject_handle, regexp_handle, replacement_handle);
2966 }
2967 }
2968
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002969 // Guessing the number of parts that the final result string is built
2970 // from. Global regexps can match any number of times, so we guess
2971 // conservatively.
2972 int expected_parts =
2973 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002974 ReplacementStringBuilder builder(isolate->heap(),
2975 subject_handle,
2976 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002977
2978 // Index of end of last match.
2979 int prev = 0;
2980
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002981 // Number of parts added by compiled replacement plus preceeding
2982 // string and possibly suffix after last match. It is possible for
2983 // all components to use two elements when encoded as two smis.
2984 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002985 bool matched = true;
2986 do {
2987 ASSERT(last_match_info_handle->HasFastElements());
2988 // Increase the capacity of the builder before entering local handle-scope,
2989 // so its internal buffer can safely allocate a new handle if it grows.
2990 builder.EnsureCapacity(parts_added_per_loop);
2991
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002992 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002993 int start, end;
2994 {
2995 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002996 FixedArray* match_info_array =
2997 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002998
2999 ASSERT_EQ(capture_count * 2 + 2,
3000 RegExpImpl::GetLastCaptureCount(match_info_array));
3001 start = RegExpImpl::GetCapture(match_info_array, 0);
3002 end = RegExpImpl::GetCapture(match_info_array, 1);
3003 }
3004
3005 if (prev < start) {
3006 builder.AddSubjectSlice(prev, start);
3007 }
3008 compiled_replacement.Apply(&builder,
3009 start,
3010 end,
3011 last_match_info_handle);
3012 prev = end;
3013
3014 // Only continue checking for global regexps.
3015 if (!is_global) break;
3016
3017 // Continue from where the match ended, unless it was an empty match.
3018 int next = end;
3019 if (start == end) {
3020 next = end + 1;
3021 if (next > length) break;
3022 }
3023
3024 match = RegExpImpl::Exec(regexp_handle,
3025 subject_handle,
3026 next,
3027 last_match_info_handle);
3028 if (match.is_null()) {
3029 return Failure::Exception();
3030 }
3031 matched = !match->IsNull();
3032 } while (matched);
3033
3034 if (prev < length) {
3035 builder.AddSubjectSlice(prev, length);
3036 }
3037
3038 return *(builder.ToString());
3039}
3040
3041
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003042template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003043MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003044 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003045 String* subject,
3046 JSRegExp* regexp,
3047 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003048 ASSERT(subject->IsFlat());
3049
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003050 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003051
3052 Handle<String> subject_handle(subject);
3053 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003054
3055 // Shortcut for simple non-regexp global replacements
3056 if (regexp_handle->GetFlags().is_global() &&
3057 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3058 Handle<String> empty_string_handle(HEAP->empty_string());
3059 if (subject_handle->HasOnlyAsciiChars()) {
3060 return StringReplaceStringWithString<SeqAsciiString>(
3061 isolate, subject_handle, regexp_handle, empty_string_handle);
3062 } else {
3063 return StringReplaceStringWithString<SeqTwoByteString>(
3064 isolate, subject_handle, regexp_handle, empty_string_handle);
3065 }
3066 }
3067
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003068 Handle<JSArray> last_match_info_handle(last_match_info);
3069 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3070 subject_handle,
3071 0,
3072 last_match_info_handle);
3073 if (match.is_null()) return Failure::Exception();
3074 if (match->IsNull()) return *subject_handle;
3075
3076 ASSERT(last_match_info_handle->HasFastElements());
3077
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003078 int start, end;
3079 {
3080 AssertNoAllocation match_info_array_is_not_in_a_handle;
3081 FixedArray* match_info_array =
3082 FixedArray::cast(last_match_info_handle->elements());
3083
3084 start = RegExpImpl::GetCapture(match_info_array, 0);
3085 end = RegExpImpl::GetCapture(match_info_array, 1);
3086 }
3087
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003088 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003089 int new_length = length - (end - start);
3090 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003091 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003092 }
3093 Handle<ResultSeqString> answer;
3094 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003095 answer = Handle<ResultSeqString>::cast(
3096 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003097 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003098 answer = Handle<ResultSeqString>::cast(
3099 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003100 }
3101
3102 // If the regexp isn't global, only match once.
3103 if (!regexp_handle->GetFlags().is_global()) {
3104 if (start > 0) {
3105 String::WriteToFlat(*subject_handle,
3106 answer->GetChars(),
3107 0,
3108 start);
3109 }
3110 if (end < length) {
3111 String::WriteToFlat(*subject_handle,
3112 answer->GetChars() + start,
3113 end,
3114 length);
3115 }
3116 return *answer;
3117 }
3118
3119 int prev = 0; // Index of end of last match.
3120 int next = 0; // Start of next search (prev unless last match was empty).
3121 int position = 0;
3122
3123 do {
3124 if (prev < start) {
3125 // Add substring subject[prev;start] to answer string.
3126 String::WriteToFlat(*subject_handle,
3127 answer->GetChars() + position,
3128 prev,
3129 start);
3130 position += start - prev;
3131 }
3132 prev = end;
3133 next = end;
3134 // Continue from where the match ended, unless it was an empty match.
3135 if (start == end) {
3136 next++;
3137 if (next > length) break;
3138 }
3139 match = RegExpImpl::Exec(regexp_handle,
3140 subject_handle,
3141 next,
3142 last_match_info_handle);
3143 if (match.is_null()) return Failure::Exception();
3144 if (match->IsNull()) break;
3145
3146 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003147 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003148 {
3149 AssertNoAllocation match_info_array_is_not_in_a_handle;
3150 FixedArray* match_info_array =
3151 FixedArray::cast(last_match_info_handle->elements());
3152 start = RegExpImpl::GetCapture(match_info_array, 0);
3153 end = RegExpImpl::GetCapture(match_info_array, 1);
3154 }
3155 } while (true);
3156
3157 if (prev < length) {
3158 // Add substring subject[prev;length] to answer string.
3159 String::WriteToFlat(*subject_handle,
3160 answer->GetChars() + position,
3161 prev,
3162 length);
3163 position += length - prev;
3164 }
3165
3166 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003167 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003168 }
3169
3170 // Shorten string and fill
3171 int string_size = ResultSeqString::SizeFor(position);
3172 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3173 int delta = allocated_string_size - string_size;
3174
3175 answer->set_length(position);
3176 if (delta == 0) return *answer;
3177
3178 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003179 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003180 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3181 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3182 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003183
3184 return *answer;
3185}
3186
3187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003188RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003189 ASSERT(args.length() == 4);
3190
3191 CONVERT_CHECKED(String, subject, args[0]);
3192 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003193 Object* flat_subject;
3194 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3195 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3196 return maybe_flat_subject;
3197 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003198 }
3199 subject = String::cast(flat_subject);
3200 }
3201
3202 CONVERT_CHECKED(String, replacement, args[2]);
3203 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003204 Object* flat_replacement;
3205 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3206 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3207 return maybe_flat_replacement;
3208 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003209 }
3210 replacement = String::cast(flat_replacement);
3211 }
3212
3213 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3214 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3215
3216 ASSERT(last_match_info->HasFastElements());
3217
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003218 if (replacement->length() == 0) {
3219 if (subject->HasOnlyAsciiChars()) {
3220 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003221 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003222 } else {
3223 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003224 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003225 }
3226 }
3227
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003228 return StringReplaceRegExpWithString(isolate,
3229 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003230 regexp,
3231 replacement,
3232 last_match_info);
3233}
3234
3235
ager@chromium.org7c537e22008-10-16 08:43:32 +00003236// Perform string match of pattern on subject, starting at start index.
3237// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003238// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003239int Runtime::StringMatch(Isolate* isolate,
3240 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003241 Handle<String> pat,
3242 int start_index) {
3243 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003244 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003245
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003246 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003247 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003248
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003249 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003250 if (start_index + pattern_length > subject_length) return -1;
3251
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003252 if (!sub->IsFlat()) FlattenString(sub);
3253 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003254
ager@chromium.org7c537e22008-10-16 08:43:32 +00003255 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003256 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003257 String::FlatContent seq_sub = sub->GetFlatContent();
3258 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003259
ager@chromium.org7c537e22008-10-16 08:43:32 +00003260 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003261 if (seq_pat.IsAscii()) {
3262 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3263 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003264 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003265 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003266 pat_vector,
3267 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003268 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003269 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003270 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003271 pat_vector,
3272 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003273 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003274 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3275 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003276 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003277 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003278 pat_vector,
3279 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003280 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003281 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003282 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003283 pat_vector,
3284 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003285}
3286
3287
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003288RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003289 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003290 ASSERT(args.length() == 3);
3291
ager@chromium.org7c537e22008-10-16 08:43:32 +00003292 CONVERT_ARG_CHECKED(String, sub, 0);
3293 CONVERT_ARG_CHECKED(String, pat, 1);
3294
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003295 Object* index = args[2];
3296 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003297 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003298
ager@chromium.org870a0b62008-11-04 11:43:05 +00003299 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003300 int position =
3301 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003302 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003303}
3304
3305
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003306template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003307static int StringMatchBackwards(Vector<const schar> subject,
3308 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003309 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003310 int pattern_length = pattern.length();
3311 ASSERT(pattern_length >= 1);
3312 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003313
3314 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003315 for (int i = 0; i < pattern_length; i++) {
3316 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003317 if (c > String::kMaxAsciiCharCode) {
3318 return -1;
3319 }
3320 }
3321 }
3322
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003323 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003324 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003325 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003326 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003327 while (j < pattern_length) {
3328 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003329 break;
3330 }
3331 j++;
3332 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003333 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003334 return i;
3335 }
3336 }
3337 return -1;
3338}
3339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003340RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003341 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003342 ASSERT(args.length() == 3);
3343
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003344 CONVERT_ARG_CHECKED(String, sub, 0);
3345 CONVERT_ARG_CHECKED(String, pat, 1);
3346
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003347 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003348 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003349 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003350
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003351 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003352 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003354 if (start_index + pat_length > sub_length) {
3355 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003356 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003357
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003358 if (pat_length == 0) {
3359 return Smi::FromInt(start_index);
3360 }
3361
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003362 if (!sub->IsFlat()) FlattenString(sub);
3363 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003364
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003365 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003366 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3367
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003368 String::FlatContent sub_content = sub->GetFlatContent();
3369 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003370
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003371 if (pat_content.IsAscii()) {
3372 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3373 if (sub_content.IsAscii()) {
3374 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003375 pat_vector,
3376 start_index);
3377 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003378 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003379 pat_vector,
3380 start_index);
3381 }
3382 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003383 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3384 if (sub_content.IsAscii()) {
3385 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003386 pat_vector,
3387 start_index);
3388 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003389 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003390 pat_vector,
3391 start_index);
3392 }
3393 }
3394
3395 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003396}
3397
3398
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003399RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003400 NoHandleAllocation ha;
3401 ASSERT(args.length() == 2);
3402
3403 CONVERT_CHECKED(String, str1, args[0]);
3404 CONVERT_CHECKED(String, str2, args[1]);
3405
3406 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003407 int str1_length = str1->length();
3408 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409
3410 // Decide trivial cases without flattening.
3411 if (str1_length == 0) {
3412 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3413 return Smi::FromInt(-str2_length);
3414 } else {
3415 if (str2_length == 0) return Smi::FromInt(str1_length);
3416 }
3417
3418 int end = str1_length < str2_length ? str1_length : str2_length;
3419
3420 // No need to flatten if we are going to find the answer on the first
3421 // character. At this point we know there is at least one character
3422 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003423 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003424 if (d != 0) return Smi::FromInt(d);
3425
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003426 str1->TryFlatten();
3427 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003428
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003429 StringInputBuffer& buf1 =
3430 *isolate->runtime_state()->string_locale_compare_buf1();
3431 StringInputBuffer& buf2 =
3432 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003433
3434 buf1.Reset(str1);
3435 buf2.Reset(str2);
3436
3437 for (int i = 0; i < end; i++) {
3438 uint16_t char1 = buf1.GetNext();
3439 uint16_t char2 = buf2.GetNext();
3440 if (char1 != char2) return Smi::FromInt(char1 - char2);
3441 }
3442
3443 return Smi::FromInt(str1_length - str2_length);
3444}
3445
3446
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003447RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448 NoHandleAllocation ha;
3449 ASSERT(args.length() == 3);
3450
3451 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003452 int start, end;
3453 // We have a fast integer-only case here to avoid a conversion to double in
3454 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003455 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3456 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3457 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3458 start = from_number;
3459 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003460 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003461 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3462 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003463 start = FastD2I(from_number);
3464 end = FastD2I(to_number);
3465 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466 RUNTIME_ASSERT(end >= start);
3467 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003468 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003469 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003470 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003471}
3472
3473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003474RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003475 ASSERT_EQ(3, args.length());
3476
3477 CONVERT_ARG_CHECKED(String, subject, 0);
3478 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3479 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3480 HandleScope handles;
3481
3482 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3483
3484 if (match.is_null()) {
3485 return Failure::Exception();
3486 }
3487 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003488 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003489 }
3490 int length = subject->length();
3491
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003492 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003493 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003494 int start;
3495 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003496 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003497 {
3498 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003499 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003500 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3501 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3502 }
3503 offsets.Add(start);
3504 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003505 if (start == end) if (++end > length) break;
3506 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003507 if (match.is_null()) {
3508 return Failure::Exception();
3509 }
3510 } while (!match->IsNull());
3511 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003512 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003513 Handle<String> substring = isolate->factory()->
3514 NewSubString(subject, offsets.at(0), offsets.at(1));
3515 elements->set(0, *substring);
3516 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003517 int from = offsets.at(i * 2);
3518 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003519 Handle<String> substring = isolate->factory()->
3520 NewProperSubString(subject, from, to);
3521 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003522 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003523 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003524 result->set_length(Smi::FromInt(matches));
3525 return *result;
3526}
3527
3528
lrn@chromium.org25156de2010-04-06 13:10:27 +00003529// Two smis before and after the match, for very long strings.
3530const int kMaxBuilderEntriesPerRegExpMatch = 5;
3531
3532
3533static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3534 Handle<JSArray> last_match_info,
3535 int match_start,
3536 int match_end) {
3537 // Fill last_match_info with a single capture.
3538 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3539 AssertNoAllocation no_gc;
3540 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3541 RegExpImpl::SetLastCaptureCount(elements, 2);
3542 RegExpImpl::SetLastInput(elements, *subject);
3543 RegExpImpl::SetLastSubject(elements, *subject);
3544 RegExpImpl::SetCapture(elements, 0, match_start);
3545 RegExpImpl::SetCapture(elements, 1, match_end);
3546}
3547
3548
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003549template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003550static bool SearchStringMultiple(Isolate* isolate,
3551 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003552 Vector<const PatternChar> pattern,
3553 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003554 FixedArrayBuilder* builder,
3555 int* match_pos) {
3556 int pos = *match_pos;
3557 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003558 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003559 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003560 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003561 while (pos <= max_search_start) {
3562 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3563 *match_pos = pos;
3564 return false;
3565 }
3566 // Position of end of previous match.
3567 int match_end = pos + pattern_length;
3568 int new_pos = search.Search(subject, match_end);
3569 if (new_pos >= 0) {
3570 // A match.
3571 if (new_pos > match_end) {
3572 ReplacementStringBuilder::AddSubjectSlice(builder,
3573 match_end,
3574 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003575 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003576 pos = new_pos;
3577 builder->Add(pattern_string);
3578 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003579 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003580 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003581 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003582
lrn@chromium.org25156de2010-04-06 13:10:27 +00003583 if (pos < max_search_start) {
3584 ReplacementStringBuilder::AddSubjectSlice(builder,
3585 pos + pattern_length,
3586 subject_length);
3587 }
3588 *match_pos = pos;
3589 return true;
3590}
3591
3592
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003593static bool SearchStringMultiple(Isolate* isolate,
3594 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003595 Handle<String> pattern,
3596 Handle<JSArray> last_match_info,
3597 FixedArrayBuilder* builder) {
3598 ASSERT(subject->IsFlat());
3599 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003600
3601 // Treating as if a previous match was before first character.
3602 int match_pos = -pattern->length();
3603
3604 for (;;) { // Break when search complete.
3605 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3606 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003607 String::FlatContent subject_content = subject->GetFlatContent();
3608 String::FlatContent pattern_content = pattern->GetFlatContent();
3609 if (subject_content.IsAscii()) {
3610 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3611 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003612 if (SearchStringMultiple(isolate,
3613 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003614 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003615 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003616 builder,
3617 &match_pos)) break;
3618 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 if (SearchStringMultiple(isolate,
3620 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003621 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003622 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003623 builder,
3624 &match_pos)) break;
3625 }
3626 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003627 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3628 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003629 if (SearchStringMultiple(isolate,
3630 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003631 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003632 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003633 builder,
3634 &match_pos)) break;
3635 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003636 if (SearchStringMultiple(isolate,
3637 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003638 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003639 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003640 builder,
3641 &match_pos)) break;
3642 }
3643 }
3644 }
3645
3646 if (match_pos >= 0) {
3647 SetLastMatchInfoNoCaptures(subject,
3648 last_match_info,
3649 match_pos,
3650 match_pos + pattern->length());
3651 return true;
3652 }
3653 return false; // No matches at all.
3654}
3655
3656
3657static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003658 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003659 Handle<String> subject,
3660 Handle<JSRegExp> regexp,
3661 Handle<JSArray> last_match_array,
3662 FixedArrayBuilder* builder) {
3663 ASSERT(subject->IsFlat());
3664 int match_start = -1;
3665 int match_end = 0;
3666 int pos = 0;
3667 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3668 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3669
3670 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003671 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003672 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003673 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003674
3675 for (;;) { // Break on failure, return on exception.
3676 RegExpImpl::IrregexpResult result =
3677 RegExpImpl::IrregexpExecOnce(regexp,
3678 subject,
3679 pos,
3680 register_vector);
3681 if (result == RegExpImpl::RE_SUCCESS) {
3682 match_start = register_vector[0];
3683 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3684 if (match_end < match_start) {
3685 ReplacementStringBuilder::AddSubjectSlice(builder,
3686 match_end,
3687 match_start);
3688 }
3689 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003690 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003691 if (!first) {
3692 builder->Add(*isolate->factory()->NewProperSubString(subject,
3693 match_start,
3694 match_end));
3695 } else {
3696 builder->Add(*isolate->factory()->NewSubString(subject,
3697 match_start,
3698 match_end));
3699 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003700 if (match_start != match_end) {
3701 pos = match_end;
3702 } else {
3703 pos = match_end + 1;
3704 if (pos > subject_length) break;
3705 }
3706 } else if (result == RegExpImpl::RE_FAILURE) {
3707 break;
3708 } else {
3709 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3710 return result;
3711 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003712 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003713 }
3714
3715 if (match_start >= 0) {
3716 if (match_end < subject_length) {
3717 ReplacementStringBuilder::AddSubjectSlice(builder,
3718 match_end,
3719 subject_length);
3720 }
3721 SetLastMatchInfoNoCaptures(subject,
3722 last_match_array,
3723 match_start,
3724 match_end);
3725 return RegExpImpl::RE_SUCCESS;
3726 } else {
3727 return RegExpImpl::RE_FAILURE; // No matches at all.
3728 }
3729}
3730
3731
3732static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003733 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003734 Handle<String> subject,
3735 Handle<JSRegExp> regexp,
3736 Handle<JSArray> last_match_array,
3737 FixedArrayBuilder* builder) {
3738
3739 ASSERT(subject->IsFlat());
3740 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3741 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3742
3743 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003744 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003745
3746 RegExpImpl::IrregexpResult result =
3747 RegExpImpl::IrregexpExecOnce(regexp,
3748 subject,
3749 0,
3750 register_vector);
3751
3752 int capture_count = regexp->CaptureCount();
3753 int subject_length = subject->length();
3754
3755 // Position to search from.
3756 int pos = 0;
3757 // End of previous match. Differs from pos if match was empty.
3758 int match_end = 0;
3759 if (result == RegExpImpl::RE_SUCCESS) {
3760 // Need to keep a copy of the previous match for creating last_match_info
3761 // at the end, so we have two vectors that we swap between.
3762 OffsetsVector registers2(required_registers);
3763 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003764 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003765 do {
3766 int match_start = register_vector[0];
3767 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3768 if (match_end < match_start) {
3769 ReplacementStringBuilder::AddSubjectSlice(builder,
3770 match_end,
3771 match_start);
3772 }
3773 match_end = register_vector[1];
3774
3775 {
3776 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003777 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003778 // Arguments array to replace function is match, captures, index and
3779 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003780 Handle<FixedArray> elements =
3781 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003782 Handle<String> match;
3783 if (!first) {
3784 match = isolate->factory()->NewProperSubString(subject,
3785 match_start,
3786 match_end);
3787 } else {
3788 match = isolate->factory()->NewSubString(subject,
3789 match_start,
3790 match_end);
3791 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003792 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003793 for (int i = 1; i <= capture_count; i++) {
3794 int start = register_vector[i * 2];
3795 if (start >= 0) {
3796 int end = register_vector[i * 2 + 1];
3797 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003798 Handle<String> substring;
3799 if (!first) {
3800 substring = isolate->factory()->NewProperSubString(subject,
3801 start,
3802 end);
3803 } else {
3804 substring = isolate->factory()->NewSubString(subject, start, end);
3805 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003806 elements->set(i, *substring);
3807 } else {
3808 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003809 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003810 }
3811 }
3812 elements->set(capture_count + 1, Smi::FromInt(match_start));
3813 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003814 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003815 }
3816 // Swap register vectors, so the last successful match is in
3817 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003818 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003819 prev_register_vector = register_vector;
3820 register_vector = tmp;
3821
3822 if (match_end > match_start) {
3823 pos = match_end;
3824 } else {
3825 pos = match_end + 1;
3826 if (pos > subject_length) {
3827 break;
3828 }
3829 }
3830
3831 result = RegExpImpl::IrregexpExecOnce(regexp,
3832 subject,
3833 pos,
3834 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003835 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003836 } while (result == RegExpImpl::RE_SUCCESS);
3837
3838 if (result != RegExpImpl::RE_EXCEPTION) {
3839 // Finished matching, with at least one match.
3840 if (match_end < subject_length) {
3841 ReplacementStringBuilder::AddSubjectSlice(builder,
3842 match_end,
3843 subject_length);
3844 }
3845
3846 int last_match_capture_count = (capture_count + 1) * 2;
3847 int last_match_array_size =
3848 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3849 last_match_array->EnsureSize(last_match_array_size);
3850 AssertNoAllocation no_gc;
3851 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3852 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3853 RegExpImpl::SetLastSubject(elements, *subject);
3854 RegExpImpl::SetLastInput(elements, *subject);
3855 for (int i = 0; i < last_match_capture_count; i++) {
3856 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3857 }
3858 return RegExpImpl::RE_SUCCESS;
3859 }
3860 }
3861 // No matches at all, return failure or exception result directly.
3862 return result;
3863}
3864
3865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003866RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003867 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003868 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003869
3870 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003871 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003872 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3873 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3874 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3875
3876 ASSERT(last_match_info->HasFastElements());
3877 ASSERT(regexp->GetFlags().is_global());
3878 Handle<FixedArray> result_elements;
3879 if (result_array->HasFastElements()) {
3880 result_elements =
3881 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003882 }
3883 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003884 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003885 }
3886 FixedArrayBuilder builder(result_elements);
3887
3888 if (regexp->TypeTag() == JSRegExp::ATOM) {
3889 Handle<String> pattern(
3890 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003891 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003892 if (SearchStringMultiple(isolate, subject, pattern,
3893 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003894 return *builder.ToJSArray(result_array);
3895 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003896 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003897 }
3898
3899 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3900
3901 RegExpImpl::IrregexpResult result;
3902 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003903 result = SearchRegExpNoCaptureMultiple(isolate,
3904 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003905 regexp,
3906 last_match_info,
3907 &builder);
3908 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003909 result = SearchRegExpMultiple(isolate,
3910 subject,
3911 regexp,
3912 last_match_info,
3913 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003914 }
3915 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003916 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003917 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3918 return Failure::Exception();
3919}
3920
3921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003922RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003923 NoHandleAllocation ha;
3924 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003925 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003926 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003927
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003928 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003929 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003930 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003931 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003932 // Character array used for conversion.
3933 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003934 return isolate->heap()->
3935 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003936 }
3937 }
3938
3939 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003940 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003941 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003942 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003943 }
3944 if (isinf(value)) {
3945 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003946 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003947 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003948 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003949 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003950 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003951 MaybeObject* result =
3952 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003953 DeleteArray(str);
3954 return result;
3955}
3956
3957
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003958RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003959 NoHandleAllocation ha;
3960 ASSERT(args.length() == 2);
3961
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003962 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003963 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003964 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003965 }
3966 if (isinf(value)) {
3967 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003968 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003970 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003972 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003973 int f = FastD2I(f_number);
3974 RUNTIME_ASSERT(f >= 0);
3975 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003976 MaybeObject* res =
3977 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003979 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003980}
3981
3982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003983RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984 NoHandleAllocation ha;
3985 ASSERT(args.length() == 2);
3986
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003987 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003988 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003989 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990 }
3991 if (isinf(value)) {
3992 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003993 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003994 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003995 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003996 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003997 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998 int f = FastD2I(f_number);
3999 RUNTIME_ASSERT(f >= -1 && f <= 20);
4000 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004001 MaybeObject* res =
4002 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004003 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004004 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004005}
4006
4007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004008RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 NoHandleAllocation ha;
4010 ASSERT(args.length() == 2);
4011
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004012 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004013 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004014 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004015 }
4016 if (isinf(value)) {
4017 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004018 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004020 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004022 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004023 int f = FastD2I(f_number);
4024 RUNTIME_ASSERT(f >= 1 && f <= 21);
4025 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004026 MaybeObject* res =
4027 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004028 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004029 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004030}
4031
4032
4033// Returns a single character string where first character equals
4034// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004035static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004036 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004037 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004038 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004039 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004041 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042}
4043
4044
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004045MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4046 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004047 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048 // Handle [] indexing on Strings
4049 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004050 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4051 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004052 }
4053
4054 // Handle [] indexing on String objects
4055 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004056 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4057 Handle<Object> result =
4058 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4059 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060 }
4061
4062 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004063 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004064 return prototype->GetElement(index);
4065 }
4066
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004067 return GetElement(object, index);
4068}
4069
4070
lrn@chromium.org303ada72010-10-27 09:33:13 +00004071MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 return object->GetElement(index);
4073}
4074
4075
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004076MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4077 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004078 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004079 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004080
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004082 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004083 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004084 isolate->factory()->NewTypeError("non_object_property_load",
4085 HandleVector(args, 2));
4086 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004087 }
4088
4089 // Check if the given key is an array index.
4090 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004091 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004092 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093 }
4094
4095 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004096 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004097 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004098 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 bool has_pending_exception = false;
4101 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004102 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004103 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004104 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004105 }
4106
ager@chromium.org32912102009-01-16 10:38:43 +00004107 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108 // the element if so.
4109 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004110 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004112 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113 }
4114}
4115
4116
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004117RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118 NoHandleAllocation ha;
4119 ASSERT(args.length() == 2);
4120
4121 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004122 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004124 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004125}
4126
4127
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004128// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004129RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004130 NoHandleAllocation ha;
4131 ASSERT(args.length() == 2);
4132
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004133 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004134 // itself.
4135 //
4136 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004137 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004138 // global proxy object never has properties. This is the case
4139 // because the global proxy object forwards everything to its hidden
4140 // prototype including local lookups.
4141 //
4142 // Additionally, we need to make sure that we do not cache results
4143 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004144 if (args[0]->IsJSObject() &&
4145 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00004146 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004147 args[1]->IsString()) {
4148 JSObject* receiver = JSObject::cast(args[0]);
4149 String* key = String::cast(args[1]);
4150 if (receiver->HasFastProperties()) {
4151 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004152 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004153 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4154 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004155 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004156 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004157 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004158 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004159 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004160 LookupResult result;
4161 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00004162 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004163 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004164 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004165 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004166 }
4167 } else {
4168 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004169 StringDictionary* dictionary = receiver->property_dictionary();
4170 int entry = dictionary->FindEntry(key);
4171 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004172 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004173 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004174 if (!receiver->IsGlobalObject()) return value;
4175 value = JSGlobalPropertyCell::cast(value)->value();
4176 if (!value->IsTheHole()) return value;
4177 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004178 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004179 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004180 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4181 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004182 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004183 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004184 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004185 if (index >= 0 && index < str->length()) {
4186 Handle<Object> result = GetCharAt(str, index);
4187 return *result;
4188 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004189 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004190
4191 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004192 return Runtime::GetObjectProperty(isolate,
4193 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004194 args.at<Object>(1));
4195}
4196
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004197// Implements part of 8.12.9 DefineOwnProperty.
4198// There are 3 cases that lead here:
4199// Step 4b - define a new accessor property.
4200// Steps 9c & 12 - replace an existing data property with an accessor property.
4201// Step 12 - update an existing accessor property with an accessor or generic
4202// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004203RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004204 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004205 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004206 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4207 CONVERT_CHECKED(String, name, args[1]);
4208 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004209 Object* fun = args[3];
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004210 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004211 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4212 int unchecked = flag_attr->value();
4213 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4214 RUNTIME_ASSERT(!obj->IsNull());
4215 LookupResult result;
4216 obj->LocalLookupRealNamedProperty(name, &result);
4217
4218 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4219 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4220 // delete it to avoid running into trouble in DefineAccessor, which
4221 // handles this incorrectly if the property is readonly (does nothing)
4222 if (result.IsProperty() &&
4223 (result.type() == FIELD || result.type() == NORMAL
4224 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004225 Object* ok;
4226 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004227 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004228 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4229 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004230 }
4231 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4232}
4233
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004234// Implements part of 8.12.9 DefineOwnProperty.
4235// There are 3 cases that lead here:
4236// Step 4a - define a new data property.
4237// Steps 9b & 12 - replace an existing accessor property with a data property.
4238// Step 12 - update an existing data property with a data or generic
4239// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004240RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004241 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004242 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004243 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4244 CONVERT_ARG_CHECKED(String, name, 1);
4245 Handle<Object> obj_value = args.at<Object>(2);
4246
4247 CONVERT_CHECKED(Smi, flag, args[3]);
4248 int unchecked = flag->value();
4249 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4250
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004251 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4252
4253 // Check if this is an element.
4254 uint32_t index;
4255 bool is_element = name->AsArrayIndex(&index);
4256
4257 // Special case for elements if any of the flags are true.
4258 // If elements are in fast case we always implicitly assume that:
4259 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4260 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
4261 is_element) {
4262 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004263 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004264 // We do not need to do access checks here since these has already
4265 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004266 Handle<Object> proto(js_object->GetPrototype());
4267 // If proxy is detached, ignore the assignment. Alternatively,
4268 // we could throw an exception.
4269 if (proto->IsNull()) return *obj_value;
4270 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004271 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004272
4273 // Don't allow element properties to be redefined on objects with external
4274 // array elements.
4275 if (js_object->HasExternalArrayElements()) {
4276 Handle<Object> args[2] = { js_object, name };
4277 Handle<Object> error =
4278 isolate->factory()->NewTypeError("redef_external_array_element",
4279 HandleVector(args, 2));
4280 return isolate->Throw(*error);
4281 }
4282
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004283 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004284 // Make sure that we never go back to fast case.
4285 dictionary->set_requires_slow_elements();
4286 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004287 Handle<NumberDictionary> extended_dictionary =
4288 NumberDictionarySet(dictionary, index, obj_value, details);
4289 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004290 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004291 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4292 } else {
4293 js_object->set_elements(*extended_dictionary);
4294 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004295 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004296 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004297 }
4298
ager@chromium.org5c838252010-02-19 08:53:10 +00004299 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004300 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004301
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004302 // To be compatible with safari we do not change the value on API objects
4303 // in defineProperty. Firefox disagrees here, and actually changes the value.
4304 if (result.IsProperty() &&
4305 (result.type() == CALLBACKS) &&
4306 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004307 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004308 }
4309
ager@chromium.org5c838252010-02-19 08:53:10 +00004310 // Take special care when attributes are different and there is already
4311 // a property. For simplicity we normalize the property which enables us
4312 // to not worry about changing the instance_descriptor and creating a new
4313 // map. The current version of SetObjectProperty does not handle attributes
4314 // correctly in the case where a property is a field and is reset with
4315 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004316 if (result.IsProperty() &&
4317 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004318 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004319 if (js_object->IsJSGlobalProxy()) {
4320 // Since the result is a property, the prototype will exist so
4321 // we don't have to check for null.
4322 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004323 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004324 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004325 // Use IgnoreAttributes version since a readonly property may be
4326 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004327 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4328 *obj_value,
4329 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004330 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004332 return Runtime::ForceSetObjectProperty(isolate,
4333 js_object,
4334 name,
4335 obj_value,
4336 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004337}
4338
4339
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004340// Special case for elements if any of the flags are true.
4341// If elements are in fast case we always implicitly assume that:
4342// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4343static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4344 Handle<JSObject> js_object,
4345 uint32_t index,
4346 Handle<Object> value,
4347 PropertyAttributes attr) {
4348 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004349 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004350 // Make sure that we never go back to fast case.
4351 dictionary->set_requires_slow_elements();
4352 PropertyDetails details = PropertyDetails(attr, NORMAL);
4353 Handle<NumberDictionary> extended_dictionary =
4354 NumberDictionarySet(dictionary, index, value, details);
4355 if (*extended_dictionary != *dictionary) {
4356 js_object->set_elements(*extended_dictionary);
4357 }
4358 return *value;
4359}
4360
4361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004362MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4363 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004364 Handle<Object> key,
4365 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004366 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004367 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004368 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004369
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004370 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004371 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004372 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004373 isolate->factory()->NewTypeError("non_object_property_store",
4374 HandleVector(args, 2));
4375 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004376 }
4377
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004378 if (object->IsJSProxy()) {
4379 bool has_pending_exception = false;
4380 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4381 if (has_pending_exception) return Failure::Exception();
4382 return JSProxy::cast(*object)->SetProperty(
4383 String::cast(*name), *value, attr, strict_mode);
4384 }
4385
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004386 // If the object isn't a JavaScript object, we ignore the store.
4387 if (!object->IsJSObject()) return *value;
4388
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004389 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4390
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004391 // Check if the given key is an array index.
4392 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004393 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004394 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4395 // of a string using [] notation. We need to support this too in
4396 // JavaScript.
4397 // In the case of a String object we just need to redirect the assignment to
4398 // the underlying string if the index is in range. Since the underlying
4399 // string does nothing with the assignment then we can ignore such
4400 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004401 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004402 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004403 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004404
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004405 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4406 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4407 }
4408
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004409 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004410 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004411 return *value;
4412 }
4413
4414 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004415 Handle<Object> result;
4416 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004417 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4418 return NormalizeObjectSetElement(isolate,
4419 js_object,
4420 index,
4421 value,
4422 attr);
4423 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004424 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004425 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004426 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004427 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004428 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004429 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004430 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004431 return *value;
4432 }
4433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004434 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004435 bool has_pending_exception = false;
4436 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4437 if (has_pending_exception) return Failure::Exception();
4438 Handle<String> name = Handle<String>::cast(converted);
4439
4440 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004441 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004442 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004443 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004444 }
4445}
4446
4447
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004448MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4449 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004450 Handle<Object> key,
4451 Handle<Object> value,
4452 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004453 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004454
4455 // Check if the given key is an array index.
4456 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004457 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004458 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4459 // of a string using [] notation. We need to support this too in
4460 // JavaScript.
4461 // In the case of a String object we just need to redirect the assignment to
4462 // the underlying string if the index is in range. Since the underlying
4463 // string does nothing with the assignment then we can ignore such
4464 // assignments.
4465 if (js_object->IsStringObjectWithCharacterAt(index)) {
4466 return *value;
4467 }
4468
whesse@chromium.org7b260152011-06-20 15:33:18 +00004469 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004470 }
4471
4472 if (key->IsString()) {
4473 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004474 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004475 } else {
4476 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004477 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004478 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4479 *value,
4480 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004481 }
4482 }
4483
4484 // Call-back into JavaScript to convert the key to a string.
4485 bool has_pending_exception = false;
4486 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4487 if (has_pending_exception) return Failure::Exception();
4488 Handle<String> name = Handle<String>::cast(converted);
4489
4490 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004491 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004492 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004493 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004494 }
4495}
4496
4497
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004498MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004499 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004500 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004501 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004502
4503 // Check if the given key is an array index.
4504 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004505 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004506 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4507 // characters of a string using [] notation. In the case of a
4508 // String object we just need to redirect the deletion to the
4509 // underlying string if the index is in range. Since the
4510 // underlying string does nothing with the deletion, we can ignore
4511 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004512 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004513 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004514 }
4515
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004516 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004517 }
4518
4519 Handle<String> key_string;
4520 if (key->IsString()) {
4521 key_string = Handle<String>::cast(key);
4522 } else {
4523 // Call-back into JavaScript to convert the key to a string.
4524 bool has_pending_exception = false;
4525 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4526 if (has_pending_exception) return Failure::Exception();
4527 key_string = Handle<String>::cast(converted);
4528 }
4529
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004530 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004531 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004532}
4533
4534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004535RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004536 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004537 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004538
4539 Handle<Object> object = args.at<Object>(0);
4540 Handle<Object> key = args.at<Object>(1);
4541 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004542 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004543 RUNTIME_ASSERT(
4544 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004545 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004546 PropertyAttributes attributes =
4547 static_cast<PropertyAttributes>(unchecked_attributes);
4548
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004549 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004550 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004551 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004552 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4553 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004554 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004555 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004556
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004557 return Runtime::SetObjectProperty(isolate,
4558 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004559 key,
4560 value,
4561 attributes,
4562 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004563}
4564
4565
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004566// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004567// This is used to decide if we should transform null and undefined
4568// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004569RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004570 NoHandleAllocation ha;
4571 RUNTIME_ASSERT(args.length() == 1);
4572
4573 Handle<Object> object = args.at<Object>(0);
4574
4575 if (object->IsJSFunction()) {
4576 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004577 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004578 }
4579 return isolate->heap()->undefined_value();
4580}
4581
4582
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004583// Set a local property, even if it is READ_ONLY. If the property does not
4584// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004585RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004586 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004587 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004588 CONVERT_CHECKED(JSObject, object, args[0]);
4589 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004590 // Compute attributes.
4591 PropertyAttributes attributes = NONE;
4592 if (args.length() == 4) {
4593 CONVERT_CHECKED(Smi, value_obj, args[3]);
4594 int unchecked_value = value_obj->value();
4595 // Only attribute bits should be set.
4596 RUNTIME_ASSERT(
4597 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4598 attributes = static_cast<PropertyAttributes>(unchecked_value);
4599 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004600
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004601 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004602 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603}
4604
4605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004606RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004607 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004608 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004609
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004610 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004611 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004612 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004613 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004614 ? JSReceiver::STRICT_DELETION
4615 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616}
4617
4618
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004619static Object* HasLocalPropertyImplementation(Isolate* isolate,
4620 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004621 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004622 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004623 // Handle hidden prototypes. If there's a hidden prototype above this thing
4624 // then we have to check it for properties, because they are supposed to
4625 // look like they are on this object.
4626 Handle<Object> proto(object->GetPrototype());
4627 if (proto->IsJSObject() &&
4628 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004629 return HasLocalPropertyImplementation(isolate,
4630 Handle<JSObject>::cast(proto),
4631 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004632 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004633 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004634}
4635
4636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004637RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004638 NoHandleAllocation ha;
4639 ASSERT(args.length() == 2);
4640 CONVERT_CHECKED(String, key, args[1]);
4641
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004642 uint32_t index;
4643 const bool key_is_array_index = key->AsArrayIndex(&index);
4644
ager@chromium.org9085a012009-05-11 19:22:57 +00004645 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004646 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004647 if (obj->IsJSObject()) {
4648 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004649 // Fast case: either the key is a real named property or it is not
4650 // an array index and there are no interceptors or hidden
4651 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004652 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004653 Map* map = object->map();
4654 if (!key_is_array_index &&
4655 !map->has_named_interceptor() &&
4656 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4657 return isolate->heap()->false_value();
4658 }
4659 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004660 HandleScope scope(isolate);
4661 return HasLocalPropertyImplementation(isolate,
4662 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004663 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004664 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004665 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004666 String* string = String::cast(obj);
4667 if (index < static_cast<uint32_t>(string->length())) {
4668 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669 }
4670 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004671 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004672}
4673
4674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004675RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004676 NoHandleAllocation na;
4677 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004678 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4679 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004680
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004681 bool result = receiver->HasProperty(key);
4682 if (isolate->has_pending_exception()) return Failure::Exception();
4683 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004684}
4685
4686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004687RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688 NoHandleAllocation na;
4689 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004690 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4691 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004692
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004693 bool result = receiver->HasElement(index->value());
4694 if (isolate->has_pending_exception()) return Failure::Exception();
4695 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004696}
4697
4698
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004699RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004700 NoHandleAllocation ha;
4701 ASSERT(args.length() == 2);
4702
4703 CONVERT_CHECKED(JSObject, object, args[0]);
4704 CONVERT_CHECKED(String, key, args[1]);
4705
4706 uint32_t index;
4707 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004708 JSObject::LocalElementType type = object->HasLocalElement(index);
4709 switch (type) {
4710 case JSObject::UNDEFINED_ELEMENT:
4711 case JSObject::STRING_CHARACTER_ELEMENT:
4712 return isolate->heap()->false_value();
4713 case JSObject::INTERCEPTED_ELEMENT:
4714 case JSObject::FAST_ELEMENT:
4715 return isolate->heap()->true_value();
4716 case JSObject::DICTIONARY_ELEMENT: {
4717 if (object->IsJSGlobalProxy()) {
4718 Object* proto = object->GetPrototype();
4719 if (proto->IsNull()) {
4720 return isolate->heap()->false_value();
4721 }
4722 ASSERT(proto->IsJSGlobalObject());
4723 object = JSObject::cast(proto);
4724 }
4725 FixedArray* elements = FixedArray::cast(object->elements());
4726 NumberDictionary* dictionary = NULL;
4727 if (elements->map() ==
4728 isolate->heap()->non_strict_arguments_elements_map()) {
4729 dictionary = NumberDictionary::cast(elements->get(1));
4730 } else {
4731 dictionary = NumberDictionary::cast(elements);
4732 }
4733 int entry = dictionary->FindEntry(index);
4734 ASSERT(entry != NumberDictionary::kNotFound);
4735 PropertyDetails details = dictionary->DetailsAt(entry);
4736 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4737 }
4738 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004739 }
4740
ager@chromium.org870a0b62008-11-04 11:43:05 +00004741 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004742 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004743}
4744
4745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004746RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004747 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004748 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004749 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004750 return *GetKeysFor(object);
4751}
4752
4753
4754// Returns either a FixedArray as Runtime_GetPropertyNames,
4755// or, if the given object has an enum cache that contains
4756// all enumerable properties of the object and its prototypes
4757// have none, the map of the object. This is used to speed up
4758// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004759RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004760 ASSERT(args.length() == 1);
4761
4762 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4763
4764 if (raw_object->IsSimpleEnum()) return raw_object->map();
4765
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004766 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004767 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004768 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4769 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004770
4771 // Test again, since cache may have been built by preceding call.
4772 if (object->IsSimpleEnum()) return object->map();
4773
4774 return *content;
4775}
4776
4777
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004778// Find the length of the prototype chain that is to to handled as one. If a
4779// prototype object is hidden it is to be viewed as part of the the object it
4780// is prototype for.
4781static int LocalPrototypeChainLength(JSObject* obj) {
4782 int count = 1;
4783 Object* proto = obj->GetPrototype();
4784 while (proto->IsJSObject() &&
4785 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4786 count++;
4787 proto = JSObject::cast(proto)->GetPrototype();
4788 }
4789 return count;
4790}
4791
4792
4793// Return the names of the local named properties.
4794// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004795RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004796 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004797 ASSERT(args.length() == 1);
4798 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004799 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004800 }
4801 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4802
4803 // Skip the global proxy as it has no properties and always delegates to the
4804 // real global object.
4805 if (obj->IsJSGlobalProxy()) {
4806 // Only collect names if access is permitted.
4807 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004808 !isolate->MayNamedAccess(*obj,
4809 isolate->heap()->undefined_value(),
4810 v8::ACCESS_KEYS)) {
4811 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4812 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004813 }
4814 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4815 }
4816
4817 // Find the number of objects making up this.
4818 int length = LocalPrototypeChainLength(*obj);
4819
4820 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004821 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004822 int total_property_count = 0;
4823 Handle<JSObject> jsproto = obj;
4824 for (int i = 0; i < length; i++) {
4825 // Only collect names if access is permitted.
4826 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004827 !isolate->MayNamedAccess(*jsproto,
4828 isolate->heap()->undefined_value(),
4829 v8::ACCESS_KEYS)) {
4830 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4831 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004832 }
4833 int n;
4834 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4835 local_property_count[i] = n;
4836 total_property_count += n;
4837 if (i < length - 1) {
4838 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4839 }
4840 }
4841
4842 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004843 Handle<FixedArray> names =
4844 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004845
4846 // Get the property names.
4847 jsproto = obj;
4848 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004849 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004850 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004851 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4852 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004853 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004854 proto_with_hidden_properties++;
4855 }
4856 if (i < length - 1) {
4857 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4858 }
4859 }
4860
4861 // Filter out name of hidden propeties object.
4862 if (proto_with_hidden_properties > 0) {
4863 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004864 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004865 names->length() - proto_with_hidden_properties);
4866 int dest_pos = 0;
4867 for (int i = 0; i < total_property_count; i++) {
4868 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004869 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004870 continue;
4871 }
4872 names->set(dest_pos++, name);
4873 }
4874 }
4875
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004876 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004877}
4878
4879
4880// Return the names of the local indexed properties.
4881// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004882RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004883 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004884 ASSERT(args.length() == 1);
4885 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004886 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004887 }
4888 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4889
4890 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004891 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004892 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004893 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004894}
4895
4896
4897// Return information on whether an object has a named or indexed interceptor.
4898// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004899RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004900 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004901 ASSERT(args.length() == 1);
4902 if (!args[0]->IsJSObject()) {
4903 return Smi::FromInt(0);
4904 }
4905 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4906
4907 int result = 0;
4908 if (obj->HasNamedInterceptor()) result |= 2;
4909 if (obj->HasIndexedInterceptor()) result |= 1;
4910
4911 return Smi::FromInt(result);
4912}
4913
4914
4915// Return property names from named interceptor.
4916// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004917RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004918 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004919 ASSERT(args.length() == 1);
4920 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4921
4922 if (obj->HasNamedInterceptor()) {
4923 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4924 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4925 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004926 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004927}
4928
4929
4930// Return element names from indexed interceptor.
4931// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004932RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004933 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004934 ASSERT(args.length() == 1);
4935 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4936
4937 if (obj->HasIndexedInterceptor()) {
4938 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4939 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4940 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004941 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004942}
4943
4944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004945RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004946 ASSERT_EQ(args.length(), 1);
4947 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004948 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004949 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004950
4951 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004952 // Do access checks before going to the global object.
4953 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004954 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004955 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004956 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4957 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004958 }
4959
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004960 Handle<Object> proto(object->GetPrototype());
4961 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004962 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004963 object = Handle<JSObject>::cast(proto);
4964 }
4965
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004966 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4967 LOCAL_ONLY);
4968 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4969 // property array and since the result is mutable we have to create
4970 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004971 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004972 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004973 for (int i = 0; i < length; i++) {
4974 Object* entry = contents->get(i);
4975 if (entry->IsString()) {
4976 copy->set(i, entry);
4977 } else {
4978 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004979 HandleScope scope(isolate);
4980 Handle<Object> entry_handle(entry, isolate);
4981 Handle<Object> entry_str =
4982 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004983 copy->set(i, *entry_str);
4984 }
4985 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004986 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004987}
4988
4989
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004990RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004991 NoHandleAllocation ha;
4992 ASSERT(args.length() == 1);
4993
4994 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004995 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004996 it.AdvanceToArgumentsFrame();
4997 JavaScriptFrame* frame = it.frame();
4998
4999 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005000 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005001
5002 // Try to convert the key to an index. If successful and within
5003 // index return the the argument from the frame.
5004 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005005 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005006 return frame->GetParameter(index);
5007 }
5008
5009 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005010 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005011 bool exception = false;
5012 Handle<Object> converted =
5013 Execution::ToString(args.at<Object>(0), &exception);
5014 if (exception) return Failure::Exception();
5015 Handle<String> key = Handle<String>::cast(converted);
5016
5017 // Try to convert the string key into an array index.
5018 if (key->AsArrayIndex(&index)) {
5019 if (index < n) {
5020 return frame->GetParameter(index);
5021 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005022 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005023 }
5024 }
5025
5026 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005027 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5028 if (key->Equals(isolate->heap()->callee_symbol())) {
5029 Object* function = frame->function();
5030 if (function->IsJSFunction() &&
5031 JSFunction::cast(function)->shared()->strict_mode()) {
5032 return isolate->Throw(*isolate->factory()->NewTypeError(
5033 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5034 }
5035 return function;
5036 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005037
5038 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005039 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005040}
5041
5042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005043RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005044 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005045
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005046 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005047 Handle<Object> object = args.at<Object>(0);
5048 if (object->IsJSObject()) {
5049 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005050 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005051 MaybeObject* ok = js_object->TransformToFastProperties(0);
5052 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005053 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005054 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005055 return *object;
5056}
5057
5058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005059RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005060 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005061
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005062 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005063 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005064 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005065 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005066 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005067 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005068 return *object;
5069}
5070
5071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005072RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005073 NoHandleAllocation ha;
5074 ASSERT(args.length() == 1);
5075
5076 return args[0]->ToBoolean();
5077}
5078
5079
5080// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5081// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005082RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005083 NoHandleAllocation ha;
5084
5085 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005086 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005087 HeapObject* heap_obj = HeapObject::cast(obj);
5088
5089 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005090 if (heap_obj->map()->is_undetectable()) {
5091 return isolate->heap()->undefined_symbol();
5092 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005093
5094 InstanceType instance_type = heap_obj->map()->instance_type();
5095 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005096 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005097 }
5098
5099 switch (instance_type) {
5100 case ODDBALL_TYPE:
5101 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005102 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005103 }
5104 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005105 return FLAG_harmony_typeof
5106 ? isolate->heap()->null_symbol()
5107 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005108 }
5109 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005110 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005111 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005112 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005113 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005114 default:
5115 // For any kind of object not handled above, the spec rule for
5116 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005117 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005118 }
5119}
5120
5121
lrn@chromium.org25156de2010-04-06 13:10:27 +00005122static bool AreDigits(const char*s, int from, int to) {
5123 for (int i = from; i < to; i++) {
5124 if (s[i] < '0' || s[i] > '9') return false;
5125 }
5126
5127 return true;
5128}
5129
5130
5131static int ParseDecimalInteger(const char*s, int from, int to) {
5132 ASSERT(to - from < 10); // Overflow is not possible.
5133 ASSERT(from < to);
5134 int d = s[from] - '0';
5135
5136 for (int i = from + 1; i < to; i++) {
5137 d = 10 * d + (s[i] - '0');
5138 }
5139
5140 return d;
5141}
5142
5143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005144RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005145 NoHandleAllocation ha;
5146 ASSERT(args.length() == 1);
5147 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005148 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005149
5150 // Fast case: short integer or some sorts of junk values.
5151 int len = subject->length();
5152 if (subject->IsSeqAsciiString()) {
5153 if (len == 0) return Smi::FromInt(0);
5154
5155 char const* data = SeqAsciiString::cast(subject)->GetChars();
5156 bool minus = (data[0] == '-');
5157 int start_pos = (minus ? 1 : 0);
5158
5159 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005160 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005161 } else if (data[start_pos] > '9') {
5162 // Fast check for a junk value. A valid string may start from a
5163 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5164 // the 'I' character ('Infinity'). All of that have codes not greater than
5165 // '9' except 'I'.
5166 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005167 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005168 }
5169 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5170 // The maximal/minimal smi has 10 digits. If the string has less digits we
5171 // know it will fit into the smi-data type.
5172 int d = ParseDecimalInteger(data, start_pos, len);
5173 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005174 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005175 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005176 } else if (!subject->HasHashCode() &&
5177 len <= String::kMaxArrayIndexSize &&
5178 (len == 1 || data[0] != '0')) {
5179 // String hash is not calculated yet but all the data are present.
5180 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005181 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005182#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005183 subject->Hash(); // Force hash calculation.
5184 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5185 static_cast<int>(hash));
5186#endif
5187 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005188 }
5189 return Smi::FromInt(d);
5190 }
5191 }
5192
5193 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005194 return isolate->heap()->NumberFromDouble(
5195 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196}
5197
5198
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005199RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005200 NoHandleAllocation ha;
5201 ASSERT(args.length() == 1);
5202
5203 CONVERT_CHECKED(JSArray, codes, args[0]);
5204 int length = Smi::cast(codes->length())->value();
5205
5206 // Check if the string can be ASCII.
5207 int i;
5208 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005209 Object* element;
5210 { MaybeObject* maybe_element = codes->GetElement(i);
5211 // We probably can't get an exception here, but just in order to enforce
5212 // the checking of inputs in the runtime calls we check here.
5213 if (!maybe_element->ToObject(&element)) return maybe_element;
5214 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005215 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5216 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5217 break;
5218 }
5219
lrn@chromium.org303ada72010-10-27 09:33:13 +00005220 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005221 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005222 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005223 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005224 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005225 }
5226
lrn@chromium.org303ada72010-10-27 09:33:13 +00005227 Object* object = NULL;
5228 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005229 String* result = String::cast(object);
5230 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005231 Object* element;
5232 { MaybeObject* maybe_element = codes->GetElement(i);
5233 if (!maybe_element->ToObject(&element)) return maybe_element;
5234 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005235 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005236 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005237 }
5238 return result;
5239}
5240
5241
5242// kNotEscaped is generated by the following:
5243//
5244// #!/bin/perl
5245// for (my $i = 0; $i < 256; $i++) {
5246// print "\n" if $i % 16 == 0;
5247// my $c = chr($i);
5248// my $escaped = 1;
5249// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5250// print $escaped ? "0, " : "1, ";
5251// }
5252
5253
5254static bool IsNotEscaped(uint16_t character) {
5255 // Only for 8 bit characters, the rest are always escaped (in a different way)
5256 ASSERT(character < 256);
5257 static const char kNotEscaped[256] = {
5258 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5259 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5260 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5261 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5262 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5263 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5264 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5265 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5266 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5267 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5268 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5269 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5270 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5271 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5272 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5274 };
5275 return kNotEscaped[character] != 0;
5276}
5277
5278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005279RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005280 const char hex_chars[] = "0123456789ABCDEF";
5281 NoHandleAllocation ha;
5282 ASSERT(args.length() == 1);
5283 CONVERT_CHECKED(String, source, args[0]);
5284
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005285 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005286
5287 int escaped_length = 0;
5288 int length = source->length();
5289 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005290 Access<StringInputBuffer> buffer(
5291 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005292 buffer->Reset(source);
5293 while (buffer->has_more()) {
5294 uint16_t character = buffer->GetNext();
5295 if (character >= 256) {
5296 escaped_length += 6;
5297 } else if (IsNotEscaped(character)) {
5298 escaped_length++;
5299 } else {
5300 escaped_length += 3;
5301 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005302 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005303 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005304 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005305 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005306 return Failure::OutOfMemoryException();
5307 }
5308 }
5309 }
5310 // No length change implies no change. Return original string if no change.
5311 if (escaped_length == length) {
5312 return source;
5313 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005314 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005315 { MaybeObject* maybe_o =
5316 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005317 if (!maybe_o->ToObject(&o)) return maybe_o;
5318 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319 String* destination = String::cast(o);
5320 int dest_position = 0;
5321
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005322 Access<StringInputBuffer> buffer(
5323 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005324 buffer->Rewind();
5325 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005326 uint16_t chr = buffer->GetNext();
5327 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005328 destination->Set(dest_position, '%');
5329 destination->Set(dest_position+1, 'u');
5330 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5331 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5332 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5333 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005334 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005335 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005336 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005337 dest_position++;
5338 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005339 destination->Set(dest_position, '%');
5340 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5341 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005342 dest_position += 3;
5343 }
5344 }
5345 return destination;
5346}
5347
5348
5349static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5350 static const signed char kHexValue['g'] = {
5351 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5352 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5353 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5354 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5355 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5356 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5357 -1, 10, 11, 12, 13, 14, 15 };
5358
5359 if (character1 > 'f') return -1;
5360 int hi = kHexValue[character1];
5361 if (hi == -1) return -1;
5362 if (character2 > 'f') return -1;
5363 int lo = kHexValue[character2];
5364 if (lo == -1) return -1;
5365 return (hi << 4) + lo;
5366}
5367
5368
ager@chromium.org870a0b62008-11-04 11:43:05 +00005369static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005370 int i,
5371 int length,
5372 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005373 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005374 int32_t hi = 0;
5375 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005376 if (character == '%' &&
5377 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005378 source->Get(i + 1) == 'u' &&
5379 (hi = TwoDigitHex(source->Get(i + 2),
5380 source->Get(i + 3))) != -1 &&
5381 (lo = TwoDigitHex(source->Get(i + 4),
5382 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005383 *step = 6;
5384 return (hi << 8) + lo;
5385 } else if (character == '%' &&
5386 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005387 (lo = TwoDigitHex(source->Get(i + 1),
5388 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005389 *step = 3;
5390 return lo;
5391 } else {
5392 *step = 1;
5393 return character;
5394 }
5395}
5396
5397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005398RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005399 NoHandleAllocation ha;
5400 ASSERT(args.length() == 1);
5401 CONVERT_CHECKED(String, source, args[0]);
5402
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005403 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005404
5405 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005406 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005407
5408 int unescaped_length = 0;
5409 for (int i = 0; i < length; unescaped_length++) {
5410 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005411 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005412 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005413 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005414 i += step;
5415 }
5416
5417 // No length change implies no change. Return original string if no change.
5418 if (unescaped_length == length)
5419 return source;
5420
lrn@chromium.org303ada72010-10-27 09:33:13 +00005421 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005422 { MaybeObject* maybe_o =
5423 ascii ?
5424 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5425 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005426 if (!maybe_o->ToObject(&o)) return maybe_o;
5427 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005428 String* destination = String::cast(o);
5429
5430 int dest_position = 0;
5431 for (int i = 0; i < length; dest_position++) {
5432 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005433 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005434 i += step;
5435 }
5436 return destination;
5437}
5438
5439
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005440static const unsigned int kQuoteTableLength = 128u;
5441
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005442static const int kJsonQuotesCharactersPerEntry = 8;
5443static const char* const JsonQuotes =
5444 "\\u0000 \\u0001 \\u0002 \\u0003 "
5445 "\\u0004 \\u0005 \\u0006 \\u0007 "
5446 "\\b \\t \\n \\u000b "
5447 "\\f \\r \\u000e \\u000f "
5448 "\\u0010 \\u0011 \\u0012 \\u0013 "
5449 "\\u0014 \\u0015 \\u0016 \\u0017 "
5450 "\\u0018 \\u0019 \\u001a \\u001b "
5451 "\\u001c \\u001d \\u001e \\u001f "
5452 " ! \\\" # "
5453 "$ % & ' "
5454 "( ) * + "
5455 ", - . / "
5456 "0 1 2 3 "
5457 "4 5 6 7 "
5458 "8 9 : ; "
5459 "< = > ? "
5460 "@ A B C "
5461 "D E F G "
5462 "H I J K "
5463 "L M N O "
5464 "P Q R S "
5465 "T U V W "
5466 "X Y Z [ "
5467 "\\\\ ] ^ _ "
5468 "` a b c "
5469 "d e f g "
5470 "h i j k "
5471 "l m n o "
5472 "p q r s "
5473 "t u v w "
5474 "x y z { "
5475 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005476
5477
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005478// For a string that is less than 32k characters it should always be
5479// possible to allocate it in new space.
5480static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5481
5482
5483// Doing JSON quoting cannot make the string more than this many times larger.
5484static const int kJsonQuoteWorstCaseBlowup = 6;
5485
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005486static const int kSpaceForQuotesAndComma = 3;
5487static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005488
5489// Covers the entire ASCII range (all other characters are unchanged by JSON
5490// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005491static const byte JsonQuoteLengths[kQuoteTableLength] = {
5492 6, 6, 6, 6, 6, 6, 6, 6,
5493 2, 2, 2, 6, 2, 2, 6, 6,
5494 6, 6, 6, 6, 6, 6, 6, 6,
5495 6, 6, 6, 6, 6, 6, 6, 6,
5496 1, 1, 2, 1, 1, 1, 1, 1,
5497 1, 1, 1, 1, 1, 1, 1, 1,
5498 1, 1, 1, 1, 1, 1, 1, 1,
5499 1, 1, 1, 1, 1, 1, 1, 1,
5500 1, 1, 1, 1, 1, 1, 1, 1,
5501 1, 1, 1, 1, 1, 1, 1, 1,
5502 1, 1, 1, 1, 1, 1, 1, 1,
5503 1, 1, 1, 1, 2, 1, 1, 1,
5504 1, 1, 1, 1, 1, 1, 1, 1,
5505 1, 1, 1, 1, 1, 1, 1, 1,
5506 1, 1, 1, 1, 1, 1, 1, 1,
5507 1, 1, 1, 1, 1, 1, 1, 1,
5508};
5509
5510
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005511template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005512MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005513
5514
5515template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005516MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5517 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005518}
5519
5520
5521template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005522MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5523 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005524}
5525
5526
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005527template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005528static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5529 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005530 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005531 const Char* read_cursor = characters.start();
5532 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005533 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005534 int quoted_length = kSpaceForQuotes;
5535 while (read_cursor < end) {
5536 Char c = *(read_cursor++);
5537 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5538 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005539 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005540 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005541 }
5542 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005543 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5544 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005545 Object* new_object;
5546 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005547 return new_alloc;
5548 }
5549 StringType* new_string = StringType::cast(new_object);
5550
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005551 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005552 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005553 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005554 *(write_cursor++) = '"';
5555
5556 read_cursor = characters.start();
5557 while (read_cursor < end) {
5558 Char c = *(read_cursor++);
5559 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5560 *(write_cursor++) = c;
5561 } else {
5562 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5563 const char* replacement = JsonQuotes +
5564 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5565 for (int i = 0; i < len; i++) {
5566 *write_cursor++ = *replacement++;
5567 }
5568 }
5569 }
5570 *(write_cursor++) = '"';
5571 return new_string;
5572}
5573
5574
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005575template <typename SinkChar, typename SourceChar>
5576static inline SinkChar* WriteQuoteJsonString(
5577 Isolate* isolate,
5578 SinkChar* write_cursor,
5579 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005580 // SinkChar is only char if SourceChar is guaranteed to be char.
5581 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005582 const SourceChar* read_cursor = characters.start();
5583 const SourceChar* end = read_cursor + characters.length();
5584 *(write_cursor++) = '"';
5585 while (read_cursor < end) {
5586 SourceChar c = *(read_cursor++);
5587 if (sizeof(SourceChar) > 1u &&
5588 static_cast<unsigned>(c) >= kQuoteTableLength) {
5589 *(write_cursor++) = static_cast<SinkChar>(c);
5590 } else {
5591 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5592 const char* replacement = JsonQuotes +
5593 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5594 write_cursor[0] = replacement[0];
5595 if (len > 1) {
5596 write_cursor[1] = replacement[1];
5597 if (len > 2) {
5598 ASSERT(len == 6);
5599 write_cursor[2] = replacement[2];
5600 write_cursor[3] = replacement[3];
5601 write_cursor[4] = replacement[4];
5602 write_cursor[5] = replacement[5];
5603 }
5604 }
5605 write_cursor += len;
5606 }
5607 }
5608 *(write_cursor++) = '"';
5609 return write_cursor;
5610}
5611
5612
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005613template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005614static MaybeObject* QuoteJsonString(Isolate* isolate,
5615 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005616 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005617 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005618 int worst_case_length =
5619 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005620 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005621 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005622 }
5623
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005624 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5625 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005626 Object* new_object;
5627 if (!new_alloc->ToObject(&new_object)) {
5628 return new_alloc;
5629 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005630 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005631 // Even if our string is small enough to fit in new space we still have to
5632 // handle it being allocated in old space as may happen in the third
5633 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5634 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005635 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005636 }
5637 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005638 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005639
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005640 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005641 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005642 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005643 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5644 write_cursor,
5645 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005646 int final_length = static_cast<int>(
5647 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005648 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005649 isolate->heap()->new_space()->
5650 template ShrinkStringAtAllocationBoundary<StringType>(
5651 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005652 return new_string;
5653}
5654
5655
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005656RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005657 NoHandleAllocation ha;
5658 CONVERT_CHECKED(String, str, args[0]);
5659 if (!str->IsFlat()) {
5660 MaybeObject* try_flatten = str->TryFlatten();
5661 Object* flat;
5662 if (!try_flatten->ToObject(&flat)) {
5663 return try_flatten;
5664 }
5665 str = String::cast(flat);
5666 ASSERT(str->IsFlat());
5667 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005668 String::FlatContent flat = str->GetFlatContent();
5669 ASSERT(flat.IsFlat());
5670 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005671 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005672 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005673 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005674 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005675 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005676 }
5677}
5678
5679
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005680RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005681 NoHandleAllocation ha;
5682 CONVERT_CHECKED(String, str, args[0]);
5683 if (!str->IsFlat()) {
5684 MaybeObject* try_flatten = str->TryFlatten();
5685 Object* flat;
5686 if (!try_flatten->ToObject(&flat)) {
5687 return try_flatten;
5688 }
5689 str = String::cast(flat);
5690 ASSERT(str->IsFlat());
5691 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005692 String::FlatContent flat = str->GetFlatContent();
5693 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005694 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005695 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005696 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005697 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005698 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005699 }
5700}
5701
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005702
5703template <typename Char, typename StringType>
5704static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5705 FixedArray* array,
5706 int worst_case_length) {
5707 int length = array->length();
5708
5709 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5710 worst_case_length);
5711 Object* new_object;
5712 if (!new_alloc->ToObject(&new_object)) {
5713 return new_alloc;
5714 }
5715 if (!isolate->heap()->new_space()->Contains(new_object)) {
5716 // Even if our string is small enough to fit in new space we still have to
5717 // handle it being allocated in old space as may happen in the third
5718 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5719 // CEntryStub::GenerateCore.
5720 return isolate->heap()->undefined_value();
5721 }
5722 AssertNoAllocation no_gc;
5723 StringType* new_string = StringType::cast(new_object);
5724 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5725
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005726 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005727 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005728 *(write_cursor++) = '[';
5729 for (int i = 0; i < length; i++) {
5730 if (i != 0) *(write_cursor++) = ',';
5731 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005732 String::FlatContent content = str->GetFlatContent();
5733 ASSERT(content.IsFlat());
5734 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005735 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5736 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005737 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005738 } else {
5739 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5740 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005741 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005742 }
5743 }
5744 *(write_cursor++) = ']';
5745
5746 int final_length = static_cast<int>(
5747 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005748 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005749 isolate->heap()->new_space()->
5750 template ShrinkStringAtAllocationBoundary<StringType>(
5751 new_string, final_length);
5752 return new_string;
5753}
5754
5755
5756RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5757 NoHandleAllocation ha;
5758 ASSERT(args.length() == 1);
5759 CONVERT_CHECKED(JSArray, array, args[0]);
5760
5761 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5762 FixedArray* elements = FixedArray::cast(array->elements());
5763 int n = elements->length();
5764 bool ascii = true;
5765 int total_length = 0;
5766
5767 for (int i = 0; i < n; i++) {
5768 Object* elt = elements->get(i);
5769 if (!elt->IsString()) return isolate->heap()->undefined_value();
5770 String* element = String::cast(elt);
5771 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5772 total_length += element->length();
5773 if (ascii && element->IsTwoByteRepresentation()) {
5774 ascii = false;
5775 }
5776 }
5777
5778 int worst_case_length =
5779 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5780 + total_length * kJsonQuoteWorstCaseBlowup;
5781
5782 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5783 return isolate->heap()->undefined_value();
5784 }
5785
5786 if (ascii) {
5787 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5788 elements,
5789 worst_case_length);
5790 } else {
5791 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5792 elements,
5793 worst_case_length);
5794 }
5795}
5796
5797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005798RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005799 NoHandleAllocation ha;
5800
5801 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005802 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005803
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005804 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005805
lrn@chromium.org25156de2010-04-06 13:10:27 +00005806 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005807 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005808 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005809}
5810
5811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005812RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005813 NoHandleAllocation ha;
5814 CONVERT_CHECKED(String, str, args[0]);
5815
5816 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005817 double value = StringToDouble(isolate->unicode_cache(),
5818 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005819
5820 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005821 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005822}
5823
5824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005825template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005826MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005827 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005828 String* s,
5829 int length,
5830 int input_string_length,
5831 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005832 // We try this twice, once with the assumption that the result is no longer
5833 // than the input and, if that assumption breaks, again with the exact
5834 // length. This may not be pretty, but it is nicer than what was here before
5835 // and I hereby claim my vaffel-is.
5836 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005837 // Allocate the resulting string.
5838 //
5839 // NOTE: This assumes that the upper/lower case of an ascii
5840 // character is also ascii. This is currently the case, but it
5841 // might break in the future if we implement more context and locale
5842 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005843 Object* o;
5844 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005845 ? isolate->heap()->AllocateRawAsciiString(length)
5846 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005847 if (!maybe_o->ToObject(&o)) return maybe_o;
5848 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005849 String* result = String::cast(o);
5850 bool has_changed_character = false;
5851
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005852 // Convert all characters to upper case, assuming that they will fit
5853 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005854 Access<StringInputBuffer> buffer(
5855 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005856 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005857 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005858 // We can assume that the string is not empty
5859 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005860 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005861 bool has_next = buffer->has_more();
5862 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005863 int char_length = mapping->get(current, next, chars);
5864 if (char_length == 0) {
5865 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005866 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005867 i++;
5868 } else if (char_length == 1) {
5869 // Common case: converting the letter resulted in one character.
5870 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005871 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005872 has_changed_character = true;
5873 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005874 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005875 // We've assumed that the result would be as long as the
5876 // input but here is a character that converts to several
5877 // characters. No matter, we calculate the exact length
5878 // of the result and try the whole thing again.
5879 //
5880 // Note that this leaves room for optimization. We could just
5881 // memcpy what we already have to the result string. Also,
5882 // the result string is the last object allocated we could
5883 // "realloc" it and probably, in the vast majority of cases,
5884 // extend the existing string to be able to hold the full
5885 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005886 int next_length = 0;
5887 if (has_next) {
5888 next_length = mapping->get(next, 0, chars);
5889 if (next_length == 0) next_length = 1;
5890 }
5891 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005892 while (buffer->has_more()) {
5893 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005894 // NOTE: we use 0 as the next character here because, while
5895 // the next character may affect what a character converts to,
5896 // it does not in any case affect the length of what it convert
5897 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005898 int char_length = mapping->get(current, 0, chars);
5899 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005900 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005901 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005902 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005903 return Failure::OutOfMemoryException();
5904 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005905 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005906 // Try again with the real length.
5907 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005908 } else {
5909 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005910 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005911 i++;
5912 }
5913 has_changed_character = true;
5914 }
5915 current = next;
5916 }
5917 if (has_changed_character) {
5918 return result;
5919 } else {
5920 // If we didn't actually change anything in doing the conversion
5921 // we simple return the result and let the converted string
5922 // become garbage; there is no reason to keep two identical strings
5923 // alive.
5924 return s;
5925 }
5926}
5927
5928
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005929namespace {
5930
lrn@chromium.org303ada72010-10-27 09:33:13 +00005931static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5932
5933
5934// Given a word and two range boundaries returns a word with high bit
5935// set in every byte iff the corresponding input byte was strictly in
5936// the range (m, n). All the other bits in the result are cleared.
5937// This function is only useful when it can be inlined and the
5938// boundaries are statically known.
5939// Requires: all bytes in the input word and the boundaries must be
5940// ascii (less than 0x7F).
5941static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5942 // Every byte in an ascii string is less than or equal to 0x7F.
5943 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5944 // Use strict inequalities since in edge cases the function could be
5945 // further simplified.
5946 ASSERT(0 < m && m < n && n < 0x7F);
5947 // Has high bit set in every w byte less than n.
5948 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5949 // Has high bit set in every w byte greater than m.
5950 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5951 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5952}
5953
5954
5955enum AsciiCaseConversion {
5956 ASCII_TO_LOWER,
5957 ASCII_TO_UPPER
5958};
5959
5960
5961template <AsciiCaseConversion dir>
5962struct FastAsciiConverter {
5963 static bool Convert(char* dst, char* src, int length) {
5964#ifdef DEBUG
5965 char* saved_dst = dst;
5966 char* saved_src = src;
5967#endif
5968 // We rely on the distance between upper and lower case letters
5969 // being a known power of 2.
5970 ASSERT('a' - 'A' == (1 << 5));
5971 // Boundaries for the range of input characters than require conversion.
5972 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5973 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5974 bool changed = false;
5975 char* const limit = src + length;
5976#ifdef V8_HOST_CAN_READ_UNALIGNED
5977 // Process the prefix of the input that requires no conversion one
5978 // (machine) word at a time.
5979 while (src <= limit - sizeof(uintptr_t)) {
5980 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5981 if (AsciiRangeMask(w, lo, hi) != 0) {
5982 changed = true;
5983 break;
5984 }
5985 *reinterpret_cast<uintptr_t*>(dst) = w;
5986 src += sizeof(uintptr_t);
5987 dst += sizeof(uintptr_t);
5988 }
5989 // Process the remainder of the input performing conversion when
5990 // required one word at a time.
5991 while (src <= limit - sizeof(uintptr_t)) {
5992 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5993 uintptr_t m = AsciiRangeMask(w, lo, hi);
5994 // The mask has high (7th) bit set in every byte that needs
5995 // conversion and we know that the distance between cases is
5996 // 1 << 5.
5997 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5998 src += sizeof(uintptr_t);
5999 dst += sizeof(uintptr_t);
6000 }
6001#endif
6002 // Process the last few bytes of the input (or the whole input if
6003 // unaligned access is not supported).
6004 while (src < limit) {
6005 char c = *src;
6006 if (lo < c && c < hi) {
6007 c ^= (1 << 5);
6008 changed = true;
6009 }
6010 *dst = c;
6011 ++src;
6012 ++dst;
6013 }
6014#ifdef DEBUG
6015 CheckConvert(saved_dst, saved_src, length, changed);
6016#endif
6017 return changed;
6018 }
6019
6020#ifdef DEBUG
6021 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6022 bool expected_changed = false;
6023 for (int i = 0; i < length; i++) {
6024 if (dst[i] == src[i]) continue;
6025 expected_changed = true;
6026 if (dir == ASCII_TO_LOWER) {
6027 ASSERT('A' <= src[i] && src[i] <= 'Z');
6028 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6029 } else {
6030 ASSERT(dir == ASCII_TO_UPPER);
6031 ASSERT('a' <= src[i] && src[i] <= 'z');
6032 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6033 }
6034 }
6035 ASSERT(expected_changed == changed);
6036 }
6037#endif
6038};
6039
6040
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006041struct ToLowerTraits {
6042 typedef unibrow::ToLowercase UnibrowConverter;
6043
lrn@chromium.org303ada72010-10-27 09:33:13 +00006044 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006045};
6046
6047
6048struct ToUpperTraits {
6049 typedef unibrow::ToUppercase UnibrowConverter;
6050
lrn@chromium.org303ada72010-10-27 09:33:13 +00006051 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006052};
6053
6054} // namespace
6055
6056
6057template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006058MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006059 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006060 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006061 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006062 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006063 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006064 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006065
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006066 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006067 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006068 if (length == 0) return s;
6069
6070 // Simpler handling of ascii strings.
6071 //
6072 // NOTE: This assumes that the upper/lower case of an ascii
6073 // character is also ascii. This is currently the case, but it
6074 // might break in the future if we implement more context and locale
6075 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006076 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006077 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006078 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006079 if (!maybe_o->ToObject(&o)) return maybe_o;
6080 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006081 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006082 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006083 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006084 return has_changed_character ? result : s;
6085 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006086
lrn@chromium.org303ada72010-10-27 09:33:13 +00006087 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006088 { MaybeObject* maybe_answer =
6089 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006090 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6091 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006092 if (answer->IsSmi()) {
6093 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006094 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006095 ConvertCaseHelper(isolate,
6096 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006097 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6098 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006099 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006100 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006101}
6102
6103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006104RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006105 return ConvertCase<ToLowerTraits>(
6106 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006107}
6108
6109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006110RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006111 return ConvertCase<ToUpperTraits>(
6112 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006113}
6114
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006115
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006116static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
6117 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
6118}
6119
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006121RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006122 NoHandleAllocation ha;
6123 ASSERT(args.length() == 3);
6124
6125 CONVERT_CHECKED(String, s, args[0]);
6126 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6127 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6128
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006129 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006130 int length = s->length();
6131
6132 int left = 0;
6133 if (trimLeft) {
6134 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6135 left++;
6136 }
6137 }
6138
6139 int right = length;
6140 if (trimRight) {
6141 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6142 right--;
6143 }
6144 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006145 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006146}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006147
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006149RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006150 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006151 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006152 CONVERT_ARG_CHECKED(String, subject, 0);
6153 CONVERT_ARG_CHECKED(String, pattern, 1);
6154 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6155
6156 int subject_length = subject->length();
6157 int pattern_length = pattern->length();
6158 RUNTIME_ASSERT(pattern_length > 0);
6159
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006160 if (limit == 0xffffffffu) {
6161 Handle<Object> cached_answer(StringSplitCache::Lookup(
6162 isolate->heap()->string_split_cache(),
6163 *subject,
6164 *pattern));
6165 if (*cached_answer != Smi::FromInt(0)) {
6166 Handle<JSArray> result =
6167 isolate->factory()->NewJSArrayWithElements(
6168 Handle<FixedArray>::cast(cached_answer));
6169 return *result;
6170 }
6171 }
6172
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006173 // The limit can be very large (0xffffffffu), but since the pattern
6174 // isn't empty, we can never create more parts than ~half the length
6175 // of the subject.
6176
6177 if (!subject->IsFlat()) FlattenString(subject);
6178
6179 static const int kMaxInitialListCapacity = 16;
6180
danno@chromium.org40cb8782011-05-25 07:58:50 +00006181 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006182
6183 // Find (up to limit) indices of separator and end-of-string in subject
6184 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6185 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006186 if (!pattern->IsFlat()) FlattenString(pattern);
6187
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006188 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006189
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006190 if (static_cast<uint32_t>(indices.length()) < limit) {
6191 indices.Add(subject_length);
6192 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006193
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006194 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006195
6196 // Create JSArray of substrings separated by separator.
6197 int part_count = indices.length();
6198
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006199 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006200 MaybeObject* maybe_result = result->EnsureCanContainNonSmiElements();
6201 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006202 result->set_length(Smi::FromInt(part_count));
6203
6204 ASSERT(result->HasFastElements());
6205
6206 if (part_count == 1 && indices.at(0) == subject_length) {
6207 FixedArray::cast(result->elements())->set(0, *subject);
6208 return *result;
6209 }
6210
6211 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6212 int part_start = 0;
6213 for (int i = 0; i < part_count; i++) {
6214 HandleScope local_loop_handle;
6215 int part_end = indices.at(i);
6216 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006217 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006218 elements->set(i, *substring);
6219 part_start = part_end + pattern_length;
6220 }
6221
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006222 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006223 if (result->HasFastElements()) {
6224 StringSplitCache::Enter(isolate->heap(),
6225 isolate->heap()->string_split_cache(),
6226 *subject,
6227 *pattern,
6228 *elements);
6229 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006230 }
6231
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006232 return *result;
6233}
6234
6235
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006236// Copies ascii characters to the given fixed array looking up
6237// one-char strings in the cache. Gives up on the first char that is
6238// not in the cache and fills the remainder with smi zeros. Returns
6239// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006240static int CopyCachedAsciiCharsToArray(Heap* heap,
6241 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006242 FixedArray* elements,
6243 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006244 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006245 FixedArray* ascii_cache = heap->single_character_string_cache();
6246 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006247 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006248 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006249 for (i = 0; i < length; ++i) {
6250 Object* value = ascii_cache->get(chars[i]);
6251 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006252 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006253 }
6254 if (i < length) {
6255 ASSERT(Smi::FromInt(0) == 0);
6256 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6257 }
6258#ifdef DEBUG
6259 for (int j = 0; j < length; ++j) {
6260 Object* element = elements->get(j);
6261 ASSERT(element == Smi::FromInt(0) ||
6262 (element->IsString() && String::cast(element)->LooksValid()));
6263 }
6264#endif
6265 return i;
6266}
6267
6268
6269// Converts a String to JSArray.
6270// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006271RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006272 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006273 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006274 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006275 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006276
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006277 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006278 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006279
6280 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006281 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006282 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006283 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006284 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006285 { MaybeObject* maybe_obj =
6286 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006287 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6288 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006289 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006290 String::FlatContent content = s->GetFlatContent();
6291 if (content.IsAscii()) {
6292 Vector<const char> chars = content.ToAsciiVector();
6293 // Note, this will initialize all elements (not only the prefix)
6294 // to prevent GC from seeing partially initialized array.
6295 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6296 chars.start(),
6297 *elements,
6298 length);
6299 } else {
6300 MemsetPointer(elements->data_start(),
6301 isolate->heap()->undefined_value(),
6302 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006303 }
6304 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006305 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006306 }
6307 for (int i = position; i < length; ++i) {
6308 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6309 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006310 }
6311
6312#ifdef DEBUG
6313 for (int i = 0; i < length; ++i) {
6314 ASSERT(String::cast(elements->get(i))->length() == 1);
6315 }
6316#endif
6317
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006318 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006319}
6320
6321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006322RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006323 NoHandleAllocation ha;
6324 ASSERT(args.length() == 1);
6325 CONVERT_CHECKED(String, value, args[0]);
6326 return value->ToObject();
6327}
6328
6329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006330bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006331 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006332 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006333 return char_length == 0;
6334}
6335
6336
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006337RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006338 NoHandleAllocation ha;
6339 ASSERT(args.length() == 1);
6340
6341 Object* number = args[0];
6342 RUNTIME_ASSERT(number->IsNumber());
6343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006344 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006345}
6346
6347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006348RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006349 NoHandleAllocation ha;
6350 ASSERT(args.length() == 1);
6351
6352 Object* number = args[0];
6353 RUNTIME_ASSERT(number->IsNumber());
6354
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006355 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006356}
6357
6358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006359RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006360 NoHandleAllocation ha;
6361 ASSERT(args.length() == 1);
6362
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006363 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006364
6365 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6366 if (number > 0 && number <= Smi::kMaxValue) {
6367 return Smi::FromInt(static_cast<int>(number));
6368 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006369 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006370}
6371
6372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006373RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006374 NoHandleAllocation ha;
6375 ASSERT(args.length() == 1);
6376
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006377 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006378
6379 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6380 if (number > 0 && number <= Smi::kMaxValue) {
6381 return Smi::FromInt(static_cast<int>(number));
6382 }
6383
6384 double double_value = DoubleToInteger(number);
6385 // Map both -0 and +0 to +0.
6386 if (double_value == 0) double_value = 0;
6387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006388 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006389}
6390
6391
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006392RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006393 NoHandleAllocation ha;
6394 ASSERT(args.length() == 1);
6395
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006396 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006397 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006398}
6399
6400
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006401RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006402 NoHandleAllocation ha;
6403 ASSERT(args.length() == 1);
6404
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006405 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006406
6407 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6408 if (number > 0 && number <= Smi::kMaxValue) {
6409 return Smi::FromInt(static_cast<int>(number));
6410 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006411 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006412}
6413
6414
ager@chromium.org870a0b62008-11-04 11:43:05 +00006415// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6416// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006417RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006418 NoHandleAllocation ha;
6419 ASSERT(args.length() == 1);
6420
6421 Object* obj = args[0];
6422 if (obj->IsSmi()) {
6423 return obj;
6424 }
6425 if (obj->IsHeapNumber()) {
6426 double value = HeapNumber::cast(obj)->value();
6427 int int_value = FastD2I(value);
6428 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6429 return Smi::FromInt(int_value);
6430 }
6431 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006432 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006433}
6434
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006436RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006437 NoHandleAllocation ha;
6438 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006439 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006440}
6441
6442
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006443RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006444 NoHandleAllocation ha;
6445 ASSERT(args.length() == 2);
6446
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006447 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6448 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006449 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006450}
6451
6452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006453RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006454 NoHandleAllocation ha;
6455 ASSERT(args.length() == 2);
6456
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006457 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6458 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006459 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006460}
6461
6462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006463RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006464 NoHandleAllocation ha;
6465 ASSERT(args.length() == 2);
6466
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006467 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6468 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006469 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006470}
6471
6472
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006473RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006474 NoHandleAllocation ha;
6475 ASSERT(args.length() == 1);
6476
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006477 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006478 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006479}
6480
6481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006482RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006483 NoHandleAllocation ha;
6484 ASSERT(args.length() == 0);
6485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006486 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006487}
6488
6489
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006490RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006491 NoHandleAllocation ha;
6492 ASSERT(args.length() == 2);
6493
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006494 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6495 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006496 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006497}
6498
6499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006500RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006501 NoHandleAllocation ha;
6502 ASSERT(args.length() == 2);
6503
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006504 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6505 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006506
ager@chromium.org3811b432009-10-28 14:53:37 +00006507 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006508 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006509 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006510}
6511
6512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006513RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006514 NoHandleAllocation ha;
6515 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006516 CONVERT_CHECKED(String, str1, args[0]);
6517 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006518 isolate->counters()->string_add_runtime()->Increment();
6519 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006520}
6521
6522
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006523template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006524static inline void StringBuilderConcatHelper(String* special,
6525 sinkchar* sink,
6526 FixedArray* fixed_array,
6527 int array_length) {
6528 int position = 0;
6529 for (int i = 0; i < array_length; i++) {
6530 Object* element = fixed_array->get(i);
6531 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006532 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006533 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006534 int pos;
6535 int len;
6536 if (encoded_slice > 0) {
6537 // Position and length encoded in one smi.
6538 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6539 len = StringBuilderSubstringLength::decode(encoded_slice);
6540 } else {
6541 // Position and length encoded in two smis.
6542 Object* obj = fixed_array->get(++i);
6543 ASSERT(obj->IsSmi());
6544 pos = Smi::cast(obj)->value();
6545 len = -encoded_slice;
6546 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006547 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006548 sink + position,
6549 pos,
6550 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006551 position += len;
6552 } else {
6553 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006554 int element_length = string->length();
6555 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006556 position += element_length;
6557 }
6558 }
6559}
6560
6561
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006562RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006563 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006564 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006565 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006566 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006567 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006568 return Failure::OutOfMemoryException();
6569 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006570 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006571 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006572
6573 // This assumption is used by the slice encoding in one or two smis.
6574 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6575
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006576 MaybeObject* maybe_result = array->EnsureCanContainNonSmiElements();
6577 if (maybe_result->IsFailure()) return maybe_result;
6578
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006579 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006580 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006581 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582 }
6583 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006584 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006585 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006586 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587
6588 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006589 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006590 } else if (array_length == 1) {
6591 Object* first = fixed_array->get(0);
6592 if (first->IsString()) return first;
6593 }
6594
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006595 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006596 int position = 0;
6597 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006598 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006599 Object* elt = fixed_array->get(i);
6600 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006601 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006602 int smi_value = Smi::cast(elt)->value();
6603 int pos;
6604 int len;
6605 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006606 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006607 pos = StringBuilderSubstringPosition::decode(smi_value);
6608 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006609 } else {
6610 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006611 len = -smi_value;
6612 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006613 i++;
6614 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006615 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006616 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006617 Object* next_smi = fixed_array->get(i);
6618 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006619 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006620 }
6621 pos = Smi::cast(next_smi)->value();
6622 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006623 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006624 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006626 ASSERT(pos >= 0);
6627 ASSERT(len >= 0);
6628 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006629 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006630 }
6631 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006632 } else if (elt->IsString()) {
6633 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006634 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006635 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006636 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006637 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006638 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006639 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006640 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006641 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006642 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006643 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006644 return Failure::OutOfMemoryException();
6645 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006646 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006647 }
6648
6649 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006650 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006651
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006653 { MaybeObject* maybe_object =
6654 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006655 if (!maybe_object->ToObject(&object)) return maybe_object;
6656 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006657 SeqAsciiString* answer = SeqAsciiString::cast(object);
6658 StringBuilderConcatHelper(special,
6659 answer->GetChars(),
6660 fixed_array,
6661 array_length);
6662 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006663 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006664 { MaybeObject* maybe_object =
6665 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006666 if (!maybe_object->ToObject(&object)) return maybe_object;
6667 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006668 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6669 StringBuilderConcatHelper(special,
6670 answer->GetChars(),
6671 fixed_array,
6672 array_length);
6673 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006674 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006675}
6676
6677
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006678RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006679 NoHandleAllocation ha;
6680 ASSERT(args.length() == 3);
6681 CONVERT_CHECKED(JSArray, array, args[0]);
6682 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006683 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006684 return Failure::OutOfMemoryException();
6685 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006686 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006687 CONVERT_CHECKED(String, separator, args[2]);
6688
6689 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006690 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006691 }
6692 FixedArray* fixed_array = FixedArray::cast(array->elements());
6693 if (fixed_array->length() < array_length) {
6694 array_length = fixed_array->length();
6695 }
6696
6697 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006698 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006699 } else if (array_length == 1) {
6700 Object* first = fixed_array->get(0);
6701 if (first->IsString()) return first;
6702 }
6703
6704 int separator_length = separator->length();
6705 int max_nof_separators =
6706 (String::kMaxLength + separator_length - 1) / separator_length;
6707 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006708 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006709 return Failure::OutOfMemoryException();
6710 }
6711 int length = (array_length - 1) * separator_length;
6712 for (int i = 0; i < array_length; i++) {
6713 Object* element_obj = fixed_array->get(i);
6714 if (!element_obj->IsString()) {
6715 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006716 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006717 }
6718 String* element = String::cast(element_obj);
6719 int increment = element->length();
6720 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006721 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006722 return Failure::OutOfMemoryException();
6723 }
6724 length += increment;
6725 }
6726
6727 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006728 { MaybeObject* maybe_object =
6729 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006730 if (!maybe_object->ToObject(&object)) return maybe_object;
6731 }
6732 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6733
6734 uc16* sink = answer->GetChars();
6735#ifdef DEBUG
6736 uc16* end = sink + length;
6737#endif
6738
6739 String* first = String::cast(fixed_array->get(0));
6740 int first_length = first->length();
6741 String::WriteToFlat(first, sink, 0, first_length);
6742 sink += first_length;
6743
6744 for (int i = 1; i < array_length; i++) {
6745 ASSERT(sink + separator_length <= end);
6746 String::WriteToFlat(separator, sink, 0, separator_length);
6747 sink += separator_length;
6748
6749 String* element = String::cast(fixed_array->get(i));
6750 int element_length = element->length();
6751 ASSERT(sink + element_length <= end);
6752 String::WriteToFlat(element, sink, 0, element_length);
6753 sink += element_length;
6754 }
6755 ASSERT(sink == end);
6756
6757 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6758 return answer;
6759}
6760
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006761template <typename Char>
6762static void JoinSparseArrayWithSeparator(FixedArray* elements,
6763 int elements_length,
6764 uint32_t array_length,
6765 String* separator,
6766 Vector<Char> buffer) {
6767 int previous_separator_position = 0;
6768 int separator_length = separator->length();
6769 int cursor = 0;
6770 for (int i = 0; i < elements_length; i += 2) {
6771 int position = NumberToInt32(elements->get(i));
6772 String* string = String::cast(elements->get(i + 1));
6773 int string_length = string->length();
6774 if (string->length() > 0) {
6775 while (previous_separator_position < position) {
6776 String::WriteToFlat<Char>(separator, &buffer[cursor],
6777 0, separator_length);
6778 cursor += separator_length;
6779 previous_separator_position++;
6780 }
6781 String::WriteToFlat<Char>(string, &buffer[cursor],
6782 0, string_length);
6783 cursor += string->length();
6784 }
6785 }
6786 if (separator_length > 0) {
6787 // Array length must be representable as a signed 32-bit number,
6788 // otherwise the total string length would have been too large.
6789 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6790 int last_array_index = static_cast<int>(array_length - 1);
6791 while (previous_separator_position < last_array_index) {
6792 String::WriteToFlat<Char>(separator, &buffer[cursor],
6793 0, separator_length);
6794 cursor += separator_length;
6795 previous_separator_position++;
6796 }
6797 }
6798 ASSERT(cursor <= buffer.length());
6799}
6800
6801
6802RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6803 NoHandleAllocation ha;
6804 ASSERT(args.length() == 3);
6805 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006806 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6807 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006808 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6809 CONVERT_CHECKED(String, separator, args[2]);
6810 // elements_array is fast-mode JSarray of alternating positions
6811 // (increasing order) and strings.
6812 // array_length is length of original array (used to add separators);
6813 // separator is string to put between elements. Assumed to be non-empty.
6814
6815 // Find total length of join result.
6816 int string_length = 0;
6817 bool is_ascii = true;
6818 int max_string_length = SeqAsciiString::kMaxLength;
6819 bool overflow = false;
6820 CONVERT_NUMBER_CHECKED(int, elements_length,
6821 Int32, elements_array->length());
6822 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6823 FixedArray* elements = FixedArray::cast(elements_array->elements());
6824 for (int i = 0; i < elements_length; i += 2) {
6825 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6826 CONVERT_CHECKED(String, string, elements->get(i + 1));
6827 int length = string->length();
6828 if (is_ascii && !string->IsAsciiRepresentation()) {
6829 is_ascii = false;
6830 max_string_length = SeqTwoByteString::kMaxLength;
6831 }
6832 if (length > max_string_length ||
6833 max_string_length - length < string_length) {
6834 overflow = true;
6835 break;
6836 }
6837 string_length += length;
6838 }
6839 int separator_length = separator->length();
6840 if (!overflow && separator_length > 0) {
6841 if (array_length <= 0x7fffffffu) {
6842 int separator_count = static_cast<int>(array_length) - 1;
6843 int remaining_length = max_string_length - string_length;
6844 if ((remaining_length / separator_length) >= separator_count) {
6845 string_length += separator_length * (array_length - 1);
6846 } else {
6847 // Not room for the separators within the maximal string length.
6848 overflow = true;
6849 }
6850 } else {
6851 // Nonempty separator and at least 2^31-1 separators necessary
6852 // means that the string is too large to create.
6853 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6854 overflow = true;
6855 }
6856 }
6857 if (overflow) {
6858 // Throw OutOfMemory exception for creating too large a string.
6859 V8::FatalProcessOutOfMemory("Array join result too large.");
6860 }
6861
6862 if (is_ascii) {
6863 MaybeObject* result_allocation =
6864 isolate->heap()->AllocateRawAsciiString(string_length);
6865 if (result_allocation->IsFailure()) return result_allocation;
6866 SeqAsciiString* result_string =
6867 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6868 JoinSparseArrayWithSeparator<char>(elements,
6869 elements_length,
6870 array_length,
6871 separator,
6872 Vector<char>(result_string->GetChars(),
6873 string_length));
6874 return result_string;
6875 } else {
6876 MaybeObject* result_allocation =
6877 isolate->heap()->AllocateRawTwoByteString(string_length);
6878 if (result_allocation->IsFailure()) return result_allocation;
6879 SeqTwoByteString* result_string =
6880 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6881 JoinSparseArrayWithSeparator<uc16>(elements,
6882 elements_length,
6883 array_length,
6884 separator,
6885 Vector<uc16>(result_string->GetChars(),
6886 string_length));
6887 return result_string;
6888 }
6889}
6890
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006891
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006892RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006893 NoHandleAllocation ha;
6894 ASSERT(args.length() == 2);
6895
6896 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6897 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006898 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006899}
6900
6901
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006902RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006903 NoHandleAllocation ha;
6904 ASSERT(args.length() == 2);
6905
6906 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6907 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006908 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006909}
6910
6911
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006912RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006913 NoHandleAllocation ha;
6914 ASSERT(args.length() == 2);
6915
6916 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6917 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006918 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006919}
6920
6921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006922RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006923 NoHandleAllocation ha;
6924 ASSERT(args.length() == 1);
6925
6926 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006927 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006928}
6929
6930
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006931RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006932 NoHandleAllocation ha;
6933 ASSERT(args.length() == 2);
6934
6935 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6936 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006937 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006938}
6939
6940
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006941RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006942 NoHandleAllocation ha;
6943 ASSERT(args.length() == 2);
6944
6945 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6946 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006947 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006948}
6949
6950
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006951RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006952 NoHandleAllocation ha;
6953 ASSERT(args.length() == 2);
6954
6955 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6956 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006957 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006958}
6959
6960
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006961RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006962 NoHandleAllocation ha;
6963 ASSERT(args.length() == 2);
6964
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006965 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6966 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006967 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6968 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6969 if (x == y) return Smi::FromInt(EQUAL);
6970 Object* result;
6971 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6972 result = Smi::FromInt(EQUAL);
6973 } else {
6974 result = Smi::FromInt(NOT_EQUAL);
6975 }
6976 return result;
6977}
6978
6979
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006980RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981 NoHandleAllocation ha;
6982 ASSERT(args.length() == 2);
6983
6984 CONVERT_CHECKED(String, x, args[0]);
6985 CONVERT_CHECKED(String, y, args[1]);
6986
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006987 bool not_equal = !x->Equals(y);
6988 // This is slightly convoluted because the value that signifies
6989 // equality is 0 and inequality is 1 so we have to negate the result
6990 // from String::Equals.
6991 ASSERT(not_equal == 0 || not_equal == 1);
6992 STATIC_CHECK(EQUAL == 0);
6993 STATIC_CHECK(NOT_EQUAL == 1);
6994 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006995}
6996
6997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006998RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006999 NoHandleAllocation ha;
7000 ASSERT(args.length() == 3);
7001
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007002 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7003 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007004 if (isnan(x) || isnan(y)) return args[2];
7005 if (x == y) return Smi::FromInt(EQUAL);
7006 if (isless(x, y)) return Smi::FromInt(LESS);
7007 return Smi::FromInt(GREATER);
7008}
7009
7010
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007011// Compare two Smis as if they were converted to strings and then
7012// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007013RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007014 NoHandleAllocation ha;
7015 ASSERT(args.length() == 2);
7016
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007017 // Extract the integer values from the Smis.
7018 CONVERT_CHECKED(Smi, x, args[0]);
7019 CONVERT_CHECKED(Smi, y, args[1]);
7020 int x_value = x->value();
7021 int y_value = y->value();
7022
7023 // If the integers are equal so are the string representations.
7024 if (x_value == y_value) return Smi::FromInt(EQUAL);
7025
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007026 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007027 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007028 if (x_value == 0 || y_value == 0)
7029 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007030
ager@chromium.org32912102009-01-16 10:38:43 +00007031 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007032 // smallest because the char code of '-' is less than the char code
7033 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007034
7035 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7036 // architectures using 32-bit Smis.
7037 uint32_t x_scaled = x_value;
7038 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007039 if (x_value < 0 || y_value < 0) {
7040 if (y_value >= 0) return Smi::FromInt(LESS);
7041 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007042 x_scaled = -x_value;
7043 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007044 }
7045
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007046 static const uint32_t kPowersOf10[] = {
7047 1, 10, 100, 1000, 10*1000, 100*1000,
7048 1000*1000, 10*1000*1000, 100*1000*1000,
7049 1000*1000*1000
7050 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007051
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007052 // If the integers have the same number of decimal digits they can be
7053 // compared directly as the numeric order is the same as the
7054 // lexicographic order. If one integer has fewer digits, it is scaled
7055 // by some power of 10 to have the same number of digits as the longer
7056 // integer. If the scaled integers are equal it means the shorter
7057 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007058
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007059 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7060 int x_log2 = IntegerLog2(x_scaled);
7061 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7062 x_log10 -= x_scaled < kPowersOf10[x_log10];
7063
7064 int y_log2 = IntegerLog2(y_scaled);
7065 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7066 y_log10 -= y_scaled < kPowersOf10[y_log10];
7067
7068 int tie = EQUAL;
7069
7070 if (x_log10 < y_log10) {
7071 // X has fewer digits. We would like to simply scale up X but that
7072 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7073 // be scaled up to 9_000_000_000. So we scale up by the next
7074 // smallest power and scale down Y to drop one digit. It is OK to
7075 // drop one digit from the longer integer since the final digit is
7076 // past the length of the shorter integer.
7077 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7078 y_scaled /= 10;
7079 tie = LESS;
7080 } else if (y_log10 < x_log10) {
7081 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7082 x_scaled /= 10;
7083 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007084 }
7085
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007086 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7087 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7088 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007089}
7090
7091
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007092static Object* StringInputBufferCompare(RuntimeState* state,
7093 String* x,
7094 String* y) {
7095 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7096 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007097 bufx.Reset(x);
7098 bufy.Reset(y);
7099 while (bufx.has_more() && bufy.has_more()) {
7100 int d = bufx.GetNext() - bufy.GetNext();
7101 if (d < 0) return Smi::FromInt(LESS);
7102 else if (d > 0) return Smi::FromInt(GREATER);
7103 }
7104
7105 // x is (non-trivial) prefix of y:
7106 if (bufy.has_more()) return Smi::FromInt(LESS);
7107 // y is prefix of x:
7108 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7109}
7110
7111
7112static Object* FlatStringCompare(String* x, String* y) {
7113 ASSERT(x->IsFlat());
7114 ASSERT(y->IsFlat());
7115 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7116 int prefix_length = x->length();
7117 if (y->length() < prefix_length) {
7118 prefix_length = y->length();
7119 equal_prefix_result = Smi::FromInt(GREATER);
7120 } else if (y->length() > prefix_length) {
7121 equal_prefix_result = Smi::FromInt(LESS);
7122 }
7123 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007124 String::FlatContent x_content = x->GetFlatContent();
7125 String::FlatContent y_content = y->GetFlatContent();
7126 if (x_content.IsAscii()) {
7127 Vector<const char> x_chars = x_content.ToAsciiVector();
7128 if (y_content.IsAscii()) {
7129 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007130 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007131 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007132 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007133 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7134 }
7135 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007136 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7137 if (y_content.IsAscii()) {
7138 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007139 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7140 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007141 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007142 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7143 }
7144 }
7145 Object* result;
7146 if (r == 0) {
7147 result = equal_prefix_result;
7148 } else {
7149 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7150 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007151 ASSERT(result ==
7152 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007153 return result;
7154}
7155
7156
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007157RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007158 NoHandleAllocation ha;
7159 ASSERT(args.length() == 2);
7160
7161 CONVERT_CHECKED(String, x, args[0]);
7162 CONVERT_CHECKED(String, y, args[1]);
7163
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007164 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007166 // A few fast case tests before we flatten.
7167 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007168 if (y->length() == 0) {
7169 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007170 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007171 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007172 return Smi::FromInt(LESS);
7173 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007174
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007175 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007176 if (d < 0) return Smi::FromInt(LESS);
7177 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007178
lrn@chromium.org303ada72010-10-27 09:33:13 +00007179 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007180 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007181 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7182 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007183 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007184 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7185 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007186
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007187 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007188 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007189}
7190
7191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007192RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007193 NoHandleAllocation ha;
7194 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007195 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007196
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007197 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007198 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007199}
7200
7201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007202RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007203 NoHandleAllocation ha;
7204 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007205 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007206
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007207 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007208 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007209}
7210
7211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007212RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007213 NoHandleAllocation ha;
7214 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007215 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007216
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007217 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007218 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007219}
7220
7221
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007222static const double kPiDividedBy4 = 0.78539816339744830962;
7223
7224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007225RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007226 NoHandleAllocation ha;
7227 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007228 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007229
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007230 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7231 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007232 double result;
7233 if (isinf(x) && isinf(y)) {
7234 // Make sure that the result in case of two infinite arguments
7235 // is a multiple of Pi / 4. The sign of the result is determined
7236 // by the first argument (x) and the sign of the second argument
7237 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007238 int multiplier = (x < 0) ? -1 : 1;
7239 if (y < 0) multiplier *= 3;
7240 result = multiplier * kPiDividedBy4;
7241 } else {
7242 result = atan2(x, y);
7243 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007244 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007245}
7246
7247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007248RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007249 NoHandleAllocation ha;
7250 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007251 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007252
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007253 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007254 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007255}
7256
7257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007258RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007259 NoHandleAllocation ha;
7260 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007261 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007262
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007263 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007264 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007265}
7266
7267
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007268RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007269 NoHandleAllocation ha;
7270 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007271 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007272
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007273 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007274 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007275}
7276
7277
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007278RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007279 NoHandleAllocation ha;
7280 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007281 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007282
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007283 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007284 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007285}
7286
7287
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007288RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007289 NoHandleAllocation ha;
7290 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007291 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007292
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007293 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007294 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007295}
7296
7297
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007298RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007299 NoHandleAllocation ha;
7300 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007301 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007302
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007303 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007304
7305 // If the second argument is a smi, it is much faster to call the
7306 // custom powi() function than the generic pow().
7307 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007308 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007309 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007310 }
7311
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007312 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007313 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314}
7315
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007316// Fast version of Math.pow if we know that y is not an integer and
7317// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007318RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007319 NoHandleAllocation ha;
7320 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007321 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7322 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007323 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007324 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007325 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007326 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007327 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007328 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007329 }
7330}
7331
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007332
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007333RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007334 NoHandleAllocation ha;
7335 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007336 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007337
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007338 if (!args[0]->IsHeapNumber()) {
7339 // Must be smi. Return the argument unchanged for all the other types
7340 // to make fuzz-natives test happy.
7341 return args[0];
7342 }
7343
7344 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7345
7346 double value = number->value();
7347 int exponent = number->get_exponent();
7348 int sign = number->get_sign();
7349
danno@chromium.org160a7b02011-04-18 15:51:38 +00007350 if (exponent < -1) {
7351 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7352 if (sign) return isolate->heap()->minus_zero_value();
7353 return Smi::FromInt(0);
7354 }
7355
7356 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7357 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7358 // agument holds for 32-bit smis).
7359 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007360 return Smi::FromInt(static_cast<int>(value + 0.5));
7361 }
7362
7363 // If the magnitude is big enough, there's no place for fraction part. If we
7364 // try to add 0.5 to this number, 1.0 will be added instead.
7365 if (exponent >= 52) {
7366 return number;
7367 }
7368
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007369 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007370
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007371 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007372 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007373}
7374
7375
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007376RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377 NoHandleAllocation ha;
7378 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007379 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007381 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007382 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007383}
7384
7385
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007386RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387 NoHandleAllocation ha;
7388 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007389 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007390
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007391 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007392 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393}
7394
7395
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007396RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397 NoHandleAllocation ha;
7398 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007401 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007402 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403}
7404
7405
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007406static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007407 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7408 181, 212, 243, 273, 304, 334};
7409 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7410 182, 213, 244, 274, 305, 335};
7411
7412 year += month / 12;
7413 month %= 12;
7414 if (month < 0) {
7415 year--;
7416 month += 12;
7417 }
7418
7419 ASSERT(month >= 0);
7420 ASSERT(month < 12);
7421
7422 // year_delta is an arbitrary number such that:
7423 // a) year_delta = -1 (mod 400)
7424 // b) year + year_delta > 0 for years in the range defined by
7425 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7426 // Jan 1 1970. This is required so that we don't run into integer
7427 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007428 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007429 // operations.
7430 static const int year_delta = 399999;
7431 static const int base_day = 365 * (1970 + year_delta) +
7432 (1970 + year_delta) / 4 -
7433 (1970 + year_delta) / 100 +
7434 (1970 + year_delta) / 400;
7435
7436 int year1 = year + year_delta;
7437 int day_from_year = 365 * year1 +
7438 year1 / 4 -
7439 year1 / 100 +
7440 year1 / 400 -
7441 base_day;
7442
7443 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007444 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007445 }
7446
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007447 return day_from_year + day_from_month_leap[month] + day - 1;
7448}
7449
7450
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007451RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007452 NoHandleAllocation ha;
7453 ASSERT(args.length() == 3);
7454
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007455 CONVERT_SMI_ARG_CHECKED(year, 0);
7456 CONVERT_SMI_ARG_CHECKED(month, 1);
7457 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007458
7459 return Smi::FromInt(MakeDay(year, month, date));
7460}
7461
7462
7463static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7464static const int kDaysIn4Years = 4 * 365 + 1;
7465static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7466static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7467static const int kDays1970to2000 = 30 * 365 + 7;
7468static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7469 kDays1970to2000;
7470static const int kYearsOffset = 400000;
7471
7472static const char kDayInYear[] = {
7473 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7474 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7475 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7476 22, 23, 24, 25, 26, 27, 28,
7477 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7478 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7479 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7480 22, 23, 24, 25, 26, 27, 28, 29, 30,
7481 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7482 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7483 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7484 22, 23, 24, 25, 26, 27, 28, 29, 30,
7485 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7486 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7487 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7488 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7489 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7490 22, 23, 24, 25, 26, 27, 28, 29, 30,
7491 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7492 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7493 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7494 22, 23, 24, 25, 26, 27, 28, 29, 30,
7495 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7496 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7497
7498 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7499 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7500 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7501 22, 23, 24, 25, 26, 27, 28,
7502 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7503 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7504 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7505 22, 23, 24, 25, 26, 27, 28, 29, 30,
7506 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7507 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7508 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7509 22, 23, 24, 25, 26, 27, 28, 29, 30,
7510 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7511 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7512 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7513 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7514 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7515 22, 23, 24, 25, 26, 27, 28, 29, 30,
7516 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7517 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7518 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7519 22, 23, 24, 25, 26, 27, 28, 29, 30,
7520 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7521 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7522
7523 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7524 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7525 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7526 22, 23, 24, 25, 26, 27, 28, 29,
7527 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7528 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7529 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7530 22, 23, 24, 25, 26, 27, 28, 29, 30,
7531 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7532 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7533 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7534 22, 23, 24, 25, 26, 27, 28, 29, 30,
7535 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7536 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7537 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7538 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7539 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7540 22, 23, 24, 25, 26, 27, 28, 29, 30,
7541 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7542 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7543 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7544 22, 23, 24, 25, 26, 27, 28, 29, 30,
7545 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7546 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7547
7548 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7549 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7550 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7551 22, 23, 24, 25, 26, 27, 28,
7552 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7553 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7554 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7555 22, 23, 24, 25, 26, 27, 28, 29, 30,
7556 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7557 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7558 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7559 22, 23, 24, 25, 26, 27, 28, 29, 30,
7560 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7561 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7562 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7563 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7564 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7565 22, 23, 24, 25, 26, 27, 28, 29, 30,
7566 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7567 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7568 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7569 22, 23, 24, 25, 26, 27, 28, 29, 30,
7570 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7571 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7572
7573static const char kMonthInYear[] = {
7574 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7575 0, 0, 0, 0, 0, 0,
7576 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7577 1, 1, 1,
7578 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7579 2, 2, 2, 2, 2, 2,
7580 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7581 3, 3, 3, 3, 3,
7582 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7583 4, 4, 4, 4, 4, 4,
7584 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7585 5, 5, 5, 5, 5,
7586 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7587 6, 6, 6, 6, 6, 6,
7588 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7589 7, 7, 7, 7, 7, 7,
7590 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7591 8, 8, 8, 8, 8,
7592 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7593 9, 9, 9, 9, 9, 9,
7594 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7595 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7596 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7597 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7598
7599 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7600 0, 0, 0, 0, 0, 0,
7601 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7602 1, 1, 1,
7603 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7604 2, 2, 2, 2, 2, 2,
7605 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7606 3, 3, 3, 3, 3,
7607 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7608 4, 4, 4, 4, 4, 4,
7609 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7610 5, 5, 5, 5, 5,
7611 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7612 6, 6, 6, 6, 6, 6,
7613 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7614 7, 7, 7, 7, 7, 7,
7615 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7616 8, 8, 8, 8, 8,
7617 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7618 9, 9, 9, 9, 9, 9,
7619 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7620 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7621 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7622 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7623
7624 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7625 0, 0, 0, 0, 0, 0,
7626 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7627 1, 1, 1, 1,
7628 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7629 2, 2, 2, 2, 2, 2,
7630 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7631 3, 3, 3, 3, 3,
7632 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7633 4, 4, 4, 4, 4, 4,
7634 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7635 5, 5, 5, 5, 5,
7636 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7637 6, 6, 6, 6, 6, 6,
7638 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7639 7, 7, 7, 7, 7, 7,
7640 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7641 8, 8, 8, 8, 8,
7642 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7643 9, 9, 9, 9, 9, 9,
7644 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7645 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7646 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7647 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7648
7649 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7650 0, 0, 0, 0, 0, 0,
7651 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7652 1, 1, 1,
7653 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7654 2, 2, 2, 2, 2, 2,
7655 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7656 3, 3, 3, 3, 3,
7657 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7658 4, 4, 4, 4, 4, 4,
7659 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7660 5, 5, 5, 5, 5,
7661 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7662 6, 6, 6, 6, 6, 6,
7663 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7664 7, 7, 7, 7, 7, 7,
7665 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7666 8, 8, 8, 8, 8,
7667 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7668 9, 9, 9, 9, 9, 9,
7669 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7670 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7671 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7672 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7673
7674
7675// This function works for dates from 1970 to 2099.
7676static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007677 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007678#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007679 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007680#endif
7681
7682 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7683 date %= kDaysIn4Years;
7684
7685 month = kMonthInYear[date];
7686 day = kDayInYear[date];
7687
7688 ASSERT(MakeDay(year, month, day) == save_date);
7689}
7690
7691
7692static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007693 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007694#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007695 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007696#endif
7697
7698 date += kDaysOffset;
7699 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7700 date %= kDaysIn400Years;
7701
7702 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7703
7704 date--;
7705 int yd1 = date / kDaysIn100Years;
7706 date %= kDaysIn100Years;
7707 year += 100 * yd1;
7708
7709 date++;
7710 int yd2 = date / kDaysIn4Years;
7711 date %= kDaysIn4Years;
7712 year += 4 * yd2;
7713
7714 date--;
7715 int yd3 = date / 365;
7716 date %= 365;
7717 year += yd3;
7718
7719 bool is_leap = (!yd1 || yd2) && !yd3;
7720
7721 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007722 ASSERT(is_leap || (date >= 0));
7723 ASSERT((date < 365) || (is_leap && (date < 366)));
7724 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7725 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7726 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007727
7728 if (is_leap) {
7729 day = kDayInYear[2*365 + 1 + date];
7730 month = kMonthInYear[2*365 + 1 + date];
7731 } else {
7732 day = kDayInYear[date];
7733 month = kMonthInYear[date];
7734 }
7735
7736 ASSERT(MakeDay(year, month, day) == save_date);
7737}
7738
7739
7740static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007741 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007742 if (date >= 0 && date < 32 * kDaysIn4Years) {
7743 DateYMDFromTimeAfter1970(date, year, month, day);
7744 } else {
7745 DateYMDFromTimeSlow(date, year, month, day);
7746 }
7747}
7748
7749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007750RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007751 NoHandleAllocation ha;
7752 ASSERT(args.length() == 2);
7753
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007754 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007755 CONVERT_CHECKED(JSArray, res_array, args[1]);
7756
7757 int year, month, day;
7758 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007760 RUNTIME_ASSERT(res_array->elements()->map() ==
7761 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007762 FixedArray* elms = FixedArray::cast(res_array->elements());
7763 RUNTIME_ASSERT(elms->length() == 3);
7764
7765 elms->set(0, Smi::FromInt(year));
7766 elms->set(1, Smi::FromInt(month));
7767 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007768
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007769 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007770}
7771
7772
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007773RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007774 HandleScope scope(isolate);
7775 ASSERT(args.length() == 3);
7776
7777 Handle<JSFunction> callee = args.at<JSFunction>(0);
7778 Object** parameters = reinterpret_cast<Object**>(args[1]);
7779 const int argument_count = Smi::cast(args[2])->value();
7780
7781 Handle<JSObject> result =
7782 isolate->factory()->NewArgumentsObject(callee, argument_count);
7783 // Allocate the elements if needed.
7784 int parameter_count = callee->shared()->formal_parameter_count();
7785 if (argument_count > 0) {
7786 if (parameter_count > 0) {
7787 int mapped_count = Min(argument_count, parameter_count);
7788 Handle<FixedArray> parameter_map =
7789 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7790 parameter_map->set_map(
7791 isolate->heap()->non_strict_arguments_elements_map());
7792
7793 Handle<Map> old_map(result->map());
7794 Handle<Map> new_map =
7795 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007796 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007797
7798 result->set_map(*new_map);
7799 result->set_elements(*parameter_map);
7800
7801 // Store the context and the arguments array at the beginning of the
7802 // parameter map.
7803 Handle<Context> context(isolate->context());
7804 Handle<FixedArray> arguments =
7805 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7806 parameter_map->set(0, *context);
7807 parameter_map->set(1, *arguments);
7808
7809 // Loop over the actual parameters backwards.
7810 int index = argument_count - 1;
7811 while (index >= mapped_count) {
7812 // These go directly in the arguments array and have no
7813 // corresponding slot in the parameter map.
7814 arguments->set(index, *(parameters - index - 1));
7815 --index;
7816 }
7817
7818 ScopeInfo<> scope_info(callee->shared()->scope_info());
7819 while (index >= 0) {
7820 // Detect duplicate names to the right in the parameter list.
7821 Handle<String> name = scope_info.parameter_name(index);
7822 int context_slot_count = scope_info.number_of_context_slots();
7823 bool duplicate = false;
7824 for (int j = index + 1; j < parameter_count; ++j) {
7825 if (scope_info.parameter_name(j).is_identical_to(name)) {
7826 duplicate = true;
7827 break;
7828 }
7829 }
7830
7831 if (duplicate) {
7832 // This goes directly in the arguments array with a hole in the
7833 // parameter map.
7834 arguments->set(index, *(parameters - index - 1));
7835 parameter_map->set_the_hole(index + 2);
7836 } else {
7837 // The context index goes in the parameter map with a hole in the
7838 // arguments array.
7839 int context_index = -1;
7840 for (int j = Context::MIN_CONTEXT_SLOTS;
7841 j < context_slot_count;
7842 ++j) {
7843 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7844 context_index = j;
7845 break;
7846 }
7847 }
7848 ASSERT(context_index >= 0);
7849 arguments->set_the_hole(index);
7850 parameter_map->set(index + 2, Smi::FromInt(context_index));
7851 }
7852
7853 --index;
7854 }
7855 } else {
7856 // If there is no aliasing, the arguments object elements are not
7857 // special in any way.
7858 Handle<FixedArray> elements =
7859 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7860 result->set_elements(*elements);
7861 for (int i = 0; i < argument_count; ++i) {
7862 elements->set(i, *(parameters - i - 1));
7863 }
7864 }
7865 }
7866 return *result;
7867}
7868
7869
7870RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007871 NoHandleAllocation ha;
7872 ASSERT(args.length() == 3);
7873
7874 JSFunction* callee = JSFunction::cast(args[0]);
7875 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007876 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007877
lrn@chromium.org303ada72010-10-27 09:33:13 +00007878 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007879 { MaybeObject* maybe_result =
7880 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007881 if (!maybe_result->ToObject(&result)) return maybe_result;
7882 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007883 // Allocate the elements if needed.
7884 if (length > 0) {
7885 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007886 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007887 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007888 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7889 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007890
7891 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007892 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007893 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007894 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007895
7896 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007897 for (int i = 0; i < length; i++) {
7898 array->set(i, *--parameters, mode);
7899 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007900 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007901 }
7902 return result;
7903}
7904
7905
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007906RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007907 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007908 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007909 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007910 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007911 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007912
whesse@chromium.org7b260152011-06-20 15:33:18 +00007913 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007914 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007915 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007916 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007917 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7918 context,
7919 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007920 return *result;
7921}
7922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007923
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007924static SmartArrayPointer<Object**> GetNonBoundArguments(int bound_argc,
7925 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007926 // Find frame containing arguments passed to the caller.
7927 JavaScriptFrameIterator it;
7928 JavaScriptFrame* frame = it.frame();
7929 List<JSFunction*> functions(2);
7930 frame->GetFunctions(&functions);
7931 if (functions.length() > 1) {
7932 int inlined_frame_index = functions.length() - 1;
7933 JSFunction* inlined_function = functions[inlined_frame_index];
7934 int args_count = inlined_function->shared()->formal_parameter_count();
7935 ScopedVector<SlotRef> args_slots(args_count);
7936 SlotRef::ComputeSlotMappingForArguments(frame,
7937 inlined_frame_index,
7938 &args_slots);
7939
7940 *total_argc = bound_argc + args_count;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007941 SmartArrayPointer<Object**> param_data(NewArray<Object**>(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007942 for (int i = 0; i < args_count; i++) {
7943 Handle<Object> val = args_slots[i].GetValue();
7944 param_data[bound_argc + i] = val.location();
7945 }
7946 return param_data;
7947 } else {
7948 it.AdvanceToArgumentsFrame();
7949 frame = it.frame();
7950 int args_count = frame->ComputeParametersCount();
7951
7952 *total_argc = bound_argc + args_count;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007953 SmartArrayPointer<Object**> param_data(NewArray<Object**>(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007954 for (int i = 0; i < args_count; i++) {
7955 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7956 param_data[bound_argc + i] = val.location();
7957 }
7958 return param_data;
7959 }
7960}
7961
7962
7963RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007964 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007965 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007966 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007967 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007968
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007969 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007970 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007971 int bound_argc = 0;
7972 if (!args[1]->IsNull()) {
7973 CONVERT_ARG_CHECKED(JSArray, params, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007974 RUNTIME_ASSERT(params->HasFastTypeElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007975 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007976 bound_argc = Smi::cast(params->length())->value();
7977 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007979 int total_argc = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007980 SmartArrayPointer<Object**> param_data =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007981 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007982 for (int i = 0; i < bound_argc; i++) {
7983 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007984 param_data[i] = val.location();
7985 }
7986
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007987 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007988 Handle<Object> result =
7989 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007990 if (exception) {
7991 return Failure::Exception();
7992 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007993
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007994 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007995 return *result;
7996}
7997
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007998
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007999static void TrySettingInlineConstructStub(Isolate* isolate,
8000 Handle<JSFunction> function) {
8001 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008002 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008003 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008004 }
8005 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008006 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00008007 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008008 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008009 function->shared()->set_construct_stub(
8010 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008011 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008012 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008013}
8014
8015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008016RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008017 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008018 ASSERT(args.length() == 1);
8019
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008020 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008021
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008022 // If the constructor isn't a proper function we throw a type error.
8023 if (!constructor->IsJSFunction()) {
8024 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8025 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008026 isolate->factory()->NewTypeError("not_constructor", arguments);
8027 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008028 }
8029
8030 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008031
8032 // If function should not have prototype, construction is not allowed. In this
8033 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008034 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008035 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8036 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008037 isolate->factory()->NewTypeError("not_constructor", arguments);
8038 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008039 }
8040
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008041#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008042 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008043 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008044 if (debug->StepInActive()) {
8045 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008046 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008047#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008048
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008049 if (function->has_initial_map()) {
8050 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008051 // The 'Function' function ignores the receiver object when
8052 // called using 'new' and creates a new JSFunction object that
8053 // is returned. The receiver object is only used for error
8054 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008055 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008056 // allocate JSFunctions since it does not properly initialize
8057 // the shared part of the function. Since the receiver is
8058 // ignored anyway, we use the global object as the receiver
8059 // instead of a new JSFunction object. This way, errors are
8060 // reported the same way whether or not 'Function' is called
8061 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008062 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008063 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008064 }
8065
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008066 // The function should be compiled for the optimization hints to be
8067 // available. We cannot use EnsureCompiled because that forces a
8068 // compilation through the shared function info which makes it
8069 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008070 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008071 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008072
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008073 if (!function->has_initial_map() &&
8074 shared->IsInobjectSlackTrackingInProgress()) {
8075 // The tracking is already in progress for another function. We can only
8076 // track one initial_map at a time, so we force the completion before the
8077 // function is called as a constructor for the first time.
8078 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008079 }
8080
8081 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008082 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8083 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008084 // Delay setting the stub if inobject slack tracking is in progress.
8085 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008086 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008087 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008088
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008089 isolate->counters()->constructed_objects()->Increment();
8090 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008091
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008092 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008093}
8094
8095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008096RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008097 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008098 ASSERT(args.length() == 1);
8099
8100 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8101 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008102 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008104 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008105}
8106
8107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008108RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008109 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008110 ASSERT(args.length() == 1);
8111
8112 Handle<JSFunction> function = args.at<JSFunction>(0);
8113#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008114 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008115 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008116 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008117 PrintF("]\n");
8118 }
8119#endif
8120
lrn@chromium.org34e60782011-09-15 07:25:40 +00008121 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008122 ASSERT(!function->is_compiled());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008123 if (!CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008124 return Failure::Exception();
8125 }
8126
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008127 // All done. Return the compiled code.
8128 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008129 return function->code();
8130}
8131
8132
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008133RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008134 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008135 ASSERT(args.length() == 1);
8136 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008137
8138 // If the function is not compiled ignore the lazy
8139 // recompilation. This can happen if the debugger is activated and
8140 // the function is returned to the not compiled state.
8141 if (!function->shared()->is_compiled()) {
8142 function->ReplaceCode(function->shared()->code());
8143 return function->code();
8144 }
8145
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008146 // If the function is not optimizable or debugger is active continue using the
8147 // code from the full compiler.
8148 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008149 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008150 if (FLAG_trace_opt) {
8151 PrintF("[failed to optimize ");
8152 function->PrintName();
8153 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8154 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008155 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008156 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008157 function->ReplaceCode(function->shared()->code());
8158 return function->code();
8159 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008160 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008161 return function->code();
8162 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008163 if (FLAG_trace_opt) {
8164 PrintF("[failed to optimize ");
8165 function->PrintName();
8166 PrintF(": optimized compilation failed]\n");
8167 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008168 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008169 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008170}
8171
8172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008173RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008174 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008175 ASSERT(args.length() == 1);
8176 RUNTIME_ASSERT(args[0]->IsSmi());
8177 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008178 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008179 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8180 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008181 int frames = deoptimizer->output_count();
8182
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008183 deoptimizer->MaterializeHeapNumbers();
8184 delete deoptimizer;
8185
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008186 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008187 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008188 for (int i = 0; i < frames - 1; i++) it.Advance();
8189 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008190
8191 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008192 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008193 Handle<Object> arguments;
8194 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008195 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008196 if (arguments.is_null()) {
8197 // FunctionGetArguments can't throw an exception, so cast away the
8198 // doubt with an assert.
8199 arguments = Handle<Object>(
8200 Accessors::FunctionGetArguments(*function,
8201 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008202 ASSERT(*arguments != isolate->heap()->null_value());
8203 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008204 }
8205 frame->SetExpression(i, *arguments);
8206 }
8207 }
8208
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008209 if (type == Deoptimizer::EAGER) {
8210 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008211 }
8212
8213 // Avoid doing too much work when running with --always-opt and keep
8214 // the optimized code around.
8215 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008216 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008217 }
8218
8219 // Count the number of optimized activations of the function.
8220 int activations = 0;
8221 while (!it.done()) {
8222 JavaScriptFrame* frame = it.frame();
8223 if (frame->is_optimized() && frame->function() == *function) {
8224 activations++;
8225 }
8226 it.Advance();
8227 }
8228
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008229 if (activations == 0) {
8230 if (FLAG_trace_deopt) {
8231 PrintF("[removing optimized code for: ");
8232 function->PrintName();
8233 PrintF("]\n");
8234 }
8235 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008236 } else {
8237 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008238 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008239 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008240}
8241
8242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008243RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008244 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008245 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008246 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008247}
8248
8249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008250RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008251 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008252 ASSERT(args.length() == 1);
8253 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008254 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008255
8256 Deoptimizer::DeoptimizeFunction(*function);
8257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008258 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008259}
8260
8261
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008262RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8263#if defined(USE_SIMULATOR)
8264 return isolate->heap()->true_value();
8265#else
8266 return isolate->heap()->false_value();
8267#endif
8268}
8269
8270
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008271RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8272 HandleScope scope(isolate);
8273 ASSERT(args.length() == 1);
8274 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8275 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8276 function->MarkForLazyRecompilation();
8277 return isolate->heap()->undefined_value();
8278}
8279
8280
lrn@chromium.org1c092762011-05-09 09:42:16 +00008281RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8282 HandleScope scope(isolate);
8283 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008284 // The least significant bit (after untagging) indicates whether the
8285 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008286 if (!V8::UseCrankshaft()) {
8287 return Smi::FromInt(4); // 4 == "never".
8288 }
8289 if (FLAG_always_opt) {
8290 return Smi::FromInt(3); // 3 == "always".
8291 }
8292 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8293 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8294 : Smi::FromInt(2); // 2 == "no".
8295}
8296
8297
8298RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8299 HandleScope scope(isolate);
8300 ASSERT(args.length() == 1);
8301 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8302 return Smi::FromInt(function->shared()->opt_count());
8303}
8304
8305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008306RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008307 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008308 ASSERT(args.length() == 1);
8309 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8310
8311 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008312 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008313
8314 // We have hit a back edge in an unoptimized frame for a function that was
8315 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008316 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008317 // Keep track of whether we've succeeded in optimizing.
8318 bool succeeded = unoptimized->optimizable();
8319 if (succeeded) {
8320 // If we are trying to do OSR when there are already optimized
8321 // activations of the function, it means (a) the function is directly or
8322 // indirectly recursive and (b) an optimized invocation has been
8323 // deoptimized so that we are currently in an unoptimized activation.
8324 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008325 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008326 while (succeeded && !it.done()) {
8327 JavaScriptFrame* frame = it.frame();
8328 succeeded = !frame->is_optimized() || frame->function() != *function;
8329 it.Advance();
8330 }
8331 }
8332
8333 int ast_id = AstNode::kNoNumber;
8334 if (succeeded) {
8335 // The top JS function is this one, the PC is somewhere in the
8336 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008337 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008338 JavaScriptFrame* frame = it.frame();
8339 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008340 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008341 ASSERT(unoptimized->contains(frame->pc()));
8342
8343 // Use linear search of the unoptimized code's stack check table to find
8344 // the AST id matching the PC.
8345 Address start = unoptimized->instruction_start();
8346 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008347 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008348 uint32_t table_length = Memory::uint32_at(table_cursor);
8349 table_cursor += kIntSize;
8350 for (unsigned i = 0; i < table_length; ++i) {
8351 // Table entries are (AST id, pc offset) pairs.
8352 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8353 if (pc_offset == target_pc_offset) {
8354 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8355 break;
8356 }
8357 table_cursor += 2 * kIntSize;
8358 }
8359 ASSERT(ast_id != AstNode::kNoNumber);
8360 if (FLAG_trace_osr) {
8361 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8362 function->PrintName();
8363 PrintF("]\n");
8364 }
8365
8366 // Try to compile the optimized code. A true return value from
8367 // CompileOptimized means that compilation succeeded, not necessarily
8368 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008369 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8370 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008371 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8372 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008373 if (data->OsrPcOffset()->value() >= 0) {
8374 if (FLAG_trace_osr) {
8375 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008376 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008377 }
8378 ASSERT(data->OsrAstId()->value() == ast_id);
8379 } else {
8380 // We may never generate the desired OSR entry if we emit an
8381 // early deoptimize.
8382 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008383 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008384 } else {
8385 succeeded = false;
8386 }
8387 }
8388
8389 // Revert to the original stack checks in the original unoptimized code.
8390 if (FLAG_trace_osr) {
8391 PrintF("[restoring original stack checks in ");
8392 function->PrintName();
8393 PrintF("]\n");
8394 }
8395 StackCheckStub check_stub;
8396 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008397 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008398 Deoptimizer::RevertStackCheckCode(*unoptimized,
8399 *check_code,
8400 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008401
8402 // Allow OSR only at nesting level zero again.
8403 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8404
8405 // If the optimization attempt succeeded, return the AST id tagged as a
8406 // smi. This tells the builtin that we need to translate the unoptimized
8407 // frame to an optimized one.
8408 if (succeeded) {
8409 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8410 return Smi::FromInt(ast_id);
8411 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008412 if (function->IsMarkedForLazyRecompilation()) {
8413 function->ReplaceCode(function->shared()->code());
8414 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008415 return Smi::FromInt(-1);
8416 }
8417}
8418
8419
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008420RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8421 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8422 return isolate->heap()->undefined_value();
8423}
8424
8425
lrn@chromium.org34e60782011-09-15 07:25:40 +00008426RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8427 HandleScope scope(isolate);
8428 ASSERT(args.length() == 5);
8429 CONVERT_CHECKED(JSReceiver, fun, args[0]);
8430 Object* receiver = args[1];
8431 CONVERT_CHECKED(JSObject, arguments, args[2]);
8432 CONVERT_CHECKED(Smi, shift, args[3]);
8433 CONVERT_CHECKED(Smi, arity, args[4]);
8434
8435 int offset = shift->value();
8436 int argc = arity->value();
8437 ASSERT(offset >= 0);
8438 ASSERT(argc >= 0);
8439
8440 // If there are too many arguments, allocate argv via malloc.
8441 const int argv_small_size = 10;
8442 Handle<Object> argv_small_buffer[argv_small_size];
8443 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8444 Handle<Object>* argv = argv_small_buffer;
8445 if (argc > argv_small_size) {
8446 argv = new Handle<Object>[argc];
8447 if (argv == NULL) return isolate->StackOverflow();
8448 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8449 }
8450
8451 for (int i = 0; i < argc; ++i) {
8452 MaybeObject* maybe = arguments->GetElement(offset + i);
8453 Object* object;
8454 if (!maybe->To<Object>(&object)) return maybe;
8455 argv[i] = Handle<Object>(object);
8456 }
8457
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008458 bool threw;
lrn@chromium.org34e60782011-09-15 07:25:40 +00008459 Handle<JSReceiver> hfun(fun);
8460 Handle<Object> hreceiver(receiver);
8461 Handle<Object> result = Execution::Call(
8462 hfun, hreceiver, argc, reinterpret_cast<Object***>(argv), &threw, true);
8463
8464 if (threw) return Failure::Exception();
8465 return *result;
8466}
8467
8468
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008469RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008470 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008471 ASSERT(args.length() == 1);
8472 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8473 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8474}
8475
8476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008477RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008478 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008479 ASSERT(args.length() == 1);
8480 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8481 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8482}
8483
8484
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008485RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008486 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008487 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008488
kasper.lund7276f142008-07-30 08:49:36 +00008489 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008490 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008491 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008492 { MaybeObject* maybe_result =
8493 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008494 if (!maybe_result->ToObject(&result)) return maybe_result;
8495 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008496
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008497 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008498
kasper.lund7276f142008-07-30 08:49:36 +00008499 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008500}
8501
lrn@chromium.org303ada72010-10-27 09:33:13 +00008502
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008503RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8504 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008505 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008506 JSObject* extension_object;
8507 if (args[0]->IsJSObject()) {
8508 extension_object = JSObject::cast(args[0]);
8509 } else {
8510 // Convert the object to a proper JavaScript object.
8511 MaybeObject* maybe_js_object = args[0]->ToObject();
8512 if (!maybe_js_object->To(&extension_object)) {
8513 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8514 HandleScope scope(isolate);
8515 Handle<Object> handle = args.at<Object>(0);
8516 Handle<Object> result =
8517 isolate->factory()->NewTypeError("with_expression",
8518 HandleVector(&handle, 1));
8519 return isolate->Throw(*result);
8520 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008521 return maybe_js_object;
8522 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008523 }
8524 }
8525
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008526 JSFunction* function;
8527 if (args[1]->IsSmi()) {
8528 // A smi sentinel indicates a context nested inside global code rather
8529 // than some function. There is a canonical empty function that can be
8530 // gotten from the global context.
8531 function = isolate->context()->global_context()->closure();
8532 } else {
8533 function = JSFunction::cast(args[1]);
8534 }
8535
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008536 Context* context;
8537 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008538 isolate->heap()->AllocateWithContext(function,
8539 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008540 extension_object);
8541 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008542 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008543 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008544}
8545
8546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008547RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008548 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008549 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008550 String* name = String::cast(args[0]);
8551 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008552 JSFunction* function;
8553 if (args[2]->IsSmi()) {
8554 // A smi sentinel indicates a context nested inside global code rather
8555 // than some function. There is a canonical empty function that can be
8556 // gotten from the global context.
8557 function = isolate->context()->global_context()->closure();
8558 } else {
8559 function = JSFunction::cast(args[2]);
8560 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008561 Context* context;
8562 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008563 isolate->heap()->AllocateCatchContext(function,
8564 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008565 name,
8566 thrown_object);
8567 if (!maybe_context->To(&context)) return maybe_context;
8568 isolate->set_context(context);
8569 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008570}
8571
8572
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008573RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8574 NoHandleAllocation ha;
8575 ASSERT(args.length() == 2);
8576 SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
8577 JSFunction* function;
8578 if (args[1]->IsSmi()) {
8579 // A smi sentinel indicates a context nested inside global code rather
8580 // than some function. There is a canonical empty function that can be
8581 // gotten from the global context.
8582 function = isolate->context()->global_context()->closure();
8583 } else {
8584 function = JSFunction::cast(args[1]);
8585 }
8586 Context* context;
8587 MaybeObject* maybe_context =
8588 isolate->heap()->AllocateBlockContext(function,
8589 isolate->context(),
8590 scope_info);
8591 if (!maybe_context->To(&context)) return maybe_context;
8592 isolate->set_context(context);
8593 return context;
8594}
8595
8596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008597RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008598 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008599 ASSERT(args.length() == 2);
8600
8601 CONVERT_ARG_CHECKED(Context, context, 0);
8602 CONVERT_ARG_CHECKED(String, name, 1);
8603
8604 int index;
8605 PropertyAttributes attributes;
8606 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008607 BindingFlags binding_flags;
8608 Handle<Object> holder = context->Lookup(name,
8609 flags,
8610 &index,
8611 &attributes,
8612 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008613
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008614 // If the slot was not found the result is true.
8615 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008616 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008617 }
8618
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008619 // If the slot was found in a context, it should be DONT_DELETE.
8620 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008621 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008622 }
8623
8624 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008625 // the global object, or the subject of a with. Try to delete it
8626 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008627 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008628 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008629}
8630
8631
ager@chromium.orga1645e22009-09-09 19:27:10 +00008632// A mechanism to return a pair of Object pointers in registers (if possible).
8633// How this is achieved is calling convention-dependent.
8634// All currently supported x86 compiles uses calling conventions that are cdecl
8635// variants where a 64-bit value is returned in two 32-bit registers
8636// (edx:eax on ia32, r1:r0 on ARM).
8637// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8638// In Win64 calling convention, a struct of two pointers is returned in memory,
8639// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008640#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008641struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008642 MaybeObject* x;
8643 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008644};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008645
lrn@chromium.org303ada72010-10-27 09:33:13 +00008646static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008647 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008648 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8649 // In Win64 they are assigned to a hidden first argument.
8650 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008651}
8652#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008653typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008654static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008655 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008656 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008657}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008658#endif
8659
8660
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008661static inline MaybeObject* Unhole(Heap* heap,
8662 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008663 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008664 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8665 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008666 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008667}
8668
8669
danno@chromium.org40cb8782011-05-25 07:58:50 +00008670static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8671 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008672 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008673 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008674 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008675 JSFunction* context_extension_function =
8676 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008677 // If the holder isn't a context extension object, we just return it
8678 // as the receiver. This allows arguments objects to be used as
8679 // receivers, but only if they are put in the context scope chain
8680 // explicitly via a with-statement.
8681 Object* constructor = holder->map()->constructor();
8682 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008683 // Fall back to using the global object as the implicit receiver if
8684 // the property turns out to be a local variable allocated in a
8685 // context extension object - introduced via eval. Implicit global
8686 // receivers are indicated with the hole value.
8687 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008688}
8689
8690
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008691static ObjectPair LoadContextSlotHelper(Arguments args,
8692 Isolate* isolate,
8693 bool throw_error) {
8694 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008695 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008696
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008697 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008698 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008699 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008700 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008701 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008702
8703 int index;
8704 PropertyAttributes attributes;
8705 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008706 BindingFlags binding_flags;
8707 Handle<Object> holder = context->Lookup(name,
8708 flags,
8709 &index,
8710 &attributes,
8711 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008712
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008713 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008714 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008715 ASSERT(holder->IsContext());
8716 // If the "property" we were looking for is a local variable, the
8717 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008718 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008719 // Use the hole as the receiver to signal that the receiver is implicit
8720 // and that the global receiver should be used (as distinguished from an
8721 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008722 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008723 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008724 // Check for uninitialized bindings.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008725 if (binding_flags == MUTABLE_CHECK_INITIALIZED && value->IsTheHole()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008726 Handle<Object> reference_error =
8727 isolate->factory()->NewReferenceError("not_defined",
8728 HandleVector(&name, 1));
8729 return MakePair(isolate->Throw(*reference_error), NULL);
8730 } else {
8731 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8732 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008733 }
8734
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008735 // Otherwise, if the slot was found the holder is a context extension
8736 // object, subject of a with, or a global object. We read the named
8737 // property from it.
8738 if (!holder.is_null()) {
8739 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8740 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008741 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008742 Handle<Object> receiver_handle(object->IsGlobalObject()
8743 ? GlobalObject::cast(*object)->global_receiver()
8744 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008745
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008746 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008747 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008748 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008749 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008750 }
8751
8752 if (throw_error) {
8753 // The property doesn't exist - throw exception.
8754 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008755 isolate->factory()->NewReferenceError("not_defined",
8756 HandleVector(&name, 1));
8757 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008758 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008759 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008760 return MakePair(isolate->heap()->undefined_value(),
8761 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008762 }
8763}
8764
8765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008766RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008767 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008768}
8769
8770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008771RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008772 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008773}
8774
8775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008776RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008777 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008778 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008779
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008780 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008781 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008782 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008783 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008784 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8785 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008786 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008787
8788 int index;
8789 PropertyAttributes attributes;
8790 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008791 BindingFlags binding_flags;
8792 Handle<Object> holder = context->Lookup(name,
8793 flags,
8794 &index,
8795 &attributes,
8796 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008797
8798 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008799 // The property was found in a context slot.
8800 Handle<Context> context = Handle<Context>::cast(holder);
8801 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8802 context->get(index)->IsTheHole()) {
8803 Handle<Object> error =
8804 isolate->factory()->NewReferenceError("not_defined",
8805 HandleVector(&name, 1));
8806 return isolate->Throw(*error);
8807 }
8808 // Ignore if read_only variable.
8809 if ((attributes & READ_ONLY) == 0) {
8810 // Context is a fixed array and set cannot fail.
8811 context->set(index, *value);
8812 } else if (strict_mode == kStrictMode) {
8813 // Setting read only property in strict mode.
8814 Handle<Object> error =
8815 isolate->factory()->NewTypeError("strict_cannot_assign",
8816 HandleVector(&name, 1));
8817 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008818 }
8819 return *value;
8820 }
8821
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008822 // Slow case: The property is not in a context slot. It is either in a
8823 // context extension object, a property of the subject of a with, or a
8824 // property of the global object.
8825 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008826
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008827 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008828 // The property exists on the holder.
8829 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008830 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008831 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008832 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008833
8834 if (strict_mode == kStrictMode) {
8835 // Throw in strict mode (assignment to undefined variable).
8836 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008837 isolate->factory()->NewReferenceError(
8838 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008839 return isolate->Throw(*error);
8840 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008841 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008842 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008843 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008844 }
8845
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008846 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008847 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008848 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008849 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008850 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008851 SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008852 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008853 // Setting read only property in strict mode.
8854 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008855 isolate->factory()->NewTypeError(
8856 "strict_cannot_assign", HandleVector(&name, 1));
8857 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008858 }
8859 return *value;
8860}
8861
8862
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008863RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008864 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008865 ASSERT(args.length() == 1);
8866
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008867 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008868}
8869
8870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008871RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008872 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008873 ASSERT(args.length() == 1);
8874
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008875 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008876}
8877
8878
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008879RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008880 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008881 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008882}
8883
8884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008885RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008886 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008887 ASSERT(args.length() == 1);
8888
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008889 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008890 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008891 isolate->factory()->NewReferenceError("not_defined",
8892 HandleVector(&name, 1));
8893 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008894}
8895
8896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008897RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008898 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008899
8900 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008901 if (isolate->stack_guard()->IsStackOverflow()) {
8902 NoHandleAllocation na;
8903 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008904 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008905
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008906 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008907}
8908
8909
8910// NOTE: These PrintXXX functions are defined for all builds (not just
8911// DEBUG builds) because we may want to be able to trace function
8912// calls in all modes.
8913static void PrintString(String* str) {
8914 // not uncommon to have empty strings
8915 if (str->length() > 0) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008916 SmartArrayPointer<char> s =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008917 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8918 PrintF("%s", *s);
8919 }
8920}
8921
8922
8923static void PrintObject(Object* obj) {
8924 if (obj->IsSmi()) {
8925 PrintF("%d", Smi::cast(obj)->value());
8926 } else if (obj->IsString() || obj->IsSymbol()) {
8927 PrintString(String::cast(obj));
8928 } else if (obj->IsNumber()) {
8929 PrintF("%g", obj->Number());
8930 } else if (obj->IsFailure()) {
8931 PrintF("<failure>");
8932 } else if (obj->IsUndefined()) {
8933 PrintF("<undefined>");
8934 } else if (obj->IsNull()) {
8935 PrintF("<null>");
8936 } else if (obj->IsTrue()) {
8937 PrintF("<true>");
8938 } else if (obj->IsFalse()) {
8939 PrintF("<false>");
8940 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008941 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008942 }
8943}
8944
8945
8946static int StackSize() {
8947 int n = 0;
8948 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8949 return n;
8950}
8951
8952
8953static void PrintTransition(Object* result) {
8954 // indentation
8955 { const int nmax = 80;
8956 int n = StackSize();
8957 if (n <= nmax)
8958 PrintF("%4d:%*s", n, n, "");
8959 else
8960 PrintF("%4d:%*s", n, nmax, "...");
8961 }
8962
8963 if (result == NULL) {
8964 // constructor calls
8965 JavaScriptFrameIterator it;
8966 JavaScriptFrame* frame = it.frame();
8967 if (frame->IsConstructor()) PrintF("new ");
8968 // function name
8969 Object* fun = frame->function();
8970 if (fun->IsJSFunction()) {
8971 PrintObject(JSFunction::cast(fun)->shared()->name());
8972 } else {
8973 PrintObject(fun);
8974 }
8975 // function arguments
8976 // (we are intentionally only printing the actually
8977 // supplied parameters, not all parameters required)
8978 PrintF("(this=");
8979 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008980 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981 for (int i = 0; i < length; i++) {
8982 PrintF(", ");
8983 PrintObject(frame->GetParameter(i));
8984 }
8985 PrintF(") {\n");
8986
8987 } else {
8988 // function result
8989 PrintF("} -> ");
8990 PrintObject(result);
8991 PrintF("\n");
8992 }
8993}
8994
8995
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008996RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008997 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008998 NoHandleAllocation ha;
8999 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009000 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009001}
9002
9003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009004RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009005 NoHandleAllocation ha;
9006 PrintTransition(args[0]);
9007 return args[0]; // return TOS
9008}
9009
9010
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009011RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009012 NoHandleAllocation ha;
9013 ASSERT(args.length() == 1);
9014
9015#ifdef DEBUG
9016 if (args[0]->IsString()) {
9017 // If we have a string, assume it's a code "marker"
9018 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009019 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009020 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009021 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9022 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009023 } else {
9024 PrintF("DebugPrint: ");
9025 }
9026 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009027 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009028 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009029 HeapObject::cast(args[0])->map()->Print();
9030 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009031#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009032 // ShortPrint is available in release mode. Print is not.
9033 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009034#endif
9035 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009036 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009037
9038 return args[0]; // return TOS
9039}
9040
9041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009042RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009043 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009044 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009045 isolate->PrintStack();
9046 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009047}
9048
9049
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009050RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009051 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009052 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053
9054 // According to ECMA-262, section 15.9.1, page 117, the precision of
9055 // the number in a Date object representing a particular instant in
9056 // time is milliseconds. Therefore, we floor the result of getting
9057 // the OS time.
9058 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009059 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009060}
9061
9062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009063RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009064 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009065 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009066
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009067 CONVERT_ARG_CHECKED(String, str, 0);
9068 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009069
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009070 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009071
9072 MaybeObject* maybe_result_array =
9073 output->EnsureCanContainNonSmiElements();
9074 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009075 RUNTIME_ASSERT(output->HasFastElements());
9076
9077 AssertNoAllocation no_allocation;
9078
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009079 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009080 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9081 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009082 String::FlatContent str_content = str->GetFlatContent();
9083 if (str_content.IsAscii()) {
9084 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009085 output_array,
9086 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009087 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009088 ASSERT(str_content.IsTwoByte());
9089 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009090 output_array,
9091 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009092 }
9093
9094 if (result) {
9095 return *output;
9096 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009097 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098 }
9099}
9100
9101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009102RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009103 NoHandleAllocation ha;
9104 ASSERT(args.length() == 1);
9105
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009106 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009107 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009108 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009109}
9110
9111
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009112RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009113 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009114 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009115
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009116 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009117}
9118
9119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009120RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009121 NoHandleAllocation ha;
9122 ASSERT(args.length() == 1);
9123
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009124 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009125 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009126}
9127
9128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009129RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009130 ASSERT(args.length() == 1);
9131 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009132 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009133 return JSGlobalObject::cast(global)->global_receiver();
9134}
9135
9136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009137RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009138 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009139 ASSERT_EQ(1, args.length());
9140 CONVERT_ARG_CHECKED(String, source, 0);
9141
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009142 source = Handle<String>(source->TryFlattenGetString());
9143 // Optimized fast case where we only have ascii characters.
9144 Handle<Object> result;
9145 if (source->IsSeqAsciiString()) {
9146 result = JsonParser<true>::Parse(source);
9147 } else {
9148 result = JsonParser<false>::Parse(source);
9149 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009150 if (result.is_null()) {
9151 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009152 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009153 return Failure::Exception();
9154 }
9155 return *result;
9156}
9157
9158
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009159bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9160 Handle<Context> context) {
9161 if (context->allow_code_gen_from_strings()->IsFalse()) {
9162 // Check with callback if set.
9163 AllowCodeGenerationFromStringsCallback callback =
9164 isolate->allow_code_gen_callback();
9165 if (callback == NULL) {
9166 // No callback set and code generation disallowed.
9167 return false;
9168 } else {
9169 // Callback set. Let it decide if code generation is allowed.
9170 VMState state(isolate, EXTERNAL);
9171 return callback(v8::Utils::ToLocal(context));
9172 }
9173 }
9174 return true;
9175}
9176
9177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009178RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009179 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009180 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009181 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009182
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009183 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009184 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009185
9186 // Check if global context allows code generation from
9187 // strings. Throw an exception if it doesn't.
9188 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9189 return isolate->Throw(*isolate->factory()->NewError(
9190 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9191 }
9192
9193 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009194 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
9195 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009196 true,
9197 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009198 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009199 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009200 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9201 context,
9202 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009203 return *fun;
9204}
9205
9206
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009207static ObjectPair CompileGlobalEval(Isolate* isolate,
9208 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009209 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009210 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009211 Handle<Context> context = Handle<Context>(isolate->context());
9212 Handle<Context> global_context = Handle<Context>(context->global_context());
9213
9214 // Check if global context allows code generation from
9215 // strings. Throw an exception if it doesn't.
9216 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9217 isolate->Throw(*isolate->factory()->NewError(
9218 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9219 return MakePair(Failure::Exception(), NULL);
9220 }
9221
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009222 // Deal with a normal eval call with a string argument. Compile it
9223 // and return the compiled function bound in the local context.
9224 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9225 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009226 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009227 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009228 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009229 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009230 Handle<JSFunction> compiled =
9231 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009232 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009233 return MakePair(*compiled, *receiver);
9234}
9235
9236
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009237RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009238 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009239
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009240 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009241 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009242 Handle<Object> receiver; // Will be overwritten.
9243
9244 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009245 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009246#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009247 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009248 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009249 StackFrameLocator locator;
9250 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009251 ASSERT(Context::cast(frame->context()) == *context);
9252#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009253
9254 // Find where the 'eval' symbol is bound. It is unaliased only if
9255 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009256 int index = -1;
9257 PropertyAttributes attributes = ABSENT;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009258 BindingFlags binding_flags;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009259 while (true) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009260 // Don't follow context chains in Context::Lookup and implement the loop
9261 // up the context chain here, so that we can know the context where eval
9262 // was found.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009263 receiver = context->Lookup(isolate->factory()->eval_symbol(),
9264 FOLLOW_PROTOTYPE_CHAIN,
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009265 &index,
9266 &attributes,
9267 &binding_flags);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009268 // Stop search when eval is found or when the global context is
9269 // reached.
9270 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009271 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009272 }
9273
iposva@chromium.org245aa852009-02-10 00:49:54 +00009274 // If eval could not be resolved, it has been deleted and we need to
9275 // throw a reference error.
9276 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009277 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00009278 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009279 isolate->factory()->NewReferenceError("not_defined",
9280 HandleVector(&name, 1));
9281 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009282 }
9283
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009284 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009285 // 'eval' is not bound in the global context. Just call the function
9286 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00009287 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009288 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009289 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009290 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009291 }
9292
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009293 // 'eval' is bound in the global context, but it may have been overwritten.
9294 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009295 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009296 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009297 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009298 }
9299
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009300 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009301 return CompileGlobalEval(isolate,
9302 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009303 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009304 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009305}
9306
9307
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009308RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009309 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009311 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009312 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009313
9314 // 'eval' is bound in the global context, but it may have been overwritten.
9315 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009316 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009317 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009318 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009319 }
9320
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009321 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009322 return CompileGlobalEval(isolate,
9323 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009324 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009325 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009326}
9327
9328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009329RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009330 // This utility adjusts the property attributes for newly created Function
9331 // object ("new Function(...)") by changing the map.
9332 // All it does is changing the prototype property to enumerable
9333 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009334 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009335 ASSERT(args.length() == 1);
9336 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009337
9338 Handle<Map> map = func->shared()->strict_mode()
9339 ? isolate->strict_mode_function_instance_map()
9340 : isolate->function_instance_map();
9341
9342 ASSERT(func->map()->instance_type() == map->instance_type());
9343 ASSERT(func->map()->instance_size() == map->instance_size());
9344 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009345 return *func;
9346}
9347
9348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009349RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009350 // Allocate a block of memory in NewSpace (filled with a filler).
9351 // Use as fallback for allocation in generated code when NewSpace
9352 // is full.
9353 ASSERT(args.length() == 1);
9354 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9355 int size = size_smi->value();
9356 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9357 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009358 Heap* heap = isolate->heap();
9359 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009360 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009361 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009362 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009363 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009364 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009365 }
9366 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009367 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009368}
9369
9370
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009371// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009372// array. Returns true if the element was pushed on the stack and
9373// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009374RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009375 ASSERT(args.length() == 2);
9376 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009377 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009378 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009379 int length = Smi::cast(array->length())->value();
9380 FixedArray* elements = FixedArray::cast(array->elements());
9381 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009382 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009383 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009384 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009385 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009386 { MaybeObject* maybe_obj =
9387 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009388 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9389 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009390 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009391}
9392
9393
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009394/**
9395 * A simple visitor visits every element of Array's.
9396 * The backend storage can be a fixed array for fast elements case,
9397 * or a dictionary for sparse array. Since Dictionary is a subtype
9398 * of FixedArray, the class can be used by both fast and slow cases.
9399 * The second parameter of the constructor, fast_elements, specifies
9400 * whether the storage is a FixedArray or Dictionary.
9401 *
9402 * An index limit is used to deal with the situation that a result array
9403 * length overflows 32-bit non-negative integer.
9404 */
9405class ArrayConcatVisitor {
9406 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009407 ArrayConcatVisitor(Isolate* isolate,
9408 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009409 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009410 isolate_(isolate),
9411 storage_(Handle<FixedArray>::cast(
9412 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009413 index_offset_(0u),
9414 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009415
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009416 ~ArrayConcatVisitor() {
9417 clear_storage();
9418 }
9419
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009420 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009421 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009422 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009423
9424 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009425 if (index < static_cast<uint32_t>(storage_->length())) {
9426 storage_->set(index, *elm);
9427 return;
9428 }
9429 // Our initial estimate of length was foiled, possibly by
9430 // getters on the arrays increasing the length of later arrays
9431 // during iteration.
9432 // This shouldn't happen in anything but pathological cases.
9433 SetDictionaryMode(index);
9434 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009435 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009436 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009437 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009438 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009439 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009440 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009441 // Dictionary needed to grow.
9442 clear_storage();
9443 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009444 }
9445}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009446
9447 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009448 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9449 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009450 } else {
9451 index_offset_ += delta;
9452 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009453 }
9454
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009455 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009456 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009457 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009458 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009459 Handle<Map> map;
9460 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009461 map = isolate_->factory()->GetElementsTransitionMap(array,
9462 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009463 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009464 map = isolate_->factory()->GetElementsTransitionMap(array,
9465 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009466 }
9467 array->set_map(*map);
9468 array->set_length(*length);
9469 array->set_elements(*storage_);
9470 return array;
9471 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009472
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009473 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009474 // Convert storage to dictionary mode.
9475 void SetDictionaryMode(uint32_t index) {
9476 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009477 Handle<FixedArray> current_storage(*storage_);
9478 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009479 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009480 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9481 for (uint32_t i = 0; i < current_length; i++) {
9482 HandleScope loop_scope;
9483 Handle<Object> element(current_storage->get(i));
9484 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009485 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009486 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009487 if (!new_storage.is_identical_to(slow_storage)) {
9488 slow_storage = loop_scope.CloseAndEscape(new_storage);
9489 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009490 }
9491 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009492 clear_storage();
9493 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009494 fast_elements_ = false;
9495 }
9496
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009497 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009498 isolate_->global_handles()->Destroy(
9499 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009500 }
9501
9502 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009503 storage_ = Handle<FixedArray>::cast(
9504 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009505 }
9506
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009507 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009508 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009509 // Index after last seen index. Always less than or equal to
9510 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009511 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009512 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009513};
9514
9515
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009516static uint32_t EstimateElementCount(Handle<JSArray> array) {
9517 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9518 int element_count = 0;
9519 switch (array->GetElementsKind()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009520 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009521 // Fast elements can't have lengths that are not representable by
9522 // a 32-bit signed integer.
9523 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9524 int fast_length = static_cast<int>(length);
9525 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9526 for (int i = 0; i < fast_length; i++) {
9527 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009528 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009529 break;
9530 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009531 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009532 Handle<NumberDictionary> dictionary(
9533 NumberDictionary::cast(array->elements()));
9534 int capacity = dictionary->Capacity();
9535 for (int i = 0; i < capacity; i++) {
9536 Handle<Object> key(dictionary->KeyAt(i));
9537 if (dictionary->IsKey(*key)) {
9538 element_count++;
9539 }
9540 }
9541 break;
9542 }
9543 default:
9544 // External arrays are always dense.
9545 return length;
9546 }
9547 // As an estimate, we assume that the prototype doesn't contain any
9548 // inherited elements.
9549 return element_count;
9550}
9551
9552
9553
9554template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009555static void IterateExternalArrayElements(Isolate* isolate,
9556 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009557 bool elements_are_ints,
9558 bool elements_are_guaranteed_smis,
9559 ArrayConcatVisitor* visitor) {
9560 Handle<ExternalArrayClass> array(
9561 ExternalArrayClass::cast(receiver->elements()));
9562 uint32_t len = static_cast<uint32_t>(array->length());
9563
9564 ASSERT(visitor != NULL);
9565 if (elements_are_ints) {
9566 if (elements_are_guaranteed_smis) {
9567 for (uint32_t j = 0; j < len; j++) {
9568 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009569 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009570 visitor->visit(j, e);
9571 }
9572 } else {
9573 for (uint32_t j = 0; j < len; j++) {
9574 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009575 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009576 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9577 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9578 visitor->visit(j, e);
9579 } else {
9580 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009581 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009582 visitor->visit(j, e);
9583 }
9584 }
9585 }
9586 } else {
9587 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009588 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009589 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009590 visitor->visit(j, e);
9591 }
9592 }
9593}
9594
9595
9596// Used for sorting indices in a List<uint32_t>.
9597static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9598 uint32_t a = *ap;
9599 uint32_t b = *bp;
9600 return (a == b) ? 0 : (a < b) ? -1 : 1;
9601}
9602
9603
9604static void CollectElementIndices(Handle<JSObject> object,
9605 uint32_t range,
9606 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009607 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009608 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009609 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009610 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009611 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9612 uint32_t length = static_cast<uint32_t>(elements->length());
9613 if (range < length) length = range;
9614 for (uint32_t i = 0; i < length; i++) {
9615 if (!elements->get(i)->IsTheHole()) {
9616 indices->Add(i);
9617 }
9618 }
9619 break;
9620 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009621 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009622 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009623 uint32_t capacity = dict->Capacity();
9624 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009625 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009626 Handle<Object> k(dict->KeyAt(j));
9627 if (dict->IsKey(*k)) {
9628 ASSERT(k->IsNumber());
9629 uint32_t index = static_cast<uint32_t>(k->Number());
9630 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009631 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009632 }
9633 }
9634 }
9635 break;
9636 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009637 default: {
9638 int dense_elements_length;
9639 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009640 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009641 dense_elements_length =
9642 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009643 break;
9644 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009645 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009646 dense_elements_length =
9647 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009648 break;
9649 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009650 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009651 dense_elements_length =
9652 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009653 break;
9654 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009655 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009656 dense_elements_length =
9657 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009658 break;
9659 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009660 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009661 dense_elements_length =
9662 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009663 break;
9664 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009665 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009666 dense_elements_length =
9667 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009668 break;
9669 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009670 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009671 dense_elements_length =
9672 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009673 break;
9674 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009675 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009676 dense_elements_length =
9677 ExternalFloatArray::cast(object->elements())->length();
9678 break;
9679 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009680 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009681 dense_elements_length =
9682 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009683 break;
9684 }
9685 default:
9686 UNREACHABLE();
9687 dense_elements_length = 0;
9688 break;
9689 }
9690 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9691 if (range <= length) {
9692 length = range;
9693 // We will add all indices, so we might as well clear it first
9694 // and avoid duplicates.
9695 indices->Clear();
9696 }
9697 for (uint32_t i = 0; i < length; i++) {
9698 indices->Add(i);
9699 }
9700 if (length == range) return; // All indices accounted for already.
9701 break;
9702 }
9703 }
9704
9705 Handle<Object> prototype(object->GetPrototype());
9706 if (prototype->IsJSObject()) {
9707 // The prototype will usually have no inherited element indices,
9708 // but we have to check.
9709 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9710 }
9711}
9712
9713
9714/**
9715 * A helper function that visits elements of a JSArray in numerical
9716 * order.
9717 *
9718 * The visitor argument called for each existing element in the array
9719 * with the element index and the element's value.
9720 * Afterwards it increments the base-index of the visitor by the array
9721 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009722 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009723 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009724static bool IterateElements(Isolate* isolate,
9725 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009726 ArrayConcatVisitor* visitor) {
9727 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9728 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009729 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009730 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009731 // Run through the elements FixedArray and use HasElement and GetElement
9732 // to check the prototype for missing elements.
9733 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9734 int fast_length = static_cast<int>(length);
9735 ASSERT(fast_length <= elements->length());
9736 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009737 HandleScope loop_scope(isolate);
9738 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009739 if (!element_value->IsTheHole()) {
9740 visitor->visit(j, element_value);
9741 } else if (receiver->HasElement(j)) {
9742 // Call GetElement on receiver, not its prototype, or getters won't
9743 // have the correct receiver.
9744 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009745 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009746 visitor->visit(j, element_value);
9747 }
9748 }
9749 break;
9750 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009751 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009752 Handle<NumberDictionary> dict(receiver->element_dictionary());
9753 List<uint32_t> indices(dict->Capacity() / 2);
9754 // Collect all indices in the object and the prototypes less
9755 // than length. This might introduce duplicates in the indices list.
9756 CollectElementIndices(receiver, length, &indices);
9757 indices.Sort(&compareUInt32);
9758 int j = 0;
9759 int n = indices.length();
9760 while (j < n) {
9761 HandleScope loop_scope;
9762 uint32_t index = indices[j];
9763 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009764 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009765 visitor->visit(index, element);
9766 // Skip to next different index (i.e., omit duplicates).
9767 do {
9768 j++;
9769 } while (j < n && indices[j] == index);
9770 }
9771 break;
9772 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009773 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009774 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9775 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009776 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009777 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009778 visitor->visit(j, e);
9779 }
9780 break;
9781 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009782 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009783 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009784 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009785 break;
9786 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009787 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009788 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009789 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009790 break;
9791 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009792 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009793 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009794 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009795 break;
9796 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009797 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009798 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009799 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009800 break;
9801 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009802 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009803 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009804 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009805 break;
9806 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009807 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009808 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009809 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009810 break;
9811 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009812 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009813 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009814 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009815 break;
9816 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009817 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009818 IterateExternalArrayElements<ExternalDoubleArray, double>(
9819 isolate, receiver, false, false, visitor);
9820 break;
9821 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009822 default:
9823 UNREACHABLE();
9824 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009825 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009826 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009827 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009828}
9829
9830
9831/**
9832 * Array::concat implementation.
9833 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009834 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009835 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009836 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009837RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009838 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009839 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009840
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009841 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9842 int argument_count = static_cast<int>(arguments->length()->Number());
9843 RUNTIME_ASSERT(arguments->HasFastElements());
9844 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009845
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009846 // Pass 1: estimate the length and number of elements of the result.
9847 // The actual length can be larger if any of the arguments have getters
9848 // that mutate other arguments (but will otherwise be precise).
9849 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009850
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009851 uint32_t estimate_result_length = 0;
9852 uint32_t estimate_nof_elements = 0;
9853 {
9854 for (int i = 0; i < argument_count; i++) {
9855 HandleScope loop_scope;
9856 Handle<Object> obj(elements->get(i));
9857 uint32_t length_estimate;
9858 uint32_t element_estimate;
9859 if (obj->IsJSArray()) {
9860 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9861 length_estimate =
9862 static_cast<uint32_t>(array->length()->Number());
9863 element_estimate =
9864 EstimateElementCount(array);
9865 } else {
9866 length_estimate = 1;
9867 element_estimate = 1;
9868 }
9869 // Avoid overflows by capping at kMaxElementCount.
9870 if (JSObject::kMaxElementCount - estimate_result_length <
9871 length_estimate) {
9872 estimate_result_length = JSObject::kMaxElementCount;
9873 } else {
9874 estimate_result_length += length_estimate;
9875 }
9876 if (JSObject::kMaxElementCount - estimate_nof_elements <
9877 element_estimate) {
9878 estimate_nof_elements = JSObject::kMaxElementCount;
9879 } else {
9880 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009881 }
9882 }
9883 }
9884
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009885 // If estimated number of elements is more than half of length, a
9886 // fixed array (fast case) is more time and space-efficient than a
9887 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009888 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009889
9890 Handle<FixedArray> storage;
9891 if (fast_case) {
9892 // The backing storage array must have non-existing elements to
9893 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009894 storage = isolate->factory()->NewFixedArrayWithHoles(
9895 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009896 } else {
9897 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9898 uint32_t at_least_space_for = estimate_nof_elements +
9899 (estimate_nof_elements >> 2);
9900 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009901 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009902 }
9903
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009904 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009905
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009906 for (int i = 0; i < argument_count; i++) {
9907 Handle<Object> obj(elements->get(i));
9908 if (obj->IsJSArray()) {
9909 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009910 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009911 return Failure::Exception();
9912 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009913 } else {
9914 visitor.visit(0, obj);
9915 visitor.increase_index_offset(1);
9916 }
9917 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009918
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009919 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009920}
9921
9922
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009923// This will not allocate (flatten the string), but it may run
9924// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009925RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009926 NoHandleAllocation ha;
9927 ASSERT(args.length() == 1);
9928
9929 CONVERT_CHECKED(String, string, args[0]);
9930 StringInputBuffer buffer(string);
9931 while (buffer.has_more()) {
9932 uint16_t character = buffer.GetNext();
9933 PrintF("%c", character);
9934 }
9935 return string;
9936}
9937
ager@chromium.org5ec48922009-05-05 07:25:34 +00009938// Moves all own elements of an object, that are below a limit, to positions
9939// starting at zero. All undefined values are placed after non-undefined values,
9940// and are followed by non-existing element. Does not change the length
9941// property.
9942// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009943RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009944 ASSERT(args.length() == 2);
9945 CONVERT_CHECKED(JSObject, object, args[0]);
9946 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9947 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009948}
9949
9950
9951// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009952RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009953 ASSERT(args.length() == 2);
9954 CONVERT_CHECKED(JSArray, from, args[0]);
9955 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009956 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009957 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009958 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009959 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9960 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009961 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009962 } else if (new_elements->map() ==
9963 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009964 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009965 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009966 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009967 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009968 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009969 Object* new_map;
9970 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009971 to->set_map(Map::cast(new_map));
9972 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009973 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009974 Object* obj;
9975 { MaybeObject* maybe_obj = from->ResetElements();
9976 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9977 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009978 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009979 return to;
9980}
9981
9982
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009983// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009984RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009985 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009986 CONVERT_CHECKED(JSObject, object, args[0]);
9987 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009988 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009989 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009990 } else if (object->IsJSArray()) {
9991 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009992 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009993 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009994 }
9995}
9996
9997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009998RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009999 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010000
10001 ASSERT_EQ(3, args.length());
10002
ager@chromium.orgac091b72010-05-05 07:34:42 +000010003 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010004 Handle<Object> key1 = args.at<Object>(1);
10005 Handle<Object> key2 = args.at<Object>(2);
10006
10007 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010008 if (!key1->ToArrayIndex(&index1)
10009 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010010 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010011 }
10012
ager@chromium.orgac091b72010-05-05 07:34:42 +000010013 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
10014 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010015 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010016 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010017 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010019 RETURN_IF_EMPTY_HANDLE(isolate,
10020 SetElement(jsobject, index1, tmp2, kStrictMode));
10021 RETURN_IF_EMPTY_HANDLE(isolate,
10022 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010023
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010024 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010025}
10026
10027
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010028// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010029// might have elements. Can either return keys (positive integers) or
10030// intervals (pair of a negative integer (-start-1) followed by a
10031// positive (length)) or undefined values.
10032// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010033RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010034 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010035 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010036 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010037 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010038 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010039 // Create an array and get all the keys into it, then remove all the
10040 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010041 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010042 int keys_length = keys->length();
10043 for (int i = 0; i < keys_length; i++) {
10044 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010045 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010046 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010047 // Zap invalid keys.
10048 keys->set_undefined(i);
10049 }
10050 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010051 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010052 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010053 ASSERT(array->HasFastElements() ||
10054 array->HasFastSmiOnlyElements() ||
10055 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010056 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010057 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010058 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010059 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010060 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010061 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010062 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010063 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010064 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010065 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010066 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010067 }
10068}
10069
10070
10071// DefineAccessor takes an optional final argument which is the
10072// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10073// to the way accessors are implemented, it is set for both the getter
10074// and setter on the first call to DefineAccessor and ignored on
10075// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010076RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010077 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10078 // Compute attributes.
10079 PropertyAttributes attributes = NONE;
10080 if (args.length() == 5) {
10081 CONVERT_CHECKED(Smi, attrs, args[4]);
10082 int value = attrs->value();
10083 // Only attribute bits should be set.
10084 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10085 attributes = static_cast<PropertyAttributes>(value);
10086 }
10087
10088 CONVERT_CHECKED(JSObject, obj, args[0]);
10089 CONVERT_CHECKED(String, name, args[1]);
10090 CONVERT_CHECKED(Smi, flag, args[2]);
10091 CONVERT_CHECKED(JSFunction, fun, args[3]);
10092 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10093}
10094
10095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010096RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010097 ASSERT(args.length() == 3);
10098 CONVERT_CHECKED(JSObject, obj, args[0]);
10099 CONVERT_CHECKED(String, name, args[1]);
10100 CONVERT_CHECKED(Smi, flag, args[2]);
10101 return obj->LookupAccessor(name, flag->value() == 0);
10102}
10103
10104
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010105#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010106RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010107 ASSERT(args.length() == 0);
10108 return Execution::DebugBreakHelper();
10109}
10110
10111
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010112// Helper functions for wrapping and unwrapping stack frame ids.
10113static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010114 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010115 return Smi::FromInt(id >> 2);
10116}
10117
10118
10119static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10120 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10121}
10122
10123
10124// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010125// args[0]: debug event listener function to set or null or undefined for
10126// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010127// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010128RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010129 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010130 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10131 args[0]->IsUndefined() ||
10132 args[0]->IsNull());
10133 Handle<Object> callback = args.at<Object>(0);
10134 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010135 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010136
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010137 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010138}
10139
10140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010141RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010142 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010143 isolate->stack_guard()->DebugBreak();
10144 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010145}
10146
10147
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010148static MaybeObject* DebugLookupResultValue(Heap* heap,
10149 Object* receiver,
10150 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010151 LookupResult* result,
10152 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010153 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010154 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010155 case NORMAL:
10156 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010157 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010158 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010159 }
10160 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010161 case FIELD:
10162 value =
10163 JSObject::cast(
10164 result->holder())->FastPropertyAt(result->GetFieldIndex());
10165 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010166 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010167 }
10168 return value;
10169 case CONSTANT_FUNCTION:
10170 return result->GetConstantFunction();
10171 case CALLBACKS: {
10172 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010173 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010174 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10175 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010176 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010177 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010178 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010179 maybe_value = heap->isolate()->pending_exception();
10180 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010181 if (caught_exception != NULL) {
10182 *caught_exception = true;
10183 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010184 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010185 }
10186 return value;
10187 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010188 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010189 }
10190 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010191 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010192 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010193 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010194 case CONSTANT_TRANSITION:
10195 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010196 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010197 default:
10198 UNREACHABLE();
10199 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010200 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010201 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010202}
10203
10204
ager@chromium.org32912102009-01-16 10:38:43 +000010205// Get debugger related details for an object property.
10206// args[0]: object holding property
10207// args[1]: name of the property
10208//
10209// The array returned contains the following information:
10210// 0: Property value
10211// 1: Property details
10212// 2: Property value is exception
10213// 3: Getter function if defined
10214// 4: Setter function if defined
10215// Items 2-4 are only filled if the property has either a getter or a setter
10216// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010217RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010218 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010219
10220 ASSERT(args.length() == 2);
10221
10222 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10223 CONVERT_ARG_CHECKED(String, name, 1);
10224
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010225 // Make sure to set the current context to the context before the debugger was
10226 // entered (if the debugger is entered). The reason for switching context here
10227 // is that for some property lookups (accessors and interceptors) callbacks
10228 // into the embedding application can occour, and the embedding application
10229 // could have the assumption that its own global context is the current
10230 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010231 SaveContext save(isolate);
10232 if (isolate->debug()->InDebugger()) {
10233 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010234 }
10235
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010236 // Skip the global proxy as it has no properties and always delegates to the
10237 // real global object.
10238 if (obj->IsJSGlobalProxy()) {
10239 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10240 }
10241
10242
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010243 // Check if the name is trivially convertible to an index and get the element
10244 // if so.
10245 uint32_t index;
10246 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010247 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010248 Object* element_or_char;
10249 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010250 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010251 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10252 return maybe_element_or_char;
10253 }
10254 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010255 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010256 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010257 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010258 }
10259
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010260 // Find the number of objects making up this.
10261 int length = LocalPrototypeChainLength(*obj);
10262
10263 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010264 Handle<JSObject> jsproto = obj;
10265 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010266 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010267 jsproto->LocalLookup(*name, &result);
10268 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010269 // LookupResult is not GC safe as it holds raw object pointers.
10270 // GC can happen later in this code so put the required fields into
10271 // local variables using handles when required for later use.
10272 PropertyType result_type = result.type();
10273 Handle<Object> result_callback_obj;
10274 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010275 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10276 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010277 }
10278 Smi* property_details = result.GetPropertyDetails().AsSmi();
10279 // DebugLookupResultValue can cause GC so details from LookupResult needs
10280 // to be copied to handles before this.
10281 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010282 Object* raw_value;
10283 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010284 DebugLookupResultValue(isolate->heap(), *obj, *name,
10285 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010286 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10287 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010288 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010289
10290 // If the callback object is a fixed array then it contains JavaScript
10291 // getter and/or setter.
10292 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10293 result_callback_obj->IsFixedArray();
10294 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010295 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010296 details->set(0, *value);
10297 details->set(1, property_details);
10298 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010299 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010300 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10301 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10302 }
10303
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010304 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010305 }
10306 if (i < length - 1) {
10307 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10308 }
10309 }
10310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010311 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010312}
10313
10314
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010315RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010316 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010317
10318 ASSERT(args.length() == 2);
10319
10320 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10321 CONVERT_ARG_CHECKED(String, name, 1);
10322
10323 LookupResult result;
10324 obj->Lookup(*name, &result);
10325 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010326 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010327 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010328 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010329}
10330
10331
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010332// Return the property type calculated from the property details.
10333// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010334RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010335 ASSERT(args.length() == 1);
10336 CONVERT_CHECKED(Smi, details, args[0]);
10337 PropertyType type = PropertyDetails(details).type();
10338 return Smi::FromInt(static_cast<int>(type));
10339}
10340
10341
10342// Return the property attribute calculated from the property details.
10343// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010344RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010345 ASSERT(args.length() == 1);
10346 CONVERT_CHECKED(Smi, details, args[0]);
10347 PropertyAttributes attributes = PropertyDetails(details).attributes();
10348 return Smi::FromInt(static_cast<int>(attributes));
10349}
10350
10351
10352// Return the property insertion index calculated from the property details.
10353// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010354RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010355 ASSERT(args.length() == 1);
10356 CONVERT_CHECKED(Smi, details, args[0]);
10357 int index = PropertyDetails(details).index();
10358 return Smi::FromInt(index);
10359}
10360
10361
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010362// Return property value from named interceptor.
10363// args[0]: object
10364// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010365RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010366 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010367 ASSERT(args.length() == 2);
10368 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10369 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10370 CONVERT_ARG_CHECKED(String, name, 1);
10371
10372 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010373 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010374}
10375
10376
10377// Return element value from indexed interceptor.
10378// args[0]: object
10379// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010380RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010381 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010382 ASSERT(args.length() == 2);
10383 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10384 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10385 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10386
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010387 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010388}
10389
10390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010391RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010392 ASSERT(args.length() >= 1);
10393 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010394 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010395 if (isolate->debug()->break_id() == 0 ||
10396 break_id != isolate->debug()->break_id()) {
10397 return isolate->Throw(
10398 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010399 }
10400
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010401 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010402}
10403
10404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010405RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010406 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010407 ASSERT(args.length() == 1);
10408
10409 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010410 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010411 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10412 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010413 if (!maybe_result->ToObject(&result)) return maybe_result;
10414 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010415
10416 // Count all frames which are relevant to debugging stack trace.
10417 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010418 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010419 if (id == StackFrame::NO_ID) {
10420 // If there is no JavaScript stack frame count is 0.
10421 return Smi::FromInt(0);
10422 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010423
10424 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10425 n += it.frame()->GetInlineCount();
10426 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010427 return Smi::FromInt(n);
10428}
10429
10430
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010431class FrameInspector {
10432 public:
10433 FrameInspector(JavaScriptFrame* frame,
10434 int inlined_frame_index,
10435 Isolate* isolate)
10436 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10437 // Calculate the deoptimized frame.
10438 if (frame->is_optimized()) {
10439 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10440 frame, inlined_frame_index, isolate);
10441 }
10442 has_adapted_arguments_ = frame_->has_adapted_arguments();
10443 is_optimized_ = frame_->is_optimized();
10444 }
10445
10446 ~FrameInspector() {
10447 // Get rid of the calculated deoptimized frame if any.
10448 if (deoptimized_frame_ != NULL) {
10449 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10450 isolate_);
10451 }
10452 }
10453
10454 int GetParametersCount() {
10455 return is_optimized_
10456 ? deoptimized_frame_->parameters_count()
10457 : frame_->ComputeParametersCount();
10458 }
10459 int expression_count() { return deoptimized_frame_->expression_count(); }
10460 Object* GetFunction() {
10461 return is_optimized_
10462 ? deoptimized_frame_->GetFunction()
10463 : frame_->function();
10464 }
10465 Object* GetParameter(int index) {
10466 return is_optimized_
10467 ? deoptimized_frame_->GetParameter(index)
10468 : frame_->GetParameter(index);
10469 }
10470 Object* GetExpression(int index) {
10471 return is_optimized_
10472 ? deoptimized_frame_->GetExpression(index)
10473 : frame_->GetExpression(index);
10474 }
10475
10476 // To inspect all the provided arguments the frame might need to be
10477 // replaced with the arguments frame.
10478 void SetArgumentsFrame(JavaScriptFrame* frame) {
10479 ASSERT(has_adapted_arguments_);
10480 frame_ = frame;
10481 is_optimized_ = frame_->is_optimized();
10482 ASSERT(!is_optimized_);
10483 }
10484
10485 private:
10486 JavaScriptFrame* frame_;
10487 DeoptimizedFrameInfo* deoptimized_frame_;
10488 Isolate* isolate_;
10489 bool is_optimized_;
10490 bool has_adapted_arguments_;
10491
10492 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10493};
10494
10495
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010496static const int kFrameDetailsFrameIdIndex = 0;
10497static const int kFrameDetailsReceiverIndex = 1;
10498static const int kFrameDetailsFunctionIndex = 2;
10499static const int kFrameDetailsArgumentCountIndex = 3;
10500static const int kFrameDetailsLocalCountIndex = 4;
10501static const int kFrameDetailsSourcePositionIndex = 5;
10502static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010503static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010504static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010505static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010506
10507// Return an array with frame details
10508// args[0]: number: break id
10509// args[1]: number: frame index
10510//
10511// The array returned contains the following information:
10512// 0: Frame id
10513// 1: Receiver
10514// 2: Function
10515// 3: Argument count
10516// 4: Local count
10517// 5: Source position
10518// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010519// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010520// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010521// Arguments name, value
10522// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010523// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010524RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010525 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010526 ASSERT(args.length() == 2);
10527
10528 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010529 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010530 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10531 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010532 if (!maybe_check->ToObject(&check)) return maybe_check;
10533 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010535 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010536
10537 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010538 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010539 if (id == StackFrame::NO_ID) {
10540 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010541 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010542 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010543
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010544 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010545
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010546 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010547 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010548 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010549 if (index < count + it.frame()->GetInlineCount()) break;
10550 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010551 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010552 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010553
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010554 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010555 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010556 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010557 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010558 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010559
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010560 // Traverse the saved contexts chain to find the active context for the
10561 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010562 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010563 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010564 save = save->prev();
10565 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010566 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010567
10568 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010569 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010570
10571 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010572 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010573 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010575 // Check for constructor frame. Inlined frames cannot be construct calls.
10576 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010577 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010578 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010579
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010580 // Get scope info and read from it for local variable information.
10581 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010582 Handle<SharedFunctionInfo> shared(function->shared());
10583 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010584 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010585 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010586
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010587 // Get the locals names and values into a temporary array.
10588 //
10589 // TODO(1240907): Hide compiler-introduced stack variables
10590 // (e.g. .result)? For users of the debugger, they will probably be
10591 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010592 Handle<FixedArray> locals =
10593 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010595 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010596 int i = 0;
10597 for (; i < info.number_of_stack_slots(); ++i) {
10598 // Use the value from the stack.
10599 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010600 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010601 }
10602 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010603 // Get the context containing declarations.
10604 Handle<Context> context(
10605 Context::cast(it.frame()->context())->declaration_context());
10606 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010607 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010608 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010610 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010611 }
10612 }
10613
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010614 // Check whether this frame is positioned at return. If not top
10615 // frame or if the frame is optimized it cannot be at a return.
10616 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010617 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010618 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010619 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010620
10621 // If positioned just before return find the value to be returned and add it
10622 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010623 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010624 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010625 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010626 Address internal_frame_sp = NULL;
10627 while (!it2.done()) {
10628 if (it2.frame()->is_internal()) {
10629 internal_frame_sp = it2.frame()->sp();
10630 } else {
10631 if (it2.frame()->is_java_script()) {
10632 if (it2.frame()->id() == it.frame()->id()) {
10633 // The internal frame just before the JavaScript frame contains the
10634 // value to return on top. A debug break at return will create an
10635 // internal frame to store the return value (eax/rax/r0) before
10636 // entering the debug break exit frame.
10637 if (internal_frame_sp != NULL) {
10638 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010639 Handle<Object>(Memory::Object_at(internal_frame_sp),
10640 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010641 break;
10642 }
10643 }
10644 }
10645
10646 // Indicate that the previous frame was not an internal frame.
10647 internal_frame_sp = NULL;
10648 }
10649 it2.Advance();
10650 }
10651 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010652
10653 // Now advance to the arguments adapter frame (if any). It contains all
10654 // the provided parameters whereas the function frame always have the number
10655 // of arguments matching the functions parameters. The rest of the
10656 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010657 if (it.frame()->has_adapted_arguments()) {
10658 it.AdvanceToArgumentsFrame();
10659 frame_inspector.SetArgumentsFrame(it.frame());
10660 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010661
10662 // Find the number of arguments to fill. At least fill the number of
10663 // parameters for the function and fill more if more parameters are provided.
10664 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010665 if (argument_count < frame_inspector.GetParametersCount()) {
10666 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010667 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010668#ifdef DEBUG
10669 if (it.frame()->is_optimized()) {
10670 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10671 }
10672#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010673
10674 // Calculate the size of the result.
10675 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010676 2 * (argument_count + info.NumberOfLocals()) +
10677 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010678 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010679
10680 // Add the frame id.
10681 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10682
10683 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010684 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010685
10686 // Add the arguments count.
10687 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10688
10689 // Add the locals count
10690 details->set(kFrameDetailsLocalCountIndex,
10691 Smi::FromInt(info.NumberOfLocals()));
10692
10693 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010694 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010695 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10696 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010697 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010698 }
10699
10700 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010701 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010702
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010703 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010704 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010705
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010706 // Add flags to indicate information on whether this frame is
10707 // bit 0: invoked in the debugger context.
10708 // bit 1: optimized frame.
10709 // bit 2: inlined in optimized frame
10710 int flags = 0;
10711 if (*save->context() == *isolate->debug()->debug_context()) {
10712 flags |= 1 << 0;
10713 }
10714 if (it.frame()->is_optimized()) {
10715 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010716 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010717 }
10718 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010719
10720 // Fill the dynamic part.
10721 int details_index = kFrameDetailsFirstDynamicIndex;
10722
10723 // Add arguments name and value.
10724 for (int i = 0; i < argument_count; i++) {
10725 // Name of the argument.
10726 if (i < info.number_of_parameters()) {
10727 details->set(details_index++, *info.parameter_name(i));
10728 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010729 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010730 }
10731
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010732 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010733 if (i < it.frame()->ComputeParametersCount()) {
10734 // Get the value from the stack.
10735 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010736 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010737 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010738 }
10739 }
10740
10741 // Add locals name and value from the temporary copy from the function frame.
10742 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10743 details->set(details_index++, locals->get(i));
10744 }
10745
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010746 // Add the value being returned.
10747 if (at_return) {
10748 details->set(details_index++, *return_value);
10749 }
10750
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010751 // Add the receiver (same as in function frame).
10752 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10753 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010754 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010755 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10756 // If the receiver is not a JSObject and the function is not a
10757 // builtin or strict-mode we have hit an optimization where a
10758 // value object is not converted into a wrapped JS objects. To
10759 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010760 // by creating correct wrapper object based on the calling frame's
10761 // global context.
10762 it.Advance();
10763 Handle<Context> calling_frames_global_context(
10764 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010765 receiver =
10766 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010767 }
10768 details->set(kFrameDetailsReceiverIndex, *receiver);
10769
10770 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010771 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010772}
10773
10774
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010775// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010776static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010777 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010778 Handle<SerializedScopeInfo> serialized_scope_info,
10779 ScopeInfo<>& scope_info,
10780 Handle<Context> context,
10781 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010782 // Fill all context locals to the context extension.
10783 for (int i = Context::MIN_CONTEXT_SLOTS;
10784 i < scope_info.number_of_context_slots();
10785 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010786 int context_index = serialized_scope_info->ContextSlotIndex(
10787 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010788
whesse@chromium.org7b260152011-06-20 15:33:18 +000010789 RETURN_IF_EMPTY_HANDLE_VALUE(
10790 isolate,
10791 SetProperty(scope_object,
10792 scope_info.context_slot_name(i),
10793 Handle<Object>(context->get(context_index), isolate),
10794 NONE,
10795 kNonStrictMode),
10796 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010797 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010798
10799 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010800}
10801
10802
10803// Create a plain JSObject which materializes the local scope for the specified
10804// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010805static Handle<JSObject> MaterializeLocalScope(
10806 Isolate* isolate,
10807 JavaScriptFrame* frame,
10808 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010809 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010810 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010811 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10812 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010813 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010814
10815 // Allocate and initialize a JSObject with all the arguments, stack locals
10816 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010817 Handle<JSObject> local_scope =
10818 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010819
10820 // First fill all parameters.
10821 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010822 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010823 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010824 SetProperty(local_scope,
10825 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010826 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010827 NONE,
10828 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010829 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010830 }
10831
10832 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010833 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010834 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010835 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010836 SetProperty(local_scope,
10837 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010838 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010839 NONE,
10840 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010841 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010842 }
10843
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010844 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10845 // Third fill all context locals.
10846 Handle<Context> frame_context(Context::cast(frame->context()));
10847 Handle<Context> function_context(frame_context->declaration_context());
10848 if (!CopyContextLocalsToScopeObject(isolate,
10849 serialized_scope_info, scope_info,
10850 function_context, local_scope)) {
10851 return Handle<JSObject>();
10852 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010853
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010854 // Finally copy any properties from the function context extension.
10855 // These will be variables introduced by eval.
10856 if (function_context->closure() == *function) {
10857 if (function_context->has_extension() &&
10858 !function_context->IsGlobalContext()) {
10859 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10860 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10861 for (int i = 0; i < keys->length(); i++) {
10862 // Names of variables introduced by eval are strings.
10863 ASSERT(keys->get(i)->IsString());
10864 Handle<String> key(String::cast(keys->get(i)));
10865 RETURN_IF_EMPTY_HANDLE_VALUE(
10866 isolate,
10867 SetProperty(local_scope,
10868 key,
10869 GetProperty(ext, key),
10870 NONE,
10871 kNonStrictMode),
10872 Handle<JSObject>());
10873 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010874 }
10875 }
10876 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010877
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010878 return local_scope;
10879}
10880
10881
10882// Create a plain JSObject which materializes the closure content for the
10883// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010884static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10885 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010886 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010887
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010888 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010889 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10890 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010891
10892 // Allocate and initialize a JSObject with all the content of theis function
10893 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010894 Handle<JSObject> closure_scope =
10895 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010896
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010897 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010898 if (!CopyContextLocalsToScopeObject(isolate,
10899 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010900 context, closure_scope)) {
10901 return Handle<JSObject>();
10902 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010903
10904 // Finally copy any properties from the function context extension. This will
10905 // be variables introduced by eval.
10906 if (context->has_extension()) {
10907 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010908 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010909 for (int i = 0; i < keys->length(); i++) {
10910 // Names of variables introduced by eval are strings.
10911 ASSERT(keys->get(i)->IsString());
10912 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010913 RETURN_IF_EMPTY_HANDLE_VALUE(
10914 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010915 SetProperty(closure_scope,
10916 key,
10917 GetProperty(ext, key),
10918 NONE,
10919 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010920 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010921 }
10922 }
10923
10924 return closure_scope;
10925}
10926
10927
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010928// Create a plain JSObject which materializes the scope for the specified
10929// catch context.
10930static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10931 Handle<Context> context) {
10932 ASSERT(context->IsCatchContext());
10933 Handle<String> name(String::cast(context->extension()));
10934 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10935 Handle<JSObject> catch_scope =
10936 isolate->factory()->NewJSObject(isolate->object_function());
10937 RETURN_IF_EMPTY_HANDLE_VALUE(
10938 isolate,
10939 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10940 Handle<JSObject>());
10941 return catch_scope;
10942}
10943
10944
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010945// Create a plain JSObject which materializes the block scope for the specified
10946// block context.
10947static Handle<JSObject> MaterializeBlockScope(
10948 Isolate* isolate,
10949 Handle<Context> context) {
10950 ASSERT(context->IsBlockContext());
10951 Handle<SerializedScopeInfo> serialized_scope_info(
10952 SerializedScopeInfo::cast(context->extension()));
10953 ScopeInfo<> scope_info(*serialized_scope_info);
10954
10955 // Allocate and initialize a JSObject with all the arguments, stack locals
10956 // heap locals and extension properties of the debugged function.
10957 Handle<JSObject> block_scope =
10958 isolate->factory()->NewJSObject(isolate->object_function());
10959
10960 // Fill all context locals.
10961 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10962 if (!CopyContextLocalsToScopeObject(isolate,
10963 serialized_scope_info, scope_info,
10964 context, block_scope)) {
10965 return Handle<JSObject>();
10966 }
10967 }
10968
10969 return block_scope;
10970}
10971
10972
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010973// Iterate over the actual scopes visible from a stack frame. All scopes are
10974// backed by an actual context except the local scope, which is inserted
10975// "artifically" in the context chain.
10976class ScopeIterator {
10977 public:
10978 enum ScopeType {
10979 ScopeTypeGlobal = 0,
10980 ScopeTypeLocal,
10981 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010982 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010983 ScopeTypeCatch,
10984 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010985 };
10986
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010987 ScopeIterator(Isolate* isolate,
10988 JavaScriptFrame* frame,
10989 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010990 : isolate_(isolate),
10991 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010992 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010993 function_(JSFunction::cast(frame->function())),
10994 context_(Context::cast(frame->context())),
10995 local_done_(false),
10996 at_local_(false) {
10997
10998 // Check whether the first scope is actually a local scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000010999 // If there is a stack slot for .result then this local scope has been
11000 // created for evaluating top level code and it is not a real local scope.
11001 // Checking for the existence of .result seems fragile, but the scope info
11002 // saved with the code object does not otherwise have that information.
11003 int index = function_->shared()->scope_info()->
11004 StackSlotIndex(isolate_->heap()->result_symbol());
11005 if (index >= 0) {
11006 local_done_ = true;
11007 } else if (context_->IsGlobalContext() ||
11008 context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011009 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011010 } else if (context_->closure() != *function_) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011011 // The context_ is a block or with or catch block from the outer function.
11012 ASSERT(context_->IsWithContext() ||
11013 context_->IsCatchContext() ||
11014 context_->IsBlockContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011015 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011016 }
11017 }
11018
11019 // More scopes?
11020 bool Done() { return context_.is_null(); }
11021
11022 // Move to the next scope.
11023 void Next() {
11024 // If at a local scope mark the local scope as passed.
11025 if (at_local_) {
11026 at_local_ = false;
11027 local_done_ = true;
11028
11029 // If the current context is not associated with the local scope the
11030 // current context is the next real scope, so don't move to the next
11031 // context in this case.
11032 if (context_->closure() != *function_) {
11033 return;
11034 }
11035 }
11036
11037 // The global scope is always the last in the chain.
11038 if (context_->IsGlobalContext()) {
11039 context_ = Handle<Context>();
11040 return;
11041 }
11042
11043 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011044 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011045
11046 // If passing the local scope indicate that the current scope is now the
11047 // local scope.
11048 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011049 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011050 at_local_ = true;
11051 }
11052 }
11053
11054 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011055 ScopeType Type() {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011056 if (at_local_) {
11057 return ScopeTypeLocal;
11058 }
11059 if (context_->IsGlobalContext()) {
11060 ASSERT(context_->global()->IsGlobalObject());
11061 return ScopeTypeGlobal;
11062 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011063 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011064 return ScopeTypeClosure;
11065 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011066 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011067 return ScopeTypeCatch;
11068 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011069 if (context_->IsBlockContext()) {
11070 return ScopeTypeBlock;
11071 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011072 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011073 return ScopeTypeWith;
11074 }
11075
11076 // Return the JavaScript object with the content of the current scope.
11077 Handle<JSObject> ScopeObject() {
11078 switch (Type()) {
11079 case ScopeIterator::ScopeTypeGlobal:
11080 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011081 case ScopeIterator::ScopeTypeLocal:
11082 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011083 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011084 case ScopeIterator::ScopeTypeWith:
11085 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011086 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11087 case ScopeIterator::ScopeTypeCatch:
11088 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011089 case ScopeIterator::ScopeTypeClosure:
11090 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011091 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011092 case ScopeIterator::ScopeTypeBlock:
11093 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011094 }
11095 UNREACHABLE();
11096 return Handle<JSObject>();
11097 }
11098
11099 // Return the context for this scope. For the local context there might not
11100 // be an actual context.
11101 Handle<Context> CurrentContext() {
11102 if (at_local_ && context_->closure() != *function_) {
11103 return Handle<Context>();
11104 }
11105 return context_;
11106 }
11107
11108#ifdef DEBUG
11109 // Debug print of the content of the current scope.
11110 void DebugPrint() {
11111 switch (Type()) {
11112 case ScopeIterator::ScopeTypeGlobal:
11113 PrintF("Global:\n");
11114 CurrentContext()->Print();
11115 break;
11116
11117 case ScopeIterator::ScopeTypeLocal: {
11118 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011119 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011120 scope_info.Print();
11121 if (!CurrentContext().is_null()) {
11122 CurrentContext()->Print();
11123 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011124 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011125 if (extension->IsJSContextExtensionObject()) {
11126 extension->Print();
11127 }
11128 }
11129 }
11130 break;
11131 }
11132
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011133 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011134 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011135 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011136 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011137
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011138 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011139 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011140 CurrentContext()->extension()->Print();
11141 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011142 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011143
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011144 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011145 PrintF("Closure:\n");
11146 CurrentContext()->Print();
11147 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011148 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011149 if (extension->IsJSContextExtensionObject()) {
11150 extension->Print();
11151 }
11152 }
11153 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011154
11155 default:
11156 UNREACHABLE();
11157 }
11158 PrintF("\n");
11159 }
11160#endif
11161
11162 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011163 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011164 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011165 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011166 Handle<JSFunction> function_;
11167 Handle<Context> context_;
11168 bool local_done_;
11169 bool at_local_;
11170
11171 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11172};
11173
11174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011175RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011176 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011177 ASSERT(args.length() == 2);
11178
11179 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011180 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011181 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11182 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011183 if (!maybe_check->ToObject(&check)) return maybe_check;
11184 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011185 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11186
11187 // Get the frame where the debugging is performed.
11188 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011189 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011190 JavaScriptFrame* frame = it.frame();
11191
11192 // Count the visible scopes.
11193 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011194 for (ScopeIterator it(isolate, frame, 0);
11195 !it.Done();
11196 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011197 n++;
11198 }
11199
11200 return Smi::FromInt(n);
11201}
11202
11203
11204static const int kScopeDetailsTypeIndex = 0;
11205static const int kScopeDetailsObjectIndex = 1;
11206static const int kScopeDetailsSize = 2;
11207
11208// Return an array with scope details
11209// args[0]: number: break id
11210// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011211// args[2]: number: inlined frame index
11212// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011213//
11214// The array returned contains the following information:
11215// 0: Scope type
11216// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011217RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011218 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011219 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011220
11221 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011222 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011223 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11224 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011225 if (!maybe_check->ToObject(&check)) return maybe_check;
11226 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011227 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011228 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11229 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011230
11231 // Get the frame where the debugging is performed.
11232 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011233 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011234 JavaScriptFrame* frame = frame_it.frame();
11235
11236 // Find the requested scope.
11237 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011238 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011239 for (; !it.Done() && n < index; it.Next()) {
11240 n++;
11241 }
11242 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011243 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011244 }
11245
11246 // Calculate the size of the result.
11247 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011248 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011249
11250 // Fill in scope details.
11251 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011252 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011253 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011254 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011255
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011256 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011257}
11258
11259
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011260RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011261 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011262 ASSERT(args.length() == 0);
11263
11264#ifdef DEBUG
11265 // Print the scopes for the top frame.
11266 StackFrameLocator locator;
11267 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011268 for (ScopeIterator it(isolate, frame, 0);
11269 !it.Done();
11270 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011271 it.DebugPrint();
11272 }
11273#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011274 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011275}
11276
11277
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011278RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011279 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011280 ASSERT(args.length() == 1);
11281
11282 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011283 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011284 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11285 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011286 if (!maybe_result->ToObject(&result)) return maybe_result;
11287 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011288
11289 // Count all archived V8 threads.
11290 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011291 for (ThreadState* thread =
11292 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011293 thread != NULL;
11294 thread = thread->Next()) {
11295 n++;
11296 }
11297
11298 // Total number of threads is current thread and archived threads.
11299 return Smi::FromInt(n + 1);
11300}
11301
11302
11303static const int kThreadDetailsCurrentThreadIndex = 0;
11304static const int kThreadDetailsThreadIdIndex = 1;
11305static const int kThreadDetailsSize = 2;
11306
11307// Return an array with thread details
11308// args[0]: number: break id
11309// args[1]: number: thread index
11310//
11311// The array returned contains the following information:
11312// 0: Is current thread?
11313// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011314RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011315 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011316 ASSERT(args.length() == 2);
11317
11318 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011319 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011320 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11321 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011322 if (!maybe_check->ToObject(&check)) return maybe_check;
11323 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011324 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11325
11326 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011327 Handle<FixedArray> details =
11328 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011329
11330 // Thread index 0 is current thread.
11331 if (index == 0) {
11332 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011333 details->set(kThreadDetailsCurrentThreadIndex,
11334 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011335 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011336 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011337 } else {
11338 // Find the thread with the requested index.
11339 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011340 ThreadState* thread =
11341 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011342 while (index != n && thread != NULL) {
11343 thread = thread->Next();
11344 n++;
11345 }
11346 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011347 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011348 }
11349
11350 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011351 details->set(kThreadDetailsCurrentThreadIndex,
11352 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011353 details->set(kThreadDetailsThreadIdIndex,
11354 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011355 }
11356
11357 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011358 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011359}
11360
11361
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011362// Sets the disable break state
11363// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011364RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011365 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011366 ASSERT(args.length() == 1);
11367 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011368 isolate->debug()->set_disable_break(disable_break);
11369 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011370}
11371
11372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011373RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011374 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011375 ASSERT(args.length() == 1);
11376
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011377 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11378 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011379 // Find the number of break points
11380 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011381 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011382 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011383 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011384 Handle<FixedArray>::cast(break_locations));
11385}
11386
11387
11388// Set a break point in a function
11389// args[0]: function
11390// args[1]: number: break source position (within the function source)
11391// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011392RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011393 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011394 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011395 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11396 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011397 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11398 RUNTIME_ASSERT(source_position >= 0);
11399 Handle<Object> break_point_object_arg = args.at<Object>(2);
11400
11401 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011402 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11403 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011404
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011405 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011406}
11407
11408
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011409Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11410 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011411 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011412 // Iterate the heap looking for SharedFunctionInfo generated from the
11413 // script. The inner most SharedFunctionInfo containing the source position
11414 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011415 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011416 // which is found is not compiled it is compiled and the heap is iterated
11417 // again as the compilation might create inner functions from the newly
11418 // compiled function and the actual requested break point might be in one of
11419 // these functions.
11420 bool done = false;
11421 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011422 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011423 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011424 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011425 { // Extra scope for iterator and no-allocation.
11426 isolate->heap()->EnsureHeapIsIterable();
11427 AssertNoAllocation no_alloc_during_heap_iteration;
11428 HeapIterator iterator;
11429 for (HeapObject* obj = iterator.next();
11430 obj != NULL; obj = iterator.next()) {
11431 if (obj->IsSharedFunctionInfo()) {
11432 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11433 if (shared->script() == *script) {
11434 // If the SharedFunctionInfo found has the requested script data and
11435 // contains the source position it is a candidate.
11436 int start_position = shared->function_token_position();
11437 if (start_position == RelocInfo::kNoPosition) {
11438 start_position = shared->start_position();
11439 }
11440 if (start_position <= position &&
11441 position <= shared->end_position()) {
11442 // If there is no candidate or this function is within the current
11443 // candidate this is the new candidate.
11444 if (target.is_null()) {
11445 target_start_position = start_position;
11446 target = shared;
11447 } else {
11448 if (target_start_position == start_position &&
11449 shared->end_position() == target->end_position()) {
11450 // If a top-level function contain only one function
11451 // declartion the source for the top-level and the
11452 // function is the same. In that case prefer the non
11453 // top-level function.
11454 if (!shared->is_toplevel()) {
11455 target_start_position = start_position;
11456 target = shared;
11457 }
11458 } else if (target_start_position <= start_position &&
11459 shared->end_position() <= target->end_position()) {
11460 // This containment check includes equality as a function
11461 // inside a top-level function can share either start or end
11462 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011463 target_start_position = start_position;
11464 target = shared;
11465 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011466 }
11467 }
11468 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011469 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011470 } // End for loop.
11471 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011472
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011473 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011474 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011475 }
11476
11477 // If the candidate found is compiled we are done. NOTE: when lazy
11478 // compilation of inner functions is introduced some additional checking
11479 // needs to be done here to compile inner functions.
11480 done = target->is_compiled();
11481 if (!done) {
11482 // If the candidate is not compiled compile it to reveal any inner
11483 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011484 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011485 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011486 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011487
11488 return *target;
11489}
11490
11491
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011492// Changes the state of a break point in a script and returns source position
11493// where break point was set. NOTE: Regarding performance see the NOTE for
11494// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011495// args[0]: script to set break point in
11496// args[1]: number: break source position (within the script source)
11497// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011498RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011499 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011500 ASSERT(args.length() == 3);
11501 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11502 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11503 RUNTIME_ASSERT(source_position >= 0);
11504 Handle<Object> break_point_object_arg = args.at<Object>(2);
11505
11506 // Get the script from the script wrapper.
11507 RUNTIME_ASSERT(wrapper->value()->IsScript());
11508 Handle<Script> script(Script::cast(wrapper->value()));
11509
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011510 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011511 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011512 if (!result->IsUndefined()) {
11513 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11514 // Find position within function. The script position might be before the
11515 // source position of the first function.
11516 int position;
11517 if (shared->start_position() > source_position) {
11518 position = 0;
11519 } else {
11520 position = source_position - shared->start_position();
11521 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011522 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011523 position += shared->start_position();
11524 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011525 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011526 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011527}
11528
11529
11530// Clear a break point
11531// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011532RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011533 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011534 ASSERT(args.length() == 1);
11535 Handle<Object> break_point_object_arg = args.at<Object>(0);
11536
11537 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011538 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011539
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011540 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011541}
11542
11543
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011544// Change the state of break on exceptions.
11545// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11546// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011547RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011548 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011549 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011550 RUNTIME_ASSERT(args[0]->IsNumber());
11551 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011552
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011553 // If the number doesn't match an enum value, the ChangeBreakOnException
11554 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011555 ExceptionBreakType type =
11556 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011557 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011558 isolate->debug()->ChangeBreakOnException(type, enable);
11559 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011560}
11561
11562
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011563// Returns the state of break on exceptions
11564// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011565RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011566 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011567 ASSERT(args.length() == 1);
11568 RUNTIME_ASSERT(args[0]->IsNumber());
11569
11570 ExceptionBreakType type =
11571 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011572 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011573 return Smi::FromInt(result);
11574}
11575
11576
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011577// Prepare for stepping
11578// args[0]: break id for checking execution state
11579// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011580// args[2]: number of times to perform the step, for step out it is the number
11581// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011582RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011583 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011584 ASSERT(args.length() == 3);
11585 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011586 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011587 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11588 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011589 if (!maybe_check->ToObject(&check)) return maybe_check;
11590 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011591 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011592 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011593 }
11594
11595 // Get the step action and check validity.
11596 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11597 if (step_action != StepIn &&
11598 step_action != StepNext &&
11599 step_action != StepOut &&
11600 step_action != StepInMin &&
11601 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011602 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011603 }
11604
11605 // Get the number of steps.
11606 int step_count = NumberToInt32(args[2]);
11607 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011608 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011609 }
11610
ager@chromium.orga1645e22009-09-09 19:27:10 +000011611 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011612 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011613
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011614 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011615 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11616 step_count);
11617 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011618}
11619
11620
11621// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011622RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011623 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011624 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 isolate->debug()->ClearStepping();
11626 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011627}
11628
11629
11630// Creates a copy of the with context chain. The copy of the context chain is
11631// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011632static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011633 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011634 Handle<Context> current,
11635 Handle<Context> base) {
11636 // At the end of the chain. Return the base context to link to.
11637 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11638 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011639 }
11640
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011641 // Recursively copy the with and catch contexts.
11642 HandleScope scope(isolate);
11643 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011644 Handle<Context> new_previous =
11645 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011646 Handle<Context> new_current;
11647 if (current->IsCatchContext()) {
11648 Handle<String> name(String::cast(current->extension()));
11649 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11650 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011651 isolate->factory()->NewCatchContext(function,
11652 new_previous,
11653 name,
11654 thrown_object);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011655 } else if (current->IsBlockContext()) {
11656 Handle<SerializedScopeInfo> scope_info(
11657 SerializedScopeInfo::cast(current->extension()));
11658 new_current =
11659 isolate->factory()->NewBlockContext(function, new_previous, scope_info);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011660 // Copy context slots.
11661 int num_context_slots = scope_info->NumberOfContextSlots();
11662 for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
11663 new_current->set(i, current->get(i));
11664 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011665 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011666 ASSERT(current->IsWithContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011667 Handle<JSObject> extension(JSObject::cast(current->extension()));
11668 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011669 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011670 }
11671 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011672}
11673
11674
11675// Helper function to find or create the arguments object for
11676// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011677static Handle<Object> GetArgumentsObject(Isolate* isolate,
11678 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011679 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011680 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011681 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011682 const ScopeInfo<>* sinfo,
11683 Handle<Context> function_context) {
11684 // Try to find the value of 'arguments' to pass as parameter. If it is not
11685 // found (that is the debugged function does not reference 'arguments' and
11686 // does not support eval) then create an 'arguments' object.
11687 int index;
11688 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011689 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011690 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011691 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011692 }
11693 }
11694
11695 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011696 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11697 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011698 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011699 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011700 }
11701 }
11702
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011703 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11704
11705 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011706 Handle<JSObject> arguments =
11707 isolate->factory()->NewArgumentsObject(function, length);
11708 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011709
11710 AssertNoAllocation no_gc;
11711 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011712 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011713 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011714 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011715 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011716 return arguments;
11717}
11718
11719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011720static const char kSourceStr[] =
11721 "(function(arguments,__source__){return eval(__source__);})";
11722
11723
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011724// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011725// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011726// extension part has all the parameters and locals of the function on the
11727// stack frame. A function which calls eval with the code to evaluate is then
11728// compiled in this context and called in this context. As this context
11729// replaces the context of the function on the stack frame a new (empty)
11730// function is created as well to be used as the closure for the context.
11731// This function and the context acts as replacements for the function on the
11732// stack frame presenting the same view of the values of parameters and
11733// local variables as if the piece of JavaScript was evaluated at the point
11734// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011735RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011736 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011737
11738 // Check the execution state and decode arguments frame and source to be
11739 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011740 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011741 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011742 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11743 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011744 if (!maybe_check_result->ToObject(&check_result)) {
11745 return maybe_check_result;
11746 }
11747 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011748 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011749 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11750 CONVERT_ARG_CHECKED(String, source, 3);
11751 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11752 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011753
11754 // Handle the processing of break.
11755 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011756
11757 // Get the frame where the debugging is performed.
11758 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011759 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011760 JavaScriptFrame* frame = it.frame();
11761 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011762 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011763 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011764
11765 // Traverse the saved contexts chain to find the active context for the
11766 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011767 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011768 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011769 save = save->prev();
11770 }
11771 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011772 SaveContext savex(isolate);
11773 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011774
11775 // Create the (empty) function replacing the function on the stack frame for
11776 // the purpose of evaluating in the context created below. It is important
11777 // that this function does not describe any parameters and local variables
11778 // in the context. If it does then this will cause problems with the lookup
11779 // in Context::Lookup, where context slots for parameters and local variables
11780 // are looked at before the extension object.
11781 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011782 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11783 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011784 go_between->set_context(function->context());
11785#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011786 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011787 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11788 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11789#endif
11790
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011791 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011792 Handle<JSObject> local_scope = MaterializeLocalScope(
11793 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011794 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011795
11796 // Allocate a new context for the debug evaluation and set the extension
11797 // object build.
11798 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011799 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11800 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011801 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011802 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011803 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011804 Handle<Context> function_context;
11805 // Get the function's context if it has one.
11806 if (scope_info->HasHeapAllocatedLocals()) {
11807 function_context = Handle<Context>(frame_context->declaration_context());
11808 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011809 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011810
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011811 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011812 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011813 context =
11814 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011815 }
11816
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011817 // Wrap the evaluation statement in a new function compiled in the newly
11818 // created context. The function has one parameter which has to be called
11819 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011820 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011821 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011822
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011823 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011824 isolate->factory()->NewStringFromAscii(
11825 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011826
11827 // Currently, the eval code will be executed in non-strict mode,
11828 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011829 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011830 Compiler::CompileEval(function_source,
11831 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011832 context->IsGlobalContext(),
11833 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011834 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011835 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011836 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011837
11838 // Invoke the result of the compilation to get the evaluation function.
11839 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011840 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011841 Handle<Object> evaluation_function =
11842 Execution::Call(compiled_function, receiver, 0, NULL,
11843 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011844 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011845
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011846 Handle<Object> arguments = GetArgumentsObject(isolate,
11847 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011848 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011849 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011850
11851 // Invoke the evaluation function and return the result.
11852 const int argc = 2;
11853 Object** argv[argc] = { arguments.location(),
11854 Handle<Object>::cast(source).location() };
11855 Handle<Object> result =
11856 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11857 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011858 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011859
11860 // Skip the global proxy as it has no properties and always delegates to the
11861 // real global object.
11862 if (result->IsJSGlobalProxy()) {
11863 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11864 }
11865
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011866 return *result;
11867}
11868
11869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011870RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011871 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011872
11873 // Check the execution state and decode arguments frame and source to be
11874 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011875 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011876 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011877 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11878 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011879 if (!maybe_check_result->ToObject(&check_result)) {
11880 return maybe_check_result;
11881 }
11882 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011883 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011884 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011885 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011886
11887 // Handle the processing of break.
11888 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011889
11890 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011891 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011892 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011893 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011894 top = top->prev();
11895 }
11896 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011897 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011898 }
11899
11900 // Get the global context now set to the top context from before the
11901 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011902 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011903
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011904 bool is_global = true;
11905
11906 if (additional_context->IsJSObject()) {
11907 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011908 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11909 isolate->factory()->empty_string(),
11910 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011911 go_between->set_context(*context);
11912 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011913 isolate->factory()->NewFunctionContext(
11914 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011915 context->set_extension(JSObject::cast(*additional_context));
11916 is_global = false;
11917 }
11918
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011919 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011920 // Currently, the eval code will be executed in non-strict mode,
11921 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011922 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011923 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011924 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011925 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011926 Handle<JSFunction>(
11927 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11928 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011929
11930 // Invoke the result of the compilation to get the evaluation function.
11931 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011932 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011933 Handle<Object> result =
11934 Execution::Call(compiled_function, receiver, 0, NULL,
11935 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011936 // Clear the oneshot breakpoints so that the debugger does not step further.
11937 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011938 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011939 return *result;
11940}
11941
11942
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011943RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011944 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011945 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011946
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011947 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011948 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011949
11950 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011951 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011952 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11953 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11954 // because using
11955 // instances->set(i, *GetScriptWrapper(script))
11956 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11957 // already have deferenced the instances handle.
11958 Handle<JSValue> wrapper = GetScriptWrapper(script);
11959 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011960 }
11961
11962 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011963 Handle<JSObject> result =
11964 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011965 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011966 return *result;
11967}
11968
11969
11970// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011971static int DebugReferencedBy(HeapIterator* iterator,
11972 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011973 Object* instance_filter, int max_references,
11974 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011975 JSFunction* arguments_function) {
11976 NoHandleAllocation ha;
11977 AssertNoAllocation no_alloc;
11978
11979 // Iterate the heap.
11980 int count = 0;
11981 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011982 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011983 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011984 (max_references == 0 || count < max_references)) {
11985 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011986 if (heap_obj->IsJSObject()) {
11987 // Skip context extension objects and argument arrays as these are
11988 // checked in the context of functions using them.
11989 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011990 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011991 obj->map()->constructor() == arguments_function) {
11992 continue;
11993 }
11994
11995 // Check if the JS object has a reference to the object looked for.
11996 if (obj->ReferencesObject(target)) {
11997 // Check instance filter if supplied. This is normally used to avoid
11998 // references from mirror objects (see Runtime_IsInPrototypeChain).
11999 if (!instance_filter->IsUndefined()) {
12000 Object* V = obj;
12001 while (true) {
12002 Object* prototype = V->GetPrototype();
12003 if (prototype->IsNull()) {
12004 break;
12005 }
12006 if (instance_filter == prototype) {
12007 obj = NULL; // Don't add this object.
12008 break;
12009 }
12010 V = prototype;
12011 }
12012 }
12013
12014 if (obj != NULL) {
12015 // Valid reference found add to instance array if supplied an update
12016 // count.
12017 if (instances != NULL && count < instances_size) {
12018 instances->set(count, obj);
12019 }
12020 last = obj;
12021 count++;
12022 }
12023 }
12024 }
12025 }
12026
12027 // Check for circular reference only. This can happen when the object is only
12028 // referenced from mirrors and has a circular reference in which case the
12029 // object is not really alive and would have been garbage collected if not
12030 // referenced from the mirror.
12031 if (count == 1 && last == target) {
12032 count = 0;
12033 }
12034
12035 // Return the number of referencing objects found.
12036 return count;
12037}
12038
12039
12040// Scan the heap for objects with direct references to an object
12041// args[0]: the object to find references to
12042// args[1]: constructor function for instances to exclude (Mirror)
12043// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012044RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012045 ASSERT(args.length() == 3);
12046
12047 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012048 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12049 // The heap iterator reserves the right to do a GC to make the heap iterable.
12050 // Due to the GC above we know it won't need to do that, but it seems cleaner
12051 // to get the heap iterator constructed before we start having unprotected
12052 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012053
12054 // Check parameters.
12055 CONVERT_CHECKED(JSObject, target, args[0]);
12056 Object* instance_filter = args[1];
12057 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12058 instance_filter->IsJSObject());
12059 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12060 RUNTIME_ASSERT(max_references >= 0);
12061
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012062
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012063 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012064 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012065 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012066 JSFunction* arguments_function =
12067 JSFunction::cast(arguments_boilerplate->map()->constructor());
12068
12069 // Get the number of referencing objects.
12070 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012071 HeapIterator heap_iterator;
12072 count = DebugReferencedBy(&heap_iterator,
12073 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012074 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012075
12076 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012077 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012078 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012079 if (!maybe_object->ToObject(&object)) return maybe_object;
12080 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012081 FixedArray* instances = FixedArray::cast(object);
12082
12083 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012084 // AllocateFixedArray above does not make the heap non-iterable.
12085 ASSERT(HEAP->IsHeapIterable());
12086 HeapIterator heap_iterator2;
12087 count = DebugReferencedBy(&heap_iterator2,
12088 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012089 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012090
12091 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012092 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012093 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012094 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012095 if (!maybe_result->ToObject(&result)) return maybe_result;
12096 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012097}
12098
12099
12100// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012101static int DebugConstructedBy(HeapIterator* iterator,
12102 JSFunction* constructor,
12103 int max_references,
12104 FixedArray* instances,
12105 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012106 AssertNoAllocation no_alloc;
12107
12108 // Iterate the heap.
12109 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012110 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012111 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012112 (max_references == 0 || count < max_references)) {
12113 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012114 if (heap_obj->IsJSObject()) {
12115 JSObject* obj = JSObject::cast(heap_obj);
12116 if (obj->map()->constructor() == constructor) {
12117 // Valid reference found add to instance array if supplied an update
12118 // count.
12119 if (instances != NULL && count < instances_size) {
12120 instances->set(count, obj);
12121 }
12122 count++;
12123 }
12124 }
12125 }
12126
12127 // Return the number of referencing objects found.
12128 return count;
12129}
12130
12131
12132// Scan the heap for objects constructed by a specific function.
12133// args[0]: the constructor to find instances of
12134// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012135RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012136 ASSERT(args.length() == 2);
12137
12138 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012139 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012140
12141 // Check parameters.
12142 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12143 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12144 RUNTIME_ASSERT(max_references >= 0);
12145
12146 // Get the number of referencing objects.
12147 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012148 HeapIterator heap_iterator;
12149 count = DebugConstructedBy(&heap_iterator,
12150 constructor,
12151 max_references,
12152 NULL,
12153 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012154
12155 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012156 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012157 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012158 if (!maybe_object->ToObject(&object)) return maybe_object;
12159 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012160 FixedArray* instances = FixedArray::cast(object);
12161
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012162 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012163 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012164 HeapIterator heap_iterator2;
12165 count = DebugConstructedBy(&heap_iterator2,
12166 constructor,
12167 max_references,
12168 instances,
12169 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012170
12171 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012172 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012173 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12174 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012175 if (!maybe_result->ToObject(&result)) return maybe_result;
12176 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012177 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012178}
12179
12180
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012181// Find the effective prototype object as returned by __proto__.
12182// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012183RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012184 ASSERT(args.length() == 1);
12185
12186 CONVERT_CHECKED(JSObject, obj, args[0]);
12187
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012188 // Use the __proto__ accessor.
12189 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012190}
12191
12192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012193RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012194 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012195 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012196 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012197}
12198
12199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012200RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012201#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012202 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012203 ASSERT(args.length() == 1);
12204 // Get the function and make sure it is compiled.
12205 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012206 Handle<SharedFunctionInfo> shared(func->shared());
12207 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012208 return Failure::Exception();
12209 }
12210 func->code()->PrintLn();
12211#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012212 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012213}
ager@chromium.org9085a012009-05-11 19:22:57 +000012214
12215
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012216RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012217#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012218 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012219 ASSERT(args.length() == 1);
12220 // Get the function and make sure it is compiled.
12221 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012222 Handle<SharedFunctionInfo> shared(func->shared());
12223 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012224 return Failure::Exception();
12225 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012226 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012227#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012228 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012229}
12230
12231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012232RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012233 NoHandleAllocation ha;
12234 ASSERT(args.length() == 1);
12235
12236 CONVERT_CHECKED(JSFunction, f, args[0]);
12237 return f->shared()->inferred_name();
12238}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012239
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012240
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012241static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12242 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012243 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012244 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012245 int counter = 0;
12246 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012247 for (HeapObject* obj = iterator->next();
12248 obj != NULL;
12249 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012250 ASSERT(obj != NULL);
12251 if (!obj->IsSharedFunctionInfo()) {
12252 continue;
12253 }
12254 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12255 if (shared->script() != script) {
12256 continue;
12257 }
12258 if (counter < buffer_size) {
12259 buffer->set(counter, shared);
12260 }
12261 counter++;
12262 }
12263 return counter;
12264}
12265
12266// For a script finds all SharedFunctionInfo's in the heap that points
12267// to this script. Returns JSArray of SharedFunctionInfo wrapped
12268// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012269RUNTIME_FUNCTION(MaybeObject*,
12270 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012271 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012272 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012273 CONVERT_CHECKED(JSValue, script_value, args[0]);
12274
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012275
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012276 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12277
12278 const int kBufferSize = 32;
12279
12280 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012281 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012282 int number;
12283 {
12284 isolate->heap()->EnsureHeapIsIterable();
12285 AssertNoAllocation no_allocations;
12286 HeapIterator heap_iterator;
12287 Script* scr = *script;
12288 FixedArray* arr = *array;
12289 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12290 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012291 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012292 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012293 isolate->heap()->EnsureHeapIsIterable();
12294 AssertNoAllocation no_allocations;
12295 HeapIterator heap_iterator;
12296 Script* scr = *script;
12297 FixedArray* arr = *array;
12298 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012299 }
12300
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012301 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012302 result->set_length(Smi::FromInt(number));
12303
12304 LiveEdit::WrapSharedFunctionInfos(result);
12305
12306 return *result;
12307}
12308
12309// For a script calculates compilation information about all its functions.
12310// The script source is explicitly specified by the second argument.
12311// The source of the actual script is not used, however it is important that
12312// all generated code keeps references to this particular instance of script.
12313// Returns a JSArray of compilation infos. The array is ordered so that
12314// each function with all its descendant is always stored in a continues range
12315// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012316RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012317 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012318 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012319 CONVERT_CHECKED(JSValue, script, args[0]);
12320 CONVERT_ARG_CHECKED(String, source, 1);
12321 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12322
12323 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012325 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012326 return Failure::Exception();
12327 }
12328
12329 return result;
12330}
12331
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012332// Changes the source of the script to a new_source.
12333// If old_script_name is provided (i.e. is a String), also creates a copy of
12334// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012335RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012336 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012337 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012338 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12339 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012340 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012341
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012342 CONVERT_CHECKED(Script, original_script_pointer,
12343 original_script_value->value());
12344 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012345
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012346 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12347 new_source,
12348 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012349
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012350 if (old_script->IsScript()) {
12351 Handle<Script> script_handle(Script::cast(old_script));
12352 return *(GetScriptWrapper(script_handle));
12353 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012354 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012355 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012356}
12357
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012359RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012360 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012361 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012362 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12363 return LiveEdit::FunctionSourceUpdated(shared_info);
12364}
12365
12366
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012367// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012368RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012369 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012370 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012371 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12372 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12373
ager@chromium.orgac091b72010-05-05 07:34:42 +000012374 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012375}
12376
12377// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012378RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012379 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012380 HandleScope scope(isolate);
12381 Handle<Object> function_object(args[0], isolate);
12382 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012383
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012384 if (function_object->IsJSValue()) {
12385 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12386 if (script_object->IsJSValue()) {
12387 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012388 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012389 }
12390
12391 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12392 } else {
12393 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12394 // and we check it in this function.
12395 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012396
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012397 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012398}
12399
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012400
12401// In a code of a parent function replaces original function as embedded object
12402// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012403RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012404 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012405 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012406
12407 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12408 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12409 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12410
12411 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12412 subst_wrapper);
12413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012414 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012415}
12416
12417
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012418// Updates positions of a shared function info (first parameter) according
12419// to script source change. Text change is described in second parameter as
12420// array of groups of 3 numbers:
12421// (change_begin, change_end, change_end_new_position).
12422// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012423RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012424 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012425 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012426 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12427 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12428
ager@chromium.orgac091b72010-05-05 07:34:42 +000012429 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012430}
12431
12432
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012433// For array of SharedFunctionInfo's (each wrapped in JSValue)
12434// checks that none of them have activations on stacks (of any thread).
12435// Returns array of the same length with corresponding results of
12436// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012437RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012438 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012439 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012440 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012441 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012442
ager@chromium.org357bf652010-04-12 11:30:10 +000012443 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012444}
12445
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012446// Compares 2 strings line-by-line, then token-wise and returns diff in form
12447// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12448// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012449RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012450 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012451 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012452 CONVERT_ARG_CHECKED(String, s1, 0);
12453 CONVERT_ARG_CHECKED(String, s2, 1);
12454
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012455 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012456}
12457
12458
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012459// A testing entry. Returns statement position which is the closest to
12460// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012461RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012462 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012463 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012464 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12465 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12466
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012467 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012468
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012469 if (code->kind() != Code::FUNCTION &&
12470 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012471 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012472 }
12473
12474 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012475 int closest_pc = 0;
12476 int distance = kMaxInt;
12477 while (!it.done()) {
12478 int statement_position = static_cast<int>(it.rinfo()->data());
12479 // Check if this break point is closer that what was previously found.
12480 if (source_position <= statement_position &&
12481 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012482 closest_pc =
12483 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012484 distance = statement_position - source_position;
12485 // Check whether we can't get any closer.
12486 if (distance == 0) break;
12487 }
12488 it.next();
12489 }
12490
12491 return Smi::FromInt(closest_pc);
12492}
12493
12494
ager@chromium.org357bf652010-04-12 11:30:10 +000012495// Calls specified function with or without entering the debugger.
12496// This is used in unit tests to run code as if debugger is entered or simply
12497// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012498RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012499 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012500 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012501 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12502 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12503
12504 Handle<Object> result;
12505 bool pending_exception;
12506 {
12507 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012508 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012509 &pending_exception);
12510 } else {
12511 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012512 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012513 &pending_exception);
12514 }
12515 }
12516 if (!pending_exception) {
12517 return *result;
12518 } else {
12519 return Failure::Exception();
12520 }
12521}
12522
12523
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012524// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012525RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012526 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012527 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012528 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12529 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012530 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012531}
12532
12533
12534// Performs a GC.
12535// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012536RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012537 isolate->heap()->CollectAllGarbage(true);
12538 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012539}
12540
12541
12542// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012543RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012544 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012545 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012546 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012547 }
12548 return Smi::FromInt(usage);
12549}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012550
12551
12552// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012553RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012554#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012555 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012556#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012557 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012558#endif
12559}
12560
12561
12562// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012563RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012564#ifdef LIVE_OBJECT_LIST
12565 return LiveObjectList::Capture();
12566#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012567 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012568#endif
12569}
12570
12571
12572// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012573RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012574#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012575 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012576 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012577 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012578#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012579 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012580#endif
12581}
12582
12583
12584// Generates the response to a debugger request for a dump of the objects
12585// contained in the difference between the captured live object lists
12586// specified by id1 and id2.
12587// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12588// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012589RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012590#ifdef LIVE_OBJECT_LIST
12591 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012592 CONVERT_SMI_ARG_CHECKED(id1, 0);
12593 CONVERT_SMI_ARG_CHECKED(id2, 1);
12594 CONVERT_SMI_ARG_CHECKED(start, 2);
12595 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012596 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12597 EnterDebugger enter_debugger;
12598 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12599#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012600 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012601#endif
12602}
12603
12604
12605// Gets the specified object as requested by the debugger.
12606// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012607RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012608#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012609 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012610 Object* result = LiveObjectList::GetObj(obj_id);
12611 return result;
12612#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012613 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012614#endif
12615}
12616
12617
12618// Gets the obj id for the specified address if valid.
12619// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012620RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012621#ifdef LIVE_OBJECT_LIST
12622 HandleScope scope;
12623 CONVERT_ARG_CHECKED(String, address, 0);
12624 Object* result = LiveObjectList::GetObjId(address);
12625 return result;
12626#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012627 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012628#endif
12629}
12630
12631
12632// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012633RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012634#ifdef LIVE_OBJECT_LIST
12635 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012636 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012637 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12638 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12639 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12640 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12641 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12642
12643 Handle<JSObject> instance_filter;
12644 if (args[1]->IsJSObject()) {
12645 instance_filter = args.at<JSObject>(1);
12646 }
12647 bool verbose = false;
12648 if (args[2]->IsBoolean()) {
12649 verbose = args[2]->IsTrue();
12650 }
12651 int start = 0;
12652 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012653 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012654 }
12655 int limit = Smi::kMaxValue;
12656 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012657 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012658 }
12659
12660 return LiveObjectList::GetObjRetainers(obj_id,
12661 instance_filter,
12662 verbose,
12663 start,
12664 limit,
12665 filter_obj);
12666#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012667 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012668#endif
12669}
12670
12671
12672// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012673RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012674#ifdef LIVE_OBJECT_LIST
12675 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012676 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12677 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012678 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12679
12680 Handle<JSObject> instance_filter;
12681 if (args[2]->IsJSObject()) {
12682 instance_filter = args.at<JSObject>(2);
12683 }
12684
12685 Object* result =
12686 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12687 return result;
12688#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012689 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012690#endif
12691}
12692
12693
12694// Generates the response to a debugger request for a list of all
12695// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012696RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012697#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012698 CONVERT_SMI_ARG_CHECKED(start, 0);
12699 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012700 return LiveObjectList::Info(start, count);
12701#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012702 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012703#endif
12704}
12705
12706
12707// Gets a dump of the specified object as requested by the debugger.
12708// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012709RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012710#ifdef LIVE_OBJECT_LIST
12711 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012712 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012713 Object* result = LiveObjectList::PrintObj(obj_id);
12714 return result;
12715#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012716 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012717#endif
12718}
12719
12720
12721// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012722RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012723#ifdef LIVE_OBJECT_LIST
12724 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012725 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012726#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012727 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012728#endif
12729}
12730
12731
12732// Generates the response to a debugger request for a summary of the types
12733// of objects in the difference between the captured live object lists
12734// specified by id1 and id2.
12735// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12736// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012737RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012738#ifdef LIVE_OBJECT_LIST
12739 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012740 CONVERT_SMI_ARG_CHECKED(id1, 0);
12741 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012742 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12743
12744 EnterDebugger enter_debugger;
12745 return LiveObjectList::Summarize(id1, id2, filter_obj);
12746#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012747 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012748#endif
12749}
12750
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012751#endif // ENABLE_DEBUGGER_SUPPORT
12752
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012754RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012755 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012756 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012757 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012758}
12759
12760
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012761RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012762 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012763 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012764 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012765}
12766
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012767
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012768// Finds the script object from the script data. NOTE: This operation uses
12769// heap traversal to find the function generated for the source position
12770// for the requested break point. For lazily compiled functions several heap
12771// traversals might be required rendering this operation as a rather slow
12772// operation. However for setting break points which is normally done through
12773// some kind of user interaction the performance is not crucial.
12774static Handle<Object> Runtime_GetScriptFromScriptName(
12775 Handle<String> script_name) {
12776 // Scan the heap for Script objects to find the script with the requested
12777 // script data.
12778 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012779 script_name->GetHeap()->EnsureHeapIsIterable();
12780 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012781 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012782 HeapObject* obj = NULL;
12783 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012784 // If a script is found check if it has the script data requested.
12785 if (obj->IsScript()) {
12786 if (Script::cast(obj)->name()->IsString()) {
12787 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12788 script = Handle<Script>(Script::cast(obj));
12789 }
12790 }
12791 }
12792 }
12793
12794 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012795 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012796
12797 // Return the script found.
12798 return GetScriptWrapper(script);
12799}
12800
12801
12802// Get the script object from script data. NOTE: Regarding performance
12803// see the NOTE for GetScriptFromScriptData.
12804// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012805RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012806 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012807
12808 ASSERT(args.length() == 1);
12809
12810 CONVERT_CHECKED(String, script_name, args[0]);
12811
12812 // Find the requested script.
12813 Handle<Object> result =
12814 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12815 return *result;
12816}
12817
12818
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012819// Determines whether the given stack frame should be displayed in
12820// a stack trace. The caller is the error constructor that asked
12821// for the stack trace to be collected. The first time a construct
12822// call to this function is encountered it is skipped. The seen_caller
12823// in/out parameter is used to remember if the caller has been seen
12824// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012825static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12826 Object* caller,
12827 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012828 // Only display JS frames.
12829 if (!raw_frame->is_java_script())
12830 return false;
12831 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12832 Object* raw_fun = frame->function();
12833 // Not sure when this can happen but skip it just in case.
12834 if (!raw_fun->IsJSFunction())
12835 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012836 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012837 *seen_caller = true;
12838 return false;
12839 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012840 // Skip all frames until we've seen the caller.
12841 if (!(*seen_caller)) return false;
12842 // Also, skip the most obvious builtin calls. We recognize builtins
12843 // as (1) functions called with the builtins object as the receiver and
12844 // as (2) functions from native scripts called with undefined as the
12845 // receiver (direct calls to helper functions in the builtins
12846 // code). Some builtin calls (such as Number.ADD which is invoked
12847 // using 'call') are very difficult to recognize so we're leaving
12848 // them in for now.
12849 if (frame->receiver()->IsJSBuiltinsObject()) {
12850 return false;
12851 }
12852 JSFunction* fun = JSFunction::cast(raw_fun);
12853 Object* raw_script = fun->shared()->script();
12854 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12855 int script_type = Script::cast(raw_script)->type()->value();
12856 return script_type != Script::TYPE_NATIVE;
12857 }
12858 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012859}
12860
12861
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012862// Collect the raw data for a stack trace. Returns an array of 4
12863// element segments each containing a receiver, function, code and
12864// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012865RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012866 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012867 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012868 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012870 HandleScope scope(isolate);
12871 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012872
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012873 limit = Max(limit, 0); // Ensure that limit is not negative.
12874 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012875 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012876 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012877
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012878 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012879 // If the caller parameter is a function we skip frames until we're
12880 // under it before starting to collect.
12881 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012882 int cursor = 0;
12883 int frames_seen = 0;
12884 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012885 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012886 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012887 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012888 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012889 // Set initial size to the maximum inlining level + 1 for the outermost
12890 // function.
12891 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012892 frame->Summarize(&frames);
12893 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012894 if (cursor + 4 > elements->length()) {
12895 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12896 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012897 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012898 for (int i = 0; i < cursor; i++) {
12899 new_elements->set(i, elements->get(i));
12900 }
12901 elements = new_elements;
12902 }
12903 ASSERT(cursor + 4 <= elements->length());
12904
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012905 Handle<Object> recv = frames[i].receiver();
12906 Handle<JSFunction> fun = frames[i].function();
12907 Handle<Code> code = frames[i].code();
12908 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012909 elements->set(cursor++, *recv);
12910 elements->set(cursor++, *fun);
12911 elements->set(cursor++, *code);
12912 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012913 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012914 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012915 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012916 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012917 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012918 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012919 return *result;
12920}
12921
12922
ager@chromium.org3811b432009-10-28 14:53:37 +000012923// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012924RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012925 ASSERT_EQ(args.length(), 0);
12926
12927 NoHandleAllocation ha;
12928
12929 const char* version_string = v8::V8::GetVersion();
12930
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012931 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12932 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012933}
12934
12935
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012936RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012937 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012938 OS::PrintError("abort: %s\n",
12939 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012940 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012941 OS::Abort();
12942 UNREACHABLE();
12943 return NULL;
12944}
12945
12946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012947RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012948 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012949 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012950 Object* key = args[1];
12951
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012952 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012953 Object* o = cache->get(finger_index);
12954 if (o == key) {
12955 // The fastest case: hit the same place again.
12956 return cache->get(finger_index + 1);
12957 }
12958
12959 for (int i = finger_index - 2;
12960 i >= JSFunctionResultCache::kEntriesIndex;
12961 i -= 2) {
12962 o = cache->get(i);
12963 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012964 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012965 return cache->get(i + 1);
12966 }
12967 }
12968
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012969 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012970 ASSERT(size <= cache->length());
12971
12972 for (int i = size - 2; i > finger_index; i -= 2) {
12973 o = cache->get(i);
12974 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012975 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012976 return cache->get(i + 1);
12977 }
12978 }
12979
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012980 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012981 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012982
12983 Handle<JSFunctionResultCache> cache_handle(cache);
12984 Handle<Object> key_handle(key);
12985 Handle<Object> value;
12986 {
12987 Handle<JSFunction> factory(JSFunction::cast(
12988 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12989 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012990 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012991 // This handle is nor shared, nor used later, so it's safe.
12992 Object** argv[] = { key_handle.location() };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012993 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012994 value = Execution::Call(factory,
12995 receiver,
12996 1,
12997 argv,
12998 &pending_exception);
12999 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013000 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013001
13002#ifdef DEBUG
13003 cache_handle->JSFunctionResultCacheVerify();
13004#endif
13005
13006 // Function invocation may have cleared the cache. Reread all the data.
13007 finger_index = cache_handle->finger_index();
13008 size = cache_handle->size();
13009
13010 // If we have spare room, put new data into it, otherwise evict post finger
13011 // entry which is likely to be the least recently used.
13012 int index = -1;
13013 if (size < cache_handle->length()) {
13014 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13015 index = size;
13016 } else {
13017 index = finger_index + JSFunctionResultCache::kEntrySize;
13018 if (index == cache_handle->length()) {
13019 index = JSFunctionResultCache::kEntriesIndex;
13020 }
13021 }
13022
13023 ASSERT(index % 2 == 0);
13024 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13025 ASSERT(index < cache_handle->length());
13026
13027 cache_handle->set(index, *key_handle);
13028 cache_handle->set(index + 1, *value);
13029 cache_handle->set_finger_index(index);
13030
13031#ifdef DEBUG
13032 cache_handle->JSFunctionResultCacheVerify();
13033#endif
13034
13035 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013036}
13037
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013039RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013040 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013041 CONVERT_ARG_CHECKED(String, type, 0);
13042 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013043 return *isolate->factory()->NewJSMessageObject(
13044 type,
13045 arguments,
13046 0,
13047 0,
13048 isolate->factory()->undefined_value(),
13049 isolate->factory()->undefined_value(),
13050 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013051}
13052
13053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013054RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013055 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13056 return message->type();
13057}
13058
13059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013060RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013061 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13062 return message->arguments();
13063}
13064
13065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013066RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013067 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13068 return Smi::FromInt(message->start_position());
13069}
13070
13071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013072RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013073 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13074 return message->script();
13075}
13076
13077
kasper.lund44510672008-07-25 07:37:58 +000013078#ifdef DEBUG
13079// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13080// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013081RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013082 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013083 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013084#define COUNT_ENTRY(Name, argc, ressize) + 1
13085 int entry_count = 0
13086 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13087 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13088 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13089#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013090 Factory* factory = isolate->factory();
13091 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013092 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013093 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013094#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013095 { \
13096 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013097 Handle<String> name; \
13098 /* Inline runtime functions have an underscore in front of the name. */ \
13099 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013100 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013101 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13102 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013103 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013104 Vector<const char>(#Name, StrLength(#Name))); \
13105 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013106 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013107 pair_elements->set(0, *name); \
13108 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013109 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013110 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013111 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013112 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013113 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013114 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013115 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013116 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013117#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013118 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013119 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013120 return *result;
13121}
kasper.lund44510672008-07-25 07:37:58 +000013122#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013123
13124
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013125RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013126 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013127 CONVERT_CHECKED(String, format, args[0]);
13128 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013129 String::FlatContent format_content = format->GetFlatContent();
13130 RUNTIME_ASSERT(format_content.IsAscii());
13131 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013132 LOGGER->LogRuntime(chars, elms);
13133 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013134}
13135
13136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013137RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013138 UNREACHABLE(); // implemented as macro in the parser
13139 return NULL;
13140}
13141
13142
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013143#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13144 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13145 CONVERT_CHECKED(JSObject, obj, args[0]); \
13146 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13147 }
13148
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013149ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013150ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13151ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13152ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13153ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13154ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13155ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13156ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13157ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13158ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13159ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13160ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13161ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13162ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13163
13164#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013166// ----------------------------------------------------------------------------
13167// Implementation of Runtime
13168
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013169#define F(name, number_of_args, result_size) \
13170 { Runtime::k##name, Runtime::RUNTIME, #name, \
13171 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013172
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013173
13174#define I(name, number_of_args, result_size) \
13175 { Runtime::kInline##name, Runtime::INLINE, \
13176 "_" #name, NULL, number_of_args, result_size },
13177
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013178static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013179 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013180 INLINE_FUNCTION_LIST(I)
13181 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013182};
13183
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013184
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013185MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13186 Object* dictionary) {
13187 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013188 ASSERT(dictionary != NULL);
13189 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13190 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013191 Object* name_symbol;
13192 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013193 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013194 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13195 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013196 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013197 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13198 String::cast(name_symbol),
13199 Smi::FromInt(i),
13200 PropertyDetails(NONE, NORMAL));
13201 if (!maybe_dictionary->ToObject(&dictionary)) {
13202 // Non-recoverable failure. Calling code must restart heap
13203 // initialization.
13204 return maybe_dictionary;
13205 }
13206 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013207 }
13208 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013209}
13210
13211
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013212const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13213 Heap* heap = name->GetHeap();
13214 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013215 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013216 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013217 int function_index = Smi::cast(smi_index)->value();
13218 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013219 }
13220 return NULL;
13221}
13222
13223
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013224const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013225 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13226}
13227
13228
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013229void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013230 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013231 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013232 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013233 if (isolate->heap()->new_space()->AddFreshPage()) {
13234 return;
13235 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013236 // Try to do a garbage collection; ignore it if it fails. The C
13237 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013238 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013239 } else {
13240 // Handle last resort GC and make sure to allow future allocations
13241 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013242 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013243 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013244 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013245}
13246
13247
13248} } // namespace v8::internal