blob: 048551bf145adeeb39cc8014b0bc99b73fb37859 [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 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"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000045#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000046#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000047#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#include "platform.h"
49#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000052#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000053#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000054#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000055#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056
kasperl@chromium.org71affb52009-05-26 05:44:31 +000057namespace v8 {
58namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
60
ager@chromium.org3e875802009-06-29 08:26:34 +000061#define RUNTIME_ASSERT(value) \
62 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64// Cast the given object to a value of the specified type and store
65// it in a variable with the given name. If the object is not of the
66// expected type call IllegalOperation and return.
67#define CONVERT_CHECKED(Type, name, obj) \
68 RUNTIME_ASSERT(obj->Is##Type()); \
69 Type* name = Type::cast(obj);
70
71#define CONVERT_ARG_CHECKED(Type, name, index) \
72 RUNTIME_ASSERT(args[index]->Is##Type()); \
73 Handle<Type> name = args.at<Type>(index);
74
kasper.lundbd3ec4e2008-07-09 11:06:54 +000075// Cast the given object to a boolean and store it in a variable with
76// the given name. If the object is not a boolean call IllegalOperation
77// and return.
78#define CONVERT_BOOLEAN_CHECKED(name, obj) \
79 RUNTIME_ASSERT(obj->IsBoolean()); \
80 bool name = (obj)->IsTrue();
81
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000082// Cast the given object to a Smi and store its value in an int variable
83// with the given name. If the object is not a Smi call IllegalOperation
84// and return.
85#define CONVERT_SMI_CHECKED(name, obj) \
86 RUNTIME_ASSERT(obj->IsSmi()); \
87 int name = Smi::cast(obj)->value();
88
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089// Cast the given object to a double and store it in a variable with
90// the given name. If the object is not a number (as opposed to
91// the number not-a-number) call IllegalOperation and return.
92#define CONVERT_DOUBLE_CHECKED(name, obj) \
93 RUNTIME_ASSERT(obj->IsNumber()); \
94 double name = (obj)->Number();
95
96// Call the specified converter on the object *comand store the result in
97// a variable of the specified type with the given name. If the
98// object is not a Number call IllegalOperation and return.
99#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
100 RUNTIME_ASSERT(obj->IsNumber()); \
101 type name = NumberTo##Type(obj);
102
103// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000104static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105
106
lrn@chromium.org303ada72010-10-27 09:33:13 +0000107MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000108 StackLimitCheck check;
109 if (check.HasOverflowed()) return Top::StackOverflow();
110
lrn@chromium.org303ada72010-10-27 09:33:13 +0000111 Object* result;
112 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
113 if (!maybe_result->ToObject(&result)) return maybe_result;
114 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000115 JSObject* copy = JSObject::cast(result);
116
117 // Deep copy local properties.
118 if (copy->HasFastProperties()) {
119 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000120 for (int i = 0; i < properties->length(); i++) {
121 Object* value = properties->get(i);
122 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000123 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000124 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
125 if (!maybe_result->ToObject(&result)) return maybe_result;
126 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000127 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000128 }
129 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000130 int nof = copy->map()->inobject_properties();
131 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000132 Object* value = copy->InObjectPropertyAt(i);
133 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000134 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000135 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
136 if (!maybe_result->ToObject(&result)) return maybe_result;
137 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000138 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000139 }
140 }
141 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000142 { MaybeObject* maybe_result =
143 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
144 if (!maybe_result->ToObject(&result)) return maybe_result;
145 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 FixedArray* names = FixedArray::cast(result);
147 copy->GetLocalPropertyNames(names, 0);
148 for (int i = 0; i < names->length(); i++) {
149 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 // Only deep copy fields from the object literal expression.
154 // In particular, don't try to copy the length attribute of
155 // an array.
156 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000157 Object* value =
158 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000159 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000160 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
162 if (!maybe_result->ToObject(&result)) return maybe_result;
163 }
164 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000165 // Creating object copy for literals. No strict mode needed.
166 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 if (!maybe_result->ToObject(&result)) return maybe_result;
168 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000169 }
170 }
171 }
172
173 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000174 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000175 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000176 switch (copy->GetElementsKind()) {
177 case JSObject::FAST_ELEMENTS: {
178 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000179 if (elements->map() == Heap::fixed_cow_array_map()) {
180 Counters::cow_arrays_created_runtime.Increment();
181#ifdef DEBUG
182 for (int i = 0; i < elements->length(); i++) {
183 ASSERT(!elements->get(i)->IsJSObject());
184 }
185#endif
186 } else {
187 for (int i = 0; i < elements->length(); i++) {
188 Object* value = elements->get(i);
189 if (value->IsJSObject()) {
190 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000191 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000194 elements->set(i, result);
195 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
197 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000198 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 case JSObject::DICTIONARY_ELEMENTS: {
201 NumberDictionary* element_dictionary = copy->element_dictionary();
202 int capacity = element_dictionary->Capacity();
203 for (int i = 0; i < capacity; i++) {
204 Object* k = element_dictionary->KeyAt(i);
205 if (element_dictionary->IsKey(k)) {
206 Object* value = element_dictionary->ValueAt(i);
207 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000208 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
210 if (!maybe_result->ToObject(&result)) return maybe_result;
211 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000212 element_dictionary->ValueAtPut(i, result);
213 }
214 }
215 }
216 break;
217 }
218 default:
219 UNREACHABLE();
220 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000221 }
222 return copy;
223}
224
225
lrn@chromium.org303ada72010-10-27 09:33:13 +0000226static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000227 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
228 return DeepCopyBoilerplate(boilerplate);
229}
230
231
lrn@chromium.org303ada72010-10-27 09:33:13 +0000232static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000234 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235}
236
237
ager@chromium.org236ad962008-09-25 09:45:57 +0000238static Handle<Map> ComputeObjectLiteralMap(
239 Handle<Context> context,
240 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000241 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000242 int properties_length = constant_properties->length();
243 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000244 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000245 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000246 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000247 for (int p = 0; p != properties_length; p += 2) {
248 Object* key = constant_properties->get(p);
249 uint32_t element_index = 0;
250 if (key->IsSymbol()) {
251 number_of_symbol_keys++;
252 } else if (key->ToArrayIndex(&element_index)) {
253 // An index key does not require space in the property backing store.
254 number_of_properties--;
255 } else {
256 // Bail out as a non-symbol non-index key makes caching impossible.
257 // ASSERT to make sure that the if condition after the loop is false.
258 ASSERT(number_of_symbol_keys != number_of_properties);
259 break;
260 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000262 // If we only have symbols and array indices among keys then we can
263 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000265 if ((number_of_symbol_keys == number_of_properties) &&
266 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 // Create the fixed array with the key.
268 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000269 if (number_of_symbol_keys > 0) {
270 int index = 0;
271 for (int p = 0; p < properties_length; p += 2) {
272 Object* key = constant_properties->get(p);
273 if (key->IsSymbol()) {
274 keys->set(index++, key);
275 }
276 }
277 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000279 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000280 return Factory::ObjectLiteralMapFromCache(context, keys);
281 }
282 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000283 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000284 return Factory::CopyMap(
285 Handle<Map>(context->object_function()->initial_map()),
286 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000287}
288
289
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000290static Handle<Object> CreateLiteralBoilerplate(
291 Handle<FixedArray> literals,
292 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000293
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000294
295static Handle<Object> CreateObjectLiteralBoilerplate(
296 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000297 Handle<FixedArray> constant_properties,
298 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299 // Get the global context from the literals array. This is the
300 // context in which the function was created and we use the object
301 // function from this context to create the object literal. We do
302 // not use the object function from the current global context
303 // because this might be the object function from another context
304 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000305 Handle<Context> context =
306 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
307
308 bool is_result_from_cache;
309 Handle<Map> map = ComputeObjectLiteralMap(context,
310 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000311 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000312
ager@chromium.org236ad962008-09-25 09:45:57 +0000313 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000314
315 // Normalize the elements of the boilerplate to save space if needed.
316 if (!should_have_fast_elements) NormalizeElements(boilerplate);
317
ager@chromium.org32912102009-01-16 10:38:43 +0000318 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000320 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000321 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000322 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323 for (int index = 0; index < length; index +=2) {
324 Handle<Object> key(constant_properties->get(index+0));
325 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000326 if (value->IsFixedArray()) {
327 // The value contains the constant_properties of a
328 // simple object literal.
329 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
330 value = CreateLiteralBoilerplate(literals, array);
331 if (value.is_null()) return value;
332 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000333 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000334 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000335 if (key->IsSymbol()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000336 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
337 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000338 result = SetOwnElement(boilerplate,
339 element_index,
340 value,
341 kNonStrictMode);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000342 } else {
343 Handle<String> name(String::cast(*key));
344 ASSERT(!name->AsArrayIndex(&element_index));
345 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
346 value, NONE);
347 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000348 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349 // Array index (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000350 result = SetOwnElement(boilerplate,
351 element_index,
352 value,
353 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354 } else {
355 // Non-uint32 number.
356 ASSERT(key->IsNumber());
357 double num = key->Number();
358 char arr[100];
359 Vector<char> buffer(arr, ARRAY_SIZE(arr));
360 const char* str = DoubleToCString(num, buffer);
361 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000362 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
363 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000365 // If setting the property on the boilerplate throws an
366 // exception, the exception is converted to an empty handle in
367 // the handle based operations. In that case, we need to
368 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000369 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000370 }
371 }
372
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000373 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000374}
375
376
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000377static Handle<Object> CreateArrayLiteralBoilerplate(
378 Handle<FixedArray> literals,
379 Handle<FixedArray> elements) {
380 // Create the JSArray.
381 Handle<JSFunction> constructor(
382 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
383 Handle<Object> object = Factory::NewJSObject(constructor);
384
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000385 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
386 Handle<FixedArray> copied_elements =
387 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000388
389 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000390 if (is_cow) {
391#ifdef DEBUG
392 // Copy-on-write arrays must be shallow (and simple).
393 for (int i = 0; i < content->length(); i++) {
394 ASSERT(!content->get(i)->IsFixedArray());
395 }
396#endif
397 } else {
398 for (int i = 0; i < content->length(); i++) {
399 if (content->get(i)->IsFixedArray()) {
400 // The value contains the constant_properties of a
401 // simple object literal.
402 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
403 Handle<Object> result =
404 CreateLiteralBoilerplate(literals, fa);
405 if (result.is_null()) return result;
406 content->set(i, *result);
407 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000408 }
409 }
410
411 // Set the elements.
412 Handle<JSArray>::cast(object)->SetContent(*content);
413 return object;
414}
415
416
417static Handle<Object> CreateLiteralBoilerplate(
418 Handle<FixedArray> literals,
419 Handle<FixedArray> array) {
420 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
421 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000422 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
423 return CreateObjectLiteralBoilerplate(literals, elements, true);
424 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
425 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000426 case CompileTimeValue::ARRAY_LITERAL:
427 return CreateArrayLiteralBoilerplate(literals, elements);
428 default:
429 UNREACHABLE();
430 return Handle<Object>::null();
431 }
432}
433
434
lrn@chromium.org303ada72010-10-27 09:33:13 +0000435static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000436 // Takes a FixedArray of elements containing the literal elements of
437 // the array literal and produces JSArray with those elements.
438 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000439 // which contains the context from which to get the Array function
440 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000441 HandleScope scope;
442 ASSERT(args.length() == 3);
443 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
444 CONVERT_SMI_CHECKED(literals_index, args[1]);
445 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000446
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000447 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
448 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000450 // Update the functions literal and return the boilerplate.
451 literals->set(literals_index, *object);
452 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000453}
454
455
lrn@chromium.org303ada72010-10-27 09:33:13 +0000456static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000457 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000458 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000459 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
460 CONVERT_SMI_CHECKED(literals_index, args[1]);
461 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000462 CONVERT_SMI_CHECKED(fast_elements, args[3]);
463 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000464
465 // Check if boilerplate exists. If not, create it first.
466 Handle<Object> boilerplate(literals->get(literals_index));
467 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000468 boilerplate = CreateObjectLiteralBoilerplate(literals,
469 constant_properties,
470 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000471 if (boilerplate.is_null()) return Failure::Exception();
472 // Update the functions literal and return the boilerplate.
473 literals->set(literals_index, *boilerplate);
474 }
475 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
476}
477
478
lrn@chromium.org303ada72010-10-27 09:33:13 +0000479static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000480 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000481 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000482 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
483 CONVERT_SMI_CHECKED(literals_index, args[1]);
484 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000485 CONVERT_SMI_CHECKED(fast_elements, args[3]);
486 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000487
488 // Check if boilerplate exists. If not, create it first.
489 Handle<Object> boilerplate(literals->get(literals_index));
490 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000491 boilerplate = CreateObjectLiteralBoilerplate(literals,
492 constant_properties,
493 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000494 if (boilerplate.is_null()) return Failure::Exception();
495 // Update the functions literal and return the boilerplate.
496 literals->set(literals_index, *boilerplate);
497 }
498 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
499}
500
501
lrn@chromium.org303ada72010-10-27 09:33:13 +0000502static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000503 HandleScope scope;
504 ASSERT(args.length() == 3);
505 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
506 CONVERT_SMI_CHECKED(literals_index, args[1]);
507 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
508
509 // Check if boilerplate exists. If not, create it first.
510 Handle<Object> boilerplate(literals->get(literals_index));
511 if (*boilerplate == Heap::undefined_value()) {
512 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
513 if (boilerplate.is_null()) return Failure::Exception();
514 // Update the functions literal and return the boilerplate.
515 literals->set(literals_index, *boilerplate);
516 }
517 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
518}
519
520
lrn@chromium.org303ada72010-10-27 09:33:13 +0000521static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000522 HandleScope scope;
523 ASSERT(args.length() == 3);
524 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
525 CONVERT_SMI_CHECKED(literals_index, args[1]);
526 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
527
528 // Check if boilerplate exists. If not, create it first.
529 Handle<Object> boilerplate(literals->get(literals_index));
530 if (*boilerplate == Heap::undefined_value()) {
531 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
532 if (boilerplate.is_null()) return Failure::Exception();
533 // Update the functions literal and return the boilerplate.
534 literals->set(literals_index, *boilerplate);
535 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000536 if (JSObject::cast(*boilerplate)->elements()->map() ==
537 Heap::fixed_cow_array_map()) {
538 Counters::cow_arrays_created_runtime.Increment();
539 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
541}
542
543
lrn@chromium.org303ada72010-10-27 09:33:13 +0000544static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000545 ASSERT(args.length() == 2);
546 CONVERT_CHECKED(String, key, args[0]);
547 Object* value = args[1];
548 // Create a catch context extension object.
549 JSFunction* constructor =
550 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000551 Object* object;
552 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
553 if (!maybe_object->ToObject(&object)) return maybe_object;
554 }
ager@chromium.org32912102009-01-16 10:38:43 +0000555 // Assign the exception value to the catch variable and make sure
556 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000557 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000558 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
559 JSObject::cast(object)->SetProperty(
560 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000561 if (!maybe_value->ToObject(&value)) return maybe_value;
562 }
ager@chromium.org32912102009-01-16 10:38:43 +0000563 return object;
564}
565
566
lrn@chromium.org303ada72010-10-27 09:33:13 +0000567static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568 NoHandleAllocation ha;
569 ASSERT(args.length() == 1);
570 Object* obj = args[0];
571 if (!obj->IsJSObject()) return Heap::null_value();
572 return JSObject::cast(obj)->class_name();
573}
574
ager@chromium.org7c537e22008-10-16 08:43:32 +0000575
lrn@chromium.org303ada72010-10-27 09:33:13 +0000576static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000577 NoHandleAllocation ha;
578 ASSERT(args.length() == 2);
579 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
580 Object* O = args[0];
581 Object* V = args[1];
582 while (true) {
583 Object* prototype = V->GetPrototype();
584 if (prototype->IsNull()) return Heap::false_value();
585 if (O == prototype) return Heap::true_value();
586 V = prototype;
587 }
588}
589
590
ager@chromium.org9085a012009-05-11 19:22:57 +0000591// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000592static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000593 NoHandleAllocation ha;
594 ASSERT(args.length() == 2);
595 CONVERT_CHECKED(JSObject, jsobject, args[0]);
596 CONVERT_CHECKED(JSObject, proto, args[1]);
597
598 // Sanity checks. The old prototype (that we are replacing) could
599 // theoretically be null, but if it is not null then check that we
600 // didn't already install a hidden prototype here.
601 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
602 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
603 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
604
605 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000606 Object* map_or_failure;
607 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
608 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
609 return maybe_map_or_failure;
610 }
611 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000612 Map* new_proto_map = Map::cast(map_or_failure);
613
lrn@chromium.org303ada72010-10-27 09:33:13 +0000614 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
615 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
616 return maybe_map_or_failure;
617 }
618 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000619 Map* new_map = Map::cast(map_or_failure);
620
621 // Set proto's prototype to be the old prototype of the object.
622 new_proto_map->set_prototype(jsobject->GetPrototype());
623 proto->set_map(new_proto_map);
624 new_proto_map->set_is_hidden_prototype();
625
626 // Set the object's prototype to proto.
627 new_map->set_prototype(proto);
628 jsobject->set_map(new_map);
629
630 return Heap::undefined_value();
631}
632
633
lrn@chromium.org303ada72010-10-27 09:33:13 +0000634static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000635 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000636 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000637 JavaScriptFrameIterator it;
638 return Heap::ToBoolean(it.frame()->IsConstructor());
639}
640
641
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000642// Recursively traverses hidden prototypes if property is not found
643static void GetOwnPropertyImplementation(JSObject* obj,
644 String* name,
645 LookupResult* result) {
646 obj->LocalLookupRealNamedProperty(name, result);
647
648 if (!result->IsProperty()) {
649 Object* proto = obj->GetPrototype();
650 if (proto->IsJSObject() &&
651 JSObject::cast(proto)->map()->is_hidden_prototype())
652 GetOwnPropertyImplementation(JSObject::cast(proto),
653 name, result);
654 }
655}
656
657
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000658static bool CheckAccessException(LookupResult* result,
659 v8::AccessType access_type) {
660 if (result->type() == CALLBACKS) {
661 Object* callback = result->GetCallbackObject();
662 if (callback->IsAccessorInfo()) {
663 AccessorInfo* info = AccessorInfo::cast(callback);
664 bool can_access =
665 (access_type == v8::ACCESS_HAS &&
666 (info->all_can_read() || info->all_can_write())) ||
667 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
668 (access_type == v8::ACCESS_SET && info->all_can_write());
669 return can_access;
670 }
671 }
672
673 return false;
674}
675
676
677static bool CheckAccess(JSObject* obj,
678 String* name,
679 LookupResult* result,
680 v8::AccessType access_type) {
681 ASSERT(result->IsProperty());
682
683 JSObject* holder = result->holder();
684 JSObject* current = obj;
685 while (true) {
686 if (current->IsAccessCheckNeeded() &&
687 !Top::MayNamedAccess(current, name, access_type)) {
688 // Access check callback denied the access, but some properties
689 // can have a special permissions which override callbacks descision
690 // (currently see v8::AccessControl).
691 break;
692 }
693
694 if (current == holder) {
695 return true;
696 }
697
698 current = JSObject::cast(current->GetPrototype());
699 }
700
701 // API callbacks can have per callback access exceptions.
702 switch (result->type()) {
703 case CALLBACKS: {
704 if (CheckAccessException(result, access_type)) {
705 return true;
706 }
707 break;
708 }
709 case INTERCEPTOR: {
710 // If the object has an interceptor, try real named properties.
711 // Overwrite the result to fetch the correct property later.
712 holder->LookupRealNamedProperty(name, result);
713 if (result->IsProperty()) {
714 if (CheckAccessException(result, access_type)) {
715 return true;
716 }
717 }
718 break;
719 }
720 default:
721 break;
722 }
723
724 Top::ReportFailedAccessCheck(current, access_type);
725 return false;
726}
727
728
729// TODO(1095): we should traverse hidden prototype hierachy as well.
730static bool CheckElementAccess(JSObject* obj,
731 uint32_t index,
732 v8::AccessType access_type) {
733 if (obj->IsAccessCheckNeeded() &&
734 !Top::MayIndexedAccess(obj, index, access_type)) {
735 return false;
736 }
737
738 return true;
739}
740
741
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000742// Enumerator used as indices into the array returned from GetOwnProperty
743enum PropertyDescriptorIndices {
744 IS_ACCESSOR_INDEX,
745 VALUE_INDEX,
746 GETTER_INDEX,
747 SETTER_INDEX,
748 WRITABLE_INDEX,
749 ENUMERABLE_INDEX,
750 CONFIGURABLE_INDEX,
751 DESCRIPTOR_SIZE
752};
753
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000754// Returns an array with the property description:
755// if args[1] is not a property on args[0]
756// returns undefined
757// if args[1] is a data property on args[0]
758// [false, value, Writeable, Enumerable, Configurable]
759// if args[1] is an accessor on args[0]
760// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000761static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000762 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000763 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000764 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000765 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
766 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000767 CONVERT_ARG_CHECKED(JSObject, obj, 0);
768 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000769
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000770 // This could be an element.
771 uint32_t index;
772 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000773 switch (obj->HasLocalElement(index)) {
774 case JSObject::UNDEFINED_ELEMENT:
775 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000776
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000777 case JSObject::STRING_CHARACTER_ELEMENT: {
778 // Special handling of string objects according to ECMAScript 5
779 // 15.5.5.2. Note that this might be a string object with elements
780 // other than the actual string value. This is covered by the
781 // subsequent cases.
782 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
783 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000784 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000785
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000786 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
787 elms->set(VALUE_INDEX, *substr);
788 elms->set(WRITABLE_INDEX, Heap::false_value());
789 elms->set(ENUMERABLE_INDEX, Heap::false_value());
790 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
791 return *desc;
792 }
793
794 case JSObject::INTERCEPTED_ELEMENT:
795 case JSObject::FAST_ELEMENT: {
796 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000797 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000798 RETURN_IF_EMPTY_HANDLE(value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000799 elms->set(VALUE_INDEX, *value);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000800 elms->set(WRITABLE_INDEX, Heap::true_value());
801 elms->set(ENUMERABLE_INDEX, Heap::true_value());
802 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
803 return *desc;
804 }
805
806 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000807 Handle<JSObject> holder = obj;
808 if (obj->IsJSGlobalProxy()) {
809 Object* proto = obj->GetPrototype();
810 if (proto->IsNull()) return Heap::undefined_value();
811 ASSERT(proto->IsJSGlobalObject());
812 holder = Handle<JSObject>(JSObject::cast(proto));
813 }
814 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000815 int entry = dictionary->FindEntry(index);
816 ASSERT(entry != NumberDictionary::kNotFound);
817 PropertyDetails details = dictionary->DetailsAt(entry);
818 switch (details.type()) {
819 case CALLBACKS: {
820 // This is an accessor property with getter and/or setter.
821 FixedArray* callbacks =
822 FixedArray::cast(dictionary->ValueAt(entry));
823 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000824 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
825 elms->set(GETTER_INDEX, callbacks->get(0));
826 }
827 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
828 elms->set(SETTER_INDEX, callbacks->get(1));
829 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000830 break;
831 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000832 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000833 // This is a data property.
834 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000835 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000836 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000837 elms->set(VALUE_INDEX, *value);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000838 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
839 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000840 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000841 default:
842 UNREACHABLE();
843 break;
844 }
845 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
846 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
847 return *desc;
848 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000849 }
850 }
851
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000852 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000853 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000854
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000855 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000856 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000857 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000858
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000859 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
860 return Heap::false_value();
861 }
862
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000863 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
864 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000865
866 bool is_js_accessor = (result.type() == CALLBACKS) &&
867 (result.GetCallbackObject()->IsFixedArray());
868
869 if (is_js_accessor) {
870 // __defineGetter__/__defineSetter__ callback.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000871 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000872
873 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
874 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
875 elms->set(GETTER_INDEX, structure->get(0));
876 }
877 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
878 elms->set(SETTER_INDEX, structure->get(1));
879 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000880 } else {
881 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
882 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
883
884 PropertyAttributes attrs;
885 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000886 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000887 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
888 if (!maybe_value->ToObject(&value)) return maybe_value;
889 }
890 elms->set(VALUE_INDEX, value);
891 }
892
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000893 return *desc;
894}
895
896
lrn@chromium.org303ada72010-10-27 09:33:13 +0000897static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000898 ASSERT(args.length() == 1);
899 CONVERT_CHECKED(JSObject, obj, args[0]);
900 return obj->PreventExtensions();
901}
902
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000903
lrn@chromium.org303ada72010-10-27 09:33:13 +0000904static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000905 ASSERT(args.length() == 1);
906 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000907 if (obj->IsJSGlobalProxy()) {
908 Object* proto = obj->GetPrototype();
909 if (proto->IsNull()) return Heap::false_value();
910 ASSERT(proto->IsJSGlobalObject());
911 obj = JSObject::cast(proto);
912 }
913 return obj->map()->is_extensible() ? Heap::true_value()
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000914 : Heap::false_value();
915}
916
917
lrn@chromium.org303ada72010-10-27 09:33:13 +0000918static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000919 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000920 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000921 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
922 CONVERT_ARG_CHECKED(String, pattern, 1);
923 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000924 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
925 if (result.is_null()) return Failure::Exception();
926 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927}
928
929
lrn@chromium.org303ada72010-10-27 09:33:13 +0000930static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931 HandleScope scope;
932 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000933 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934 return *Factory::CreateApiFunction(data);
935}
936
937
lrn@chromium.org303ada72010-10-27 09:33:13 +0000938static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000939 ASSERT(args.length() == 1);
940 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000941 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942 return Heap::ToBoolean(result);
943}
944
945
lrn@chromium.org303ada72010-10-27 09:33:13 +0000946static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000947 ASSERT(args.length() == 2);
948 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000949 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000950 int index = field->value();
951 int offset = index * kPointerSize + HeapObject::kHeaderSize;
952 InstanceType type = templ->map()->instance_type();
953 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
954 type == OBJECT_TEMPLATE_INFO_TYPE);
955 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000956 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000957 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
958 } else {
959 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
960 }
961 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000962}
963
964
lrn@chromium.org303ada72010-10-27 09:33:13 +0000965static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000966 ASSERT(args.length() == 1);
967 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000968 Map* old_map = object->map();
969 bool needs_access_checks = old_map->is_access_check_needed();
970 if (needs_access_checks) {
971 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000972 Object* new_map;
973 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
974 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
975 }
ager@chromium.org32912102009-01-16 10:38:43 +0000976
977 Map::cast(new_map)->set_is_access_check_needed(false);
978 object->set_map(Map::cast(new_map));
979 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000980 return needs_access_checks ? Heap::true_value() : Heap::false_value();
981}
982
983
lrn@chromium.org303ada72010-10-27 09:33:13 +0000984static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000985 ASSERT(args.length() == 1);
986 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000987 Map* old_map = object->map();
988 if (!old_map->is_access_check_needed()) {
989 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000990 Object* new_map;
991 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
992 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
993 }
ager@chromium.org32912102009-01-16 10:38:43 +0000994
995 Map::cast(new_map)->set_is_access_check_needed(true);
996 object->set_map(Map::cast(new_map));
997 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000998 return Heap::undefined_value();
999}
1000
1001
lrn@chromium.org303ada72010-10-27 09:33:13 +00001002static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 HandleScope scope;
1004 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
1005 Handle<Object> args[2] = { type_handle, name };
1006 Handle<Object> error =
1007 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
1008 return Top::Throw(*error);
1009}
1010
1011
lrn@chromium.org303ada72010-10-27 09:33:13 +00001012static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001013 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014 HandleScope scope;
1015 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
1016
ager@chromium.org3811b432009-10-28 14:53:37 +00001017 Handle<Context> context = args.at<Context>(0);
1018 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001020 StrictModeFlag strict_mode =
1021 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1022 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023
1024 // Compute the property attributes. According to ECMA-262, section
1025 // 13, page 71, the property must be read-only and
1026 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1027 // property as read-only, so we don't either.
1028 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1029
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001030 // Traverse the name/value pairs and set the properties.
1031 int length = pairs->length();
1032 for (int i = 0; i < length; i += 2) {
1033 HandleScope scope;
1034 Handle<String> name(String::cast(pairs->get(i)));
1035 Handle<Object> value(pairs->get(i + 1));
1036
1037 // We have to declare a global const property. To capture we only
1038 // assign to it when evaluating the assignment for "const x =
1039 // <expr>" the initial value is the hole.
1040 bool is_const_property = value->IsTheHole();
1041
1042 if (value->IsUndefined() || is_const_property) {
1043 // Lookup the property in the global object, and don't set the
1044 // value of the variable if the property is already there.
1045 LookupResult lookup;
1046 global->Lookup(*name, &lookup);
1047 if (lookup.IsProperty()) {
1048 // Determine if the property is local by comparing the holder
1049 // against the global object. The information will be used to
1050 // avoid throwing re-declaration errors when declaring
1051 // variables or constants that exist in the prototype chain.
1052 bool is_local = (*global == lookup.holder());
1053 // Get the property attributes and determine if the property is
1054 // read-only.
1055 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1056 bool is_read_only = (attributes & READ_ONLY) != 0;
1057 if (lookup.type() == INTERCEPTOR) {
1058 // If the interceptor says the property is there, we
1059 // just return undefined without overwriting the property.
1060 // Otherwise, we continue to setting the property.
1061 if (attributes != ABSENT) {
1062 // Check if the existing property conflicts with regards to const.
1063 if (is_local && (is_read_only || is_const_property)) {
1064 const char* type = (is_read_only) ? "const" : "var";
1065 return ThrowRedeclarationError(type, name);
1066 };
1067 // The property already exists without conflicting: Go to
1068 // the next declaration.
1069 continue;
1070 }
1071 // Fall-through and introduce the absent property by using
1072 // SetProperty.
1073 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001074 // For const properties, we treat a callback with this name
1075 // even in the prototype as a conflicting declaration.
1076 if (is_const_property && (lookup.type() == CALLBACKS)) {
1077 return ThrowRedeclarationError("const", name);
1078 }
1079 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080 if (is_local && (is_read_only || is_const_property)) {
1081 const char* type = (is_read_only) ? "const" : "var";
1082 return ThrowRedeclarationError(type, name);
1083 }
1084 // The property already exists without conflicting: Go to
1085 // the next declaration.
1086 continue;
1087 }
1088 }
1089 } else {
1090 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001091 Handle<SharedFunctionInfo> shared =
1092 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001094 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001095 value = function;
1096 }
1097
1098 LookupResult lookup;
1099 global->LocalLookup(*name, &lookup);
1100
1101 PropertyAttributes attributes = is_const_property
1102 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1103 : base;
1104
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001105 // There's a local property that we need to overwrite because
1106 // we're either declaring a function or there's an interceptor
1107 // that claims the property is absent.
1108 //
1109 // Check for conflicting re-declarations. We cannot have
1110 // conflicting types in case of intercepted properties because
1111 // they are absent.
1112 if (lookup.IsProperty() &&
1113 (lookup.type() != INTERCEPTOR) &&
1114 (lookup.IsReadOnly() || is_const_property)) {
1115 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
1116 return ThrowRedeclarationError(type, name);
1117 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001119 // Safari does not allow the invocation of callback setters for
1120 // function declarations. To mimic this behavior, we do not allow
1121 // the invocation of setters for function values. This makes a
1122 // difference for global functions with the same names as event
1123 // handlers such as "function onload() {}". Firefox does call the
1124 // onload setter in those case and Safari does not. We follow
1125 // Safari for compatibility.
1126 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001127 // Do not change DONT_DELETE to false from true.
1128 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1129 attributes = static_cast<PropertyAttributes>(
1130 attributes | (lookup.GetAttributes() & DONT_DELETE));
1131 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001132 RETURN_IF_EMPTY_HANDLE(SetLocalPropertyIgnoreAttributes(global,
1133 name,
1134 value,
1135 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001136 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001137 RETURN_IF_EMPTY_HANDLE(SetProperty(global,
1138 name,
1139 value,
1140 attributes,
1141 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001142 }
1143 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001144
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001145 ASSERT(!Top::has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146 return Heap::undefined_value();
1147}
1148
1149
lrn@chromium.org303ada72010-10-27 09:33:13 +00001150static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001152 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001153
ager@chromium.org7c537e22008-10-16 08:43:32 +00001154 CONVERT_ARG_CHECKED(Context, context, 0);
1155 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001156 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001157 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001158 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001159 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001160
1161 // Declarations are always done in the function context.
1162 context = Handle<Context>(context->fcontext());
1163
1164 int index;
1165 PropertyAttributes attributes;
1166 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001167 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 context->Lookup(name, flags, &index, &attributes);
1169
1170 if (attributes != ABSENT) {
1171 // The name was declared before; check for conflicting
1172 // re-declarations: This is similar to the code in parser.cc in
1173 // the AstBuildingParser::Declare function.
1174 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1175 // Functions are not read-only.
1176 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1177 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1178 return ThrowRedeclarationError(type, name);
1179 }
1180
1181 // Initialize it if necessary.
1182 if (*initial_value != NULL) {
1183 if (index >= 0) {
1184 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001185 // the function context or the arguments object.
1186 if (holder->IsContext()) {
1187 ASSERT(holder.is_identical_to(context));
1188 if (((attributes & READ_ONLY) == 0) ||
1189 context->get(index)->IsTheHole()) {
1190 context->set(index, *initial_value);
1191 }
1192 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001193 // The holder is an arguments object.
1194 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001195 Handle<Object> result = SetElement(arguments, index, initial_value,
1196 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001197 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198 }
1199 } else {
1200 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001201 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001202 RETURN_IF_EMPTY_HANDLE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001203 SetProperty(context_ext, name, initial_value,
1204 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 }
1206 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001207
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001208 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001209 // The property is not in the function context. It needs to be
1210 // "declared" in the function context's extension context, or in the
1211 // global context.
1212 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001213 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001214 // The function context's extension context exists - use it.
1215 context_ext = Handle<JSObject>(context->extension());
1216 } else {
1217 // The function context's extension context does not exists - allocate
1218 // it.
1219 context_ext = Factory::NewJSObject(Top::context_extension_function());
1220 // And store it in the extension slot.
1221 context->set_extension(*context_ext);
1222 }
1223 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001224
ager@chromium.org7c537e22008-10-16 08:43:32 +00001225 // Declare the property by setting it to the initial value if provided,
1226 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1227 // constant declarations).
1228 ASSERT(!context_ext->HasLocalProperty(*name));
1229 Handle<Object> value(Heap::undefined_value());
1230 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001231 // Declaring a const context slot is a conflicting declaration if
1232 // there is a callback with that name in a prototype. It is
1233 // allowed to introduce const variables in
1234 // JSContextExtensionObjects. They are treated specially in
1235 // SetProperty and no setters are invoked for those since they are
1236 // not real JSObjects.
1237 if (initial_value->IsTheHole() &&
1238 !context_ext->IsJSContextExtensionObject()) {
1239 LookupResult lookup;
1240 context_ext->Lookup(*name, &lookup);
1241 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
1242 return ThrowRedeclarationError("const", name);
1243 }
1244 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001245 RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, mode,
1246 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001247 }
1248
1249 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001250}
1251
1252
lrn@chromium.org303ada72010-10-27 09:33:13 +00001253static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001255 // args[0] == name
1256 // args[1] == strict_mode
1257 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258
1259 // Determine if we need to assign to the variable if it already
1260 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001261 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1262 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263
1264 CONVERT_ARG_CHECKED(String, name, 0);
1265 GlobalObject* global = Top::context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001266 RUNTIME_ASSERT(args[1]->IsSmi());
1267 StrictModeFlag strict_mode =
1268 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1269 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270
1271 // According to ECMA-262, section 12.2, page 62, the property must
1272 // not be deletable.
1273 PropertyAttributes attributes = DONT_DELETE;
1274
1275 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001276 // there, there is a property with this name in the prototype chain.
1277 // We follow Safari and Firefox behavior and only set the property
1278 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001279 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001280 // Note that objects can have hidden prototypes, so we need to traverse
1281 // the whole chain of hidden prototypes to do a 'local' lookup.
1282 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001284 while (true) {
1285 real_holder->LocalLookup(*name, &lookup);
1286 if (lookup.IsProperty()) {
1287 // Determine if this is a redeclaration of something read-only.
1288 if (lookup.IsReadOnly()) {
1289 // If we found readonly property on one of hidden prototypes,
1290 // just shadow it.
1291 if (real_holder != Top::context()->global()) break;
1292 return ThrowRedeclarationError("const", name);
1293 }
1294
1295 // Determine if this is a redeclaration of an intercepted read-only
1296 // property and figure out if the property exists at all.
1297 bool found = true;
1298 PropertyType type = lookup.type();
1299 if (type == INTERCEPTOR) {
1300 HandleScope handle_scope;
1301 Handle<JSObject> holder(real_holder);
1302 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1303 real_holder = *holder;
1304 if (intercepted == ABSENT) {
1305 // The interceptor claims the property isn't there. We need to
1306 // make sure to introduce it.
1307 found = false;
1308 } else if ((intercepted & READ_ONLY) != 0) {
1309 // The property is present, but read-only. Since we're trying to
1310 // overwrite it with a variable declaration we must throw a
1311 // re-declaration error. However if we found readonly property
1312 // on one of hidden prototypes, just shadow it.
1313 if (real_holder != Top::context()->global()) break;
1314 return ThrowRedeclarationError("const", name);
1315 }
1316 }
1317
1318 if (found && !assign) {
1319 // The global property is there and we're not assigning any value
1320 // to it. Just return.
1321 return Heap::undefined_value();
1322 }
1323
1324 // Assign the value (or undefined) to the property.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001325 Object* value = (assign) ? args[2] : Heap::undefined_value();
1326 return real_holder->SetProperty(
1327 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001328 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001329
1330 Object* proto = real_holder->GetPrototype();
1331 if (!proto->IsJSObject())
1332 break;
1333
1334 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1335 break;
1336
1337 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 }
1339
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001340 global = Top::context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001341 if (assign) {
1342 return global->SetProperty(*name, args[2], attributes, strict_mode);
1343 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001344 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345}
1346
1347
lrn@chromium.org303ada72010-10-27 09:33:13 +00001348static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001349 // All constants are declared with an initial value. The name
1350 // of the constant is the first argument and the initial value
1351 // is the second.
1352 RUNTIME_ASSERT(args.length() == 2);
1353 CONVERT_ARG_CHECKED(String, name, 0);
1354 Handle<Object> value = args.at<Object>(1);
1355
1356 // Get the current global object from top.
1357 GlobalObject* global = Top::context()->global();
1358
1359 // According to ECMA-262, section 12.2, page 62, the property must
1360 // not be deletable. Since it's a const, it must be READ_ONLY too.
1361 PropertyAttributes attributes =
1362 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1363
1364 // Lookup the property locally in the global object. If it isn't
1365 // there, we add the property and take special precautions to always
1366 // add it as a local property even in case of callbacks in the
1367 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001368 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369 LookupResult lookup;
1370 global->LocalLookup(*name, &lookup);
1371 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001372 return global->SetLocalPropertyIgnoreAttributes(*name,
1373 *value,
1374 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001375 }
1376
1377 // Determine if this is a redeclaration of something not
1378 // read-only. In case the result is hidden behind an interceptor we
1379 // need to ask it for the property attributes.
1380 if (!lookup.IsReadOnly()) {
1381 if (lookup.type() != INTERCEPTOR) {
1382 return ThrowRedeclarationError("var", name);
1383 }
1384
1385 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1386
1387 // Throw re-declaration error if the intercepted property is present
1388 // but not read-only.
1389 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1390 return ThrowRedeclarationError("var", name);
1391 }
1392
1393 // Restore global object from context (in case of GC) and continue
1394 // with setting the value because the property is either absent or
1395 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001396 HandleScope handle_scope;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001397 Handle<GlobalObject> global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001399 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400 // property through an interceptor and only do it if it's
1401 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001402 // Passing non-strict mode because the property is writable.
1403 RETURN_IF_EMPTY_HANDLE(SetProperty(global,
1404 name,
1405 value,
1406 attributes,
1407 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001408 return *value;
1409 }
1410
1411 // Set the value, but only we're assigning the initial value to a
1412 // constant. For now, we determine this by checking if the
1413 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001414 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415 PropertyType type = lookup.type();
1416 if (type == FIELD) {
1417 FixedArray* properties = global->properties();
1418 int index = lookup.GetFieldIndex();
1419 if (properties->get(index)->IsTheHole()) {
1420 properties->set(index, *value);
1421 }
1422 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001423 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1424 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425 }
1426 } else {
1427 // Ignore re-initialization of constants that have already been
1428 // assigned a function value.
1429 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1430 }
1431
1432 // Use the set value as the result of the operation.
1433 return *value;
1434}
1435
1436
lrn@chromium.org303ada72010-10-27 09:33:13 +00001437static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001438 HandleScope scope;
1439 ASSERT(args.length() == 3);
1440
1441 Handle<Object> value(args[0]);
1442 ASSERT(!value->IsTheHole());
1443 CONVERT_ARG_CHECKED(Context, context, 1);
1444 Handle<String> name(String::cast(args[2]));
1445
1446 // Initializations are always done in the function context.
1447 context = Handle<Context>(context->fcontext());
1448
1449 int index;
1450 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001451 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001452 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001453 context->Lookup(name, flags, &index, &attributes);
1454
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001455 // In most situations, the property introduced by the const
1456 // declaration should be present in the context extension object.
1457 // However, because declaration and initialization are separate, the
1458 // property might have been deleted (if it was introduced by eval)
1459 // before we reach the initialization point.
1460 //
1461 // Example:
1462 //
1463 // function f() { eval("delete x; const x;"); }
1464 //
1465 // In that case, the initialization behaves like a normal assignment
1466 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001468 // Property was found in a context.
1469 if (holder->IsContext()) {
1470 // The holder cannot be the function context. If it is, there
1471 // should have been a const redeclaration error when declaring
1472 // the const property.
1473 ASSERT(!holder.is_identical_to(context));
1474 if ((attributes & READ_ONLY) == 0) {
1475 Handle<Context>::cast(holder)->set(index, *value);
1476 }
1477 } else {
1478 // The holder is an arguments object.
1479 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001480 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001481 RETURN_IF_EMPTY_HANDLE(
1482 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 }
1484 return *value;
1485 }
1486
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001487 // The property could not be found, we introduce it in the global
1488 // context.
1489 if (attributes == ABSENT) {
1490 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001491 // Strict mode not needed (const disallowed in strict mode).
1492 RETURN_IF_EMPTY_HANDLE(
1493 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001494 return *value;
1495 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001496
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001497 // The property was present in a context extension object.
1498 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001499
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001500 if (*context_ext == context->extension()) {
1501 // This is the property that was introduced by the const
1502 // declaration. Set it if it hasn't been set before. NOTE: We
1503 // cannot use GetProperty() to get the current value as it
1504 // 'unholes' the value.
1505 LookupResult lookup;
1506 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1507 ASSERT(lookup.IsProperty()); // the property was declared
1508 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1509
1510 PropertyType type = lookup.type();
1511 if (type == FIELD) {
1512 FixedArray* properties = context_ext->properties();
1513 int index = lookup.GetFieldIndex();
1514 if (properties->get(index)->IsTheHole()) {
1515 properties->set(index, *value);
1516 }
1517 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001518 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1519 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001520 }
1521 } else {
1522 // We should not reach here. Any real, named property should be
1523 // either a field or a dictionary slot.
1524 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001525 }
1526 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001527 // The property was found in a different context extension object.
1528 // Set it if it is not a read-only property.
1529 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001530 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001531 RETURN_IF_EMPTY_HANDLE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001532 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001533 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001535
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536 return *value;
1537}
1538
1539
lrn@chromium.org303ada72010-10-27 09:33:13 +00001540static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001541 Arguments args) {
1542 HandleScope scope;
1543 ASSERT(args.length() == 2);
1544 CONVERT_ARG_CHECKED(JSObject, object, 0);
1545 CONVERT_SMI_CHECKED(properties, args[1]);
1546 if (object->HasFastProperties()) {
1547 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1548 }
1549 return *object;
1550}
1551
1552
lrn@chromium.org303ada72010-10-27 09:33:13 +00001553static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001555 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001556 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1557 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001558 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001559 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001560 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001561 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001562 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001563 RUNTIME_ASSERT(index >= 0);
1564 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001565 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001566 Handle<Object> result = RegExpImpl::Exec(regexp,
1567 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001568 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001569 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001570 if (result.is_null()) return Failure::Exception();
1571 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572}
1573
1574
lrn@chromium.org303ada72010-10-27 09:33:13 +00001575static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001576 ASSERT(args.length() == 3);
1577 CONVERT_SMI_CHECKED(elements_count, args[0]);
1578 if (elements_count > JSArray::kMaxFastElementsLength) {
1579 return Top::ThrowIllegalOperation();
1580 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001581 Object* new_object;
1582 { MaybeObject* maybe_new_object =
1583 Heap::AllocateFixedArrayWithHoles(elements_count);
1584 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1585 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001586 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001587 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1588 NEW_SPACE,
1589 OLD_POINTER_SPACE);
1590 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1591 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001592 {
1593 AssertNoAllocation no_gc;
1594 HandleScope scope;
1595 reinterpret_cast<HeapObject*>(new_object)->
1596 set_map(Top::global_context()->regexp_result_map());
1597 }
1598 JSArray* array = JSArray::cast(new_object);
1599 array->set_properties(Heap::empty_fixed_array());
1600 array->set_elements(elements);
1601 array->set_length(Smi::FromInt(elements_count));
1602 // Write in-object properties after the length of the array.
1603 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1604 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1605 return array;
1606}
1607
1608
lrn@chromium.org303ada72010-10-27 09:33:13 +00001609static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001610 AssertNoAllocation no_alloc;
1611 ASSERT(args.length() == 5);
1612 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1613 CONVERT_CHECKED(String, source, args[1]);
1614
1615 Object* global = args[2];
1616 if (!global->IsTrue()) global = Heap::false_value();
1617
1618 Object* ignoreCase = args[3];
1619 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1620
1621 Object* multiline = args[4];
1622 if (!multiline->IsTrue()) multiline = Heap::false_value();
1623
1624 Map* map = regexp->map();
1625 Object* constructor = map->constructor();
1626 if (constructor->IsJSFunction() &&
1627 JSFunction::cast(constructor)->initial_map() == map) {
1628 // If we still have the original map, set in-object properties directly.
1629 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1630 // TODO(lrn): Consider skipping write barrier on booleans as well.
1631 // Both true and false should be in oldspace at all times.
1632 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1633 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1634 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1635 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1636 Smi::FromInt(0),
1637 SKIP_WRITE_BARRIER);
1638 return regexp;
1639 }
1640
lrn@chromium.org303ada72010-10-27 09:33:13 +00001641 // Map has changed, so use generic, but slower, method. Since these
1642 // properties were all added as DONT_DELETE they must be present and
1643 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001644 PropertyAttributes final =
1645 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1646 PropertyAttributes writable =
1647 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001648 MaybeObject* result;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001649 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
1650 source,
1651 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001652 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001653 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
1654 global,
1655 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001656 ASSERT(!result->IsFailure());
1657 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001658 regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
1659 ignoreCase,
1660 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001661 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001662 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
1663 multiline,
1664 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001665 ASSERT(!result->IsFailure());
1666 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001667 regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
1668 Smi::FromInt(0),
1669 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001670 ASSERT(!result->IsFailure());
1671 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001672 return regexp;
1673}
1674
1675
lrn@chromium.org303ada72010-10-27 09:33:13 +00001676static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001677 HandleScope scope;
1678 ASSERT(args.length() == 1);
1679 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1680 // This is necessary to enable fast checks for absence of elements
1681 // on Array.prototype and below.
1682 prototype->set_elements(Heap::empty_fixed_array());
1683 return Smi::FromInt(0);
1684}
1685
1686
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001687static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1688 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001689 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001690 Handle<String> key = Factory::LookupAsciiSymbol(name);
1691 Handle<Code> code(Builtins::builtin(builtin_name));
1692 Handle<JSFunction> optimized = Factory::NewFunction(key,
1693 JS_OBJECT_TYPE,
1694 JSObject::kHeaderSize,
1695 code,
1696 false);
1697 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001698 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001699 return optimized;
1700}
1701
1702
lrn@chromium.org303ada72010-10-27 09:33:13 +00001703static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001704 HandleScope scope;
1705 ASSERT(args.length() == 1);
1706 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1707
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001708 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1709 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001710 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1711 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1712 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1713 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001714 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001715
1716 return *holder;
1717}
1718
1719
lrn@chromium.org303ada72010-10-27 09:33:13 +00001720static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001721 // Returns a real global receiver, not one of builtins object.
1722 Context* global_context = Top::context()->global()->global_context();
1723 return global_context->global()->global_receiver();
1724}
1725
1726
lrn@chromium.org303ada72010-10-27 09:33:13 +00001727static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001728 HandleScope scope;
1729 ASSERT(args.length() == 4);
1730 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1731 int index = Smi::cast(args[1])->value();
1732 Handle<String> pattern = args.at<String>(2);
1733 Handle<String> flags = args.at<String>(3);
1734
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001735 // Get the RegExp function from the context in the literals array.
1736 // This is the RegExp function from the context in which the
1737 // function was created. We do not use the RegExp function from the
1738 // current global context because this might be the RegExp function
1739 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001740 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001741 Handle<JSFunction>(
1742 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001743 // Compute the regular expression literal.
1744 bool has_pending_exception;
1745 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001746 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1747 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001748 if (has_pending_exception) {
1749 ASSERT(Top::has_pending_exception());
1750 return Failure::Exception();
1751 }
1752 literals->set(index, *regexp);
1753 return *regexp;
1754}
1755
1756
lrn@chromium.org303ada72010-10-27 09:33:13 +00001757static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001758 NoHandleAllocation ha;
1759 ASSERT(args.length() == 1);
1760
1761 CONVERT_CHECKED(JSFunction, f, args[0]);
1762 return f->shared()->name();
1763}
1764
1765
lrn@chromium.org303ada72010-10-27 09:33:13 +00001766static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001767 NoHandleAllocation ha;
1768 ASSERT(args.length() == 2);
1769
1770 CONVERT_CHECKED(JSFunction, f, args[0]);
1771 CONVERT_CHECKED(String, name, args[1]);
1772 f->shared()->set_name(name);
1773 return Heap::undefined_value();
1774}
1775
1776
lrn@chromium.org303ada72010-10-27 09:33:13 +00001777static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001778 NoHandleAllocation ha;
1779 ASSERT(args.length() == 1);
1780
1781 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001782 Object* obj;
1783 { MaybeObject* maybe_obj = f->RemovePrototype();
1784 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1785 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001786
1787 return Heap::undefined_value();
1788}
1789
1790
lrn@chromium.org303ada72010-10-27 09:33:13 +00001791static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001792 HandleScope scope;
1793 ASSERT(args.length() == 1);
1794
1795 CONVERT_CHECKED(JSFunction, fun, args[0]);
1796 Handle<Object> script = Handle<Object>(fun->shared()->script());
1797 if (!script->IsScript()) return Heap::undefined_value();
1798
1799 return *GetScriptWrapper(Handle<Script>::cast(script));
1800}
1801
1802
lrn@chromium.org303ada72010-10-27 09:33:13 +00001803static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804 NoHandleAllocation ha;
1805 ASSERT(args.length() == 1);
1806
1807 CONVERT_CHECKED(JSFunction, f, args[0]);
1808 return f->shared()->GetSourceCode();
1809}
1810
1811
lrn@chromium.org303ada72010-10-27 09:33:13 +00001812static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001813 NoHandleAllocation ha;
1814 ASSERT(args.length() == 1);
1815
1816 CONVERT_CHECKED(JSFunction, fun, args[0]);
1817 int pos = fun->shared()->start_position();
1818 return Smi::FromInt(pos);
1819}
1820
1821
lrn@chromium.org303ada72010-10-27 09:33:13 +00001822static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001823 ASSERT(args.length() == 2);
1824
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001825 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001826 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1827
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001828 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1829
1830 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001831 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001832}
1833
1834
1835
lrn@chromium.org303ada72010-10-27 09:33:13 +00001836static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001837 NoHandleAllocation ha;
1838 ASSERT(args.length() == 2);
1839
1840 CONVERT_CHECKED(JSFunction, fun, args[0]);
1841 CONVERT_CHECKED(String, name, args[1]);
1842 fun->SetInstanceClassName(name);
1843 return Heap::undefined_value();
1844}
1845
1846
lrn@chromium.org303ada72010-10-27 09:33:13 +00001847static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001848 NoHandleAllocation ha;
1849 ASSERT(args.length() == 2);
1850
1851 CONVERT_CHECKED(JSFunction, fun, args[0]);
1852 CONVERT_CHECKED(Smi, length, args[1]);
1853 fun->shared()->set_length(length->value());
1854 return length;
1855}
1856
1857
lrn@chromium.org303ada72010-10-27 09:33:13 +00001858static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001859 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001860 ASSERT(args.length() == 2);
1861
1862 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001863 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001864 Object* obj;
1865 { MaybeObject* maybe_obj =
1866 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1867 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1868 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 return args[0]; // return TOS
1870}
1871
1872
lrn@chromium.org303ada72010-10-27 09:33:13 +00001873static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001874 NoHandleAllocation ha;
1875 ASSERT(args.length() == 1);
1876
1877 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001878 return f->shared()->IsApiFunction() ? Heap::true_value()
1879 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001880}
1881
lrn@chromium.org303ada72010-10-27 09:33:13 +00001882static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001883 NoHandleAllocation ha;
1884 ASSERT(args.length() == 1);
1885
1886 CONVERT_CHECKED(JSFunction, f, args[0]);
1887 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1888}
1889
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001890
lrn@chromium.org303ada72010-10-27 09:33:13 +00001891static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001892 HandleScope scope;
1893 ASSERT(args.length() == 2);
1894
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001895 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 Handle<Object> code = args.at<Object>(1);
1897
1898 Handle<Context> context(target->context());
1899
1900 if (!code->IsNull()) {
1901 RUNTIME_ASSERT(code->IsJSFunction());
1902 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001903 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001904
1905 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001906 return Failure::Exception();
1907 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001908 // Since we don't store the source for this we should never
1909 // optimize this.
1910 shared->code()->set_optimizable(false);
1911
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001912 // Set the code, scope info, formal parameter count,
1913 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001914 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001915 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001916 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001917 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001919 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001920 // Set the source code of the target function to undefined.
1921 // SetCode is only used for built-in constructors like String,
1922 // Array, and Object, and some web code
1923 // doesn't like seeing source code for constructors.
1924 target->shared()->set_script(Heap::undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001925 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001926 // Clear the optimization hints related to the compiled code as these are no
1927 // longer valid when the code is overwritten.
1928 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 context = Handle<Context>(fun->context());
1930
1931 // Make sure we get a fresh copy of the literal vector to avoid
1932 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001933 int number_of_literals = fun->NumberOfLiterals();
1934 Handle<FixedArray> literals =
1935 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001936 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001937 // Insert the object, regexp and array functions in the literals
1938 // array prefix. These are the functions that will be used when
1939 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001940 literals->set(JSFunction::kLiteralGlobalContextIndex,
1941 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001942 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001943 // It's okay to skip the write barrier here because the literals
1944 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001945 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001946 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947 }
1948
1949 target->set_context(*context);
1950 return *target;
1951}
1952
1953
lrn@chromium.org303ada72010-10-27 09:33:13 +00001954static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001955 HandleScope scope;
1956 ASSERT(args.length() == 2);
1957 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1958 CONVERT_SMI_CHECKED(num, args[1]);
1959 RUNTIME_ASSERT(num >= 0);
1960 SetExpectedNofProperties(function, num);
1961 return Heap::undefined_value();
1962}
1963
1964
lrn@chromium.org303ada72010-10-27 09:33:13 +00001965MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001966 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001967 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001968 if (code <= 0xffff) {
1969 return Heap::LookupSingleCharacterStringFromCode(code);
1970 }
1971 }
1972 return Heap::empty_string();
1973}
1974
1975
lrn@chromium.org303ada72010-10-27 09:33:13 +00001976static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001977 NoHandleAllocation ha;
1978 ASSERT(args.length() == 2);
1979
1980 CONVERT_CHECKED(String, subject, args[0]);
1981 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001982 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001983
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001984 uint32_t i = 0;
1985 if (index->IsSmi()) {
1986 int value = Smi::cast(index)->value();
1987 if (value < 0) return Heap::nan_value();
1988 i = value;
1989 } else {
1990 ASSERT(index->IsHeapNumber());
1991 double value = HeapNumber::cast(index)->value();
1992 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001993 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001994
1995 // Flatten the string. If someone wants to get a char at an index
1996 // in a cons string, it is likely that more indices will be
1997 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001998 Object* flat;
1999 { MaybeObject* maybe_flat = subject->TryFlatten();
2000 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2001 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002002 subject = String::cast(flat);
2003
2004 if (i >= static_cast<uint32_t>(subject->length())) {
2005 return Heap::nan_value();
2006 }
2007
2008 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002009}
2010
2011
lrn@chromium.org303ada72010-10-27 09:33:13 +00002012static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 NoHandleAllocation ha;
2014 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002015 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002016}
2017
lrn@chromium.org25156de2010-04-06 13:10:27 +00002018
2019class FixedArrayBuilder {
2020 public:
2021 explicit FixedArrayBuilder(int initial_capacity)
2022 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
2023 length_(0) {
2024 // Require a non-zero initial size. Ensures that doubling the size to
2025 // extend the array will work.
2026 ASSERT(initial_capacity > 0);
2027 }
2028
2029 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2030 : array_(backing_store),
2031 length_(0) {
2032 // Require a non-zero initial size. Ensures that doubling the size to
2033 // extend the array will work.
2034 ASSERT(backing_store->length() > 0);
2035 }
2036
2037 bool HasCapacity(int elements) {
2038 int length = array_->length();
2039 int required_length = length_ + elements;
2040 return (length >= required_length);
2041 }
2042
2043 void EnsureCapacity(int elements) {
2044 int length = array_->length();
2045 int required_length = length_ + elements;
2046 if (length < required_length) {
2047 int new_length = length;
2048 do {
2049 new_length *= 2;
2050 } while (new_length < required_length);
2051 Handle<FixedArray> extended_array =
2052 Factory::NewFixedArrayWithHoles(new_length);
2053 array_->CopyTo(0, *extended_array, 0, length_);
2054 array_ = extended_array;
2055 }
2056 }
2057
2058 void Add(Object* value) {
2059 ASSERT(length_ < capacity());
2060 array_->set(length_, value);
2061 length_++;
2062 }
2063
2064 void Add(Smi* value) {
2065 ASSERT(length_ < capacity());
2066 array_->set(length_, value);
2067 length_++;
2068 }
2069
2070 Handle<FixedArray> array() {
2071 return array_;
2072 }
2073
2074 int length() {
2075 return length_;
2076 }
2077
2078 int capacity() {
2079 return array_->length();
2080 }
2081
2082 Handle<JSArray> ToJSArray() {
2083 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
2084 result_array->set_length(Smi::FromInt(length_));
2085 return result_array;
2086 }
2087
2088 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2089 target_array->set_elements(*array_);
2090 target_array->set_length(Smi::FromInt(length_));
2091 return target_array;
2092 }
2093
2094 private:
2095 Handle<FixedArray> array_;
2096 int length_;
2097};
2098
2099
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002100// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002101const int kStringBuilderConcatHelperLengthBits = 11;
2102const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002103
2104template <typename schar>
2105static inline void StringBuilderConcatHelper(String*,
2106 schar*,
2107 FixedArray*,
2108 int);
2109
lrn@chromium.org25156de2010-04-06 13:10:27 +00002110typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2111 StringBuilderSubstringLength;
2112typedef BitField<int,
2113 kStringBuilderConcatHelperLengthBits,
2114 kStringBuilderConcatHelperPositionBits>
2115 StringBuilderSubstringPosition;
2116
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002117
2118class ReplacementStringBuilder {
2119 public:
2120 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00002121 : array_builder_(estimated_part_count),
2122 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002123 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002124 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002125 // Require a non-zero initial size. Ensures that doubling the size to
2126 // extend the array will work.
2127 ASSERT(estimated_part_count > 0);
2128 }
2129
lrn@chromium.org25156de2010-04-06 13:10:27 +00002130 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2131 int from,
2132 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002133 ASSERT(from >= 0);
2134 int length = to - from;
2135 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002136 if (StringBuilderSubstringLength::is_valid(length) &&
2137 StringBuilderSubstringPosition::is_valid(from)) {
2138 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2139 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002140 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002141 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002142 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002143 builder->Add(Smi::FromInt(-length));
2144 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002145 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002146 }
2147
2148
2149 void EnsureCapacity(int elements) {
2150 array_builder_.EnsureCapacity(elements);
2151 }
2152
2153
2154 void AddSubjectSlice(int from, int to) {
2155 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002156 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002157 }
2158
2159
2160 void AddString(Handle<String> string) {
2161 int length = string->length();
2162 ASSERT(length > 0);
2163 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002164 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002165 is_ascii_ = false;
2166 }
2167 IncrementCharacterCount(length);
2168 }
2169
2170
2171 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002172 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002173 return Factory::empty_string();
2174 }
2175
2176 Handle<String> joined_string;
2177 if (is_ascii_) {
2178 joined_string = NewRawAsciiString(character_count_);
2179 AssertNoAllocation no_alloc;
2180 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2181 char* char_buffer = seq->GetChars();
2182 StringBuilderConcatHelper(*subject_,
2183 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002184 *array_builder_.array(),
2185 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002186 } else {
2187 // Non-ASCII.
2188 joined_string = NewRawTwoByteString(character_count_);
2189 AssertNoAllocation no_alloc;
2190 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2191 uc16* char_buffer = seq->GetChars();
2192 StringBuilderConcatHelper(*subject_,
2193 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002194 *array_builder_.array(),
2195 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002196 }
2197 return joined_string;
2198 }
2199
2200
2201 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002202 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002203 V8::FatalProcessOutOfMemory("String.replace result too large.");
2204 }
2205 character_count_ += by;
2206 }
2207
lrn@chromium.org25156de2010-04-06 13:10:27 +00002208 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002209 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002210 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002211
lrn@chromium.org25156de2010-04-06 13:10:27 +00002212 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002213 Handle<String> NewRawAsciiString(int size) {
2214 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2215 }
2216
2217
2218 Handle<String> NewRawTwoByteString(int size) {
2219 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2220 }
2221
2222
2223 void AddElement(Object* element) {
2224 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002225 ASSERT(array_builder_.capacity() > array_builder_.length());
2226 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002227 }
2228
lrn@chromium.org25156de2010-04-06 13:10:27 +00002229 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002230 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002231 int character_count_;
2232 bool is_ascii_;
2233};
2234
2235
2236class CompiledReplacement {
2237 public:
2238 CompiledReplacement()
2239 : parts_(1), replacement_substrings_(0) {}
2240
2241 void Compile(Handle<String> replacement,
2242 int capture_count,
2243 int subject_length);
2244
2245 void Apply(ReplacementStringBuilder* builder,
2246 int match_from,
2247 int match_to,
2248 Handle<JSArray> last_match_info);
2249
2250 // Number of distinct parts of the replacement pattern.
2251 int parts() {
2252 return parts_.length();
2253 }
2254 private:
2255 enum PartType {
2256 SUBJECT_PREFIX = 1,
2257 SUBJECT_SUFFIX,
2258 SUBJECT_CAPTURE,
2259 REPLACEMENT_SUBSTRING,
2260 REPLACEMENT_STRING,
2261
2262 NUMBER_OF_PART_TYPES
2263 };
2264
2265 struct ReplacementPart {
2266 static inline ReplacementPart SubjectMatch() {
2267 return ReplacementPart(SUBJECT_CAPTURE, 0);
2268 }
2269 static inline ReplacementPart SubjectCapture(int capture_index) {
2270 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2271 }
2272 static inline ReplacementPart SubjectPrefix() {
2273 return ReplacementPart(SUBJECT_PREFIX, 0);
2274 }
2275 static inline ReplacementPart SubjectSuffix(int subject_length) {
2276 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2277 }
2278 static inline ReplacementPart ReplacementString() {
2279 return ReplacementPart(REPLACEMENT_STRING, 0);
2280 }
2281 static inline ReplacementPart ReplacementSubString(int from, int to) {
2282 ASSERT(from >= 0);
2283 ASSERT(to > from);
2284 return ReplacementPart(-from, to);
2285 }
2286
2287 // If tag <= 0 then it is the negation of a start index of a substring of
2288 // the replacement pattern, otherwise it's a value from PartType.
2289 ReplacementPart(int tag, int data)
2290 : tag(tag), data(data) {
2291 // Must be non-positive or a PartType value.
2292 ASSERT(tag < NUMBER_OF_PART_TYPES);
2293 }
2294 // Either a value of PartType or a non-positive number that is
2295 // the negation of an index into the replacement string.
2296 int tag;
2297 // The data value's interpretation depends on the value of tag:
2298 // tag == SUBJECT_PREFIX ||
2299 // tag == SUBJECT_SUFFIX: data is unused.
2300 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2301 // tag == REPLACEMENT_SUBSTRING ||
2302 // tag == REPLACEMENT_STRING: data is index into array of substrings
2303 // of the replacement string.
2304 // tag <= 0: Temporary representation of the substring of the replacement
2305 // string ranging over -tag .. data.
2306 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2307 // substring objects.
2308 int data;
2309 };
2310
2311 template<typename Char>
2312 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2313 Vector<Char> characters,
2314 int capture_count,
2315 int subject_length) {
2316 int length = characters.length();
2317 int last = 0;
2318 for (int i = 0; i < length; i++) {
2319 Char c = characters[i];
2320 if (c == '$') {
2321 int next_index = i + 1;
2322 if (next_index == length) { // No next character!
2323 break;
2324 }
2325 Char c2 = characters[next_index];
2326 switch (c2) {
2327 case '$':
2328 if (i > last) {
2329 // There is a substring before. Include the first "$".
2330 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2331 last = next_index + 1; // Continue after the second "$".
2332 } else {
2333 // Let the next substring start with the second "$".
2334 last = next_index;
2335 }
2336 i = next_index;
2337 break;
2338 case '`':
2339 if (i > last) {
2340 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2341 }
2342 parts->Add(ReplacementPart::SubjectPrefix());
2343 i = next_index;
2344 last = i + 1;
2345 break;
2346 case '\'':
2347 if (i > last) {
2348 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2349 }
2350 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2351 i = next_index;
2352 last = i + 1;
2353 break;
2354 case '&':
2355 if (i > last) {
2356 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2357 }
2358 parts->Add(ReplacementPart::SubjectMatch());
2359 i = next_index;
2360 last = i + 1;
2361 break;
2362 case '0':
2363 case '1':
2364 case '2':
2365 case '3':
2366 case '4':
2367 case '5':
2368 case '6':
2369 case '7':
2370 case '8':
2371 case '9': {
2372 int capture_ref = c2 - '0';
2373 if (capture_ref > capture_count) {
2374 i = next_index;
2375 continue;
2376 }
2377 int second_digit_index = next_index + 1;
2378 if (second_digit_index < length) {
2379 // Peek ahead to see if we have two digits.
2380 Char c3 = characters[second_digit_index];
2381 if ('0' <= c3 && c3 <= '9') { // Double digits.
2382 int double_digit_ref = capture_ref * 10 + c3 - '0';
2383 if (double_digit_ref <= capture_count) {
2384 next_index = second_digit_index;
2385 capture_ref = double_digit_ref;
2386 }
2387 }
2388 }
2389 if (capture_ref > 0) {
2390 if (i > last) {
2391 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2392 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002393 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002394 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2395 last = next_index + 1;
2396 }
2397 i = next_index;
2398 break;
2399 }
2400 default:
2401 i = next_index;
2402 break;
2403 }
2404 }
2405 }
2406 if (length > last) {
2407 if (last == 0) {
2408 parts->Add(ReplacementPart::ReplacementString());
2409 } else {
2410 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2411 }
2412 }
2413 }
2414
2415 ZoneList<ReplacementPart> parts_;
2416 ZoneList<Handle<String> > replacement_substrings_;
2417};
2418
2419
2420void CompiledReplacement::Compile(Handle<String> replacement,
2421 int capture_count,
2422 int subject_length) {
2423 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002424 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002425 AssertNoAllocation no_alloc;
2426 ParseReplacementPattern(&parts_,
2427 replacement->ToAsciiVector(),
2428 capture_count,
2429 subject_length);
2430 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002431 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002432 AssertNoAllocation no_alloc;
2433
2434 ParseReplacementPattern(&parts_,
2435 replacement->ToUC16Vector(),
2436 capture_count,
2437 subject_length);
2438 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002439 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002440 int substring_index = 0;
2441 for (int i = 0, n = parts_.length(); i < n; i++) {
2442 int tag = parts_[i].tag;
2443 if (tag <= 0) { // A replacement string slice.
2444 int from = -tag;
2445 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002446 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002447 parts_[i].tag = REPLACEMENT_SUBSTRING;
2448 parts_[i].data = substring_index;
2449 substring_index++;
2450 } else if (tag == REPLACEMENT_STRING) {
2451 replacement_substrings_.Add(replacement);
2452 parts_[i].data = substring_index;
2453 substring_index++;
2454 }
2455 }
2456}
2457
2458
2459void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2460 int match_from,
2461 int match_to,
2462 Handle<JSArray> last_match_info) {
2463 for (int i = 0, n = parts_.length(); i < n; i++) {
2464 ReplacementPart part = parts_[i];
2465 switch (part.tag) {
2466 case SUBJECT_PREFIX:
2467 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2468 break;
2469 case SUBJECT_SUFFIX: {
2470 int subject_length = part.data;
2471 if (match_to < subject_length) {
2472 builder->AddSubjectSlice(match_to, subject_length);
2473 }
2474 break;
2475 }
2476 case SUBJECT_CAPTURE: {
2477 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002478 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002479 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2480 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2481 if (from >= 0 && to > from) {
2482 builder->AddSubjectSlice(from, to);
2483 }
2484 break;
2485 }
2486 case REPLACEMENT_SUBSTRING:
2487 case REPLACEMENT_STRING:
2488 builder->AddString(replacement_substrings_[part.data]);
2489 break;
2490 default:
2491 UNREACHABLE();
2492 }
2493 }
2494}
2495
2496
2497
lrn@chromium.org303ada72010-10-27 09:33:13 +00002498MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2499 String* subject,
2500 JSRegExp* regexp,
2501 String* replacement,
2502 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002503 ASSERT(subject->IsFlat());
2504 ASSERT(replacement->IsFlat());
2505
2506 HandleScope handles;
2507
2508 int length = subject->length();
2509 Handle<String> subject_handle(subject);
2510 Handle<JSRegExp> regexp_handle(regexp);
2511 Handle<String> replacement_handle(replacement);
2512 Handle<JSArray> last_match_info_handle(last_match_info);
2513 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2514 subject_handle,
2515 0,
2516 last_match_info_handle);
2517 if (match.is_null()) {
2518 return Failure::Exception();
2519 }
2520 if (match->IsNull()) {
2521 return *subject_handle;
2522 }
2523
2524 int capture_count = regexp_handle->CaptureCount();
2525
2526 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002527 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002528 CompiledReplacement compiled_replacement;
2529 compiled_replacement.Compile(replacement_handle,
2530 capture_count,
2531 length);
2532
2533 bool is_global = regexp_handle->GetFlags().is_global();
2534
2535 // Guessing the number of parts that the final result string is built
2536 // from. Global regexps can match any number of times, so we guess
2537 // conservatively.
2538 int expected_parts =
2539 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2540 ReplacementStringBuilder builder(subject_handle, expected_parts);
2541
2542 // Index of end of last match.
2543 int prev = 0;
2544
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002545 // Number of parts added by compiled replacement plus preceeding
2546 // string and possibly suffix after last match. It is possible for
2547 // all components to use two elements when encoded as two smis.
2548 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002549 bool matched = true;
2550 do {
2551 ASSERT(last_match_info_handle->HasFastElements());
2552 // Increase the capacity of the builder before entering local handle-scope,
2553 // so its internal buffer can safely allocate a new handle if it grows.
2554 builder.EnsureCapacity(parts_added_per_loop);
2555
2556 HandleScope loop_scope;
2557 int start, end;
2558 {
2559 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002560 FixedArray* match_info_array =
2561 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002562
2563 ASSERT_EQ(capture_count * 2 + 2,
2564 RegExpImpl::GetLastCaptureCount(match_info_array));
2565 start = RegExpImpl::GetCapture(match_info_array, 0);
2566 end = RegExpImpl::GetCapture(match_info_array, 1);
2567 }
2568
2569 if (prev < start) {
2570 builder.AddSubjectSlice(prev, start);
2571 }
2572 compiled_replacement.Apply(&builder,
2573 start,
2574 end,
2575 last_match_info_handle);
2576 prev = end;
2577
2578 // Only continue checking for global regexps.
2579 if (!is_global) break;
2580
2581 // Continue from where the match ended, unless it was an empty match.
2582 int next = end;
2583 if (start == end) {
2584 next = end + 1;
2585 if (next > length) break;
2586 }
2587
2588 match = RegExpImpl::Exec(regexp_handle,
2589 subject_handle,
2590 next,
2591 last_match_info_handle);
2592 if (match.is_null()) {
2593 return Failure::Exception();
2594 }
2595 matched = !match->IsNull();
2596 } while (matched);
2597
2598 if (prev < length) {
2599 builder.AddSubjectSlice(prev, length);
2600 }
2601
2602 return *(builder.ToString());
2603}
2604
2605
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002606template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002607MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2608 String* subject,
2609 JSRegExp* regexp,
2610 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002611 ASSERT(subject->IsFlat());
2612
2613 HandleScope handles;
2614
2615 Handle<String> subject_handle(subject);
2616 Handle<JSRegExp> regexp_handle(regexp);
2617 Handle<JSArray> last_match_info_handle(last_match_info);
2618 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2619 subject_handle,
2620 0,
2621 last_match_info_handle);
2622 if (match.is_null()) return Failure::Exception();
2623 if (match->IsNull()) return *subject_handle;
2624
2625 ASSERT(last_match_info_handle->HasFastElements());
2626
2627 HandleScope loop_scope;
2628 int start, end;
2629 {
2630 AssertNoAllocation match_info_array_is_not_in_a_handle;
2631 FixedArray* match_info_array =
2632 FixedArray::cast(last_match_info_handle->elements());
2633
2634 start = RegExpImpl::GetCapture(match_info_array, 0);
2635 end = RegExpImpl::GetCapture(match_info_array, 1);
2636 }
2637
2638 int length = subject->length();
2639 int new_length = length - (end - start);
2640 if (new_length == 0) {
2641 return Heap::empty_string();
2642 }
2643 Handle<ResultSeqString> answer;
2644 if (ResultSeqString::kHasAsciiEncoding) {
2645 answer =
2646 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2647 } else {
2648 answer =
2649 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2650 }
2651
2652 // If the regexp isn't global, only match once.
2653 if (!regexp_handle->GetFlags().is_global()) {
2654 if (start > 0) {
2655 String::WriteToFlat(*subject_handle,
2656 answer->GetChars(),
2657 0,
2658 start);
2659 }
2660 if (end < length) {
2661 String::WriteToFlat(*subject_handle,
2662 answer->GetChars() + start,
2663 end,
2664 length);
2665 }
2666 return *answer;
2667 }
2668
2669 int prev = 0; // Index of end of last match.
2670 int next = 0; // Start of next search (prev unless last match was empty).
2671 int position = 0;
2672
2673 do {
2674 if (prev < start) {
2675 // Add substring subject[prev;start] to answer string.
2676 String::WriteToFlat(*subject_handle,
2677 answer->GetChars() + position,
2678 prev,
2679 start);
2680 position += start - prev;
2681 }
2682 prev = end;
2683 next = end;
2684 // Continue from where the match ended, unless it was an empty match.
2685 if (start == end) {
2686 next++;
2687 if (next > length) break;
2688 }
2689 match = RegExpImpl::Exec(regexp_handle,
2690 subject_handle,
2691 next,
2692 last_match_info_handle);
2693 if (match.is_null()) return Failure::Exception();
2694 if (match->IsNull()) break;
2695
2696 ASSERT(last_match_info_handle->HasFastElements());
2697 HandleScope loop_scope;
2698 {
2699 AssertNoAllocation match_info_array_is_not_in_a_handle;
2700 FixedArray* match_info_array =
2701 FixedArray::cast(last_match_info_handle->elements());
2702 start = RegExpImpl::GetCapture(match_info_array, 0);
2703 end = RegExpImpl::GetCapture(match_info_array, 1);
2704 }
2705 } while (true);
2706
2707 if (prev < length) {
2708 // Add substring subject[prev;length] to answer string.
2709 String::WriteToFlat(*subject_handle,
2710 answer->GetChars() + position,
2711 prev,
2712 length);
2713 position += length - prev;
2714 }
2715
2716 if (position == 0) {
2717 return Heap::empty_string();
2718 }
2719
2720 // Shorten string and fill
2721 int string_size = ResultSeqString::SizeFor(position);
2722 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2723 int delta = allocated_string_size - string_size;
2724
2725 answer->set_length(position);
2726 if (delta == 0) return *answer;
2727
2728 Address end_of_string = answer->address() + string_size;
2729 Heap::CreateFillerObjectAt(end_of_string, delta);
2730
2731 return *answer;
2732}
2733
2734
lrn@chromium.org303ada72010-10-27 09:33:13 +00002735static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002736 ASSERT(args.length() == 4);
2737
2738 CONVERT_CHECKED(String, subject, args[0]);
2739 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002740 Object* flat_subject;
2741 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2742 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2743 return maybe_flat_subject;
2744 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002745 }
2746 subject = String::cast(flat_subject);
2747 }
2748
2749 CONVERT_CHECKED(String, replacement, args[2]);
2750 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002751 Object* flat_replacement;
2752 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2753 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2754 return maybe_flat_replacement;
2755 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002756 }
2757 replacement = String::cast(flat_replacement);
2758 }
2759
2760 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2761 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2762
2763 ASSERT(last_match_info->HasFastElements());
2764
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002765 if (replacement->length() == 0) {
2766 if (subject->HasOnlyAsciiChars()) {
2767 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2768 subject, regexp, last_match_info);
2769 } else {
2770 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2771 subject, regexp, last_match_info);
2772 }
2773 }
2774
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002775 return StringReplaceRegExpWithString(subject,
2776 regexp,
2777 replacement,
2778 last_match_info);
2779}
2780
2781
ager@chromium.org7c537e22008-10-16 08:43:32 +00002782// Perform string match of pattern on subject, starting at start index.
2783// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002784// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002785int Runtime::StringMatch(Handle<String> sub,
2786 Handle<String> pat,
2787 int start_index) {
2788 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002789 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002790
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002791 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002792 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002793
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002794 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002795 if (start_index + pattern_length > subject_length) return -1;
2796
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002797 if (!sub->IsFlat()) FlattenString(sub);
2798 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002799
ager@chromium.org7c537e22008-10-16 08:43:32 +00002800 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002801 // Extract flattened substrings of cons strings before determining asciiness.
2802 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002803 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002804 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002805 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002806
ager@chromium.org7c537e22008-10-16 08:43:32 +00002807 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002808 if (seq_pat->IsAsciiRepresentation()) {
2809 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2810 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002811 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002812 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002813 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002814 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002815 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2816 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002817 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002818 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002819 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002820}
2821
2822
lrn@chromium.org303ada72010-10-27 09:33:13 +00002823static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002824 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002825 ASSERT(args.length() == 3);
2826
ager@chromium.org7c537e22008-10-16 08:43:32 +00002827 CONVERT_ARG_CHECKED(String, sub, 0);
2828 CONVERT_ARG_CHECKED(String, pat, 1);
2829
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002830 Object* index = args[2];
2831 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002832 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002833
ager@chromium.org870a0b62008-11-04 11:43:05 +00002834 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002835 int position = Runtime::StringMatch(sub, pat, start_index);
2836 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002837}
2838
2839
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002840template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002841static int StringMatchBackwards(Vector<const schar> subject,
2842 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002843 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002844 int pattern_length = pattern.length();
2845 ASSERT(pattern_length >= 1);
2846 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002847
2848 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002849 for (int i = 0; i < pattern_length; i++) {
2850 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002851 if (c > String::kMaxAsciiCharCode) {
2852 return -1;
2853 }
2854 }
2855 }
2856
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002857 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002858 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002859 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002860 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002861 while (j < pattern_length) {
2862 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002863 break;
2864 }
2865 j++;
2866 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002867 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002868 return i;
2869 }
2870 }
2871 return -1;
2872}
2873
lrn@chromium.org303ada72010-10-27 09:33:13 +00002874static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002875 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002876 ASSERT(args.length() == 3);
2877
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002878 CONVERT_ARG_CHECKED(String, sub, 0);
2879 CONVERT_ARG_CHECKED(String, pat, 1);
2880
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002881 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002882 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002883 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002884
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002885 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002886 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002887
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002888 if (start_index + pat_length > sub_length) {
2889 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002890 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002891
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002892 if (pat_length == 0) {
2893 return Smi::FromInt(start_index);
2894 }
2895
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002896 if (!sub->IsFlat()) FlattenString(sub);
2897 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002898
2899 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2900
2901 int position = -1;
2902
2903 if (pat->IsAsciiRepresentation()) {
2904 Vector<const char> pat_vector = pat->ToAsciiVector();
2905 if (sub->IsAsciiRepresentation()) {
2906 position = StringMatchBackwards(sub->ToAsciiVector(),
2907 pat_vector,
2908 start_index);
2909 } else {
2910 position = StringMatchBackwards(sub->ToUC16Vector(),
2911 pat_vector,
2912 start_index);
2913 }
2914 } else {
2915 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2916 if (sub->IsAsciiRepresentation()) {
2917 position = StringMatchBackwards(sub->ToAsciiVector(),
2918 pat_vector,
2919 start_index);
2920 } else {
2921 position = StringMatchBackwards(sub->ToUC16Vector(),
2922 pat_vector,
2923 start_index);
2924 }
2925 }
2926
2927 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002928}
2929
2930
lrn@chromium.org303ada72010-10-27 09:33:13 +00002931static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002932 NoHandleAllocation ha;
2933 ASSERT(args.length() == 2);
2934
2935 CONVERT_CHECKED(String, str1, args[0]);
2936 CONVERT_CHECKED(String, str2, args[1]);
2937
2938 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002939 int str1_length = str1->length();
2940 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002941
2942 // Decide trivial cases without flattening.
2943 if (str1_length == 0) {
2944 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2945 return Smi::FromInt(-str2_length);
2946 } else {
2947 if (str2_length == 0) return Smi::FromInt(str1_length);
2948 }
2949
2950 int end = str1_length < str2_length ? str1_length : str2_length;
2951
2952 // No need to flatten if we are going to find the answer on the first
2953 // character. At this point we know there is at least one character
2954 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002955 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002956 if (d != 0) return Smi::FromInt(d);
2957
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002958 str1->TryFlatten();
2959 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002960
2961 static StringInputBuffer buf1;
2962 static StringInputBuffer buf2;
2963
2964 buf1.Reset(str1);
2965 buf2.Reset(str2);
2966
2967 for (int i = 0; i < end; i++) {
2968 uint16_t char1 = buf1.GetNext();
2969 uint16_t char2 = buf2.GetNext();
2970 if (char1 != char2) return Smi::FromInt(char1 - char2);
2971 }
2972
2973 return Smi::FromInt(str1_length - str2_length);
2974}
2975
2976
lrn@chromium.org303ada72010-10-27 09:33:13 +00002977static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002978 NoHandleAllocation ha;
2979 ASSERT(args.length() == 3);
2980
2981 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002982 Object* from = args[1];
2983 Object* to = args[2];
2984 int start, end;
2985 // We have a fast integer-only case here to avoid a conversion to double in
2986 // the common case where from and to are Smis.
2987 if (from->IsSmi() && to->IsSmi()) {
2988 start = Smi::cast(from)->value();
2989 end = Smi::cast(to)->value();
2990 } else {
2991 CONVERT_DOUBLE_CHECKED(from_number, from);
2992 CONVERT_DOUBLE_CHECKED(to_number, to);
2993 start = FastD2I(from_number);
2994 end = FastD2I(to_number);
2995 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002996 RUNTIME_ASSERT(end >= start);
2997 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002998 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002999 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003000 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003001}
3002
3003
lrn@chromium.org303ada72010-10-27 09:33:13 +00003004static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003005 ASSERT_EQ(3, args.length());
3006
3007 CONVERT_ARG_CHECKED(String, subject, 0);
3008 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3009 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3010 HandleScope handles;
3011
3012 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3013
3014 if (match.is_null()) {
3015 return Failure::Exception();
3016 }
3017 if (match->IsNull()) {
3018 return Heap::null_value();
3019 }
3020 int length = subject->length();
3021
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003022 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003023 ZoneList<int> offsets(8);
3024 do {
3025 int start;
3026 int end;
3027 {
3028 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003029 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003030 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3031 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3032 }
3033 offsets.Add(start);
3034 offsets.Add(end);
3035 int index = start < end ? end : end + 1;
3036 if (index > length) break;
3037 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3038 if (match.is_null()) {
3039 return Failure::Exception();
3040 }
3041 } while (!match->IsNull());
3042 int matches = offsets.length() / 2;
3043 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
3044 for (int i = 0; i < matches ; i++) {
3045 int from = offsets.at(i * 2);
3046 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003047 Handle<String> match = Factory::NewSubString(subject, from, to);
3048 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003049 }
3050 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
3051 result->set_length(Smi::FromInt(matches));
3052 return *result;
3053}
3054
3055
lrn@chromium.org25156de2010-04-06 13:10:27 +00003056// Two smis before and after the match, for very long strings.
3057const int kMaxBuilderEntriesPerRegExpMatch = 5;
3058
3059
3060static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3061 Handle<JSArray> last_match_info,
3062 int match_start,
3063 int match_end) {
3064 // Fill last_match_info with a single capture.
3065 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3066 AssertNoAllocation no_gc;
3067 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3068 RegExpImpl::SetLastCaptureCount(elements, 2);
3069 RegExpImpl::SetLastInput(elements, *subject);
3070 RegExpImpl::SetLastSubject(elements, *subject);
3071 RegExpImpl::SetCapture(elements, 0, match_start);
3072 RegExpImpl::SetCapture(elements, 1, match_end);
3073}
3074
3075
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003076template <typename SubjectChar, typename PatternChar>
3077static bool SearchStringMultiple(Vector<const SubjectChar> subject,
3078 Vector<const PatternChar> pattern,
3079 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003080 FixedArrayBuilder* builder,
3081 int* match_pos) {
3082 int pos = *match_pos;
3083 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003084 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003085 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003086 StringSearch<PatternChar, SubjectChar> search(pattern);
3087 while (pos <= max_search_start) {
3088 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3089 *match_pos = pos;
3090 return false;
3091 }
3092 // Position of end of previous match.
3093 int match_end = pos + pattern_length;
3094 int new_pos = search.Search(subject, match_end);
3095 if (new_pos >= 0) {
3096 // A match.
3097 if (new_pos > match_end) {
3098 ReplacementStringBuilder::AddSubjectSlice(builder,
3099 match_end,
3100 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003101 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003102 pos = new_pos;
3103 builder->Add(pattern_string);
3104 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003105 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003106 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003107 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003108
lrn@chromium.org25156de2010-04-06 13:10:27 +00003109 if (pos < max_search_start) {
3110 ReplacementStringBuilder::AddSubjectSlice(builder,
3111 pos + pattern_length,
3112 subject_length);
3113 }
3114 *match_pos = pos;
3115 return true;
3116}
3117
3118
3119static bool SearchStringMultiple(Handle<String> subject,
3120 Handle<String> pattern,
3121 Handle<JSArray> last_match_info,
3122 FixedArrayBuilder* builder) {
3123 ASSERT(subject->IsFlat());
3124 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003125
3126 // Treating as if a previous match was before first character.
3127 int match_pos = -pattern->length();
3128
3129 for (;;) { // Break when search complete.
3130 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3131 AssertNoAllocation no_gc;
3132 if (subject->IsAsciiRepresentation()) {
3133 Vector<const char> subject_vector = subject->ToAsciiVector();
3134 if (pattern->IsAsciiRepresentation()) {
3135 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003136 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003137 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003138 builder,
3139 &match_pos)) break;
3140 } else {
3141 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003142 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003143 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003144 builder,
3145 &match_pos)) break;
3146 }
3147 } else {
3148 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3149 if (pattern->IsAsciiRepresentation()) {
3150 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003151 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003152 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003153 builder,
3154 &match_pos)) break;
3155 } else {
3156 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003157 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003158 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003159 builder,
3160 &match_pos)) break;
3161 }
3162 }
3163 }
3164
3165 if (match_pos >= 0) {
3166 SetLastMatchInfoNoCaptures(subject,
3167 last_match_info,
3168 match_pos,
3169 match_pos + pattern->length());
3170 return true;
3171 }
3172 return false; // No matches at all.
3173}
3174
3175
3176static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3177 Handle<String> subject,
3178 Handle<JSRegExp> regexp,
3179 Handle<JSArray> last_match_array,
3180 FixedArrayBuilder* builder) {
3181 ASSERT(subject->IsFlat());
3182 int match_start = -1;
3183 int match_end = 0;
3184 int pos = 0;
3185 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3186 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3187
3188 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003189 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003190 int subject_length = subject->length();
3191
3192 for (;;) { // Break on failure, return on exception.
3193 RegExpImpl::IrregexpResult result =
3194 RegExpImpl::IrregexpExecOnce(regexp,
3195 subject,
3196 pos,
3197 register_vector);
3198 if (result == RegExpImpl::RE_SUCCESS) {
3199 match_start = register_vector[0];
3200 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3201 if (match_end < match_start) {
3202 ReplacementStringBuilder::AddSubjectSlice(builder,
3203 match_end,
3204 match_start);
3205 }
3206 match_end = register_vector[1];
3207 HandleScope loop_scope;
3208 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3209 if (match_start != match_end) {
3210 pos = match_end;
3211 } else {
3212 pos = match_end + 1;
3213 if (pos > subject_length) break;
3214 }
3215 } else if (result == RegExpImpl::RE_FAILURE) {
3216 break;
3217 } else {
3218 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3219 return result;
3220 }
3221 }
3222
3223 if (match_start >= 0) {
3224 if (match_end < subject_length) {
3225 ReplacementStringBuilder::AddSubjectSlice(builder,
3226 match_end,
3227 subject_length);
3228 }
3229 SetLastMatchInfoNoCaptures(subject,
3230 last_match_array,
3231 match_start,
3232 match_end);
3233 return RegExpImpl::RE_SUCCESS;
3234 } else {
3235 return RegExpImpl::RE_FAILURE; // No matches at all.
3236 }
3237}
3238
3239
3240static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3241 Handle<String> subject,
3242 Handle<JSRegExp> regexp,
3243 Handle<JSArray> last_match_array,
3244 FixedArrayBuilder* builder) {
3245
3246 ASSERT(subject->IsFlat());
3247 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3248 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3249
3250 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003251 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003252
3253 RegExpImpl::IrregexpResult result =
3254 RegExpImpl::IrregexpExecOnce(regexp,
3255 subject,
3256 0,
3257 register_vector);
3258
3259 int capture_count = regexp->CaptureCount();
3260 int subject_length = subject->length();
3261
3262 // Position to search from.
3263 int pos = 0;
3264 // End of previous match. Differs from pos if match was empty.
3265 int match_end = 0;
3266 if (result == RegExpImpl::RE_SUCCESS) {
3267 // Need to keep a copy of the previous match for creating last_match_info
3268 // at the end, so we have two vectors that we swap between.
3269 OffsetsVector registers2(required_registers);
3270 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3271
3272 do {
3273 int match_start = register_vector[0];
3274 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3275 if (match_end < match_start) {
3276 ReplacementStringBuilder::AddSubjectSlice(builder,
3277 match_end,
3278 match_start);
3279 }
3280 match_end = register_vector[1];
3281
3282 {
3283 // Avoid accumulating new handles inside loop.
3284 HandleScope temp_scope;
3285 // Arguments array to replace function is match, captures, index and
3286 // subject, i.e., 3 + capture count in total.
3287 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003288 Handle<String> match = Factory::NewSubString(subject,
3289 match_start,
3290 match_end);
3291 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003292 for (int i = 1; i <= capture_count; i++) {
3293 int start = register_vector[i * 2];
3294 if (start >= 0) {
3295 int end = register_vector[i * 2 + 1];
3296 ASSERT(start <= end);
3297 Handle<String> substring = Factory::NewSubString(subject,
3298 start,
3299 end);
3300 elements->set(i, *substring);
3301 } else {
3302 ASSERT(register_vector[i * 2 + 1] < 0);
3303 elements->set(i, Heap::undefined_value());
3304 }
3305 }
3306 elements->set(capture_count + 1, Smi::FromInt(match_start));
3307 elements->set(capture_count + 2, *subject);
3308 builder->Add(*Factory::NewJSArrayWithElements(elements));
3309 }
3310 // Swap register vectors, so the last successful match is in
3311 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003312 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003313 prev_register_vector = register_vector;
3314 register_vector = tmp;
3315
3316 if (match_end > match_start) {
3317 pos = match_end;
3318 } else {
3319 pos = match_end + 1;
3320 if (pos > subject_length) {
3321 break;
3322 }
3323 }
3324
3325 result = RegExpImpl::IrregexpExecOnce(regexp,
3326 subject,
3327 pos,
3328 register_vector);
3329 } while (result == RegExpImpl::RE_SUCCESS);
3330
3331 if (result != RegExpImpl::RE_EXCEPTION) {
3332 // Finished matching, with at least one match.
3333 if (match_end < subject_length) {
3334 ReplacementStringBuilder::AddSubjectSlice(builder,
3335 match_end,
3336 subject_length);
3337 }
3338
3339 int last_match_capture_count = (capture_count + 1) * 2;
3340 int last_match_array_size =
3341 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3342 last_match_array->EnsureSize(last_match_array_size);
3343 AssertNoAllocation no_gc;
3344 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3345 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3346 RegExpImpl::SetLastSubject(elements, *subject);
3347 RegExpImpl::SetLastInput(elements, *subject);
3348 for (int i = 0; i < last_match_capture_count; i++) {
3349 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3350 }
3351 return RegExpImpl::RE_SUCCESS;
3352 }
3353 }
3354 // No matches at all, return failure or exception result directly.
3355 return result;
3356}
3357
3358
lrn@chromium.org303ada72010-10-27 09:33:13 +00003359static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003360 ASSERT(args.length() == 4);
3361 HandleScope handles;
3362
3363 CONVERT_ARG_CHECKED(String, subject, 1);
3364 if (!subject->IsFlat()) { FlattenString(subject); }
3365 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3366 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3367 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3368
3369 ASSERT(last_match_info->HasFastElements());
3370 ASSERT(regexp->GetFlags().is_global());
3371 Handle<FixedArray> result_elements;
3372 if (result_array->HasFastElements()) {
3373 result_elements =
3374 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3375 } else {
3376 result_elements = Factory::NewFixedArrayWithHoles(16);
3377 }
3378 FixedArrayBuilder builder(result_elements);
3379
3380 if (regexp->TypeTag() == JSRegExp::ATOM) {
3381 Handle<String> pattern(
3382 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003383 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003384 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3385 return *builder.ToJSArray(result_array);
3386 }
3387 return Heap::null_value();
3388 }
3389
3390 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3391
3392 RegExpImpl::IrregexpResult result;
3393 if (regexp->CaptureCount() == 0) {
3394 result = SearchRegExpNoCaptureMultiple(subject,
3395 regexp,
3396 last_match_info,
3397 &builder);
3398 } else {
3399 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3400 }
3401 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3402 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3403 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3404 return Failure::Exception();
3405}
3406
3407
lrn@chromium.org303ada72010-10-27 09:33:13 +00003408static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409 NoHandleAllocation ha;
3410 ASSERT(args.length() == 2);
3411
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003412 // Fast case where the result is a one character string.
3413 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3414 int value = Smi::cast(args[0])->value();
3415 int radix = Smi::cast(args[1])->value();
3416 if (value >= 0 && value < radix) {
3417 RUNTIME_ASSERT(radix <= 36);
3418 // Character array used for conversion.
3419 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3420 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3421 }
3422 }
3423
3424 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003425 CONVERT_DOUBLE_CHECKED(value, args[0]);
3426 if (isnan(value)) {
3427 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3428 }
3429 if (isinf(value)) {
3430 if (value < 0) {
3431 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3432 }
3433 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3434 }
3435 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3436 int radix = FastD2I(radix_number);
3437 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3438 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003439 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003440 DeleteArray(str);
3441 return result;
3442}
3443
3444
lrn@chromium.org303ada72010-10-27 09:33:13 +00003445static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003446 NoHandleAllocation ha;
3447 ASSERT(args.length() == 2);
3448
3449 CONVERT_DOUBLE_CHECKED(value, args[0]);
3450 if (isnan(value)) {
3451 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3452 }
3453 if (isinf(value)) {
3454 if (value < 0) {
3455 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3456 }
3457 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3458 }
3459 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3460 int f = FastD2I(f_number);
3461 RUNTIME_ASSERT(f >= 0);
3462 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003463 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003464 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003465 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466}
3467
3468
lrn@chromium.org303ada72010-10-27 09:33:13 +00003469static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003470 NoHandleAllocation ha;
3471 ASSERT(args.length() == 2);
3472
3473 CONVERT_DOUBLE_CHECKED(value, args[0]);
3474 if (isnan(value)) {
3475 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3476 }
3477 if (isinf(value)) {
3478 if (value < 0) {
3479 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3480 }
3481 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3482 }
3483 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3484 int f = FastD2I(f_number);
3485 RUNTIME_ASSERT(f >= -1 && f <= 20);
3486 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003487 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003488 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003489 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003490}
3491
3492
lrn@chromium.org303ada72010-10-27 09:33:13 +00003493static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003494 NoHandleAllocation ha;
3495 ASSERT(args.length() == 2);
3496
3497 CONVERT_DOUBLE_CHECKED(value, args[0]);
3498 if (isnan(value)) {
3499 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3500 }
3501 if (isinf(value)) {
3502 if (value < 0) {
3503 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3504 }
3505 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3506 }
3507 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3508 int f = FastD2I(f_number);
3509 RUNTIME_ASSERT(f >= 1 && f <= 21);
3510 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003511 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003512 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003513 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003514}
3515
3516
3517// Returns a single character string where first character equals
3518// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003519static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003520 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003521 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003522 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003523 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003524 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003525 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003526}
3527
3528
lrn@chromium.org303ada72010-10-27 09:33:13 +00003529MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3530 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003531 // Handle [] indexing on Strings
3532 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003533 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3534 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003535 }
3536
3537 // Handle [] indexing on String objects
3538 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003539 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3540 Handle<Object> result =
3541 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3542 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003543 }
3544
3545 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003546 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003547 return prototype->GetElement(index);
3548 }
3549
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003550 return GetElement(object, index);
3551}
3552
3553
lrn@chromium.org303ada72010-10-27 09:33:13 +00003554MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003555 return object->GetElement(index);
3556}
3557
3558
lrn@chromium.org303ada72010-10-27 09:33:13 +00003559MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3560 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003561 HandleScope scope;
3562
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003563 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003564 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003565 Handle<Object> error =
3566 Factory::NewTypeError("non_object_property_load",
3567 HandleVector(args, 2));
3568 return Top::Throw(*error);
3569 }
3570
3571 // Check if the given key is an array index.
3572 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003573 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003574 return GetElementOrCharAt(object, index);
3575 }
3576
3577 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003578 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003580 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003582 bool has_pending_exception = false;
3583 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003584 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003585 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003586 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003587 }
3588
ager@chromium.org32912102009-01-16 10:38:43 +00003589 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003590 // the element if so.
3591 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 return GetElementOrCharAt(object, index);
3593 } else {
3594 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003595 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 }
3597}
3598
3599
lrn@chromium.org303ada72010-10-27 09:33:13 +00003600static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003601 NoHandleAllocation ha;
3602 ASSERT(args.length() == 2);
3603
3604 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003605 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606
3607 return Runtime::GetObjectProperty(object, key);
3608}
3609
3610
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003611// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003612static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003613 NoHandleAllocation ha;
3614 ASSERT(args.length() == 2);
3615
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003616 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003617 // itself.
3618 //
3619 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003620 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003621 // global proxy object never has properties. This is the case
3622 // because the global proxy object forwards everything to its hidden
3623 // prototype including local lookups.
3624 //
3625 // Additionally, we need to make sure that we do not cache results
3626 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003627 if (args[0]->IsJSObject() &&
3628 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003629 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003630 args[1]->IsString()) {
3631 JSObject* receiver = JSObject::cast(args[0]);
3632 String* key = String::cast(args[1]);
3633 if (receiver->HasFastProperties()) {
3634 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003635 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003636 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3637 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003638 Object* value = receiver->FastPropertyAt(offset);
3639 return value->IsTheHole() ? Heap::undefined_value() : value;
3640 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003641 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003642 LookupResult result;
3643 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003644 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003645 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003646 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003647 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003648 }
3649 } else {
3650 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003651 StringDictionary* dictionary = receiver->property_dictionary();
3652 int entry = dictionary->FindEntry(key);
3653 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003654 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003655 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003656 if (!receiver->IsGlobalObject()) return value;
3657 value = JSGlobalPropertyCell::cast(value)->value();
3658 if (!value->IsTheHole()) return value;
3659 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003660 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003661 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003662 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3663 // Fast case for string indexing using [] with a smi index.
3664 HandleScope scope;
3665 Handle<String> str = args.at<String>(0);
3666 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003667 if (index >= 0 && index < str->length()) {
3668 Handle<Object> result = GetCharAt(str, index);
3669 return *result;
3670 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003671 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003672
3673 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003674 return Runtime::GetObjectProperty(args.at<Object>(0),
3675 args.at<Object>(1));
3676}
3677
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003678// Implements part of 8.12.9 DefineOwnProperty.
3679// There are 3 cases that lead here:
3680// Step 4b - define a new accessor property.
3681// Steps 9c & 12 - replace an existing data property with an accessor property.
3682// Step 12 - update an existing accessor property with an accessor or generic
3683// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003684static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003685 ASSERT(args.length() == 5);
3686 HandleScope scope;
3687 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3688 CONVERT_CHECKED(String, name, args[1]);
3689 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003690 Object* fun = args[3];
3691 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003692 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3693 int unchecked = flag_attr->value();
3694 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3695 RUNTIME_ASSERT(!obj->IsNull());
3696 LookupResult result;
3697 obj->LocalLookupRealNamedProperty(name, &result);
3698
3699 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3700 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3701 // delete it to avoid running into trouble in DefineAccessor, which
3702 // handles this incorrectly if the property is readonly (does nothing)
3703 if (result.IsProperty() &&
3704 (result.type() == FIELD || result.type() == NORMAL
3705 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003706 Object* ok;
3707 { MaybeObject* maybe_ok =
3708 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3709 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3710 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003711 }
3712 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3713}
3714
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003715// Implements part of 8.12.9 DefineOwnProperty.
3716// There are 3 cases that lead here:
3717// Step 4a - define a new data property.
3718// Steps 9b & 12 - replace an existing accessor property with a data property.
3719// Step 12 - update an existing data property with a data or generic
3720// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003721static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003722 ASSERT(args.length() == 4);
3723 HandleScope scope;
3724 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3725 CONVERT_ARG_CHECKED(String, name, 1);
3726 Handle<Object> obj_value = args.at<Object>(2);
3727
3728 CONVERT_CHECKED(Smi, flag, args[3]);
3729 int unchecked = flag->value();
3730 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3731
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003732 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3733
3734 // Check if this is an element.
3735 uint32_t index;
3736 bool is_element = name->AsArrayIndex(&index);
3737
3738 // Special case for elements if any of the flags are true.
3739 // If elements are in fast case we always implicitly assume that:
3740 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3741 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3742 is_element) {
3743 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003744 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003745 // We do not need to do access checks here since these has already
3746 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003747 Handle<Object> proto(js_object->GetPrototype());
3748 // If proxy is detached, ignore the assignment. Alternatively,
3749 // we could throw an exception.
3750 if (proto->IsNull()) return *obj_value;
3751 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003752 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003753 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003754 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003755 // Make sure that we never go back to fast case.
3756 dictionary->set_requires_slow_elements();
3757 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003758 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003759 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003760 }
3761
ager@chromium.org5c838252010-02-19 08:53:10 +00003762 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003763 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003764
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003765 // To be compatible with safari we do not change the value on API objects
3766 // in defineProperty. Firefox disagrees here, and actually changes the value.
3767 if (result.IsProperty() &&
3768 (result.type() == CALLBACKS) &&
3769 result.GetCallbackObject()->IsAccessorInfo()) {
3770 return Heap::undefined_value();
3771 }
3772
ager@chromium.org5c838252010-02-19 08:53:10 +00003773 // Take special care when attributes are different and there is already
3774 // a property. For simplicity we normalize the property which enables us
3775 // to not worry about changing the instance_descriptor and creating a new
3776 // map. The current version of SetObjectProperty does not handle attributes
3777 // correctly in the case where a property is a field and is reset with
3778 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003779 if (result.IsProperty() &&
3780 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003781 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003782 if (js_object->IsJSGlobalProxy()) {
3783 // Since the result is a property, the prototype will exist so
3784 // we don't have to check for null.
3785 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003786 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003787 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003788 // Use IgnoreAttributes version since a readonly property may be
3789 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003790 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3791 *obj_value,
3792 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003793 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003794
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003795 return Runtime::ForceSetObjectProperty(js_object, name, obj_value, attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003796}
3797
3798
lrn@chromium.org303ada72010-10-27 09:33:13 +00003799MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3800 Handle<Object> key,
3801 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003802 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003803 StrictModeFlag strict_mode) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003804 HandleScope scope;
3805
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003806 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003807 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003808 Handle<Object> error =
3809 Factory::NewTypeError("non_object_property_store",
3810 HandleVector(args, 2));
3811 return Top::Throw(*error);
3812 }
3813
3814 // If the object isn't a JavaScript object, we ignore the store.
3815 if (!object->IsJSObject()) return *value;
3816
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003817 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3818
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003819 // Check if the given key is an array index.
3820 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003821 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003822 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3823 // of a string using [] notation. We need to support this too in
3824 // JavaScript.
3825 // In the case of a String object we just need to redirect the assignment to
3826 // the underlying string if the index is in range. Since the underlying
3827 // string does nothing with the assignment then we can ignore such
3828 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003829 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003830 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003831 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003832
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003833 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003834 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003835 return *value;
3836 }
3837
3838 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003839 Handle<Object> result;
3840 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003841 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003842 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003843 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003844 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003845 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003846 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003847 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003848 return *value;
3849 }
3850
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003851 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003852 bool has_pending_exception = false;
3853 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3854 if (has_pending_exception) return Failure::Exception();
3855 Handle<String> name = Handle<String>::cast(converted);
3856
3857 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003858 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003859 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003860 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003861 }
3862}
3863
3864
lrn@chromium.org303ada72010-10-27 09:33:13 +00003865MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3866 Handle<Object> key,
3867 Handle<Object> value,
3868 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003869 HandleScope scope;
3870
3871 // Check if the given key is an array index.
3872 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003873 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003874 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3875 // of a string using [] notation. We need to support this too in
3876 // JavaScript.
3877 // In the case of a String object we just need to redirect the assignment to
3878 // the underlying string if the index is in range. Since the underlying
3879 // string does nothing with the assignment then we can ignore such
3880 // assignments.
3881 if (js_object->IsStringObjectWithCharacterAt(index)) {
3882 return *value;
3883 }
3884
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003885 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003886 }
3887
3888 if (key->IsString()) {
3889 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003890 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003891 } else {
3892 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003893 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003894 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
3895 *value,
3896 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003897 }
3898 }
3899
3900 // Call-back into JavaScript to convert the key to a string.
3901 bool has_pending_exception = false;
3902 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3903 if (has_pending_exception) return Failure::Exception();
3904 Handle<String> name = Handle<String>::cast(converted);
3905
3906 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003907 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003908 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003909 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003910 }
3911}
3912
3913
lrn@chromium.org303ada72010-10-27 09:33:13 +00003914MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3915 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003916 HandleScope scope;
3917
3918 // Check if the given key is an array index.
3919 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003920 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003921 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3922 // characters of a string using [] notation. In the case of a
3923 // String object we just need to redirect the deletion to the
3924 // underlying string if the index is in range. Since the
3925 // underlying string does nothing with the deletion, we can ignore
3926 // such deletions.
3927 if (js_object->IsStringObjectWithCharacterAt(index)) {
3928 return Heap::true_value();
3929 }
3930
3931 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3932 }
3933
3934 Handle<String> key_string;
3935 if (key->IsString()) {
3936 key_string = Handle<String>::cast(key);
3937 } else {
3938 // Call-back into JavaScript to convert the key to a string.
3939 bool has_pending_exception = false;
3940 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3941 if (has_pending_exception) return Failure::Exception();
3942 key_string = Handle<String>::cast(converted);
3943 }
3944
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003945 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003946 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3947}
3948
3949
lrn@chromium.org303ada72010-10-27 09:33:13 +00003950static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003951 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003952 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003953
3954 Handle<Object> object = args.at<Object>(0);
3955 Handle<Object> key = args.at<Object>(1);
3956 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003957 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
3958 RUNTIME_ASSERT(
3959 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003960 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003961 PropertyAttributes attributes =
3962 static_cast<PropertyAttributes>(unchecked_attributes);
3963
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003964 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003965 if (args.length() == 5) {
3966 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
3967 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
3968 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003969 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003971
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003972 return Runtime::SetObjectProperty(object,
3973 key,
3974 value,
3975 attributes,
3976 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977}
3978
3979
3980// Set a local property, even if it is READ_ONLY. If the property does not
3981// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003982static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003983 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003984 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 CONVERT_CHECKED(JSObject, object, args[0]);
3986 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003987 // Compute attributes.
3988 PropertyAttributes attributes = NONE;
3989 if (args.length() == 4) {
3990 CONVERT_CHECKED(Smi, value_obj, args[3]);
3991 int unchecked_value = value_obj->value();
3992 // Only attribute bits should be set.
3993 RUNTIME_ASSERT(
3994 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3995 attributes = static_cast<PropertyAttributes>(unchecked_value);
3996 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003997
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003998 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003999 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004000}
4001
4002
lrn@chromium.org303ada72010-10-27 09:33:13 +00004003static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004005 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004006
4007 CONVERT_CHECKED(JSObject, object, args[0]);
4008 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004009 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004010 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004011 ? JSObject::STRICT_DELETION
4012 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004013}
4014
4015
ager@chromium.org9085a012009-05-11 19:22:57 +00004016static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
4017 Handle<String> key) {
4018 if (object->HasLocalProperty(*key)) return Heap::true_value();
4019 // Handle hidden prototypes. If there's a hidden prototype above this thing
4020 // then we have to check it for properties, because they are supposed to
4021 // look like they are on this object.
4022 Handle<Object> proto(object->GetPrototype());
4023 if (proto->IsJSObject() &&
4024 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
4025 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
4026 }
4027 return Heap::false_value();
4028}
4029
4030
lrn@chromium.org303ada72010-10-27 09:33:13 +00004031static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 NoHandleAllocation ha;
4033 ASSERT(args.length() == 2);
4034 CONVERT_CHECKED(String, key, args[1]);
4035
ager@chromium.org9085a012009-05-11 19:22:57 +00004036 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004037 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004038 if (obj->IsJSObject()) {
4039 JSObject* object = JSObject::cast(obj);
4040 // Fast case - no interceptors.
4041 if (object->HasRealNamedProperty(key)) return Heap::true_value();
4042 // Slow case. Either it's not there or we have an interceptor. We should
4043 // have handles for this kind of deal.
4044 HandleScope scope;
4045 return HasLocalPropertyImplementation(Handle<JSObject>(object),
4046 Handle<String>(key));
4047 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048 // Well, there is one exception: Handle [] on strings.
4049 uint32_t index;
4050 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004051 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004052 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 return Heap::true_value();
4054 }
4055 }
4056 return Heap::false_value();
4057}
4058
4059
lrn@chromium.org303ada72010-10-27 09:33:13 +00004060static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004061 NoHandleAllocation na;
4062 ASSERT(args.length() == 2);
4063
4064 // Only JS objects can have properties.
4065 if (args[0]->IsJSObject()) {
4066 JSObject* object = JSObject::cast(args[0]);
4067 CONVERT_CHECKED(String, key, args[1]);
4068 if (object->HasProperty(key)) return Heap::true_value();
4069 }
4070 return Heap::false_value();
4071}
4072
4073
lrn@chromium.org303ada72010-10-27 09:33:13 +00004074static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 NoHandleAllocation na;
4076 ASSERT(args.length() == 2);
4077
4078 // Only JS objects can have elements.
4079 if (args[0]->IsJSObject()) {
4080 JSObject* object = JSObject::cast(args[0]);
4081 CONVERT_CHECKED(Smi, index_obj, args[1]);
4082 uint32_t index = index_obj->value();
4083 if (object->HasElement(index)) return Heap::true_value();
4084 }
4085 return Heap::false_value();
4086}
4087
4088
lrn@chromium.org303ada72010-10-27 09:33:13 +00004089static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090 NoHandleAllocation ha;
4091 ASSERT(args.length() == 2);
4092
4093 CONVERT_CHECKED(JSObject, object, args[0]);
4094 CONVERT_CHECKED(String, key, args[1]);
4095
4096 uint32_t index;
4097 if (key->AsArrayIndex(&index)) {
4098 return Heap::ToBoolean(object->HasElement(index));
4099 }
4100
ager@chromium.org870a0b62008-11-04 11:43:05 +00004101 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
4102 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004103}
4104
4105
lrn@chromium.org303ada72010-10-27 09:33:13 +00004106static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 HandleScope scope;
4108 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004109 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004110 return *GetKeysFor(object);
4111}
4112
4113
4114// Returns either a FixedArray as Runtime_GetPropertyNames,
4115// or, if the given object has an enum cache that contains
4116// all enumerable properties of the object and its prototypes
4117// have none, the map of the object. This is used to speed up
4118// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004119static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004120 ASSERT(args.length() == 1);
4121
4122 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4123
4124 if (raw_object->IsSimpleEnum()) return raw_object->map();
4125
4126 HandleScope scope;
4127 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004128 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4129 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004130
4131 // Test again, since cache may have been built by preceding call.
4132 if (object->IsSimpleEnum()) return object->map();
4133
4134 return *content;
4135}
4136
4137
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004138// Find the length of the prototype chain that is to to handled as one. If a
4139// prototype object is hidden it is to be viewed as part of the the object it
4140// is prototype for.
4141static int LocalPrototypeChainLength(JSObject* obj) {
4142 int count = 1;
4143 Object* proto = obj->GetPrototype();
4144 while (proto->IsJSObject() &&
4145 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4146 count++;
4147 proto = JSObject::cast(proto)->GetPrototype();
4148 }
4149 return count;
4150}
4151
4152
4153// Return the names of the local named properties.
4154// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004155static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004156 HandleScope scope;
4157 ASSERT(args.length() == 1);
4158 if (!args[0]->IsJSObject()) {
4159 return Heap::undefined_value();
4160 }
4161 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4162
4163 // Skip the global proxy as it has no properties and always delegates to the
4164 // real global object.
4165 if (obj->IsJSGlobalProxy()) {
4166 // Only collect names if access is permitted.
4167 if (obj->IsAccessCheckNeeded() &&
4168 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
4169 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4170 return *Factory::NewJSArray(0);
4171 }
4172 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4173 }
4174
4175 // Find the number of objects making up this.
4176 int length = LocalPrototypeChainLength(*obj);
4177
4178 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004179 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004180 int total_property_count = 0;
4181 Handle<JSObject> jsproto = obj;
4182 for (int i = 0; i < length; i++) {
4183 // Only collect names if access is permitted.
4184 if (jsproto->IsAccessCheckNeeded() &&
4185 !Top::MayNamedAccess(*jsproto,
4186 Heap::undefined_value(),
4187 v8::ACCESS_KEYS)) {
4188 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4189 return *Factory::NewJSArray(0);
4190 }
4191 int n;
4192 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4193 local_property_count[i] = n;
4194 total_property_count += n;
4195 if (i < length - 1) {
4196 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4197 }
4198 }
4199
4200 // Allocate an array with storage for all the property names.
4201 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4202
4203 // Get the property names.
4204 jsproto = obj;
4205 int proto_with_hidden_properties = 0;
4206 for (int i = 0; i < length; i++) {
4207 jsproto->GetLocalPropertyNames(*names,
4208 i == 0 ? 0 : local_property_count[i - 1]);
4209 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4210 proto_with_hidden_properties++;
4211 }
4212 if (i < length - 1) {
4213 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4214 }
4215 }
4216
4217 // Filter out name of hidden propeties object.
4218 if (proto_with_hidden_properties > 0) {
4219 Handle<FixedArray> old_names = names;
4220 names = Factory::NewFixedArray(
4221 names->length() - proto_with_hidden_properties);
4222 int dest_pos = 0;
4223 for (int i = 0; i < total_property_count; i++) {
4224 Object* name = old_names->get(i);
4225 if (name == Heap::hidden_symbol()) {
4226 continue;
4227 }
4228 names->set(dest_pos++, name);
4229 }
4230 }
4231
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004232 return *Factory::NewJSArrayWithElements(names);
4233}
4234
4235
4236// Return the names of the local indexed properties.
4237// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004238static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004239 HandleScope scope;
4240 ASSERT(args.length() == 1);
4241 if (!args[0]->IsJSObject()) {
4242 return Heap::undefined_value();
4243 }
4244 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4245
4246 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4247 Handle<FixedArray> names = Factory::NewFixedArray(n);
4248 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4249 return *Factory::NewJSArrayWithElements(names);
4250}
4251
4252
4253// Return information on whether an object has a named or indexed interceptor.
4254// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004255static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004256 HandleScope scope;
4257 ASSERT(args.length() == 1);
4258 if (!args[0]->IsJSObject()) {
4259 return Smi::FromInt(0);
4260 }
4261 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4262
4263 int result = 0;
4264 if (obj->HasNamedInterceptor()) result |= 2;
4265 if (obj->HasIndexedInterceptor()) result |= 1;
4266
4267 return Smi::FromInt(result);
4268}
4269
4270
4271// Return property names from named interceptor.
4272// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004273static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004274 HandleScope scope;
4275 ASSERT(args.length() == 1);
4276 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4277
4278 if (obj->HasNamedInterceptor()) {
4279 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4280 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4281 }
4282 return Heap::undefined_value();
4283}
4284
4285
4286// Return element names from indexed interceptor.
4287// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004288static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004289 HandleScope scope;
4290 ASSERT(args.length() == 1);
4291 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4292
4293 if (obj->HasIndexedInterceptor()) {
4294 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4295 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4296 }
4297 return Heap::undefined_value();
4298}
4299
4300
lrn@chromium.org303ada72010-10-27 09:33:13 +00004301static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004302 ASSERT_EQ(args.length(), 1);
4303 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4304 HandleScope scope;
4305 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004306
4307 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004308 // Do access checks before going to the global object.
4309 if (object->IsAccessCheckNeeded() &&
4310 !Top::MayNamedAccess(*object, Heap::undefined_value(),
4311 v8::ACCESS_KEYS)) {
4312 Top::ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4313 return *Factory::NewJSArray(0);
4314 }
4315
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004316 Handle<Object> proto(object->GetPrototype());
4317 // If proxy is detached we simply return an empty array.
4318 if (proto->IsNull()) return *Factory::NewJSArray(0);
4319 object = Handle<JSObject>::cast(proto);
4320 }
4321
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004322 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4323 LOCAL_ONLY);
4324 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4325 // property array and since the result is mutable we have to create
4326 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004327 int length = contents->length();
4328 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4329 for (int i = 0; i < length; i++) {
4330 Object* entry = contents->get(i);
4331 if (entry->IsString()) {
4332 copy->set(i, entry);
4333 } else {
4334 ASSERT(entry->IsNumber());
4335 HandleScope scope;
4336 Handle<Object> entry_handle(entry);
4337 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4338 copy->set(i, *entry_str);
4339 }
4340 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004341 return *Factory::NewJSArrayWithElements(copy);
4342}
4343
4344
lrn@chromium.org303ada72010-10-27 09:33:13 +00004345static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346 NoHandleAllocation ha;
4347 ASSERT(args.length() == 1);
4348
4349 // Compute the frame holding the arguments.
4350 JavaScriptFrameIterator it;
4351 it.AdvanceToArgumentsFrame();
4352 JavaScriptFrame* frame = it.frame();
4353
4354 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004355 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004356
4357 // Try to convert the key to an index. If successful and within
4358 // index return the the argument from the frame.
4359 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004360 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004361 return frame->GetParameter(index);
4362 }
4363
4364 // Convert the key to a string.
4365 HandleScope scope;
4366 bool exception = false;
4367 Handle<Object> converted =
4368 Execution::ToString(args.at<Object>(0), &exception);
4369 if (exception) return Failure::Exception();
4370 Handle<String> key = Handle<String>::cast(converted);
4371
4372 // Try to convert the string key into an array index.
4373 if (key->AsArrayIndex(&index)) {
4374 if (index < n) {
4375 return frame->GetParameter(index);
4376 } else {
4377 return Top::initial_object_prototype()->GetElement(index);
4378 }
4379 }
4380
4381 // Handle special arguments properties.
4382 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4383 if (key->Equals(Heap::callee_symbol())) return frame->function();
4384
4385 // Lookup in the initial Object.prototype object.
4386 return Top::initial_object_prototype()->GetProperty(*key);
4387}
4388
4389
lrn@chromium.org303ada72010-10-27 09:33:13 +00004390static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004391 HandleScope scope;
4392
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004393 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004394 Handle<Object> object = args.at<Object>(0);
4395 if (object->IsJSObject()) {
4396 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004397 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004398 MaybeObject* ok = js_object->TransformToFastProperties(0);
4399 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004400 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004401 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004402 return *object;
4403}
4404
4405
lrn@chromium.org303ada72010-10-27 09:33:13 +00004406static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004407 HandleScope scope;
4408
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004409 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004410 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004411 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004412 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004413 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004414 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004415 return *object;
4416}
4417
4418
lrn@chromium.org303ada72010-10-27 09:33:13 +00004419static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004420 NoHandleAllocation ha;
4421 ASSERT(args.length() == 1);
4422
4423 return args[0]->ToBoolean();
4424}
4425
4426
4427// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4428// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004429static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004430 NoHandleAllocation ha;
4431
4432 Object* obj = args[0];
4433 if (obj->IsNumber()) return Heap::number_symbol();
4434 HeapObject* heap_obj = HeapObject::cast(obj);
4435
4436 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004437 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004438
4439 InstanceType instance_type = heap_obj->map()->instance_type();
4440 if (instance_type < FIRST_NONSTRING_TYPE) {
4441 return Heap::string_symbol();
4442 }
4443
4444 switch (instance_type) {
4445 case ODDBALL_TYPE:
4446 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4447 return Heap::boolean_symbol();
4448 }
4449 if (heap_obj->IsNull()) {
4450 return Heap::object_symbol();
4451 }
4452 ASSERT(heap_obj->IsUndefined());
4453 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004454 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004455 return Heap::function_symbol();
4456 default:
4457 // For any kind of object not handled above, the spec rule for
4458 // host objects gives that it is okay to return "object"
4459 return Heap::object_symbol();
4460 }
4461}
4462
4463
lrn@chromium.org25156de2010-04-06 13:10:27 +00004464static bool AreDigits(const char*s, int from, int to) {
4465 for (int i = from; i < to; i++) {
4466 if (s[i] < '0' || s[i] > '9') return false;
4467 }
4468
4469 return true;
4470}
4471
4472
4473static int ParseDecimalInteger(const char*s, int from, int to) {
4474 ASSERT(to - from < 10); // Overflow is not possible.
4475 ASSERT(from < to);
4476 int d = s[from] - '0';
4477
4478 for (int i = from + 1; i < to; i++) {
4479 d = 10 * d + (s[i] - '0');
4480 }
4481
4482 return d;
4483}
4484
4485
lrn@chromium.org303ada72010-10-27 09:33:13 +00004486static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004487 NoHandleAllocation ha;
4488 ASSERT(args.length() == 1);
4489 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004490 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004491
4492 // Fast case: short integer or some sorts of junk values.
4493 int len = subject->length();
4494 if (subject->IsSeqAsciiString()) {
4495 if (len == 0) return Smi::FromInt(0);
4496
4497 char const* data = SeqAsciiString::cast(subject)->GetChars();
4498 bool minus = (data[0] == '-');
4499 int start_pos = (minus ? 1 : 0);
4500
4501 if (start_pos == len) {
4502 return Heap::nan_value();
4503 } else if (data[start_pos] > '9') {
4504 // Fast check for a junk value. A valid string may start from a
4505 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4506 // the 'I' character ('Infinity'). All of that have codes not greater than
4507 // '9' except 'I'.
4508 if (data[start_pos] != 'I') {
4509 return Heap::nan_value();
4510 }
4511 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4512 // The maximal/minimal smi has 10 digits. If the string has less digits we
4513 // know it will fit into the smi-data type.
4514 int d = ParseDecimalInteger(data, start_pos, len);
4515 if (minus) {
4516 if (d == 0) return Heap::minus_zero_value();
4517 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004518 } else if (!subject->HasHashCode() &&
4519 len <= String::kMaxArrayIndexSize &&
4520 (len == 1 || data[0] != '0')) {
4521 // String hash is not calculated yet but all the data are present.
4522 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004523 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004524#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004525 subject->Hash(); // Force hash calculation.
4526 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4527 static_cast<int>(hash));
4528#endif
4529 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004530 }
4531 return Smi::FromInt(d);
4532 }
4533 }
4534
4535 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004536 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4537}
4538
4539
lrn@chromium.org303ada72010-10-27 09:33:13 +00004540static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004541 NoHandleAllocation ha;
4542 ASSERT(args.length() == 1);
4543
4544 CONVERT_CHECKED(JSArray, codes, args[0]);
4545 int length = Smi::cast(codes->length())->value();
4546
4547 // Check if the string can be ASCII.
4548 int i;
4549 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004550 Object* element;
4551 { MaybeObject* maybe_element = codes->GetElement(i);
4552 // We probably can't get an exception here, but just in order to enforce
4553 // the checking of inputs in the runtime calls we check here.
4554 if (!maybe_element->ToObject(&element)) return maybe_element;
4555 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004556 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4557 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4558 break;
4559 }
4560
lrn@chromium.org303ada72010-10-27 09:33:13 +00004561 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004562 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004563 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004564 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004565 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004566 }
4567
lrn@chromium.org303ada72010-10-27 09:33:13 +00004568 Object* object = NULL;
4569 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004570 String* result = String::cast(object);
4571 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004572 Object* element;
4573 { MaybeObject* maybe_element = codes->GetElement(i);
4574 if (!maybe_element->ToObject(&element)) return maybe_element;
4575 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004576 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004577 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004578 }
4579 return result;
4580}
4581
4582
4583// kNotEscaped is generated by the following:
4584//
4585// #!/bin/perl
4586// for (my $i = 0; $i < 256; $i++) {
4587// print "\n" if $i % 16 == 0;
4588// my $c = chr($i);
4589// my $escaped = 1;
4590// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4591// print $escaped ? "0, " : "1, ";
4592// }
4593
4594
4595static bool IsNotEscaped(uint16_t character) {
4596 // Only for 8 bit characters, the rest are always escaped (in a different way)
4597 ASSERT(character < 256);
4598 static const char kNotEscaped[256] = {
4599 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4600 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4601 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4602 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4603 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4604 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4605 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4606 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4607 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4608 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4609 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4610 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4611 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4612 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4613 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4614 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4615 };
4616 return kNotEscaped[character] != 0;
4617}
4618
4619
lrn@chromium.org303ada72010-10-27 09:33:13 +00004620static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004621 const char hex_chars[] = "0123456789ABCDEF";
4622 NoHandleAllocation ha;
4623 ASSERT(args.length() == 1);
4624 CONVERT_CHECKED(String, source, args[0]);
4625
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004626 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004627
4628 int escaped_length = 0;
4629 int length = source->length();
4630 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004631 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004632 buffer->Reset(source);
4633 while (buffer->has_more()) {
4634 uint16_t character = buffer->GetNext();
4635 if (character >= 256) {
4636 escaped_length += 6;
4637 } else if (IsNotEscaped(character)) {
4638 escaped_length++;
4639 } else {
4640 escaped_length += 3;
4641 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004642 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004643 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004644 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004645 Top::context()->mark_out_of_memory();
4646 return Failure::OutOfMemoryException();
4647 }
4648 }
4649 }
4650 // No length change implies no change. Return original string if no change.
4651 if (escaped_length == length) {
4652 return source;
4653 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004654 Object* o;
4655 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4656 if (!maybe_o->ToObject(&o)) return maybe_o;
4657 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004658 String* destination = String::cast(o);
4659 int dest_position = 0;
4660
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004661 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004662 buffer->Rewind();
4663 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004664 uint16_t chr = buffer->GetNext();
4665 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004666 destination->Set(dest_position, '%');
4667 destination->Set(dest_position+1, 'u');
4668 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4669 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4670 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4671 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004672 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004673 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004674 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004675 dest_position++;
4676 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004677 destination->Set(dest_position, '%');
4678 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4679 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004680 dest_position += 3;
4681 }
4682 }
4683 return destination;
4684}
4685
4686
4687static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4688 static const signed char kHexValue['g'] = {
4689 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4690 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4691 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4692 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4693 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4694 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4695 -1, 10, 11, 12, 13, 14, 15 };
4696
4697 if (character1 > 'f') return -1;
4698 int hi = kHexValue[character1];
4699 if (hi == -1) return -1;
4700 if (character2 > 'f') return -1;
4701 int lo = kHexValue[character2];
4702 if (lo == -1) return -1;
4703 return (hi << 4) + lo;
4704}
4705
4706
ager@chromium.org870a0b62008-11-04 11:43:05 +00004707static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004708 int i,
4709 int length,
4710 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004711 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004712 int32_t hi = 0;
4713 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004714 if (character == '%' &&
4715 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004716 source->Get(i + 1) == 'u' &&
4717 (hi = TwoDigitHex(source->Get(i + 2),
4718 source->Get(i + 3))) != -1 &&
4719 (lo = TwoDigitHex(source->Get(i + 4),
4720 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004721 *step = 6;
4722 return (hi << 8) + lo;
4723 } else if (character == '%' &&
4724 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004725 (lo = TwoDigitHex(source->Get(i + 1),
4726 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004727 *step = 3;
4728 return lo;
4729 } else {
4730 *step = 1;
4731 return character;
4732 }
4733}
4734
4735
lrn@chromium.org303ada72010-10-27 09:33:13 +00004736static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004737 NoHandleAllocation ha;
4738 ASSERT(args.length() == 1);
4739 CONVERT_CHECKED(String, source, args[0]);
4740
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004741 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742
4743 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004744 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004745
4746 int unescaped_length = 0;
4747 for (int i = 0; i < length; unescaped_length++) {
4748 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004749 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004750 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004751 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004752 i += step;
4753 }
4754
4755 // No length change implies no change. Return original string if no change.
4756 if (unescaped_length == length)
4757 return source;
4758
lrn@chromium.org303ada72010-10-27 09:33:13 +00004759 Object* o;
4760 { MaybeObject* maybe_o = ascii ?
4761 Heap::AllocateRawAsciiString(unescaped_length) :
4762 Heap::AllocateRawTwoByteString(unescaped_length);
4763 if (!maybe_o->ToObject(&o)) return maybe_o;
4764 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004765 String* destination = String::cast(o);
4766
4767 int dest_position = 0;
4768 for (int i = 0; i < length; dest_position++) {
4769 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004770 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004771 i += step;
4772 }
4773 return destination;
4774}
4775
4776
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004777static const unsigned int kQuoteTableLength = 128u;
4778
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004779static const int kJsonQuotesCharactersPerEntry = 8;
4780static const char* const JsonQuotes =
4781 "\\u0000 \\u0001 \\u0002 \\u0003 "
4782 "\\u0004 \\u0005 \\u0006 \\u0007 "
4783 "\\b \\t \\n \\u000b "
4784 "\\f \\r \\u000e \\u000f "
4785 "\\u0010 \\u0011 \\u0012 \\u0013 "
4786 "\\u0014 \\u0015 \\u0016 \\u0017 "
4787 "\\u0018 \\u0019 \\u001a \\u001b "
4788 "\\u001c \\u001d \\u001e \\u001f "
4789 " ! \\\" # "
4790 "$ % & ' "
4791 "( ) * + "
4792 ", - . / "
4793 "0 1 2 3 "
4794 "4 5 6 7 "
4795 "8 9 : ; "
4796 "< = > ? "
4797 "@ A B C "
4798 "D E F G "
4799 "H I J K "
4800 "L M N O "
4801 "P Q R S "
4802 "T U V W "
4803 "X Y Z [ "
4804 "\\\\ ] ^ _ "
4805 "` a b c "
4806 "d e f g "
4807 "h i j k "
4808 "l m n o "
4809 "p q r s "
4810 "t u v w "
4811 "x y z { "
4812 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004813
4814
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004815// For a string that is less than 32k characters it should always be
4816// possible to allocate it in new space.
4817static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4818
4819
4820// Doing JSON quoting cannot make the string more than this many times larger.
4821static const int kJsonQuoteWorstCaseBlowup = 6;
4822
4823
4824// Covers the entire ASCII range (all other characters are unchanged by JSON
4825// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004826static const byte JsonQuoteLengths[kQuoteTableLength] = {
4827 6, 6, 6, 6, 6, 6, 6, 6,
4828 2, 2, 2, 6, 2, 2, 6, 6,
4829 6, 6, 6, 6, 6, 6, 6, 6,
4830 6, 6, 6, 6, 6, 6, 6, 6,
4831 1, 1, 2, 1, 1, 1, 1, 1,
4832 1, 1, 1, 1, 1, 1, 1, 1,
4833 1, 1, 1, 1, 1, 1, 1, 1,
4834 1, 1, 1, 1, 1, 1, 1, 1,
4835 1, 1, 1, 1, 1, 1, 1, 1,
4836 1, 1, 1, 1, 1, 1, 1, 1,
4837 1, 1, 1, 1, 1, 1, 1, 1,
4838 1, 1, 1, 1, 2, 1, 1, 1,
4839 1, 1, 1, 1, 1, 1, 1, 1,
4840 1, 1, 1, 1, 1, 1, 1, 1,
4841 1, 1, 1, 1, 1, 1, 1, 1,
4842 1, 1, 1, 1, 1, 1, 1, 1,
4843};
4844
4845
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004846template <typename StringType>
4847MaybeObject* AllocateRawString(int length);
4848
4849
4850template <>
4851MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4852 return Heap::AllocateRawTwoByteString(length);
4853}
4854
4855
4856template <>
4857MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4858 return Heap::AllocateRawAsciiString(length);
4859}
4860
4861
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004862template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004863static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004864 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004865 const Char* read_cursor = characters.start();
4866 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004867 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004868 int quoted_length = kSpaceForQuotes;
4869 while (read_cursor < end) {
4870 Char c = *(read_cursor++);
4871 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4872 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004873 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004874 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004875 }
4876 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004877 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4878 Object* new_object;
4879 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004880 return new_alloc;
4881 }
4882 StringType* new_string = StringType::cast(new_object);
4883
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004884 Char* write_cursor = reinterpret_cast<Char*>(
4885 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004886 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004887 *(write_cursor++) = '"';
4888
4889 read_cursor = characters.start();
4890 while (read_cursor < end) {
4891 Char c = *(read_cursor++);
4892 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4893 *(write_cursor++) = c;
4894 } else {
4895 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4896 const char* replacement = JsonQuotes +
4897 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4898 for (int i = 0; i < len; i++) {
4899 *write_cursor++ = *replacement++;
4900 }
4901 }
4902 }
4903 *(write_cursor++) = '"';
4904 return new_string;
4905}
4906
4907
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004908template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004909static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4910 int length = characters.length();
4911 Counters::quote_json_char_count.Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004912 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004913 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4914 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004915 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004916 }
4917
4918 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4919 Object* new_object;
4920 if (!new_alloc->ToObject(&new_object)) {
4921 return new_alloc;
4922 }
4923 if (!Heap::new_space()->Contains(new_object)) {
4924 // Even if our string is small enough to fit in new space we still have to
4925 // handle it being allocated in old space as may happen in the third
4926 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4927 // CEntryStub::GenerateCore.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004928 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004929 }
4930 StringType* new_string = StringType::cast(new_object);
4931 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004932
4933 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4934 Char* write_cursor = reinterpret_cast<Char*>(
4935 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004936 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004937 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004938
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004939 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004940 const Char* end = read_cursor + length;
4941 while (read_cursor < end) {
4942 Char c = *(read_cursor++);
4943 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4944 *(write_cursor++) = c;
4945 } else {
4946 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4947 const char* replacement = JsonQuotes +
4948 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4949 write_cursor[0] = replacement[0];
4950 if (len > 1) {
4951 write_cursor[1] = replacement[1];
4952 if (len > 2) {
4953 ASSERT(len == 6);
4954 write_cursor[2] = replacement[2];
4955 write_cursor[3] = replacement[3];
4956 write_cursor[4] = replacement[4];
4957 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004958 }
4959 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004960 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004961 }
4962 }
4963 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004964
4965 int final_length = static_cast<int>(
4966 write_cursor - reinterpret_cast<Char*>(
4967 new_string->address() + SeqAsciiString::kHeaderSize));
4968 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4969 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004970 return new_string;
4971}
4972
4973
4974static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4975 NoHandleAllocation ha;
4976 CONVERT_CHECKED(String, str, args[0]);
4977 if (!str->IsFlat()) {
4978 MaybeObject* try_flatten = str->TryFlatten();
4979 Object* flat;
4980 if (!try_flatten->ToObject(&flat)) {
4981 return try_flatten;
4982 }
4983 str = String::cast(flat);
4984 ASSERT(str->IsFlat());
4985 }
4986 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004987 return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004988 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004989 return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004990 }
4991}
4992
4993
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004994static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
4995 NoHandleAllocation ha;
4996 CONVERT_CHECKED(String, str, args[0]);
4997 if (!str->IsFlat()) {
4998 MaybeObject* try_flatten = str->TryFlatten();
4999 Object* flat;
5000 if (!try_flatten->ToObject(&flat)) {
5001 return try_flatten;
5002 }
5003 str = String::cast(flat);
5004 ASSERT(str->IsFlat());
5005 }
5006 if (str->IsTwoByteRepresentation()) {
5007 return QuoteJsonString<uc16, SeqTwoByteString, true>(str->ToUC16Vector());
5008 } else {
5009 return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
5010 }
5011}
5012
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005013
lrn@chromium.org303ada72010-10-27 09:33:13 +00005014static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005015 NoHandleAllocation ha;
5016
5017 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005018 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005019
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005020 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005021
lrn@chromium.org25156de2010-04-06 13:10:27 +00005022 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
5023 double value = StringToInt(s, radix);
5024 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005025}
5026
5027
lrn@chromium.org303ada72010-10-27 09:33:13 +00005028static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005029 NoHandleAllocation ha;
5030 CONVERT_CHECKED(String, str, args[0]);
5031
5032 // ECMA-262 section 15.1.2.3, empty string is NaN
5033 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
5034
5035 // Create a number object from the value.
5036 return Heap::NumberFromDouble(value);
5037}
5038
5039
5040static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
5041static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
5042
5043
5044template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005045MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
5046 String* s,
5047 int length,
5048 int input_string_length,
5049 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005050 // We try this twice, once with the assumption that the result is no longer
5051 // than the input and, if that assumption breaks, again with the exact
5052 // length. This may not be pretty, but it is nicer than what was here before
5053 // and I hereby claim my vaffel-is.
5054 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005055 // Allocate the resulting string.
5056 //
5057 // NOTE: This assumes that the upper/lower case of an ascii
5058 // character is also ascii. This is currently the case, but it
5059 // might break in the future if we implement more context and locale
5060 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005061 Object* o;
5062 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
5063 ? Heap::AllocateRawAsciiString(length)
5064 : Heap::AllocateRawTwoByteString(length);
5065 if (!maybe_o->ToObject(&o)) return maybe_o;
5066 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005067 String* result = String::cast(o);
5068 bool has_changed_character = false;
5069
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005070 // Convert all characters to upper case, assuming that they will fit
5071 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005072 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005073 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005074 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005075 // We can assume that the string is not empty
5076 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005077 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005078 bool has_next = buffer->has_more();
5079 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005080 int char_length = mapping->get(current, next, chars);
5081 if (char_length == 0) {
5082 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005083 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005084 i++;
5085 } else if (char_length == 1) {
5086 // Common case: converting the letter resulted in one character.
5087 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005088 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005089 has_changed_character = true;
5090 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005091 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005092 // We've assumed that the result would be as long as the
5093 // input but here is a character that converts to several
5094 // characters. No matter, we calculate the exact length
5095 // of the result and try the whole thing again.
5096 //
5097 // Note that this leaves room for optimization. We could just
5098 // memcpy what we already have to the result string. Also,
5099 // the result string is the last object allocated we could
5100 // "realloc" it and probably, in the vast majority of cases,
5101 // extend the existing string to be able to hold the full
5102 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005103 int next_length = 0;
5104 if (has_next) {
5105 next_length = mapping->get(next, 0, chars);
5106 if (next_length == 0) next_length = 1;
5107 }
5108 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005109 while (buffer->has_more()) {
5110 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005111 // NOTE: we use 0 as the next character here because, while
5112 // the next character may affect what a character converts to,
5113 // it does not in any case affect the length of what it convert
5114 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005115 int char_length = mapping->get(current, 0, chars);
5116 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005117 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005118 if (current_length > Smi::kMaxValue) {
5119 Top::context()->mark_out_of_memory();
5120 return Failure::OutOfMemoryException();
5121 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005122 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005123 // Try again with the real length.
5124 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005125 } else {
5126 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005127 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005128 i++;
5129 }
5130 has_changed_character = true;
5131 }
5132 current = next;
5133 }
5134 if (has_changed_character) {
5135 return result;
5136 } else {
5137 // If we didn't actually change anything in doing the conversion
5138 // we simple return the result and let the converted string
5139 // become garbage; there is no reason to keep two identical strings
5140 // alive.
5141 return s;
5142 }
5143}
5144
5145
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005146namespace {
5147
lrn@chromium.org303ada72010-10-27 09:33:13 +00005148static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5149
5150
5151// Given a word and two range boundaries returns a word with high bit
5152// set in every byte iff the corresponding input byte was strictly in
5153// the range (m, n). All the other bits in the result are cleared.
5154// This function is only useful when it can be inlined and the
5155// boundaries are statically known.
5156// Requires: all bytes in the input word and the boundaries must be
5157// ascii (less than 0x7F).
5158static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5159 // Every byte in an ascii string is less than or equal to 0x7F.
5160 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5161 // Use strict inequalities since in edge cases the function could be
5162 // further simplified.
5163 ASSERT(0 < m && m < n && n < 0x7F);
5164 // Has high bit set in every w byte less than n.
5165 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5166 // Has high bit set in every w byte greater than m.
5167 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5168 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5169}
5170
5171
5172enum AsciiCaseConversion {
5173 ASCII_TO_LOWER,
5174 ASCII_TO_UPPER
5175};
5176
5177
5178template <AsciiCaseConversion dir>
5179struct FastAsciiConverter {
5180 static bool Convert(char* dst, char* src, int length) {
5181#ifdef DEBUG
5182 char* saved_dst = dst;
5183 char* saved_src = src;
5184#endif
5185 // We rely on the distance between upper and lower case letters
5186 // being a known power of 2.
5187 ASSERT('a' - 'A' == (1 << 5));
5188 // Boundaries for the range of input characters than require conversion.
5189 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5190 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5191 bool changed = false;
5192 char* const limit = src + length;
5193#ifdef V8_HOST_CAN_READ_UNALIGNED
5194 // Process the prefix of the input that requires no conversion one
5195 // (machine) word at a time.
5196 while (src <= limit - sizeof(uintptr_t)) {
5197 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5198 if (AsciiRangeMask(w, lo, hi) != 0) {
5199 changed = true;
5200 break;
5201 }
5202 *reinterpret_cast<uintptr_t*>(dst) = w;
5203 src += sizeof(uintptr_t);
5204 dst += sizeof(uintptr_t);
5205 }
5206 // Process the remainder of the input performing conversion when
5207 // required one word at a time.
5208 while (src <= limit - sizeof(uintptr_t)) {
5209 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5210 uintptr_t m = AsciiRangeMask(w, lo, hi);
5211 // The mask has high (7th) bit set in every byte that needs
5212 // conversion and we know that the distance between cases is
5213 // 1 << 5.
5214 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5215 src += sizeof(uintptr_t);
5216 dst += sizeof(uintptr_t);
5217 }
5218#endif
5219 // Process the last few bytes of the input (or the whole input if
5220 // unaligned access is not supported).
5221 while (src < limit) {
5222 char c = *src;
5223 if (lo < c && c < hi) {
5224 c ^= (1 << 5);
5225 changed = true;
5226 }
5227 *dst = c;
5228 ++src;
5229 ++dst;
5230 }
5231#ifdef DEBUG
5232 CheckConvert(saved_dst, saved_src, length, changed);
5233#endif
5234 return changed;
5235 }
5236
5237#ifdef DEBUG
5238 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5239 bool expected_changed = false;
5240 for (int i = 0; i < length; i++) {
5241 if (dst[i] == src[i]) continue;
5242 expected_changed = true;
5243 if (dir == ASCII_TO_LOWER) {
5244 ASSERT('A' <= src[i] && src[i] <= 'Z');
5245 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5246 } else {
5247 ASSERT(dir == ASCII_TO_UPPER);
5248 ASSERT('a' <= src[i] && src[i] <= 'z');
5249 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5250 }
5251 }
5252 ASSERT(expected_changed == changed);
5253 }
5254#endif
5255};
5256
5257
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005258struct ToLowerTraits {
5259 typedef unibrow::ToLowercase UnibrowConverter;
5260
lrn@chromium.org303ada72010-10-27 09:33:13 +00005261 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005262};
5263
5264
5265struct ToUpperTraits {
5266 typedef unibrow::ToUppercase UnibrowConverter;
5267
lrn@chromium.org303ada72010-10-27 09:33:13 +00005268 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005269};
5270
5271} // namespace
5272
5273
5274template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005275MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005276 Arguments args,
5277 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005278 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005279 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005280 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005281
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005282 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005283 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005284 if (length == 0) return s;
5285
5286 // Simpler handling of ascii strings.
5287 //
5288 // NOTE: This assumes that the upper/lower case of an ascii
5289 // character is also ascii. This is currently the case, but it
5290 // might break in the future if we implement more context and locale
5291 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005292 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005293 Object* o;
5294 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5295 if (!maybe_o->ToObject(&o)) return maybe_o;
5296 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005297 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005298 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005299 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005300 return has_changed_character ? result : s;
5301 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005302
lrn@chromium.org303ada72010-10-27 09:33:13 +00005303 Object* answer;
5304 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5305 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5306 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005307 if (answer->IsSmi()) {
5308 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005309 { MaybeObject* maybe_answer =
5310 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5311 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5312 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005313 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005314 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005315}
5316
5317
lrn@chromium.org303ada72010-10-27 09:33:13 +00005318static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005319 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005320}
5321
5322
lrn@chromium.org303ada72010-10-27 09:33:13 +00005323static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005324 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005325}
5326
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005327
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005328static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5329 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5330}
5331
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005332
lrn@chromium.org303ada72010-10-27 09:33:13 +00005333static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005334 NoHandleAllocation ha;
5335 ASSERT(args.length() == 3);
5336
5337 CONVERT_CHECKED(String, s, args[0]);
5338 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5339 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5340
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005341 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005342 int length = s->length();
5343
5344 int left = 0;
5345 if (trimLeft) {
5346 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5347 left++;
5348 }
5349 }
5350
5351 int right = length;
5352 if (trimRight) {
5353 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5354 right--;
5355 }
5356 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005357 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005358}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005359
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005360
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005361template <typename SubjectChar, typename PatternChar>
5362void FindStringIndices(Vector<const SubjectChar> subject,
5363 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005364 ZoneList<int>* indices,
5365 unsigned int limit) {
5366 ASSERT(limit > 0);
5367 // Collect indices of pattern in subject, and the end-of-string index.
5368 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005369 StringSearch<PatternChar, SubjectChar> search(pattern);
5370 int pattern_length = pattern.length();
5371 int index = 0;
5372 while (limit > 0) {
5373 index = search.Search(subject, index);
5374 if (index < 0) return;
5375 indices->Add(index);
5376 index += pattern_length;
5377 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005378 }
5379}
5380
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005381
lrn@chromium.org303ada72010-10-27 09:33:13 +00005382static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005383 ASSERT(args.length() == 3);
5384 HandleScope handle_scope;
5385 CONVERT_ARG_CHECKED(String, subject, 0);
5386 CONVERT_ARG_CHECKED(String, pattern, 1);
5387 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5388
5389 int subject_length = subject->length();
5390 int pattern_length = pattern->length();
5391 RUNTIME_ASSERT(pattern_length > 0);
5392
5393 // The limit can be very large (0xffffffffu), but since the pattern
5394 // isn't empty, we can never create more parts than ~half the length
5395 // of the subject.
5396
5397 if (!subject->IsFlat()) FlattenString(subject);
5398
5399 static const int kMaxInitialListCapacity = 16;
5400
5401 ZoneScope scope(DELETE_ON_EXIT);
5402
5403 // Find (up to limit) indices of separator and end-of-string in subject
5404 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5405 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005406 if (!pattern->IsFlat()) FlattenString(pattern);
5407
5408 // No allocation block.
5409 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005410 AssertNoAllocation nogc;
5411 if (subject->IsAsciiRepresentation()) {
5412 Vector<const char> subject_vector = subject->ToAsciiVector();
5413 if (pattern->IsAsciiRepresentation()) {
5414 FindStringIndices(subject_vector,
5415 pattern->ToAsciiVector(),
5416 &indices,
5417 limit);
5418 } else {
5419 FindStringIndices(subject_vector,
5420 pattern->ToUC16Vector(),
5421 &indices,
5422 limit);
5423 }
5424 } else {
5425 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5426 if (pattern->IsAsciiRepresentation()) {
5427 FindStringIndices(subject_vector,
5428 pattern->ToAsciiVector(),
5429 &indices,
5430 limit);
5431 } else {
5432 FindStringIndices(subject_vector,
5433 pattern->ToUC16Vector(),
5434 &indices,
5435 limit);
5436 }
5437 }
5438 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005439
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005440 if (static_cast<uint32_t>(indices.length()) < limit) {
5441 indices.Add(subject_length);
5442 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005443
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005444 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005445
5446 // Create JSArray of substrings separated by separator.
5447 int part_count = indices.length();
5448
5449 Handle<JSArray> result = Factory::NewJSArray(part_count);
5450 result->set_length(Smi::FromInt(part_count));
5451
5452 ASSERT(result->HasFastElements());
5453
5454 if (part_count == 1 && indices.at(0) == subject_length) {
5455 FixedArray::cast(result->elements())->set(0, *subject);
5456 return *result;
5457 }
5458
5459 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5460 int part_start = 0;
5461 for (int i = 0; i < part_count; i++) {
5462 HandleScope local_loop_handle;
5463 int part_end = indices.at(i);
5464 Handle<String> substring =
5465 Factory::NewSubString(subject, part_start, part_end);
5466 elements->set(i, *substring);
5467 part_start = part_end + pattern_length;
5468 }
5469
5470 return *result;
5471}
5472
5473
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005474// Copies ascii characters to the given fixed array looking up
5475// one-char strings in the cache. Gives up on the first char that is
5476// not in the cache and fills the remainder with smi zeros. Returns
5477// the length of the successfully copied prefix.
5478static int CopyCachedAsciiCharsToArray(const char* chars,
5479 FixedArray* elements,
5480 int length) {
5481 AssertNoAllocation nogc;
5482 FixedArray* ascii_cache = Heap::single_character_string_cache();
5483 Object* undefined = Heap::undefined_value();
5484 int i;
5485 for (i = 0; i < length; ++i) {
5486 Object* value = ascii_cache->get(chars[i]);
5487 if (value == undefined) break;
5488 ASSERT(!Heap::InNewSpace(value));
5489 elements->set(i, value, SKIP_WRITE_BARRIER);
5490 }
5491 if (i < length) {
5492 ASSERT(Smi::FromInt(0) == 0);
5493 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5494 }
5495#ifdef DEBUG
5496 for (int j = 0; j < length; ++j) {
5497 Object* element = elements->get(j);
5498 ASSERT(element == Smi::FromInt(0) ||
5499 (element->IsString() && String::cast(element)->LooksValid()));
5500 }
5501#endif
5502 return i;
5503}
5504
5505
5506// Converts a String to JSArray.
5507// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005508static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005509 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005510 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005511 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005512 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005513
5514 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005515 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005516
5517 Handle<FixedArray> elements;
5518 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005519 Object* obj;
5520 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5521 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5522 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005523 elements = Handle<FixedArray>(FixedArray::cast(obj));
5524
5525 Vector<const char> chars = s->ToAsciiVector();
5526 // Note, this will initialize all elements (not only the prefix)
5527 // to prevent GC from seeing partially initialized array.
5528 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5529 *elements,
5530 length);
5531
5532 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005533 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5534 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005535 }
5536 } else {
5537 elements = Factory::NewFixedArray(length);
5538 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005539 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5540 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005541 }
5542 }
5543
5544#ifdef DEBUG
5545 for (int i = 0; i < length; ++i) {
5546 ASSERT(String::cast(elements->get(i))->length() == 1);
5547 }
5548#endif
5549
5550 return *Factory::NewJSArrayWithElements(elements);
5551}
5552
5553
lrn@chromium.org303ada72010-10-27 09:33:13 +00005554static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005555 NoHandleAllocation ha;
5556 ASSERT(args.length() == 1);
5557 CONVERT_CHECKED(String, value, args[0]);
5558 return value->ToObject();
5559}
5560
5561
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005562bool Runtime::IsUpperCaseChar(uint16_t ch) {
5563 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5564 int char_length = to_upper_mapping.get(ch, 0, chars);
5565 return char_length == 0;
5566}
5567
5568
lrn@chromium.org303ada72010-10-27 09:33:13 +00005569static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005570 NoHandleAllocation ha;
5571 ASSERT(args.length() == 1);
5572
5573 Object* number = args[0];
5574 RUNTIME_ASSERT(number->IsNumber());
5575
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005576 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577}
5578
5579
lrn@chromium.org303ada72010-10-27 09:33:13 +00005580static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005581 NoHandleAllocation ha;
5582 ASSERT(args.length() == 1);
5583
5584 Object* number = args[0];
5585 RUNTIME_ASSERT(number->IsNumber());
5586
5587 return Heap::NumberToString(number, false);
5588}
5589
5590
lrn@chromium.org303ada72010-10-27 09:33:13 +00005591static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005592 NoHandleAllocation ha;
5593 ASSERT(args.length() == 1);
5594
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005595 CONVERT_DOUBLE_CHECKED(number, args[0]);
5596
5597 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5598 if (number > 0 && number <= Smi::kMaxValue) {
5599 return Smi::FromInt(static_cast<int>(number));
5600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005601 return Heap::NumberFromDouble(DoubleToInteger(number));
5602}
5603
5604
lrn@chromium.org303ada72010-10-27 09:33:13 +00005605static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005606 NoHandleAllocation ha;
5607 ASSERT(args.length() == 1);
5608
5609 CONVERT_DOUBLE_CHECKED(number, args[0]);
5610
5611 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5612 if (number > 0 && number <= Smi::kMaxValue) {
5613 return Smi::FromInt(static_cast<int>(number));
5614 }
5615
5616 double double_value = DoubleToInteger(number);
5617 // Map both -0 and +0 to +0.
5618 if (double_value == 0) double_value = 0;
5619
5620 return Heap::NumberFromDouble(double_value);
5621}
5622
5623
lrn@chromium.org303ada72010-10-27 09:33:13 +00005624static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005625 NoHandleAllocation ha;
5626 ASSERT(args.length() == 1);
5627
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005628 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005629 return Heap::NumberFromUint32(number);
5630}
5631
5632
lrn@chromium.org303ada72010-10-27 09:33:13 +00005633static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005634 NoHandleAllocation ha;
5635 ASSERT(args.length() == 1);
5636
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005637 CONVERT_DOUBLE_CHECKED(number, args[0]);
5638
5639 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5640 if (number > 0 && number <= Smi::kMaxValue) {
5641 return Smi::FromInt(static_cast<int>(number));
5642 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005643 return Heap::NumberFromInt32(DoubleToInt32(number));
5644}
5645
5646
ager@chromium.org870a0b62008-11-04 11:43:05 +00005647// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5648// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005649static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005650 NoHandleAllocation ha;
5651 ASSERT(args.length() == 1);
5652
5653 Object* obj = args[0];
5654 if (obj->IsSmi()) {
5655 return obj;
5656 }
5657 if (obj->IsHeapNumber()) {
5658 double value = HeapNumber::cast(obj)->value();
5659 int int_value = FastD2I(value);
5660 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5661 return Smi::FromInt(int_value);
5662 }
5663 }
5664 return Heap::nan_value();
5665}
5666
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005667
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005668static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5669 NoHandleAllocation ha;
5670 ASSERT(args.length() == 0);
5671 return Heap::AllocateHeapNumber(0);
5672}
5673
5674
lrn@chromium.org303ada72010-10-27 09:33:13 +00005675static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005676 NoHandleAllocation ha;
5677 ASSERT(args.length() == 2);
5678
5679 CONVERT_DOUBLE_CHECKED(x, args[0]);
5680 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005681 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005682}
5683
5684
lrn@chromium.org303ada72010-10-27 09:33:13 +00005685static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005686 NoHandleAllocation ha;
5687 ASSERT(args.length() == 2);
5688
5689 CONVERT_DOUBLE_CHECKED(x, args[0]);
5690 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005691 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005692}
5693
5694
lrn@chromium.org303ada72010-10-27 09:33:13 +00005695static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005696 NoHandleAllocation ha;
5697 ASSERT(args.length() == 2);
5698
5699 CONVERT_DOUBLE_CHECKED(x, args[0]);
5700 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005701 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005702}
5703
5704
lrn@chromium.org303ada72010-10-27 09:33:13 +00005705static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005706 NoHandleAllocation ha;
5707 ASSERT(args.length() == 1);
5708
5709 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005710 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005711}
5712
5713
lrn@chromium.org303ada72010-10-27 09:33:13 +00005714static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005715 NoHandleAllocation ha;
5716 ASSERT(args.length() == 0);
5717
5718 return Heap::NumberFromDouble(9876543210.0);
5719}
5720
5721
lrn@chromium.org303ada72010-10-27 09:33:13 +00005722static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005723 NoHandleAllocation ha;
5724 ASSERT(args.length() == 2);
5725
5726 CONVERT_DOUBLE_CHECKED(x, args[0]);
5727 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005728 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005729}
5730
5731
lrn@chromium.org303ada72010-10-27 09:33:13 +00005732static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005733 NoHandleAllocation ha;
5734 ASSERT(args.length() == 2);
5735
5736 CONVERT_DOUBLE_CHECKED(x, args[0]);
5737 CONVERT_DOUBLE_CHECKED(y, args[1]);
5738
ager@chromium.org3811b432009-10-28 14:53:37 +00005739 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005740 // NumberFromDouble may return a Smi instead of a Number object
5741 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005742}
5743
5744
lrn@chromium.org303ada72010-10-27 09:33:13 +00005745static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005746 NoHandleAllocation ha;
5747 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005748 CONVERT_CHECKED(String, str1, args[0]);
5749 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005750 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005751 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005752}
5753
5754
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005755template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005756static inline void StringBuilderConcatHelper(String* special,
5757 sinkchar* sink,
5758 FixedArray* fixed_array,
5759 int array_length) {
5760 int position = 0;
5761 for (int i = 0; i < array_length; i++) {
5762 Object* element = fixed_array->get(i);
5763 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005764 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005765 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005766 int pos;
5767 int len;
5768 if (encoded_slice > 0) {
5769 // Position and length encoded in one smi.
5770 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5771 len = StringBuilderSubstringLength::decode(encoded_slice);
5772 } else {
5773 // Position and length encoded in two smis.
5774 Object* obj = fixed_array->get(++i);
5775 ASSERT(obj->IsSmi());
5776 pos = Smi::cast(obj)->value();
5777 len = -encoded_slice;
5778 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005779 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005780 sink + position,
5781 pos,
5782 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005783 position += len;
5784 } else {
5785 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005786 int element_length = string->length();
5787 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005788 position += element_length;
5789 }
5790 }
5791}
5792
5793
lrn@chromium.org303ada72010-10-27 09:33:13 +00005794static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005795 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005796 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005797 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005798 if (!args[1]->IsSmi()) {
5799 Top::context()->mark_out_of_memory();
5800 return Failure::OutOfMemoryException();
5801 }
5802 int array_length = Smi::cast(args[1])->value();
5803 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005804
5805 // This assumption is used by the slice encoding in one or two smis.
5806 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5807
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005808 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005809 if (!array->HasFastElements()) {
5810 return Top::Throw(Heap::illegal_argument_symbol());
5811 }
5812 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005813 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005814 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005815 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005816
5817 if (array_length == 0) {
5818 return Heap::empty_string();
5819 } else if (array_length == 1) {
5820 Object* first = fixed_array->get(0);
5821 if (first->IsString()) return first;
5822 }
5823
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005824 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005825 int position = 0;
5826 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005827 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005828 Object* elt = fixed_array->get(i);
5829 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005830 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005831 int smi_value = Smi::cast(elt)->value();
5832 int pos;
5833 int len;
5834 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005835 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005836 pos = StringBuilderSubstringPosition::decode(smi_value);
5837 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005838 } else {
5839 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005840 len = -smi_value;
5841 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005842 i++;
5843 if (i >= array_length) {
5844 return Top::Throw(Heap::illegal_argument_symbol());
5845 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005846 Object* next_smi = fixed_array->get(i);
5847 if (!next_smi->IsSmi()) {
5848 return Top::Throw(Heap::illegal_argument_symbol());
5849 }
5850 pos = Smi::cast(next_smi)->value();
5851 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005852 return Top::Throw(Heap::illegal_argument_symbol());
5853 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005854 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005855 ASSERT(pos >= 0);
5856 ASSERT(len >= 0);
5857 if (pos > special_length || len > special_length - pos) {
5858 return Top::Throw(Heap::illegal_argument_symbol());
5859 }
5860 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005861 } else if (elt->IsString()) {
5862 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005863 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005864 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005865 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005866 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005867 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005868 } else {
5869 return Top::Throw(Heap::illegal_argument_symbol());
5870 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005871 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005872 Top::context()->mark_out_of_memory();
5873 return Failure::OutOfMemoryException();
5874 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005875 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005876 }
5877
5878 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005879 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005880
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005881 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005882 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5883 if (!maybe_object->ToObject(&object)) return maybe_object;
5884 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005885 SeqAsciiString* answer = SeqAsciiString::cast(object);
5886 StringBuilderConcatHelper(special,
5887 answer->GetChars(),
5888 fixed_array,
5889 array_length);
5890 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005891 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005892 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5893 if (!maybe_object->ToObject(&object)) return maybe_object;
5894 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005895 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5896 StringBuilderConcatHelper(special,
5897 answer->GetChars(),
5898 fixed_array,
5899 array_length);
5900 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005901 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005902}
5903
5904
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005905static MaybeObject* Runtime_StringBuilderJoin(Arguments args) {
5906 NoHandleAllocation ha;
5907 ASSERT(args.length() == 3);
5908 CONVERT_CHECKED(JSArray, array, args[0]);
5909 if (!args[1]->IsSmi()) {
5910 Top::context()->mark_out_of_memory();
5911 return Failure::OutOfMemoryException();
5912 }
5913 int array_length = Smi::cast(args[1])->value();
5914 CONVERT_CHECKED(String, separator, args[2]);
5915
5916 if (!array->HasFastElements()) {
5917 return Top::Throw(Heap::illegal_argument_symbol());
5918 }
5919 FixedArray* fixed_array = FixedArray::cast(array->elements());
5920 if (fixed_array->length() < array_length) {
5921 array_length = fixed_array->length();
5922 }
5923
5924 if (array_length == 0) {
5925 return Heap::empty_string();
5926 } else if (array_length == 1) {
5927 Object* first = fixed_array->get(0);
5928 if (first->IsString()) return first;
5929 }
5930
5931 int separator_length = separator->length();
5932 int max_nof_separators =
5933 (String::kMaxLength + separator_length - 1) / separator_length;
5934 if (max_nof_separators < (array_length - 1)) {
5935 Top::context()->mark_out_of_memory();
5936 return Failure::OutOfMemoryException();
5937 }
5938 int length = (array_length - 1) * separator_length;
5939 for (int i = 0; i < array_length; i++) {
5940 Object* element_obj = fixed_array->get(i);
5941 if (!element_obj->IsString()) {
5942 // TODO(1161): handle this case.
5943 return Top::Throw(Heap::illegal_argument_symbol());
5944 }
5945 String* element = String::cast(element_obj);
5946 int increment = element->length();
5947 if (increment > String::kMaxLength - length) {
5948 Top::context()->mark_out_of_memory();
5949 return Failure::OutOfMemoryException();
5950 }
5951 length += increment;
5952 }
5953
5954 Object* object;
5955 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5956 if (!maybe_object->ToObject(&object)) return maybe_object;
5957 }
5958 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5959
5960 uc16* sink = answer->GetChars();
5961#ifdef DEBUG
5962 uc16* end = sink + length;
5963#endif
5964
5965 String* first = String::cast(fixed_array->get(0));
5966 int first_length = first->length();
5967 String::WriteToFlat(first, sink, 0, first_length);
5968 sink += first_length;
5969
5970 for (int i = 1; i < array_length; i++) {
5971 ASSERT(sink + separator_length <= end);
5972 String::WriteToFlat(separator, sink, 0, separator_length);
5973 sink += separator_length;
5974
5975 String* element = String::cast(fixed_array->get(i));
5976 int element_length = element->length();
5977 ASSERT(sink + element_length <= end);
5978 String::WriteToFlat(element, sink, 0, element_length);
5979 sink += element_length;
5980 }
5981 ASSERT(sink == end);
5982
5983 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
5984 return answer;
5985}
5986
5987
lrn@chromium.org303ada72010-10-27 09:33:13 +00005988static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989 NoHandleAllocation ha;
5990 ASSERT(args.length() == 2);
5991
5992 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5993 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5994 return Heap::NumberFromInt32(x | y);
5995}
5996
5997
lrn@chromium.org303ada72010-10-27 09:33:13 +00005998static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005999 NoHandleAllocation ha;
6000 ASSERT(args.length() == 2);
6001
6002 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6003 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6004 return Heap::NumberFromInt32(x & y);
6005}
6006
6007
lrn@chromium.org303ada72010-10-27 09:33:13 +00006008static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006009 NoHandleAllocation ha;
6010 ASSERT(args.length() == 2);
6011
6012 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6013 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6014 return Heap::NumberFromInt32(x ^ y);
6015}
6016
6017
lrn@chromium.org303ada72010-10-27 09:33:13 +00006018static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006019 NoHandleAllocation ha;
6020 ASSERT(args.length() == 1);
6021
6022 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6023 return Heap::NumberFromInt32(~x);
6024}
6025
6026
lrn@chromium.org303ada72010-10-27 09:33:13 +00006027static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006028 NoHandleAllocation ha;
6029 ASSERT(args.length() == 2);
6030
6031 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6032 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6033 return Heap::NumberFromInt32(x << (y & 0x1f));
6034}
6035
6036
lrn@chromium.org303ada72010-10-27 09:33:13 +00006037static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 NoHandleAllocation ha;
6039 ASSERT(args.length() == 2);
6040
6041 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6042 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6043 return Heap::NumberFromUint32(x >> (y & 0x1f));
6044}
6045
6046
lrn@chromium.org303ada72010-10-27 09:33:13 +00006047static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006048 NoHandleAllocation ha;
6049 ASSERT(args.length() == 2);
6050
6051 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6052 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6053 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
6054}
6055
6056
lrn@chromium.org303ada72010-10-27 09:33:13 +00006057static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006058 NoHandleAllocation ha;
6059 ASSERT(args.length() == 2);
6060
6061 CONVERT_DOUBLE_CHECKED(x, args[0]);
6062 CONVERT_DOUBLE_CHECKED(y, args[1]);
6063 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6064 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6065 if (x == y) return Smi::FromInt(EQUAL);
6066 Object* result;
6067 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6068 result = Smi::FromInt(EQUAL);
6069 } else {
6070 result = Smi::FromInt(NOT_EQUAL);
6071 }
6072 return result;
6073}
6074
6075
lrn@chromium.org303ada72010-10-27 09:33:13 +00006076static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006077 NoHandleAllocation ha;
6078 ASSERT(args.length() == 2);
6079
6080 CONVERT_CHECKED(String, x, args[0]);
6081 CONVERT_CHECKED(String, y, args[1]);
6082
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006083 bool not_equal = !x->Equals(y);
6084 // This is slightly convoluted because the value that signifies
6085 // equality is 0 and inequality is 1 so we have to negate the result
6086 // from String::Equals.
6087 ASSERT(not_equal == 0 || not_equal == 1);
6088 STATIC_CHECK(EQUAL == 0);
6089 STATIC_CHECK(NOT_EQUAL == 1);
6090 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006091}
6092
6093
lrn@chromium.org303ada72010-10-27 09:33:13 +00006094static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006095 NoHandleAllocation ha;
6096 ASSERT(args.length() == 3);
6097
6098 CONVERT_DOUBLE_CHECKED(x, args[0]);
6099 CONVERT_DOUBLE_CHECKED(y, args[1]);
6100 if (isnan(x) || isnan(y)) return args[2];
6101 if (x == y) return Smi::FromInt(EQUAL);
6102 if (isless(x, y)) return Smi::FromInt(LESS);
6103 return Smi::FromInt(GREATER);
6104}
6105
6106
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006107// Compare two Smis as if they were converted to strings and then
6108// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006109static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006110 NoHandleAllocation ha;
6111 ASSERT(args.length() == 2);
6112
6113 // Arrays for the individual characters of the two Smis. Smis are
6114 // 31 bit integers and 10 decimal digits are therefore enough.
6115 static int x_elms[10];
6116 static int y_elms[10];
6117
6118 // Extract the integer values from the Smis.
6119 CONVERT_CHECKED(Smi, x, args[0]);
6120 CONVERT_CHECKED(Smi, y, args[1]);
6121 int x_value = x->value();
6122 int y_value = y->value();
6123
6124 // If the integers are equal so are the string representations.
6125 if (x_value == y_value) return Smi::FromInt(EQUAL);
6126
6127 // If one of the integers are zero the normal integer order is the
6128 // same as the lexicographic order of the string representations.
6129 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6130
ager@chromium.org32912102009-01-16 10:38:43 +00006131 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006132 // smallest because the char code of '-' is less than the char code
6133 // of any digit. Otherwise, we make both values positive.
6134 if (x_value < 0 || y_value < 0) {
6135 if (y_value >= 0) return Smi::FromInt(LESS);
6136 if (x_value >= 0) return Smi::FromInt(GREATER);
6137 x_value = -x_value;
6138 y_value = -y_value;
6139 }
6140
6141 // Convert the integers to arrays of their decimal digits.
6142 int x_index = 0;
6143 int y_index = 0;
6144 while (x_value > 0) {
6145 x_elms[x_index++] = x_value % 10;
6146 x_value /= 10;
6147 }
6148 while (y_value > 0) {
6149 y_elms[y_index++] = y_value % 10;
6150 y_value /= 10;
6151 }
6152
6153 // Loop through the arrays of decimal digits finding the first place
6154 // where they differ.
6155 while (--x_index >= 0 && --y_index >= 0) {
6156 int diff = x_elms[x_index] - y_elms[y_index];
6157 if (diff != 0) return Smi::FromInt(diff);
6158 }
6159
6160 // If one array is a suffix of the other array, the longest array is
6161 // the representation of the largest of the Smis in the
6162 // lexicographic ordering.
6163 return Smi::FromInt(x_index - y_index);
6164}
6165
6166
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006167static Object* StringInputBufferCompare(String* x, String* y) {
6168 static StringInputBuffer bufx;
6169 static StringInputBuffer bufy;
6170 bufx.Reset(x);
6171 bufy.Reset(y);
6172 while (bufx.has_more() && bufy.has_more()) {
6173 int d = bufx.GetNext() - bufy.GetNext();
6174 if (d < 0) return Smi::FromInt(LESS);
6175 else if (d > 0) return Smi::FromInt(GREATER);
6176 }
6177
6178 // x is (non-trivial) prefix of y:
6179 if (bufy.has_more()) return Smi::FromInt(LESS);
6180 // y is prefix of x:
6181 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6182}
6183
6184
6185static Object* FlatStringCompare(String* x, String* y) {
6186 ASSERT(x->IsFlat());
6187 ASSERT(y->IsFlat());
6188 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6189 int prefix_length = x->length();
6190 if (y->length() < prefix_length) {
6191 prefix_length = y->length();
6192 equal_prefix_result = Smi::FromInt(GREATER);
6193 } else if (y->length() > prefix_length) {
6194 equal_prefix_result = Smi::FromInt(LESS);
6195 }
6196 int r;
6197 if (x->IsAsciiRepresentation()) {
6198 Vector<const char> x_chars = x->ToAsciiVector();
6199 if (y->IsAsciiRepresentation()) {
6200 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006201 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006202 } else {
6203 Vector<const uc16> y_chars = y->ToUC16Vector();
6204 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6205 }
6206 } else {
6207 Vector<const uc16> x_chars = x->ToUC16Vector();
6208 if (y->IsAsciiRepresentation()) {
6209 Vector<const char> y_chars = y->ToAsciiVector();
6210 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6211 } else {
6212 Vector<const uc16> y_chars = y->ToUC16Vector();
6213 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6214 }
6215 }
6216 Object* result;
6217 if (r == 0) {
6218 result = equal_prefix_result;
6219 } else {
6220 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6221 }
6222 ASSERT(result == StringInputBufferCompare(x, y));
6223 return result;
6224}
6225
6226
lrn@chromium.org303ada72010-10-27 09:33:13 +00006227static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006228 NoHandleAllocation ha;
6229 ASSERT(args.length() == 2);
6230
6231 CONVERT_CHECKED(String, x, args[0]);
6232 CONVERT_CHECKED(String, y, args[1]);
6233
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006234 Counters::string_compare_runtime.Increment();
6235
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006236 // A few fast case tests before we flatten.
6237 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006238 if (y->length() == 0) {
6239 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006240 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006241 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006242 return Smi::FromInt(LESS);
6243 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006244
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006245 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006246 if (d < 0) return Smi::FromInt(LESS);
6247 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006248
lrn@chromium.org303ada72010-10-27 09:33:13 +00006249 Object* obj;
6250 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
6251 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6252 }
6253 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
6254 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6255 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006256
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006257 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
6258 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006259}
6260
6261
lrn@chromium.org303ada72010-10-27 09:33:13 +00006262static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006263 NoHandleAllocation ha;
6264 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006265 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006266
6267 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006268 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006269}
6270
6271
lrn@chromium.org303ada72010-10-27 09:33:13 +00006272static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006273 NoHandleAllocation ha;
6274 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006275 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006276
6277 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006278 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006279}
6280
6281
lrn@chromium.org303ada72010-10-27 09:33:13 +00006282static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006283 NoHandleAllocation ha;
6284 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006285 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006286
6287 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006288 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006289}
6290
6291
lrn@chromium.org303ada72010-10-27 09:33:13 +00006292static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006293 NoHandleAllocation ha;
6294 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006295 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006296
6297 CONVERT_DOUBLE_CHECKED(x, args[0]);
6298 CONVERT_DOUBLE_CHECKED(y, args[1]);
6299 double result;
6300 if (isinf(x) && isinf(y)) {
6301 // Make sure that the result in case of two infinite arguments
6302 // is a multiple of Pi / 4. The sign of the result is determined
6303 // by the first argument (x) and the sign of the second argument
6304 // determines the multiplier: one or three.
6305 static double kPiDividedBy4 = 0.78539816339744830962;
6306 int multiplier = (x < 0) ? -1 : 1;
6307 if (y < 0) multiplier *= 3;
6308 result = multiplier * kPiDividedBy4;
6309 } else {
6310 result = atan2(x, y);
6311 }
6312 return Heap::AllocateHeapNumber(result);
6313}
6314
6315
lrn@chromium.org303ada72010-10-27 09:33:13 +00006316static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006317 NoHandleAllocation ha;
6318 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006319 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006320
6321 CONVERT_DOUBLE_CHECKED(x, args[0]);
6322 return Heap::NumberFromDouble(ceiling(x));
6323}
6324
6325
lrn@chromium.org303ada72010-10-27 09:33:13 +00006326static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006327 NoHandleAllocation ha;
6328 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006329 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006330
6331 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006332 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006333}
6334
6335
lrn@chromium.org303ada72010-10-27 09:33:13 +00006336static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006337 NoHandleAllocation ha;
6338 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006339 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006340
6341 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006342 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006343}
6344
6345
lrn@chromium.org303ada72010-10-27 09:33:13 +00006346static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006347 NoHandleAllocation ha;
6348 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006349 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006350
6351 CONVERT_DOUBLE_CHECKED(x, args[0]);
6352 return Heap::NumberFromDouble(floor(x));
6353}
6354
6355
lrn@chromium.org303ada72010-10-27 09:33:13 +00006356static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006357 NoHandleAllocation ha;
6358 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006359 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006360
6361 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006362 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006363}
6364
6365
lrn@chromium.org303ada72010-10-27 09:33:13 +00006366static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006367 NoHandleAllocation ha;
6368 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006369 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006370
6371 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006372
6373 // If the second argument is a smi, it is much faster to call the
6374 // custom powi() function than the generic pow().
6375 if (args[1]->IsSmi()) {
6376 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006377 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006378 }
6379
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006380 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006381 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006382}
6383
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006384// Fast version of Math.pow if we know that y is not an integer and
6385// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006386static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006387 NoHandleAllocation ha;
6388 ASSERT(args.length() == 2);
6389 CONVERT_DOUBLE_CHECKED(x, args[0]);
6390 CONVERT_DOUBLE_CHECKED(y, args[1]);
6391 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006392 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006393 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006394 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006395 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006396 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006397 }
6398}
6399
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006400
lrn@chromium.org303ada72010-10-27 09:33:13 +00006401static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006402 NoHandleAllocation ha;
6403 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006404 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006405
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006406 if (!args[0]->IsHeapNumber()) {
6407 // Must be smi. Return the argument unchanged for all the other types
6408 // to make fuzz-natives test happy.
6409 return args[0];
6410 }
6411
6412 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6413
6414 double value = number->value();
6415 int exponent = number->get_exponent();
6416 int sign = number->get_sign();
6417
6418 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6419 // should be rounded to 2^30, which is not smi.
6420 if (!sign && exponent <= kSmiValueSize - 3) {
6421 return Smi::FromInt(static_cast<int>(value + 0.5));
6422 }
6423
6424 // If the magnitude is big enough, there's no place for fraction part. If we
6425 // try to add 0.5 to this number, 1.0 will be added instead.
6426 if (exponent >= 52) {
6427 return number;
6428 }
6429
6430 if (sign && value >= -0.5) return Heap::minus_zero_value();
6431
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006432 // Do not call NumberFromDouble() to avoid extra checks.
6433 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006434}
6435
6436
lrn@chromium.org303ada72010-10-27 09:33:13 +00006437static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006438 NoHandleAllocation ha;
6439 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006440 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441
6442 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006443 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006444}
6445
6446
lrn@chromium.org303ada72010-10-27 09:33:13 +00006447static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006448 NoHandleAllocation ha;
6449 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006450 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006451
6452 CONVERT_DOUBLE_CHECKED(x, args[0]);
6453 return Heap::AllocateHeapNumber(sqrt(x));
6454}
6455
6456
lrn@chromium.org303ada72010-10-27 09:33:13 +00006457static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006458 NoHandleAllocation ha;
6459 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006460 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006461
6462 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006463 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006464}
6465
6466
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006467static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006468 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6469 181, 212, 243, 273, 304, 334};
6470 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6471 182, 213, 244, 274, 305, 335};
6472
6473 year += month / 12;
6474 month %= 12;
6475 if (month < 0) {
6476 year--;
6477 month += 12;
6478 }
6479
6480 ASSERT(month >= 0);
6481 ASSERT(month < 12);
6482
6483 // year_delta is an arbitrary number such that:
6484 // a) year_delta = -1 (mod 400)
6485 // b) year + year_delta > 0 for years in the range defined by
6486 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6487 // Jan 1 1970. This is required so that we don't run into integer
6488 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006489 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006490 // operations.
6491 static const int year_delta = 399999;
6492 static const int base_day = 365 * (1970 + year_delta) +
6493 (1970 + year_delta) / 4 -
6494 (1970 + year_delta) / 100 +
6495 (1970 + year_delta) / 400;
6496
6497 int year1 = year + year_delta;
6498 int day_from_year = 365 * year1 +
6499 year1 / 4 -
6500 year1 / 100 +
6501 year1 / 400 -
6502 base_day;
6503
6504 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006505 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006506 }
6507
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006508 return day_from_year + day_from_month_leap[month] + day - 1;
6509}
6510
6511
lrn@chromium.org303ada72010-10-27 09:33:13 +00006512static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006513 NoHandleAllocation ha;
6514 ASSERT(args.length() == 3);
6515
6516 CONVERT_SMI_CHECKED(year, args[0]);
6517 CONVERT_SMI_CHECKED(month, args[1]);
6518 CONVERT_SMI_CHECKED(date, args[2]);
6519
6520 return Smi::FromInt(MakeDay(year, month, date));
6521}
6522
6523
6524static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6525static const int kDaysIn4Years = 4 * 365 + 1;
6526static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6527static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6528static const int kDays1970to2000 = 30 * 365 + 7;
6529static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6530 kDays1970to2000;
6531static const int kYearsOffset = 400000;
6532
6533static const char kDayInYear[] = {
6534 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6535 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6536 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6537 22, 23, 24, 25, 26, 27, 28,
6538 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6539 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6540 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6541 22, 23, 24, 25, 26, 27, 28, 29, 30,
6542 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6543 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6544 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6545 22, 23, 24, 25, 26, 27, 28, 29, 30,
6546 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6547 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6548 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6549 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6550 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6551 22, 23, 24, 25, 26, 27, 28, 29, 30,
6552 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6553 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6554 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6555 22, 23, 24, 25, 26, 27, 28, 29, 30,
6556 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6557 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6558
6559 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6560 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6561 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6562 22, 23, 24, 25, 26, 27, 28,
6563 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6564 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6565 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6566 22, 23, 24, 25, 26, 27, 28, 29, 30,
6567 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6568 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6569 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6570 22, 23, 24, 25, 26, 27, 28, 29, 30,
6571 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6572 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6573 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6574 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6575 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6576 22, 23, 24, 25, 26, 27, 28, 29, 30,
6577 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6578 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6579 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6580 22, 23, 24, 25, 26, 27, 28, 29, 30,
6581 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6582 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6583
6584 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6585 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6586 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6587 22, 23, 24, 25, 26, 27, 28, 29,
6588 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6589 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6590 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6591 22, 23, 24, 25, 26, 27, 28, 29, 30,
6592 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6593 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6594 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6595 22, 23, 24, 25, 26, 27, 28, 29, 30,
6596 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6597 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6598 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6599 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6600 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6601 22, 23, 24, 25, 26, 27, 28, 29, 30,
6602 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6603 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6604 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6605 22, 23, 24, 25, 26, 27, 28, 29, 30,
6606 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6607 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6608
6609 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6610 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6611 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6612 22, 23, 24, 25, 26, 27, 28,
6613 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6614 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6615 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6616 22, 23, 24, 25, 26, 27, 28, 29, 30,
6617 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6618 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6619 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6620 22, 23, 24, 25, 26, 27, 28, 29, 30,
6621 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6622 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6623 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6624 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6625 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6626 22, 23, 24, 25, 26, 27, 28, 29, 30,
6627 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6628 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6629 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6630 22, 23, 24, 25, 26, 27, 28, 29, 30,
6631 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6632 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6633
6634static const char kMonthInYear[] = {
6635 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,
6636 0, 0, 0, 0, 0, 0,
6637 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,
6638 1, 1, 1,
6639 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,
6640 2, 2, 2, 2, 2, 2,
6641 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,
6642 3, 3, 3, 3, 3,
6643 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,
6644 4, 4, 4, 4, 4, 4,
6645 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,
6646 5, 5, 5, 5, 5,
6647 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,
6648 6, 6, 6, 6, 6, 6,
6649 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,
6650 7, 7, 7, 7, 7, 7,
6651 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,
6652 8, 8, 8, 8, 8,
6653 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,
6654 9, 9, 9, 9, 9, 9,
6655 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6656 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6657 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6658 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6659
6660 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,
6661 0, 0, 0, 0, 0, 0,
6662 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,
6663 1, 1, 1,
6664 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,
6665 2, 2, 2, 2, 2, 2,
6666 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,
6667 3, 3, 3, 3, 3,
6668 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,
6669 4, 4, 4, 4, 4, 4,
6670 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,
6671 5, 5, 5, 5, 5,
6672 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,
6673 6, 6, 6, 6, 6, 6,
6674 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,
6675 7, 7, 7, 7, 7, 7,
6676 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,
6677 8, 8, 8, 8, 8,
6678 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,
6679 9, 9, 9, 9, 9, 9,
6680 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6681 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6682 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6683 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6684
6685 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,
6686 0, 0, 0, 0, 0, 0,
6687 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,
6688 1, 1, 1, 1,
6689 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,
6690 2, 2, 2, 2, 2, 2,
6691 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,
6692 3, 3, 3, 3, 3,
6693 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,
6694 4, 4, 4, 4, 4, 4,
6695 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,
6696 5, 5, 5, 5, 5,
6697 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,
6698 6, 6, 6, 6, 6, 6,
6699 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,
6700 7, 7, 7, 7, 7, 7,
6701 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,
6702 8, 8, 8, 8, 8,
6703 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,
6704 9, 9, 9, 9, 9, 9,
6705 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6706 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6707 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6708 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6709
6710 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,
6711 0, 0, 0, 0, 0, 0,
6712 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,
6713 1, 1, 1,
6714 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,
6715 2, 2, 2, 2, 2, 2,
6716 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,
6717 3, 3, 3, 3, 3,
6718 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,
6719 4, 4, 4, 4, 4, 4,
6720 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,
6721 5, 5, 5, 5, 5,
6722 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,
6723 6, 6, 6, 6, 6, 6,
6724 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,
6725 7, 7, 7, 7, 7, 7,
6726 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,
6727 8, 8, 8, 8, 8,
6728 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,
6729 9, 9, 9, 9, 9, 9,
6730 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6731 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6732 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6733 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6734
6735
6736// This function works for dates from 1970 to 2099.
6737static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006738 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006739#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006740 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006741#endif
6742
6743 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6744 date %= kDaysIn4Years;
6745
6746 month = kMonthInYear[date];
6747 day = kDayInYear[date];
6748
6749 ASSERT(MakeDay(year, month, day) == save_date);
6750}
6751
6752
6753static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006754 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006755#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006756 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006757#endif
6758
6759 date += kDaysOffset;
6760 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6761 date %= kDaysIn400Years;
6762
6763 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6764
6765 date--;
6766 int yd1 = date / kDaysIn100Years;
6767 date %= kDaysIn100Years;
6768 year += 100 * yd1;
6769
6770 date++;
6771 int yd2 = date / kDaysIn4Years;
6772 date %= kDaysIn4Years;
6773 year += 4 * yd2;
6774
6775 date--;
6776 int yd3 = date / 365;
6777 date %= 365;
6778 year += yd3;
6779
6780 bool is_leap = (!yd1 || yd2) && !yd3;
6781
6782 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006783 ASSERT(is_leap || (date >= 0));
6784 ASSERT((date < 365) || (is_leap && (date < 366)));
6785 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6786 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6787 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006788
6789 if (is_leap) {
6790 day = kDayInYear[2*365 + 1 + date];
6791 month = kMonthInYear[2*365 + 1 + date];
6792 } else {
6793 day = kDayInYear[date];
6794 month = kMonthInYear[date];
6795 }
6796
6797 ASSERT(MakeDay(year, month, day) == save_date);
6798}
6799
6800
6801static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006802 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006803 if (date >= 0 && date < 32 * kDaysIn4Years) {
6804 DateYMDFromTimeAfter1970(date, year, month, day);
6805 } else {
6806 DateYMDFromTimeSlow(date, year, month, day);
6807 }
6808}
6809
6810
lrn@chromium.org303ada72010-10-27 09:33:13 +00006811static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006812 NoHandleAllocation ha;
6813 ASSERT(args.length() == 2);
6814
6815 CONVERT_DOUBLE_CHECKED(t, args[0]);
6816 CONVERT_CHECKED(JSArray, res_array, args[1]);
6817
6818 int year, month, day;
6819 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6820
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006821 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6822 FixedArray* elms = FixedArray::cast(res_array->elements());
6823 RUNTIME_ASSERT(elms->length() == 3);
6824
6825 elms->set(0, Smi::FromInt(year));
6826 elms->set(1, Smi::FromInt(month));
6827 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006828
6829 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006830}
6831
6832
lrn@chromium.org303ada72010-10-27 09:33:13 +00006833static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006834 NoHandleAllocation ha;
6835 ASSERT(args.length() == 3);
6836
6837 JSFunction* callee = JSFunction::cast(args[0]);
6838 Object** parameters = reinterpret_cast<Object**>(args[1]);
6839 const int length = Smi::cast(args[2])->value();
6840
lrn@chromium.org303ada72010-10-27 09:33:13 +00006841 Object* result;
6842 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6843 if (!maybe_result->ToObject(&result)) return maybe_result;
6844 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006845 // Allocate the elements if needed.
6846 if (length > 0) {
6847 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006848 Object* obj;
6849 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6850 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6851 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006852
6853 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006854 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6855 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006856 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006857
6858 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006859 for (int i = 0; i < length; i++) {
6860 array->set(i, *--parameters, mode);
6861 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006862 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006863 }
6864 return result;
6865}
6866
6867
lrn@chromium.org303ada72010-10-27 09:33:13 +00006868static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006869 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006870 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006871 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006872 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006873 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006874
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006875 // Allocate global closures in old space and allocate local closures
6876 // in new space. Additionally pretenure closures that are assigned
6877 // directly to properties.
6878 pretenure = pretenure || (context->global_context() == *context);
6879 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006880 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006881 Factory::NewFunctionFromSharedFunctionInfo(shared,
6882 context,
6883 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006884 return *result;
6885}
6886
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006887
lrn@chromium.org303ada72010-10-27 09:33:13 +00006888static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006889 HandleScope scope;
6890 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006891 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006892 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006893
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006894 // Second argument is either null or an array of bound arguments.
6895 FixedArray* bound_args = NULL;
6896 int bound_argc = 0;
6897 if (!args[1]->IsNull()) {
6898 CONVERT_ARG_CHECKED(JSArray, params, 1);
6899 RUNTIME_ASSERT(params->HasFastElements());
6900 bound_args = FixedArray::cast(params->elements());
6901 bound_argc = Smi::cast(params->length())->value();
6902 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006903
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006904 // Find frame containing arguments passed to the caller.
6905 JavaScriptFrameIterator it;
6906 JavaScriptFrame* frame = it.frame();
6907 ASSERT(!frame->is_optimized());
6908 it.AdvanceToArgumentsFrame();
6909 frame = it.frame();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00006910 int argc = frame->ComputeParametersCount();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006911
6912 // Prepend bound arguments to caller's arguments.
6913 int total_argc = bound_argc + argc;
6914 SmartPointer<Object**> param_data(NewArray<Object**>(total_argc));
6915 for (int i = 0; i < bound_argc; i++) {
6916 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006917 param_data[i] = val.location();
6918 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006919 for (int i = 0; i < argc; i++) {
6920 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
6921 param_data[bound_argc + i] = val.location();
6922 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006923
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006924 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006925 Handle<Object> result =
6926 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006927 if (exception) {
6928 return Failure::Exception();
6929 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006930
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006931 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006932 return *result;
6933}
6934
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006935
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006936static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006937 Handle<Object> prototype = Factory::null_value();
6938 if (function->has_instance_prototype()) {
6939 prototype = Handle<Object>(function->instance_prototype());
6940 }
6941 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006942 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006943 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006944 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006945 function->shared()->set_construct_stub(
6946 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006947 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006948 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006949}
6950
6951
lrn@chromium.org303ada72010-10-27 09:33:13 +00006952static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006953 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006954 ASSERT(args.length() == 1);
6955
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006956 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006957
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006958 // If the constructor isn't a proper function we throw a type error.
6959 if (!constructor->IsJSFunction()) {
6960 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6961 Handle<Object> type_error =
6962 Factory::NewTypeError("not_constructor", arguments);
6963 return Top::Throw(*type_error);
6964 }
6965
6966 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006967
6968 // If function should not have prototype, construction is not allowed. In this
6969 // case generated code bailouts here, since function has no initial_map.
6970 if (!function->should_have_prototype()) {
6971 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6972 Handle<Object> type_error =
6973 Factory::NewTypeError("not_constructor", arguments);
6974 return Top::Throw(*type_error);
6975 }
6976
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006977#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006978 // Handle stepping into constructors if step into is active.
6979 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006980 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006981 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006982#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006983
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006984 if (function->has_initial_map()) {
6985 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006986 // The 'Function' function ignores the receiver object when
6987 // called using 'new' and creates a new JSFunction object that
6988 // is returned. The receiver object is only used for error
6989 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006990 // JSFunction. Factory::NewJSObject() should not be used to
6991 // allocate JSFunctions since it does not properly initialize
6992 // the shared part of the function. Since the receiver is
6993 // ignored anyway, we use the global object as the receiver
6994 // instead of a new JSFunction object. This way, errors are
6995 // reported the same way whether or not 'Function' is called
6996 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006997 return Top::context()->global();
6998 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006999 }
7000
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007001 // The function should be compiled for the optimization hints to be
7002 // available. We cannot use EnsureCompiled because that forces a
7003 // compilation through the shared function info which makes it
7004 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007005 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007006 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007007
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007008 if (!function->has_initial_map() &&
7009 shared->IsInobjectSlackTrackingInProgress()) {
7010 // The tracking is already in progress for another function. We can only
7011 // track one initial_map at a time, so we force the completion before the
7012 // function is called as a constructor for the first time.
7013 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007014 }
7015
7016 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007017 Handle<JSObject> result = Factory::NewJSObject(function);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007018 RETURN_IF_EMPTY_HANDLE(result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007019 // Delay setting the stub if inobject slack tracking is in progress.
7020 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
7021 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007022 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007023
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007024 Counters::constructed_objects.Increment();
7025 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007026
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007027 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007028}
7029
7030
lrn@chromium.org303ada72010-10-27 09:33:13 +00007031static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007032 HandleScope scope;
7033 ASSERT(args.length() == 1);
7034
7035 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7036 function->shared()->CompleteInobjectSlackTracking();
7037 TrySettingInlineConstructStub(function);
7038
7039 return Heap::undefined_value();
7040}
7041
7042
lrn@chromium.org303ada72010-10-27 09:33:13 +00007043static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007044 HandleScope scope;
7045 ASSERT(args.length() == 1);
7046
7047 Handle<JSFunction> function = args.at<JSFunction>(0);
7048#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007049 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007051 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007052 PrintF("]\n");
7053 }
7054#endif
7055
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007056 // Compile the target function. Here we compile using CompileLazyInLoop in
7057 // order to get the optimized version. This helps code like delta-blue
7058 // that calls performance-critical routines through constructors. A
7059 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7060 // direct call. Since the in-loop tracking takes place through CallICs
7061 // this means that things called through constructors are never known to
7062 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007063 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007064 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007065 return Failure::Exception();
7066 }
7067
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007068 // All done. Return the compiled code.
7069 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007070 return function->code();
7071}
7072
7073
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007074static MaybeObject* Runtime_LazyRecompile(Arguments args) {
7075 HandleScope scope;
7076 ASSERT(args.length() == 1);
7077 Handle<JSFunction> function = args.at<JSFunction>(0);
7078 // If the function is not optimizable or debugger is active continue using the
7079 // code from the full compiler.
7080 if (!function->shared()->code()->optimizable() ||
7081 Debug::has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007082 if (FLAG_trace_opt) {
7083 PrintF("[failed to optimize ");
7084 function->PrintName();
7085 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7086 function->shared()->code()->optimizable() ? "T" : "F",
7087 Debug::has_break_points() ? "T" : "F");
7088 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007089 function->ReplaceCode(function->shared()->code());
7090 return function->code();
7091 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007092 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007093 return function->code();
7094 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007095 if (FLAG_trace_opt) {
7096 PrintF("[failed to optimize ");
7097 function->PrintName();
7098 PrintF(": optimized compilation failed]\n");
7099 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007100 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007101 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007102}
7103
7104
7105static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
7106 HandleScope scope;
7107 ASSERT(args.length() == 1);
7108 RUNTIME_ASSERT(args[0]->IsSmi());
7109 Deoptimizer::BailoutType type =
7110 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
7111 Deoptimizer* deoptimizer = Deoptimizer::Grab();
7112 ASSERT(Heap::IsAllocationAllowed());
7113 int frames = deoptimizer->output_count();
7114
7115 JavaScriptFrameIterator it;
7116 JavaScriptFrame* frame = NULL;
7117 for (int i = 0; i < frames; i++) {
7118 if (i != 0) it.Advance();
7119 frame = it.frame();
7120 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
7121 }
7122 delete deoptimizer;
7123
7124 RUNTIME_ASSERT(frame->function()->IsJSFunction());
7125 Handle<JSFunction> function(JSFunction::cast(frame->function()));
7126 Handle<Object> arguments;
7127 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00007128 if (frame->GetExpression(i) == Heap::arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007129 if (arguments.is_null()) {
7130 // FunctionGetArguments can't throw an exception, so cast away the
7131 // doubt with an assert.
7132 arguments = Handle<Object>(
7133 Accessors::FunctionGetArguments(*function,
7134 NULL)->ToObjectUnchecked());
7135 ASSERT(*arguments != Heap::null_value());
7136 ASSERT(*arguments != Heap::undefined_value());
7137 }
7138 frame->SetExpression(i, *arguments);
7139 }
7140 }
7141
7142 CompilationCache::MarkForLazyOptimizing(function);
7143 if (type == Deoptimizer::EAGER) {
7144 RUNTIME_ASSERT(function->IsOptimized());
7145 } else {
7146 RUNTIME_ASSERT(!function->IsOptimized());
7147 }
7148
7149 // Avoid doing too much work when running with --always-opt and keep
7150 // the optimized code around.
7151 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
7152 return Heap::undefined_value();
7153 }
7154
7155 // Count the number of optimized activations of the function.
7156 int activations = 0;
7157 while (!it.done()) {
7158 JavaScriptFrame* frame = it.frame();
7159 if (frame->is_optimized() && frame->function() == *function) {
7160 activations++;
7161 }
7162 it.Advance();
7163 }
7164
7165 // TODO(kasperl): For now, we cannot support removing the optimized
7166 // code when we have recursive invocations of the same function.
7167 if (activations == 0) {
7168 if (FLAG_trace_deopt) {
7169 PrintF("[removing optimized code for: ");
7170 function->PrintName();
7171 PrintF("]\n");
7172 }
7173 function->ReplaceCode(function->shared()->code());
7174 }
7175 return Heap::undefined_value();
7176}
7177
7178
7179static MaybeObject* Runtime_NotifyOSR(Arguments args) {
7180 Deoptimizer* deoptimizer = Deoptimizer::Grab();
7181 delete deoptimizer;
7182 return Heap::undefined_value();
7183}
7184
7185
7186static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
7187 HandleScope scope;
7188 ASSERT(args.length() == 1);
7189 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7190 if (!function->IsOptimized()) return Heap::undefined_value();
7191
7192 Deoptimizer::DeoptimizeFunction(*function);
7193
7194 return Heap::undefined_value();
7195}
7196
7197
7198static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
7199 HandleScope scope;
7200 ASSERT(args.length() == 1);
7201 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7202
7203 // We're not prepared to handle a function with arguments object.
7204 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7205
7206 // We have hit a back edge in an unoptimized frame for a function that was
7207 // selected for on-stack replacement. Find the unoptimized code object.
7208 Handle<Code> unoptimized(function->shared()->code());
7209 // Keep track of whether we've succeeded in optimizing.
7210 bool succeeded = unoptimized->optimizable();
7211 if (succeeded) {
7212 // If we are trying to do OSR when there are already optimized
7213 // activations of the function, it means (a) the function is directly or
7214 // indirectly recursive and (b) an optimized invocation has been
7215 // deoptimized so that we are currently in an unoptimized activation.
7216 // Check for optimized activations of this function.
7217 JavaScriptFrameIterator it;
7218 while (succeeded && !it.done()) {
7219 JavaScriptFrame* frame = it.frame();
7220 succeeded = !frame->is_optimized() || frame->function() != *function;
7221 it.Advance();
7222 }
7223 }
7224
7225 int ast_id = AstNode::kNoNumber;
7226 if (succeeded) {
7227 // The top JS function is this one, the PC is somewhere in the
7228 // unoptimized code.
7229 JavaScriptFrameIterator it;
7230 JavaScriptFrame* frame = it.frame();
7231 ASSERT(frame->function() == *function);
7232 ASSERT(frame->code() == *unoptimized);
7233 ASSERT(unoptimized->contains(frame->pc()));
7234
7235 // Use linear search of the unoptimized code's stack check table to find
7236 // the AST id matching the PC.
7237 Address start = unoptimized->instruction_start();
7238 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007239 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007240 uint32_t table_length = Memory::uint32_at(table_cursor);
7241 table_cursor += kIntSize;
7242 for (unsigned i = 0; i < table_length; ++i) {
7243 // Table entries are (AST id, pc offset) pairs.
7244 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7245 if (pc_offset == target_pc_offset) {
7246 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7247 break;
7248 }
7249 table_cursor += 2 * kIntSize;
7250 }
7251 ASSERT(ast_id != AstNode::kNoNumber);
7252 if (FLAG_trace_osr) {
7253 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7254 function->PrintName();
7255 PrintF("]\n");
7256 }
7257
7258 // Try to compile the optimized code. A true return value from
7259 // CompileOptimized means that compilation succeeded, not necessarily
7260 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007261 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7262 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007263 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7264 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007265 if (data->OsrPcOffset()->value() >= 0) {
7266 if (FLAG_trace_osr) {
7267 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007268 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007269 }
7270 ASSERT(data->OsrAstId()->value() == ast_id);
7271 } else {
7272 // We may never generate the desired OSR entry if we emit an
7273 // early deoptimize.
7274 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007275 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007276 } else {
7277 succeeded = false;
7278 }
7279 }
7280
7281 // Revert to the original stack checks in the original unoptimized code.
7282 if (FLAG_trace_osr) {
7283 PrintF("[restoring original stack checks in ");
7284 function->PrintName();
7285 PrintF("]\n");
7286 }
7287 StackCheckStub check_stub;
7288 Handle<Code> check_code = check_stub.GetCode();
7289 Handle<Code> replacement_code(
7290 Builtins::builtin(Builtins::OnStackReplacement));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007291 Deoptimizer::RevertStackCheckCode(*unoptimized,
7292 *check_code,
7293 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007294
7295 // Allow OSR only at nesting level zero again.
7296 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7297
7298 // If the optimization attempt succeeded, return the AST id tagged as a
7299 // smi. This tells the builtin that we need to translate the unoptimized
7300 // frame to an optimized one.
7301 if (succeeded) {
7302 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7303 return Smi::FromInt(ast_id);
7304 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007305 if (function->IsMarkedForLazyRecompilation()) {
7306 function->ReplaceCode(function->shared()->code());
7307 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007308 return Smi::FromInt(-1);
7309 }
7310}
7311
7312
lrn@chromium.org303ada72010-10-27 09:33:13 +00007313static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314 HandleScope scope;
7315 ASSERT(args.length() == 1);
7316 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7317 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7318}
7319
7320
lrn@chromium.org303ada72010-10-27 09:33:13 +00007321static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007322 HandleScope scope;
7323 ASSERT(args.length() == 1);
7324 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7325 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7326}
7327
7328
lrn@chromium.org303ada72010-10-27 09:33:13 +00007329static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007330 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007331 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007332
kasper.lund7276f142008-07-30 08:49:36 +00007333 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007334 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007335 Object* result;
7336 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
7337 if (!maybe_result->ToObject(&result)) return maybe_result;
7338 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007339
7340 Top::set_context(Context::cast(result));
7341
kasper.lund7276f142008-07-30 08:49:36 +00007342 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007343}
7344
lrn@chromium.org303ada72010-10-27 09:33:13 +00007345
7346MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
7347 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007349 Object* js_object = object;
7350 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007351 MaybeObject* maybe_js_object = js_object->ToObject();
7352 if (!maybe_js_object->ToObject(&js_object)) {
7353 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7354 return maybe_js_object;
7355 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007356 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007357 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007358 Handle<Object> result =
7359 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
7360 return Top::Throw(*result);
7361 }
7362 }
7363
lrn@chromium.org303ada72010-10-27 09:33:13 +00007364 Object* result;
7365 { MaybeObject* maybe_result =
7366 Heap::AllocateWithContext(Top::context(),
7367 JSObject::cast(js_object),
7368 is_catch_context);
7369 if (!maybe_result->ToObject(&result)) return maybe_result;
7370 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007372 Context* context = Context::cast(result);
7373 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374
kasper.lund7276f142008-07-30 08:49:36 +00007375 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007376}
7377
7378
lrn@chromium.org303ada72010-10-27 09:33:13 +00007379static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007380 NoHandleAllocation ha;
7381 ASSERT(args.length() == 1);
7382 return PushContextHelper(args[0], false);
7383}
7384
7385
lrn@chromium.org303ada72010-10-27 09:33:13 +00007386static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007387 NoHandleAllocation ha;
7388 ASSERT(args.length() == 1);
7389 return PushContextHelper(args[0], true);
7390}
7391
7392
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007393static MaybeObject* Runtime_DeleteContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007394 HandleScope scope;
7395 ASSERT(args.length() == 2);
7396
7397 CONVERT_ARG_CHECKED(Context, context, 0);
7398 CONVERT_ARG_CHECKED(String, name, 1);
7399
7400 int index;
7401 PropertyAttributes attributes;
7402 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007403 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007404
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007405 // If the slot was not found the result is true.
7406 if (holder.is_null()) {
7407 return Heap::true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007408 }
7409
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007410 // If the slot was found in a context, it should be DONT_DELETE.
7411 if (holder->IsContext()) {
7412 return Heap::false_value();
7413 }
7414
7415 // The slot was found in a JSObject, either a context extension object,
7416 // the global object, or an arguments object. Try to delete it
7417 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7418 // which allows deleting all parameters in functions that mention
7419 // 'arguments', we do this even for the case of slots found on an
7420 // arguments object. The slot was found on an arguments object if the
7421 // index is non-negative.
7422 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7423 if (index >= 0) {
7424 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7425 } else {
7426 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7427 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007428}
7429
7430
ager@chromium.orga1645e22009-09-09 19:27:10 +00007431// A mechanism to return a pair of Object pointers in registers (if possible).
7432// How this is achieved is calling convention-dependent.
7433// All currently supported x86 compiles uses calling conventions that are cdecl
7434// variants where a 64-bit value is returned in two 32-bit registers
7435// (edx:eax on ia32, r1:r0 on ARM).
7436// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7437// In Win64 calling convention, a struct of two pointers is returned in memory,
7438// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007439#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007440struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007441 MaybeObject* x;
7442 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007443};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007444
lrn@chromium.org303ada72010-10-27 09:33:13 +00007445static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007446 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007447 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7448 // In Win64 they are assigned to a hidden first argument.
7449 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007450}
7451#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007452typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007453static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007455 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007456}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007457#endif
7458
7459
lrn@chromium.org303ada72010-10-27 09:33:13 +00007460static inline MaybeObject* Unhole(MaybeObject* x,
7461 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007462 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7463 USE(attributes);
7464 return x->IsTheHole() ? Heap::undefined_value() : x;
7465}
7466
7467
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007468static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7469 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007470 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007471 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007472 JSFunction* context_extension_function =
7473 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007474 // If the holder isn't a context extension object, we just return it
7475 // as the receiver. This allows arguments objects to be used as
7476 // receivers, but only if they are put in the context scope chain
7477 // explicitly via a with-statement.
7478 Object* constructor = holder->map()->constructor();
7479 if (constructor != context_extension_function) return holder;
7480 // Fall back to using the global object as the receiver if the
7481 // property turns out to be a local variable allocated in a context
7482 // extension object - introduced via eval.
7483 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007484}
7485
7486
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007487static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007488 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007489 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007490
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007491 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007492 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007493 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007494 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007495 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007496
7497 int index;
7498 PropertyAttributes attributes;
7499 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007500 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007501
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007502 // If the index is non-negative, the slot has been found in a local
7503 // variable or a parameter. Read it from the context object or the
7504 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007505 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007506 // If the "property" we were looking for is a local variable or an
7507 // argument in a context, the receiver is the global object; see
7508 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7509 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007510 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007511 ? Context::cast(*holder)->get(index)
7512 : JSObject::cast(*holder)->GetElement(index);
7513 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007514 }
7515
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007516 // If the holder is found, we read the property from it.
7517 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007518 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007519 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007520 JSObject* receiver;
7521 if (object->IsGlobalObject()) {
7522 receiver = GlobalObject::cast(object)->global_receiver();
7523 } else if (context->is_exception_holder(*holder)) {
7524 receiver = Top::context()->global()->global_receiver();
7525 } else {
7526 receiver = ComputeReceiverForNonGlobal(object);
7527 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007528 // No need to unhole the value here. This is taken care of by the
7529 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007530 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007531 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007532 }
7533
7534 if (throw_error) {
7535 // The property doesn't exist - throw exception.
7536 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007537 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007538 return MakePair(Top::Throw(*reference_error), NULL);
7539 } else {
7540 // The property doesn't exist - return undefined
7541 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7542 }
7543}
7544
7545
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007546static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007547 return LoadContextSlotHelper(args, true);
7548}
7549
7550
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007551static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007552 return LoadContextSlotHelper(args, false);
7553}
7554
7555
lrn@chromium.org303ada72010-10-27 09:33:13 +00007556static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007557 HandleScope scope;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007558 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007559
7560 Handle<Object> value(args[0]);
7561 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007562 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007563 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7564 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7565 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007566 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007567
7568 int index;
7569 PropertyAttributes attributes;
7570 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007571 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007572
7573 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007574 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007575 // Ignore if read_only variable.
7576 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007577 // Context is a fixed array and set cannot fail.
7578 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007579 } else if (strict_mode == kStrictMode) {
7580 // Setting read only property in strict mode.
7581 Handle<Object> error =
7582 Factory::NewTypeError("strict_cannot_assign",
7583 HandleVector(&name, 1));
7584 return Top::Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007585 }
7586 } else {
7587 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007588 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007589 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007590 if (result.is_null()) {
7591 ASSERT(Top::has_pending_exception());
7592 return Failure::Exception();
7593 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007594 }
7595 return *value;
7596 }
7597
7598 // Slow case: The property is not in a FixedArray context.
7599 // It is either in an JSObject extension context or it was not found.
7600 Handle<JSObject> context_ext;
7601
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007602 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007603 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007604 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007605 } else {
7606 // The property was not found. It needs to be stored in the global context.
7607 ASSERT(attributes == ABSENT);
7608 attributes = NONE;
7609 context_ext = Handle<JSObject>(Top::context()->global());
7610 }
7611
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007612 // Set the property, but ignore if read_only variable on the context
7613 // extension object itself.
7614 if ((attributes & READ_ONLY) == 0 ||
7615 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007616 RETURN_IF_EMPTY_HANDLE(
7617 SetProperty(context_ext, name, value, NONE, strict_mode));
7618 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007619 // Setting read only property in strict mode.
7620 Handle<Object> error =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007621 Factory::NewTypeError("strict_cannot_assign", HandleVector(&name, 1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007622 return Top::Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007623 }
7624 return *value;
7625}
7626
7627
lrn@chromium.org303ada72010-10-27 09:33:13 +00007628static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007629 HandleScope scope;
7630 ASSERT(args.length() == 1);
7631
7632 return Top::Throw(args[0]);
7633}
7634
7635
lrn@chromium.org303ada72010-10-27 09:33:13 +00007636static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007637 HandleScope scope;
7638 ASSERT(args.length() == 1);
7639
7640 return Top::ReThrow(args[0]);
7641}
7642
7643
lrn@chromium.org303ada72010-10-27 09:33:13 +00007644static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007645 ASSERT_EQ(0, args.length());
7646 return Top::PromoteScheduledException();
7647}
7648
7649
lrn@chromium.org303ada72010-10-27 09:33:13 +00007650static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007651 HandleScope scope;
7652 ASSERT(args.length() == 1);
7653
7654 Handle<Object> name(args[0]);
7655 Handle<Object> reference_error =
7656 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7657 return Top::Throw(*reference_error);
7658}
7659
7660
lrn@chromium.org303ada72010-10-27 09:33:13 +00007661static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007662 NoHandleAllocation na;
7663 return Top::StackOverflow();
7664}
7665
7666
lrn@chromium.org303ada72010-10-27 09:33:13 +00007667static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007668 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007669
7670 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007671 if (StackGuard::IsStackOverflow()) {
7672 return Runtime_StackOverflow(args);
7673 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007674
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007675 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007676}
7677
7678
7679// NOTE: These PrintXXX functions are defined for all builds (not just
7680// DEBUG builds) because we may want to be able to trace function
7681// calls in all modes.
7682static void PrintString(String* str) {
7683 // not uncommon to have empty strings
7684 if (str->length() > 0) {
7685 SmartPointer<char> s =
7686 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7687 PrintF("%s", *s);
7688 }
7689}
7690
7691
7692static void PrintObject(Object* obj) {
7693 if (obj->IsSmi()) {
7694 PrintF("%d", Smi::cast(obj)->value());
7695 } else if (obj->IsString() || obj->IsSymbol()) {
7696 PrintString(String::cast(obj));
7697 } else if (obj->IsNumber()) {
7698 PrintF("%g", obj->Number());
7699 } else if (obj->IsFailure()) {
7700 PrintF("<failure>");
7701 } else if (obj->IsUndefined()) {
7702 PrintF("<undefined>");
7703 } else if (obj->IsNull()) {
7704 PrintF("<null>");
7705 } else if (obj->IsTrue()) {
7706 PrintF("<true>");
7707 } else if (obj->IsFalse()) {
7708 PrintF("<false>");
7709 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007710 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007711 }
7712}
7713
7714
7715static int StackSize() {
7716 int n = 0;
7717 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7718 return n;
7719}
7720
7721
7722static void PrintTransition(Object* result) {
7723 // indentation
7724 { const int nmax = 80;
7725 int n = StackSize();
7726 if (n <= nmax)
7727 PrintF("%4d:%*s", n, n, "");
7728 else
7729 PrintF("%4d:%*s", n, nmax, "...");
7730 }
7731
7732 if (result == NULL) {
7733 // constructor calls
7734 JavaScriptFrameIterator it;
7735 JavaScriptFrame* frame = it.frame();
7736 if (frame->IsConstructor()) PrintF("new ");
7737 // function name
7738 Object* fun = frame->function();
7739 if (fun->IsJSFunction()) {
7740 PrintObject(JSFunction::cast(fun)->shared()->name());
7741 } else {
7742 PrintObject(fun);
7743 }
7744 // function arguments
7745 // (we are intentionally only printing the actually
7746 // supplied parameters, not all parameters required)
7747 PrintF("(this=");
7748 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007749 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007750 for (int i = 0; i < length; i++) {
7751 PrintF(", ");
7752 PrintObject(frame->GetParameter(i));
7753 }
7754 PrintF(") {\n");
7755
7756 } else {
7757 // function result
7758 PrintF("} -> ");
7759 PrintObject(result);
7760 PrintF("\n");
7761 }
7762}
7763
7764
lrn@chromium.org303ada72010-10-27 09:33:13 +00007765static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007766 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007767 NoHandleAllocation ha;
7768 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007769 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007770}
7771
7772
lrn@chromium.org303ada72010-10-27 09:33:13 +00007773static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007774 NoHandleAllocation ha;
7775 PrintTransition(args[0]);
7776 return args[0]; // return TOS
7777}
7778
7779
lrn@chromium.org303ada72010-10-27 09:33:13 +00007780static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007781 NoHandleAllocation ha;
7782 ASSERT(args.length() == 1);
7783
7784#ifdef DEBUG
7785 if (args[0]->IsString()) {
7786 // If we have a string, assume it's a code "marker"
7787 // and print some interesting cpu debugging info.
7788 JavaScriptFrameIterator it;
7789 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007790 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7791 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007792 } else {
7793 PrintF("DebugPrint: ");
7794 }
7795 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007796 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007797 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007798 HeapObject::cast(args[0])->map()->Print();
7799 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007800#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007801 // ShortPrint is available in release mode. Print is not.
7802 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007803#endif
7804 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007805 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007806
7807 return args[0]; // return TOS
7808}
7809
7810
lrn@chromium.org303ada72010-10-27 09:33:13 +00007811static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007812 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007813 NoHandleAllocation ha;
7814 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007815 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007816}
7817
7818
lrn@chromium.org303ada72010-10-27 09:33:13 +00007819static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007820 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007821 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007822
7823 // According to ECMA-262, section 15.9.1, page 117, the precision of
7824 // the number in a Date object representing a particular instant in
7825 // time is milliseconds. Therefore, we floor the result of getting
7826 // the OS time.
7827 double millis = floor(OS::TimeCurrentMillis());
7828 return Heap::NumberFromDouble(millis);
7829}
7830
7831
lrn@chromium.org303ada72010-10-27 09:33:13 +00007832static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007833 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007834 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007835
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007836 CONVERT_ARG_CHECKED(String, str, 0);
7837 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007838
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007839 CONVERT_ARG_CHECKED(JSArray, output, 1);
7840 RUNTIME_ASSERT(output->HasFastElements());
7841
7842 AssertNoAllocation no_allocation;
7843
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007844 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007845 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7846 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007847 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007848 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007849 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007850 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007851 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7852 }
7853
7854 if (result) {
7855 return *output;
7856 } else {
7857 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007858 }
7859}
7860
7861
lrn@chromium.org303ada72010-10-27 09:33:13 +00007862static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007863 NoHandleAllocation ha;
7864 ASSERT(args.length() == 1);
7865
7866 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007867 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007868 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7869}
7870
7871
lrn@chromium.org303ada72010-10-27 09:33:13 +00007872static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007873 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007874 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007875
7876 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7877}
7878
7879
lrn@chromium.org303ada72010-10-27 09:33:13 +00007880static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007881 NoHandleAllocation ha;
7882 ASSERT(args.length() == 1);
7883
7884 CONVERT_DOUBLE_CHECKED(x, args[0]);
7885 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7886}
7887
7888
lrn@chromium.org303ada72010-10-27 09:33:13 +00007889static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007890 ASSERT(args.length() == 1);
7891 Object* global = args[0];
7892 if (!global->IsJSGlobalObject()) return Heap::null_value();
7893 return JSGlobalObject::cast(global)->global_receiver();
7894}
7895
7896
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007897static MaybeObject* Runtime_ParseJson(Arguments args) {
7898 HandleScope scope;
7899 ASSERT_EQ(1, args.length());
7900 CONVERT_ARG_CHECKED(String, source, 0);
7901
7902 Handle<Object> result = JsonParser::Parse(source);
7903 if (result.is_null()) {
7904 // Syntax error or stack overflow in scanner.
7905 ASSERT(Top::has_pending_exception());
7906 return Failure::Exception();
7907 }
7908 return *result;
7909}
7910
7911
lrn@chromium.org303ada72010-10-27 09:33:13 +00007912static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007913 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007914 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007915 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007916
ager@chromium.org381abbb2009-02-25 13:23:22 +00007917 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007918 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007919 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7920 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007921 true,
7922 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007923 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007924 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007925 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007926 return *fun;
7927}
7928
7929
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007930static ObjectPair CompileGlobalEval(Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007931 Handle<Object> receiver,
7932 StrictModeFlag mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007933 // Deal with a normal eval call with a string argument. Compile it
7934 // and return the compiled function bound in the local context.
7935 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7936 source,
7937 Handle<Context>(Top::context()),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007938 Top::context()->IsGlobalContext(),
7939 mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007940 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7941 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7942 shared,
7943 Handle<Context>(Top::context()),
7944 NOT_TENURED);
7945 return MakePair(*compiled, *receiver);
7946}
7947
7948
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007949static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007950 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007951
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007952 HandleScope scope;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007953 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007954 Handle<Object> receiver; // Will be overwritten.
7955
7956 // Compute the calling context.
7957 Handle<Context> context = Handle<Context>(Top::context());
7958#ifdef DEBUG
7959 // Make sure Top::context() agrees with the old code that traversed
7960 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007961 StackFrameLocator locator;
7962 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007963 ASSERT(Context::cast(frame->context()) == *context);
7964#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007965
7966 // Find where the 'eval' symbol is bound. It is unaliased only if
7967 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007968 int index = -1;
7969 PropertyAttributes attributes = ABSENT;
7970 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007971 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7972 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007973 // Stop search when eval is found or when the global context is
7974 // reached.
7975 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007976 if (context->is_function_context()) {
7977 context = Handle<Context>(Context::cast(context->closure()->context()));
7978 } else {
7979 context = Handle<Context>(context->previous());
7980 }
7981 }
7982
iposva@chromium.org245aa852009-02-10 00:49:54 +00007983 // If eval could not be resolved, it has been deleted and we need to
7984 // throw a reference error.
7985 if (attributes == ABSENT) {
7986 Handle<Object> name = Factory::eval_symbol();
7987 Handle<Object> reference_error =
7988 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007989 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007990 }
7991
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007992 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007993 // 'eval' is not bound in the global context. Just call the function
7994 // with the given arguments. This is not necessarily the global eval.
7995 if (receiver->IsContext()) {
7996 context = Handle<Context>::cast(receiver);
7997 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007998 } else if (receiver->IsJSContextExtensionObject()) {
7999 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008000 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008001 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008002 }
8003
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008004 // 'eval' is bound in the global context, but it may have been overwritten.
8005 // Compare it to the builtin 'GlobalEval' function to make sure.
8006 if (*callee != Top::global_context()->global_eval_fun() ||
8007 !args[1]->IsString()) {
8008 return MakePair(*callee, Top::context()->global()->global_receiver());
8009 }
8010
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008011 ASSERT(args[3]->IsSmi());
8012 return CompileGlobalEval(args.at<String>(1),
8013 args.at<Object>(2),
8014 static_cast<StrictModeFlag>(
8015 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008016}
8017
8018
8019static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008020 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008021
8022 HandleScope scope;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008023 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008024
8025 // 'eval' is bound in the global context, but it may have been overwritten.
8026 // Compare it to the builtin 'GlobalEval' function to make sure.
8027 if (*callee != Top::global_context()->global_eval_fun() ||
8028 !args[1]->IsString()) {
8029 return MakePair(*callee, Top::context()->global()->global_receiver());
8030 }
8031
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008032 ASSERT(args[3]->IsSmi());
8033 return CompileGlobalEval(args.at<String>(1),
8034 args.at<Object>(2),
8035 static_cast<StrictModeFlag>(
8036 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008037}
8038
8039
lrn@chromium.org303ada72010-10-27 09:33:13 +00008040static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008041 // This utility adjusts the property attributes for newly created Function
8042 // object ("new Function(...)") by changing the map.
8043 // All it does is changing the prototype property to enumerable
8044 // as specified in ECMA262, 15.3.5.2.
8045 HandleScope scope;
8046 ASSERT(args.length() == 1);
8047 CONVERT_ARG_CHECKED(JSFunction, func, 0);
8048 ASSERT(func->map()->instance_type() ==
8049 Top::function_instance_map()->instance_type());
8050 ASSERT(func->map()->instance_size() ==
8051 Top::function_instance_map()->instance_size());
8052 func->set_map(*Top::function_instance_map());
8053 return *func;
8054}
8055
8056
lrn@chromium.org303ada72010-10-27 09:33:13 +00008057static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008058 // Allocate a block of memory in NewSpace (filled with a filler).
8059 // Use as fallback for allocation in generated code when NewSpace
8060 // is full.
8061 ASSERT(args.length() == 1);
8062 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8063 int size = size_smi->value();
8064 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8065 RUNTIME_ASSERT(size > 0);
8066 static const int kMinFreeNewSpaceAfterGC =
8067 Heap::InitialSemiSpaceSize() * 3/4;
8068 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008069 Object* allocation;
8070 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
8071 if (maybe_allocation->ToObject(&allocation)) {
8072 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
8073 }
8074 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008075 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008076}
8077
8078
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008079// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008080// array. Returns true if the element was pushed on the stack and
8081// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008082static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008083 ASSERT(args.length() == 2);
8084 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008085 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008086 RUNTIME_ASSERT(array->HasFastElements());
8087 int length = Smi::cast(array->length())->value();
8088 FixedArray* elements = FixedArray::cast(array->elements());
8089 for (int i = 0; i < length; i++) {
8090 if (elements->get(i) == element) return Heap::false_value();
8091 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008092 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008093 // Strict not needed. Used for cycle detection in Array join implementation.
8094 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8095 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008096 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8097 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008098 return Heap::true_value();
8099}
8100
8101
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008102/**
8103 * A simple visitor visits every element of Array's.
8104 * The backend storage can be a fixed array for fast elements case,
8105 * or a dictionary for sparse array. Since Dictionary is a subtype
8106 * of FixedArray, the class can be used by both fast and slow cases.
8107 * The second parameter of the constructor, fast_elements, specifies
8108 * whether the storage is a FixedArray or Dictionary.
8109 *
8110 * An index limit is used to deal with the situation that a result array
8111 * length overflows 32-bit non-negative integer.
8112 */
8113class ArrayConcatVisitor {
8114 public:
8115 ArrayConcatVisitor(Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008116 bool fast_elements) :
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008117 storage_(Handle<FixedArray>::cast(GlobalHandles::Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008118 index_offset_(0u),
8119 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008120
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008121 ~ArrayConcatVisitor() {
8122 clear_storage();
8123 }
8124
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008125 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008126 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008127 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008128
8129 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008130 if (index < static_cast<uint32_t>(storage_->length())) {
8131 storage_->set(index, *elm);
8132 return;
8133 }
8134 // Our initial estimate of length was foiled, possibly by
8135 // getters on the arrays increasing the length of later arrays
8136 // during iteration.
8137 // This shouldn't happen in anything but pathological cases.
8138 SetDictionaryMode(index);
8139 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008140 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008141 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008142 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008143 Handle<NumberDictionary> result =
8144 Factory::DictionaryAtNumberPut(dict, index, elm);
8145 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008146 // Dictionary needed to grow.
8147 clear_storage();
8148 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008149 }
8150}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008151
8152 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008153 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8154 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008155 } else {
8156 index_offset_ += delta;
8157 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008158 }
8159
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008160 Handle<JSArray> ToArray() {
8161 Handle<JSArray> array = Factory::NewJSArray(0);
8162 Handle<Object> length =
8163 Factory::NewNumber(static_cast<double>(index_offset_));
8164 Handle<Map> map;
8165 if (fast_elements_) {
8166 map = Factory::GetFastElementsMap(Handle<Map>(array->map()));
8167 } else {
8168 map = Factory::GetSlowElementsMap(Handle<Map>(array->map()));
8169 }
8170 array->set_map(*map);
8171 array->set_length(*length);
8172 array->set_elements(*storage_);
8173 return array;
8174 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008175
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008176 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008177 // Convert storage to dictionary mode.
8178 void SetDictionaryMode(uint32_t index) {
8179 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008180 Handle<FixedArray> current_storage(*storage_);
8181 Handle<NumberDictionary> slow_storage(
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008182 Factory::NewNumberDictionary(current_storage->length()));
8183 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8184 for (uint32_t i = 0; i < current_length; i++) {
8185 HandleScope loop_scope;
8186 Handle<Object> element(current_storage->get(i));
8187 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008188 Handle<NumberDictionary> new_storage =
8189 Factory::DictionaryAtNumberPut(slow_storage, i, element);
8190 if (!new_storage.is_identical_to(slow_storage)) {
8191 slow_storage = loop_scope.CloseAndEscape(new_storage);
8192 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008193 }
8194 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008195 clear_storage();
8196 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008197 fast_elements_ = false;
8198 }
8199
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008200 inline void clear_storage() {
8201 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
8202 }
8203
8204 inline void set_storage(FixedArray* storage) {
8205 storage_ = Handle<FixedArray>::cast(GlobalHandles::Create(storage));
8206 }
8207
8208 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008209 // Index after last seen index. Always less than or equal to
8210 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008211 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008212 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008213};
8214
8215
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008216static uint32_t EstimateElementCount(Handle<JSArray> array) {
8217 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8218 int element_count = 0;
8219 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008220 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008221 // Fast elements can't have lengths that are not representable by
8222 // a 32-bit signed integer.
8223 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8224 int fast_length = static_cast<int>(length);
8225 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8226 for (int i = 0; i < fast_length; i++) {
8227 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008228 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008229 break;
8230 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008231 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008232 Handle<NumberDictionary> dictionary(
8233 NumberDictionary::cast(array->elements()));
8234 int capacity = dictionary->Capacity();
8235 for (int i = 0; i < capacity; i++) {
8236 Handle<Object> key(dictionary->KeyAt(i));
8237 if (dictionary->IsKey(*key)) {
8238 element_count++;
8239 }
8240 }
8241 break;
8242 }
8243 default:
8244 // External arrays are always dense.
8245 return length;
8246 }
8247 // As an estimate, we assume that the prototype doesn't contain any
8248 // inherited elements.
8249 return element_count;
8250}
8251
8252
8253
8254template<class ExternalArrayClass, class ElementType>
8255static void IterateExternalArrayElements(Handle<JSObject> receiver,
8256 bool elements_are_ints,
8257 bool elements_are_guaranteed_smis,
8258 ArrayConcatVisitor* visitor) {
8259 Handle<ExternalArrayClass> array(
8260 ExternalArrayClass::cast(receiver->elements()));
8261 uint32_t len = static_cast<uint32_t>(array->length());
8262
8263 ASSERT(visitor != NULL);
8264 if (elements_are_ints) {
8265 if (elements_are_guaranteed_smis) {
8266 for (uint32_t j = 0; j < len; j++) {
8267 HandleScope loop_scope;
8268 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8269 visitor->visit(j, e);
8270 }
8271 } else {
8272 for (uint32_t j = 0; j < len; j++) {
8273 HandleScope loop_scope;
8274 int64_t val = static_cast<int64_t>(array->get(j));
8275 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8276 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8277 visitor->visit(j, e);
8278 } else {
8279 Handle<Object> e =
8280 Factory::NewNumber(static_cast<ElementType>(val));
8281 visitor->visit(j, e);
8282 }
8283 }
8284 }
8285 } else {
8286 for (uint32_t j = 0; j < len; j++) {
8287 HandleScope loop_scope;
8288 Handle<Object> e = Factory::NewNumber(array->get(j));
8289 visitor->visit(j, e);
8290 }
8291 }
8292}
8293
8294
8295// Used for sorting indices in a List<uint32_t>.
8296static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8297 uint32_t a = *ap;
8298 uint32_t b = *bp;
8299 return (a == b) ? 0 : (a < b) ? -1 : 1;
8300}
8301
8302
8303static void CollectElementIndices(Handle<JSObject> object,
8304 uint32_t range,
8305 List<uint32_t>* indices) {
8306 JSObject::ElementsKind kind = object->GetElementsKind();
8307 switch (kind) {
8308 case JSObject::FAST_ELEMENTS: {
8309 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8310 uint32_t length = static_cast<uint32_t>(elements->length());
8311 if (range < length) length = range;
8312 for (uint32_t i = 0; i < length; i++) {
8313 if (!elements->get(i)->IsTheHole()) {
8314 indices->Add(i);
8315 }
8316 }
8317 break;
8318 }
8319 case JSObject::DICTIONARY_ELEMENTS: {
8320 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008321 uint32_t capacity = dict->Capacity();
8322 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008323 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008324 Handle<Object> k(dict->KeyAt(j));
8325 if (dict->IsKey(*k)) {
8326 ASSERT(k->IsNumber());
8327 uint32_t index = static_cast<uint32_t>(k->Number());
8328 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008329 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008330 }
8331 }
8332 }
8333 break;
8334 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008335 default: {
8336 int dense_elements_length;
8337 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008338 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008339 dense_elements_length =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008340 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008341 break;
8342 }
8343 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8344 dense_elements_length =
8345 ExternalByteArray::cast(object->elements())->length();
8346 break;
8347 }
8348 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8349 dense_elements_length =
8350 ExternalUnsignedByteArray::cast(object->elements())->length();
8351 break;
8352 }
8353 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8354 dense_elements_length =
8355 ExternalShortArray::cast(object->elements())->length();
8356 break;
8357 }
8358 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8359 dense_elements_length =
8360 ExternalUnsignedShortArray::cast(object->elements())->length();
8361 break;
8362 }
8363 case JSObject::EXTERNAL_INT_ELEMENTS: {
8364 dense_elements_length =
8365 ExternalIntArray::cast(object->elements())->length();
8366 break;
8367 }
8368 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8369 dense_elements_length =
8370 ExternalUnsignedIntArray::cast(object->elements())->length();
8371 break;
8372 }
8373 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8374 dense_elements_length =
8375 ExternalFloatArray::cast(object->elements())->length();
8376 break;
8377 }
8378 default:
8379 UNREACHABLE();
8380 dense_elements_length = 0;
8381 break;
8382 }
8383 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8384 if (range <= length) {
8385 length = range;
8386 // We will add all indices, so we might as well clear it first
8387 // and avoid duplicates.
8388 indices->Clear();
8389 }
8390 for (uint32_t i = 0; i < length; i++) {
8391 indices->Add(i);
8392 }
8393 if (length == range) return; // All indices accounted for already.
8394 break;
8395 }
8396 }
8397
8398 Handle<Object> prototype(object->GetPrototype());
8399 if (prototype->IsJSObject()) {
8400 // The prototype will usually have no inherited element indices,
8401 // but we have to check.
8402 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8403 }
8404}
8405
8406
8407/**
8408 * A helper function that visits elements of a JSArray in numerical
8409 * order.
8410 *
8411 * The visitor argument called for each existing element in the array
8412 * with the element index and the element's value.
8413 * Afterwards it increments the base-index of the visitor by the array
8414 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008415 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008416 */
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008417static bool IterateElements(Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008418 ArrayConcatVisitor* visitor) {
8419 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8420 switch (receiver->GetElementsKind()) {
8421 case JSObject::FAST_ELEMENTS: {
8422 // Run through the elements FixedArray and use HasElement and GetElement
8423 // to check the prototype for missing elements.
8424 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8425 int fast_length = static_cast<int>(length);
8426 ASSERT(fast_length <= elements->length());
8427 for (int j = 0; j < fast_length; j++) {
8428 HandleScope loop_scope;
8429 Handle<Object> element_value(elements->get(j));
8430 if (!element_value->IsTheHole()) {
8431 visitor->visit(j, element_value);
8432 } else if (receiver->HasElement(j)) {
8433 // Call GetElement on receiver, not its prototype, or getters won't
8434 // have the correct receiver.
8435 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008436 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008437 visitor->visit(j, element_value);
8438 }
8439 }
8440 break;
8441 }
8442 case JSObject::DICTIONARY_ELEMENTS: {
8443 Handle<NumberDictionary> dict(receiver->element_dictionary());
8444 List<uint32_t> indices(dict->Capacity() / 2);
8445 // Collect all indices in the object and the prototypes less
8446 // than length. This might introduce duplicates in the indices list.
8447 CollectElementIndices(receiver, length, &indices);
8448 indices.Sort(&compareUInt32);
8449 int j = 0;
8450 int n = indices.length();
8451 while (j < n) {
8452 HandleScope loop_scope;
8453 uint32_t index = indices[j];
8454 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008455 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008456 visitor->visit(index, element);
8457 // Skip to next different index (i.e., omit duplicates).
8458 do {
8459 j++;
8460 } while (j < n && indices[j] == index);
8461 }
8462 break;
8463 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008464 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8465 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8466 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008467 for (uint32_t j = 0; j < length; j++) {
8468 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8469 visitor->visit(j, e);
8470 }
8471 break;
8472 }
8473 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8474 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8475 receiver, true, true, visitor);
8476 break;
8477 }
8478 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8479 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8480 receiver, true, true, visitor);
8481 break;
8482 }
8483 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8484 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8485 receiver, true, true, visitor);
8486 break;
8487 }
8488 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8489 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8490 receiver, true, true, visitor);
8491 break;
8492 }
8493 case JSObject::EXTERNAL_INT_ELEMENTS: {
8494 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8495 receiver, true, false, visitor);
8496 break;
8497 }
8498 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8499 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8500 receiver, true, false, visitor);
8501 break;
8502 }
8503 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8504 IterateExternalArrayElements<ExternalFloatArray, float>(
8505 receiver, false, false, visitor);
8506 break;
8507 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008508 default:
8509 UNREACHABLE();
8510 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008511 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008512 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008513 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008514}
8515
8516
8517/**
8518 * Array::concat implementation.
8519 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008520 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008521 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008522 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008523static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008524 ASSERT(args.length() == 1);
8525 HandleScope handle_scope;
8526
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008527 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8528 int argument_count = static_cast<int>(arguments->length()->Number());
8529 RUNTIME_ASSERT(arguments->HasFastElements());
8530 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008531
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008532 // Pass 1: estimate the length and number of elements of the result.
8533 // The actual length can be larger if any of the arguments have getters
8534 // that mutate other arguments (but will otherwise be precise).
8535 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008536
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008537 uint32_t estimate_result_length = 0;
8538 uint32_t estimate_nof_elements = 0;
8539 {
8540 for (int i = 0; i < argument_count; i++) {
8541 HandleScope loop_scope;
8542 Handle<Object> obj(elements->get(i));
8543 uint32_t length_estimate;
8544 uint32_t element_estimate;
8545 if (obj->IsJSArray()) {
8546 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8547 length_estimate =
8548 static_cast<uint32_t>(array->length()->Number());
8549 element_estimate =
8550 EstimateElementCount(array);
8551 } else {
8552 length_estimate = 1;
8553 element_estimate = 1;
8554 }
8555 // Avoid overflows by capping at kMaxElementCount.
8556 if (JSObject::kMaxElementCount - estimate_result_length <
8557 length_estimate) {
8558 estimate_result_length = JSObject::kMaxElementCount;
8559 } else {
8560 estimate_result_length += length_estimate;
8561 }
8562 if (JSObject::kMaxElementCount - estimate_nof_elements <
8563 element_estimate) {
8564 estimate_nof_elements = JSObject::kMaxElementCount;
8565 } else {
8566 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008567 }
8568 }
8569 }
8570
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008571 // If estimated number of elements is more than half of length, a
8572 // fixed array (fast case) is more time and space-efficient than a
8573 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008574 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008575
8576 Handle<FixedArray> storage;
8577 if (fast_case) {
8578 // The backing storage array must have non-existing elements to
8579 // preserve holes across concat operations.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008580 storage = Factory::NewFixedArrayWithHoles(estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008581 } else {
8582 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8583 uint32_t at_least_space_for = estimate_nof_elements +
8584 (estimate_nof_elements >> 2);
8585 storage = Handle<FixedArray>::cast(
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008586 Factory::NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008587 }
8588
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008589 ArrayConcatVisitor visitor(storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008590
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008591 for (int i = 0; i < argument_count; i++) {
8592 Handle<Object> obj(elements->get(i));
8593 if (obj->IsJSArray()) {
8594 Handle<JSArray> array = Handle<JSArray>::cast(obj);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008595 if (!IterateElements(array, &visitor)) {
8596 return Failure::Exception();
8597 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008598 } else {
8599 visitor.visit(0, obj);
8600 visitor.increase_index_offset(1);
8601 }
8602 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008603
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008604 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008605}
8606
8607
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008608// This will not allocate (flatten the string), but it may run
8609// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008610static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008611 NoHandleAllocation ha;
8612 ASSERT(args.length() == 1);
8613
8614 CONVERT_CHECKED(String, string, args[0]);
8615 StringInputBuffer buffer(string);
8616 while (buffer.has_more()) {
8617 uint16_t character = buffer.GetNext();
8618 PrintF("%c", character);
8619 }
8620 return string;
8621}
8622
ager@chromium.org5ec48922009-05-05 07:25:34 +00008623// Moves all own elements of an object, that are below a limit, to positions
8624// starting at zero. All undefined values are placed after non-undefined values,
8625// and are followed by non-existing element. Does not change the length
8626// property.
8627// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008628static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008629 ASSERT(args.length() == 2);
8630 CONVERT_CHECKED(JSObject, object, args[0]);
8631 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8632 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008633}
8634
8635
8636// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008637static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008638 ASSERT(args.length() == 2);
8639 CONVERT_CHECKED(JSArray, from, args[0]);
8640 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008641 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008642 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008643 if (new_elements->map() == Heap::fixed_array_map() ||
8644 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008645 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008646 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008647 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008648 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008649 Object* new_map;
8650 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008651 to->set_map(Map::cast(new_map));
8652 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008653 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008654 Object* obj;
8655 { MaybeObject* maybe_obj = from->ResetElements();
8656 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8657 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008658 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008659 return to;
8660}
8661
8662
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008663// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008664static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008665 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008666 CONVERT_CHECKED(JSObject, object, args[0]);
8667 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008668 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008669 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008670 } else if (object->IsJSArray()) {
8671 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008672 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008673 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008674 }
8675}
8676
8677
lrn@chromium.org303ada72010-10-27 09:33:13 +00008678static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008679 HandleScope handle_scope;
8680
8681 ASSERT_EQ(3, args.length());
8682
ager@chromium.orgac091b72010-05-05 07:34:42 +00008683 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008684 Handle<Object> key1 = args.at<Object>(1);
8685 Handle<Object> key2 = args.at<Object>(2);
8686
8687 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008688 if (!key1->ToArrayIndex(&index1)
8689 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008690 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008691 }
8692
ager@chromium.orgac091b72010-05-05 07:34:42 +00008693 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8694 Handle<Object> tmp1 = GetElement(jsobject, index1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008695 RETURN_IF_EMPTY_HANDLE(tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008696 Handle<Object> tmp2 = GetElement(jsobject, index2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008697 RETURN_IF_EMPTY_HANDLE(tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008698
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008699 RETURN_IF_EMPTY_HANDLE(SetElement(jsobject, index1, tmp2, kStrictMode));
8700 RETURN_IF_EMPTY_HANDLE(SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00008701
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008702 return Heap::undefined_value();
8703}
8704
8705
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008706// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008707// might have elements. Can either return keys (positive integers) or
8708// intervals (pair of a negative integer (-start-1) followed by a
8709// positive (length)) or undefined values.
8710// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008711static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008712 ASSERT(args.length() == 2);
8713 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008714 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008715 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008716 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008717 // Create an array and get all the keys into it, then remove all the
8718 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008719 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008720 int keys_length = keys->length();
8721 for (int i = 0; i < keys_length; i++) {
8722 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008723 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008724 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008725 // Zap invalid keys.
8726 keys->set_undefined(i);
8727 }
8728 }
8729 return *Factory::NewJSArrayWithElements(keys);
8730 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008731 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008732 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8733 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008734 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008735 uint32_t actual_length =
8736 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008737 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008738 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008739 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008740 single_interval->set(1, *length_object);
8741 return *Factory::NewJSArrayWithElements(single_interval);
8742 }
8743}
8744
8745
8746// DefineAccessor takes an optional final argument which is the
8747// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8748// to the way accessors are implemented, it is set for both the getter
8749// and setter on the first call to DefineAccessor and ignored on
8750// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008751static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008752 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8753 // Compute attributes.
8754 PropertyAttributes attributes = NONE;
8755 if (args.length() == 5) {
8756 CONVERT_CHECKED(Smi, attrs, args[4]);
8757 int value = attrs->value();
8758 // Only attribute bits should be set.
8759 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8760 attributes = static_cast<PropertyAttributes>(value);
8761 }
8762
8763 CONVERT_CHECKED(JSObject, obj, args[0]);
8764 CONVERT_CHECKED(String, name, args[1]);
8765 CONVERT_CHECKED(Smi, flag, args[2]);
8766 CONVERT_CHECKED(JSFunction, fun, args[3]);
8767 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8768}
8769
8770
lrn@chromium.org303ada72010-10-27 09:33:13 +00008771static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008772 ASSERT(args.length() == 3);
8773 CONVERT_CHECKED(JSObject, obj, args[0]);
8774 CONVERT_CHECKED(String, name, args[1]);
8775 CONVERT_CHECKED(Smi, flag, args[2]);
8776 return obj->LookupAccessor(name, flag->value() == 0);
8777}
8778
8779
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008780#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008781static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008782 ASSERT(args.length() == 0);
8783 return Execution::DebugBreakHelper();
8784}
8785
8786
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008787// Helper functions for wrapping and unwrapping stack frame ids.
8788static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008789 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008790 return Smi::FromInt(id >> 2);
8791}
8792
8793
8794static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8795 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8796}
8797
8798
8799// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008800// args[0]: debug event listener function to set or null or undefined for
8801// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008802// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008803static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008804 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008805 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8806 args[0]->IsUndefined() ||
8807 args[0]->IsNull());
8808 Handle<Object> callback = args.at<Object>(0);
8809 Handle<Object> data = args.at<Object>(1);
8810 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008811
8812 return Heap::undefined_value();
8813}
8814
8815
lrn@chromium.org303ada72010-10-27 09:33:13 +00008816static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008817 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008818 StackGuard::DebugBreak();
8819 return Heap::undefined_value();
8820}
8821
8822
lrn@chromium.org303ada72010-10-27 09:33:13 +00008823static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8824 LookupResult* result,
8825 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008826 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008827 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008828 case NORMAL:
8829 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008830 if (value->IsTheHole()) {
8831 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008832 }
8833 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008834 case FIELD:
8835 value =
8836 JSObject::cast(
8837 result->holder())->FastPropertyAt(result->GetFieldIndex());
8838 if (value->IsTheHole()) {
8839 return Heap::undefined_value();
8840 }
8841 return value;
8842 case CONSTANT_FUNCTION:
8843 return result->GetConstantFunction();
8844 case CALLBACKS: {
8845 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008846 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008847 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008848 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008849 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008850 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008851 ASSERT(maybe_value->IsException());
8852 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008853 Top::clear_pending_exception();
8854 if (caught_exception != NULL) {
8855 *caught_exception = true;
8856 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008857 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008858 }
8859 return value;
8860 } else {
8861 return Heap::undefined_value();
8862 }
8863 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008864 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008865 case MAP_TRANSITION:
8866 case CONSTANT_TRANSITION:
8867 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008868 return Heap::undefined_value();
8869 default:
8870 UNREACHABLE();
8871 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008872 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008873 return Heap::undefined_value();
8874}
8875
8876
ager@chromium.org32912102009-01-16 10:38:43 +00008877// Get debugger related details for an object property.
8878// args[0]: object holding property
8879// args[1]: name of the property
8880//
8881// The array returned contains the following information:
8882// 0: Property value
8883// 1: Property details
8884// 2: Property value is exception
8885// 3: Getter function if defined
8886// 4: Setter function if defined
8887// Items 2-4 are only filled if the property has either a getter or a setter
8888// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008889static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008890 HandleScope scope;
8891
8892 ASSERT(args.length() == 2);
8893
8894 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8895 CONVERT_ARG_CHECKED(String, name, 1);
8896
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008897 // Make sure to set the current context to the context before the debugger was
8898 // entered (if the debugger is entered). The reason for switching context here
8899 // is that for some property lookups (accessors and interceptors) callbacks
8900 // into the embedding application can occour, and the embedding application
8901 // could have the assumption that its own global context is the current
8902 // context and not some internal debugger context.
8903 SaveContext save;
8904 if (Debug::InDebugger()) {
8905 Top::set_context(*Debug::debugger_entry()->GetContext());
8906 }
8907
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008908 // Skip the global proxy as it has no properties and always delegates to the
8909 // real global object.
8910 if (obj->IsJSGlobalProxy()) {
8911 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8912 }
8913
8914
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008915 // Check if the name is trivially convertible to an index and get the element
8916 // if so.
8917 uint32_t index;
8918 if (name->AsArrayIndex(&index)) {
8919 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008920 Object* element_or_char;
8921 { MaybeObject* maybe_element_or_char =
8922 Runtime::GetElementOrCharAt(obj, index);
8923 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8924 return maybe_element_or_char;
8925 }
8926 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008927 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008928 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8929 return *Factory::NewJSArrayWithElements(details);
8930 }
8931
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008932 // Find the number of objects making up this.
8933 int length = LocalPrototypeChainLength(*obj);
8934
8935 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008936 Handle<JSObject> jsproto = obj;
8937 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008938 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008939 jsproto->LocalLookup(*name, &result);
8940 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008941 // LookupResult is not GC safe as it holds raw object pointers.
8942 // GC can happen later in this code so put the required fields into
8943 // local variables using handles when required for later use.
8944 PropertyType result_type = result.type();
8945 Handle<Object> result_callback_obj;
8946 if (result_type == CALLBACKS) {
8947 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8948 }
8949 Smi* property_details = result.GetPropertyDetails().AsSmi();
8950 // DebugLookupResultValue can cause GC so details from LookupResult needs
8951 // to be copied to handles before this.
8952 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008953 Object* raw_value;
8954 { MaybeObject* maybe_raw_value =
8955 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8956 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8957 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008958 Handle<Object> value(raw_value);
8959
8960 // If the callback object is a fixed array then it contains JavaScript
8961 // getter and/or setter.
8962 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8963 result_callback_obj->IsFixedArray();
8964 Handle<FixedArray> details =
8965 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8966 details->set(0, *value);
8967 details->set(1, property_details);
8968 if (hasJavaScriptAccessors) {
8969 details->set(2,
8970 caught_exception ? Heap::true_value()
8971 : Heap::false_value());
8972 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8973 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8974 }
8975
8976 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008977 }
8978 if (i < length - 1) {
8979 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8980 }
8981 }
8982
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008983 return Heap::undefined_value();
8984}
8985
8986
lrn@chromium.org303ada72010-10-27 09:33:13 +00008987static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008988 HandleScope scope;
8989
8990 ASSERT(args.length() == 2);
8991
8992 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8993 CONVERT_ARG_CHECKED(String, name, 1);
8994
8995 LookupResult result;
8996 obj->Lookup(*name, &result);
8997 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008998 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008999 }
9000 return Heap::undefined_value();
9001}
9002
9003
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009004// Return the property type calculated from the property details.
9005// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009006static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009007 ASSERT(args.length() == 1);
9008 CONVERT_CHECKED(Smi, details, args[0]);
9009 PropertyType type = PropertyDetails(details).type();
9010 return Smi::FromInt(static_cast<int>(type));
9011}
9012
9013
9014// Return the property attribute calculated from the property details.
9015// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009016static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009017 ASSERT(args.length() == 1);
9018 CONVERT_CHECKED(Smi, details, args[0]);
9019 PropertyAttributes attributes = PropertyDetails(details).attributes();
9020 return Smi::FromInt(static_cast<int>(attributes));
9021}
9022
9023
9024// Return the property insertion index calculated from the property details.
9025// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009026static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009027 ASSERT(args.length() == 1);
9028 CONVERT_CHECKED(Smi, details, args[0]);
9029 int index = PropertyDetails(details).index();
9030 return Smi::FromInt(index);
9031}
9032
9033
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009034// Return property value from named interceptor.
9035// args[0]: object
9036// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00009037static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009038 HandleScope scope;
9039 ASSERT(args.length() == 2);
9040 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9041 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9042 CONVERT_ARG_CHECKED(String, name, 1);
9043
9044 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009045 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009046}
9047
9048
9049// Return element value from indexed interceptor.
9050// args[0]: object
9051// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00009052static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
9053 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009054 HandleScope scope;
9055 ASSERT(args.length() == 2);
9056 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9057 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9058 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9059
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009060 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009061}
9062
9063
lrn@chromium.org303ada72010-10-27 09:33:13 +00009064static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009065 ASSERT(args.length() >= 1);
9066 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009067 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009068 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009069 return Top::Throw(Heap::illegal_execution_state_symbol());
9070 }
9071
9072 return Heap::true_value();
9073}
9074
9075
lrn@chromium.org303ada72010-10-27 09:33:13 +00009076static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009077 HandleScope scope;
9078 ASSERT(args.length() == 1);
9079
9080 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009081 Object* result;
9082 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9083 if (!maybe_result->ToObject(&result)) return maybe_result;
9084 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009085
9086 // Count all frames which are relevant to debugging stack trace.
9087 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009088 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009089 if (id == StackFrame::NO_ID) {
9090 // If there is no JavaScript stack frame count is 0.
9091 return Smi::FromInt(0);
9092 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009093 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
9094 return Smi::FromInt(n);
9095}
9096
9097
9098static const int kFrameDetailsFrameIdIndex = 0;
9099static const int kFrameDetailsReceiverIndex = 1;
9100static const int kFrameDetailsFunctionIndex = 2;
9101static const int kFrameDetailsArgumentCountIndex = 3;
9102static const int kFrameDetailsLocalCountIndex = 4;
9103static const int kFrameDetailsSourcePositionIndex = 5;
9104static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009105static const int kFrameDetailsAtReturnIndex = 7;
9106static const int kFrameDetailsDebuggerFrameIndex = 8;
9107static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009108
9109// Return an array with frame details
9110// args[0]: number: break id
9111// args[1]: number: frame index
9112//
9113// The array returned contains the following information:
9114// 0: Frame id
9115// 1: Receiver
9116// 2: Function
9117// 3: Argument count
9118// 4: Local count
9119// 5: Source position
9120// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009121// 7: Is at return
9122// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009123// Arguments name, value
9124// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009125// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00009126static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009127 HandleScope scope;
9128 ASSERT(args.length() == 2);
9129
9130 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009131 Object* check;
9132 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9133 if (!maybe_check->ToObject(&check)) return maybe_check;
9134 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009135 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9136
9137 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009138 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009139 if (id == StackFrame::NO_ID) {
9140 // If there are no JavaScript stack frames return undefined.
9141 return Heap::undefined_value();
9142 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009143 int count = 0;
9144 JavaScriptFrameIterator it(id);
9145 for (; !it.done(); it.Advance()) {
9146 if (count == index) break;
9147 count++;
9148 }
9149 if (it.done()) return Heap::undefined_value();
9150
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009151 bool is_optimized_frame =
9152 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
9153
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009154 // Traverse the saved contexts chain to find the active context for the
9155 // selected frame.
9156 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009157 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009158 save = save->prev();
9159 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009160 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009161
9162 // Get the frame id.
9163 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
9164
9165 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00009166 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009167
9168 // Check for constructor frame.
9169 bool constructor = it.frame()->IsConstructor();
9170
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009171 // Get scope info and read from it for local variable information.
9172 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009173 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009174 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009175
9176 // Get the context.
9177 Handle<Context> context(Context::cast(it.frame()->context()));
9178
9179 // Get the locals names and values into a temporary array.
9180 //
9181 // TODO(1240907): Hide compiler-introduced stack variables
9182 // (e.g. .result)? For users of the debugger, they will probably be
9183 // confusing.
9184 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009185
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009186 // Fill in the names of the locals.
9187 for (int i = 0; i < info.NumberOfLocals(); i++) {
9188 locals->set(i * 2, *info.LocalName(i));
9189 }
9190
9191 // Fill in the values of the locals.
9192 for (int i = 0; i < info.NumberOfLocals(); i++) {
9193 if (is_optimized_frame) {
9194 // If we are inspecting an optimized frame use undefined as the
9195 // value for all locals.
9196 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009197 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009198 // for locals in optimized frames.
9199 locals->set(i * 2 + 1, Heap::undefined_value());
9200 } else if (i < info.number_of_stack_slots()) {
9201 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009202 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9203 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009204 // Traverse the context chain to the function context as all local
9205 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009206 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009207 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009208 context = Handle<Context>(context->previous());
9209 }
9210 ASSERT(context->is_function_context());
9211 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009212 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009213 }
9214 }
9215
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009216 // Check whether this frame is positioned at return. If not top
9217 // frame or if the frame is optimized it cannot be at a return.
9218 bool at_return = false;
9219 if (!is_optimized_frame && index == 0) {
9220 at_return = Debug::IsBreakAtReturn(it.frame());
9221 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009222
9223 // If positioned just before return find the value to be returned and add it
9224 // to the frame information.
9225 Handle<Object> return_value = Factory::undefined_value();
9226 if (at_return) {
9227 StackFrameIterator it2;
9228 Address internal_frame_sp = NULL;
9229 while (!it2.done()) {
9230 if (it2.frame()->is_internal()) {
9231 internal_frame_sp = it2.frame()->sp();
9232 } else {
9233 if (it2.frame()->is_java_script()) {
9234 if (it2.frame()->id() == it.frame()->id()) {
9235 // The internal frame just before the JavaScript frame contains the
9236 // value to return on top. A debug break at return will create an
9237 // internal frame to store the return value (eax/rax/r0) before
9238 // entering the debug break exit frame.
9239 if (internal_frame_sp != NULL) {
9240 return_value =
9241 Handle<Object>(Memory::Object_at(internal_frame_sp));
9242 break;
9243 }
9244 }
9245 }
9246
9247 // Indicate that the previous frame was not an internal frame.
9248 internal_frame_sp = NULL;
9249 }
9250 it2.Advance();
9251 }
9252 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009253
9254 // Now advance to the arguments adapter frame (if any). It contains all
9255 // the provided parameters whereas the function frame always have the number
9256 // of arguments matching the functions parameters. The rest of the
9257 // information (except for what is collected above) is the same.
9258 it.AdvanceToArgumentsFrame();
9259
9260 // Find the number of arguments to fill. At least fill the number of
9261 // parameters for the function and fill more if more parameters are provided.
9262 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009263 if (argument_count < it.frame()->ComputeParametersCount()) {
9264 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009265 }
9266
9267 // Calculate the size of the result.
9268 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009269 2 * (argument_count + info.NumberOfLocals()) +
9270 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009271 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9272
9273 // Add the frame id.
9274 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9275
9276 // Add the function (same as in function frame).
9277 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9278
9279 // Add the arguments count.
9280 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9281
9282 // Add the locals count
9283 details->set(kFrameDetailsLocalCountIndex,
9284 Smi::FromInt(info.NumberOfLocals()));
9285
9286 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009287 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009288 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9289 } else {
9290 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
9291 }
9292
9293 // Add the constructor information.
9294 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
9295
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009296 // Add the at return information.
9297 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
9298
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009299 // Add information on whether this frame is invoked in the debugger context.
9300 details->set(kFrameDetailsDebuggerFrameIndex,
9301 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
9302
9303 // Fill the dynamic part.
9304 int details_index = kFrameDetailsFirstDynamicIndex;
9305
9306 // Add arguments name and value.
9307 for (int i = 0; i < argument_count; i++) {
9308 // Name of the argument.
9309 if (i < info.number_of_parameters()) {
9310 details->set(details_index++, *info.parameter_name(i));
9311 } else {
9312 details->set(details_index++, Heap::undefined_value());
9313 }
9314
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009315 // Parameter value. If we are inspecting an optimized frame, use
9316 // undefined as the value.
9317 //
9318 // TODO(3141533): We should be able to get the actual parameter
9319 // value for optimized frames.
9320 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009321 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009322 details->set(details_index++, it.frame()->GetParameter(i));
9323 } else {
9324 details->set(details_index++, Heap::undefined_value());
9325 }
9326 }
9327
9328 // Add locals name and value from the temporary copy from the function frame.
9329 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9330 details->set(details_index++, locals->get(i));
9331 }
9332
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009333 // Add the value being returned.
9334 if (at_return) {
9335 details->set(details_index++, *return_value);
9336 }
9337
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009338 // Add the receiver (same as in function frame).
9339 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9340 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
9341 Handle<Object> receiver(it.frame()->receiver());
9342 if (!receiver->IsJSObject()) {
9343 // If the receiver is NOT a JSObject we have hit an optimization
9344 // where a value object is not converted into a wrapped JS objects.
9345 // To hide this optimization from the debugger, we wrap the receiver
9346 // by creating correct wrapper object based on the calling frame's
9347 // global context.
9348 it.Advance();
9349 Handle<Context> calling_frames_global_context(
9350 Context::cast(Context::cast(it.frame()->context())->global_context()));
9351 receiver = Factory::ToObject(receiver, calling_frames_global_context);
9352 }
9353 details->set(kFrameDetailsReceiverIndex, *receiver);
9354
9355 ASSERT_EQ(details_size, details_index);
9356 return *Factory::NewJSArrayWithElements(details);
9357}
9358
9359
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009360// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009361static bool CopyContextLocalsToScopeObject(
ager@chromium.orgb5737492010-07-15 09:29:43 +00009362 Handle<SerializedScopeInfo> serialized_scope_info,
9363 ScopeInfo<>& scope_info,
9364 Handle<Context> context,
9365 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009366 // Fill all context locals to the context extension.
9367 for (int i = Context::MIN_CONTEXT_SLOTS;
9368 i < scope_info.number_of_context_slots();
9369 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009370 int context_index = serialized_scope_info->ContextSlotIndex(
9371 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009372
9373 // Don't include the arguments shadow (.arguments) context variable.
9374 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009375 RETURN_IF_EMPTY_HANDLE_VALUE(
9376 SetProperty(scope_object,
9377 scope_info.context_slot_name(i),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009378 Handle<Object>(context->get(context_index)),
9379 NONE,
9380 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009381 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009382 }
9383 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009384
9385 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009386}
9387
9388
9389// Create a plain JSObject which materializes the local scope for the specified
9390// frame.
9391static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
9392 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009393 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009394 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9395 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009396
9397 // Allocate and initialize a JSObject with all the arguments, stack locals
9398 // heap locals and extension properties of the debugged function.
9399 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
9400
9401 // First fill all parameters.
9402 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009403 RETURN_IF_EMPTY_HANDLE_VALUE(
9404 SetProperty(local_scope,
9405 scope_info.parameter_name(i),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009406 Handle<Object>(frame->GetParameter(i)),
9407 NONE,
9408 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009409 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009410 }
9411
9412 // Second fill all stack locals.
9413 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009414 RETURN_IF_EMPTY_HANDLE_VALUE(
9415 SetProperty(local_scope,
9416 scope_info.stack_slot_name(i),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009417 Handle<Object>(frame->GetExpression(i)),
9418 NONE,
9419 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009420 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009421 }
9422
9423 // Third fill all context locals.
9424 Handle<Context> frame_context(Context::cast(frame->context()));
9425 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009426 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9427 function_context, local_scope)) {
9428 return Handle<JSObject>();
9429 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009430
9431 // Finally copy any properties from the function context extension. This will
9432 // be variables introduced by eval.
9433 if (function_context->closure() == *function) {
9434 if (function_context->has_extension() &&
9435 !function_context->IsGlobalContext()) {
9436 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009437 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009438 for (int i = 0; i < keys->length(); i++) {
9439 // Names of variables introduced by eval are strings.
9440 ASSERT(keys->get(i)->IsString());
9441 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009442 RETURN_IF_EMPTY_HANDLE_VALUE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009443 SetProperty(local_scope,
9444 key,
9445 GetProperty(ext, key),
9446 NONE,
9447 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009448 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009449 }
9450 }
9451 }
9452 return local_scope;
9453}
9454
9455
9456// Create a plain JSObject which materializes the closure content for the
9457// context.
9458static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
9459 ASSERT(context->is_function_context());
9460
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009461 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009462 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9463 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009464
9465 // Allocate and initialize a JSObject with all the content of theis function
9466 // closure.
9467 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
9468
9469 // Check whether the arguments shadow object exists.
9470 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00009471 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
9472 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009473 if (arguments_shadow_index >= 0) {
9474 // In this case all the arguments are available in the arguments shadow
9475 // object.
9476 Handle<JSObject> arguments_shadow(
9477 JSObject::cast(context->get(arguments_shadow_index)));
9478 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009479 // We don't expect exception-throwing getters on the arguments shadow.
9480 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009481 RETURN_IF_EMPTY_HANDLE_VALUE(
9482 SetProperty(closure_scope,
9483 scope_info.parameter_name(i),
9484 Handle<Object>(element),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009485 NONE,
9486 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009487 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009488 }
9489 }
9490
9491 // Fill all context locals to the context extension.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009492 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9493 context, closure_scope)) {
9494 return Handle<JSObject>();
9495 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009496
9497 // Finally copy any properties from the function context extension. This will
9498 // be variables introduced by eval.
9499 if (context->has_extension()) {
9500 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009501 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009502 for (int i = 0; i < keys->length(); i++) {
9503 // Names of variables introduced by eval are strings.
9504 ASSERT(keys->get(i)->IsString());
9505 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009506 RETURN_IF_EMPTY_HANDLE_VALUE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009507 SetProperty(closure_scope,
9508 key,
9509 GetProperty(ext, key),
9510 NONE,
9511 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009512 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009513 }
9514 }
9515
9516 return closure_scope;
9517}
9518
9519
9520// Iterate over the actual scopes visible from a stack frame. All scopes are
9521// backed by an actual context except the local scope, which is inserted
9522// "artifically" in the context chain.
9523class ScopeIterator {
9524 public:
9525 enum ScopeType {
9526 ScopeTypeGlobal = 0,
9527 ScopeTypeLocal,
9528 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009529 ScopeTypeClosure,
9530 // Every catch block contains an implicit with block (its parameter is
9531 // a JSContextExtensionObject) that extends current scope with a variable
9532 // holding exception object. Such with blocks are treated as scopes of their
9533 // own type.
9534 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009535 };
9536
9537 explicit ScopeIterator(JavaScriptFrame* frame)
9538 : frame_(frame),
9539 function_(JSFunction::cast(frame->function())),
9540 context_(Context::cast(frame->context())),
9541 local_done_(false),
9542 at_local_(false) {
9543
9544 // Check whether the first scope is actually a local scope.
9545 if (context_->IsGlobalContext()) {
9546 // If there is a stack slot for .result then this local scope has been
9547 // created for evaluating top level code and it is not a real local scope.
9548 // Checking for the existence of .result seems fragile, but the scope info
9549 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009550 int index = function_->shared()->scope_info()->
9551 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009552 at_local_ = index < 0;
9553 } else if (context_->is_function_context()) {
9554 at_local_ = true;
9555 }
9556 }
9557
9558 // More scopes?
9559 bool Done() { return context_.is_null(); }
9560
9561 // Move to the next scope.
9562 void Next() {
9563 // If at a local scope mark the local scope as passed.
9564 if (at_local_) {
9565 at_local_ = false;
9566 local_done_ = true;
9567
9568 // If the current context is not associated with the local scope the
9569 // current context is the next real scope, so don't move to the next
9570 // context in this case.
9571 if (context_->closure() != *function_) {
9572 return;
9573 }
9574 }
9575
9576 // The global scope is always the last in the chain.
9577 if (context_->IsGlobalContext()) {
9578 context_ = Handle<Context>();
9579 return;
9580 }
9581
9582 // Move to the next context.
9583 if (context_->is_function_context()) {
9584 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9585 } else {
9586 context_ = Handle<Context>(context_->previous());
9587 }
9588
9589 // If passing the local scope indicate that the current scope is now the
9590 // local scope.
9591 if (!local_done_ &&
9592 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9593 at_local_ = true;
9594 }
9595 }
9596
9597 // Return the type of the current scope.
9598 int Type() {
9599 if (at_local_) {
9600 return ScopeTypeLocal;
9601 }
9602 if (context_->IsGlobalContext()) {
9603 ASSERT(context_->global()->IsGlobalObject());
9604 return ScopeTypeGlobal;
9605 }
9606 if (context_->is_function_context()) {
9607 return ScopeTypeClosure;
9608 }
9609 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009610 // Current scope is either an explicit with statement or a with statement
9611 // implicitely generated for a catch block.
9612 // If the extension object here is a JSContextExtensionObject then
9613 // current with statement is one frome a catch block otherwise it's a
9614 // regular with statement.
9615 if (context_->extension()->IsJSContextExtensionObject()) {
9616 return ScopeTypeCatch;
9617 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009618 return ScopeTypeWith;
9619 }
9620
9621 // Return the JavaScript object with the content of the current scope.
9622 Handle<JSObject> ScopeObject() {
9623 switch (Type()) {
9624 case ScopeIterator::ScopeTypeGlobal:
9625 return Handle<JSObject>(CurrentContext()->global());
9626 break;
9627 case ScopeIterator::ScopeTypeLocal:
9628 // Materialize the content of the local scope into a JSObject.
9629 return MaterializeLocalScope(frame_);
9630 break;
9631 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009632 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009633 // Return the with object.
9634 return Handle<JSObject>(CurrentContext()->extension());
9635 break;
9636 case ScopeIterator::ScopeTypeClosure:
9637 // Materialize the content of the closure scope into a JSObject.
9638 return MaterializeClosure(CurrentContext());
9639 break;
9640 }
9641 UNREACHABLE();
9642 return Handle<JSObject>();
9643 }
9644
9645 // Return the context for this scope. For the local context there might not
9646 // be an actual context.
9647 Handle<Context> CurrentContext() {
9648 if (at_local_ && context_->closure() != *function_) {
9649 return Handle<Context>();
9650 }
9651 return context_;
9652 }
9653
9654#ifdef DEBUG
9655 // Debug print of the content of the current scope.
9656 void DebugPrint() {
9657 switch (Type()) {
9658 case ScopeIterator::ScopeTypeGlobal:
9659 PrintF("Global:\n");
9660 CurrentContext()->Print();
9661 break;
9662
9663 case ScopeIterator::ScopeTypeLocal: {
9664 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009665 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009666 scope_info.Print();
9667 if (!CurrentContext().is_null()) {
9668 CurrentContext()->Print();
9669 if (CurrentContext()->has_extension()) {
9670 Handle<JSObject> extension =
9671 Handle<JSObject>(CurrentContext()->extension());
9672 if (extension->IsJSContextExtensionObject()) {
9673 extension->Print();
9674 }
9675 }
9676 }
9677 break;
9678 }
9679
9680 case ScopeIterator::ScopeTypeWith: {
9681 PrintF("With:\n");
9682 Handle<JSObject> extension =
9683 Handle<JSObject>(CurrentContext()->extension());
9684 extension->Print();
9685 break;
9686 }
9687
ager@chromium.orga1645e22009-09-09 19:27:10 +00009688 case ScopeIterator::ScopeTypeCatch: {
9689 PrintF("Catch:\n");
9690 Handle<JSObject> extension =
9691 Handle<JSObject>(CurrentContext()->extension());
9692 extension->Print();
9693 break;
9694 }
9695
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009696 case ScopeIterator::ScopeTypeClosure: {
9697 PrintF("Closure:\n");
9698 CurrentContext()->Print();
9699 if (CurrentContext()->has_extension()) {
9700 Handle<JSObject> extension =
9701 Handle<JSObject>(CurrentContext()->extension());
9702 if (extension->IsJSContextExtensionObject()) {
9703 extension->Print();
9704 }
9705 }
9706 break;
9707 }
9708
9709 default:
9710 UNREACHABLE();
9711 }
9712 PrintF("\n");
9713 }
9714#endif
9715
9716 private:
9717 JavaScriptFrame* frame_;
9718 Handle<JSFunction> function_;
9719 Handle<Context> context_;
9720 bool local_done_;
9721 bool at_local_;
9722
9723 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9724};
9725
9726
lrn@chromium.org303ada72010-10-27 09:33:13 +00009727static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009728 HandleScope scope;
9729 ASSERT(args.length() == 2);
9730
9731 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009732 Object* check;
9733 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9734 if (!maybe_check->ToObject(&check)) return maybe_check;
9735 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009736 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9737
9738 // Get the frame where the debugging is performed.
9739 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9740 JavaScriptFrameIterator it(id);
9741 JavaScriptFrame* frame = it.frame();
9742
9743 // Count the visible scopes.
9744 int n = 0;
9745 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9746 n++;
9747 }
9748
9749 return Smi::FromInt(n);
9750}
9751
9752
9753static const int kScopeDetailsTypeIndex = 0;
9754static const int kScopeDetailsObjectIndex = 1;
9755static const int kScopeDetailsSize = 2;
9756
9757// Return an array with scope details
9758// args[0]: number: break id
9759// args[1]: number: frame index
9760// args[2]: number: scope index
9761//
9762// The array returned contains the following information:
9763// 0: Scope type
9764// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009765static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009766 HandleScope scope;
9767 ASSERT(args.length() == 3);
9768
9769 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009770 Object* check;
9771 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9772 if (!maybe_check->ToObject(&check)) return maybe_check;
9773 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009774 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9775 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9776
9777 // Get the frame where the debugging is performed.
9778 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9779 JavaScriptFrameIterator frame_it(id);
9780 JavaScriptFrame* frame = frame_it.frame();
9781
9782 // Find the requested scope.
9783 int n = 0;
9784 ScopeIterator it(frame);
9785 for (; !it.Done() && n < index; it.Next()) {
9786 n++;
9787 }
9788 if (it.Done()) {
9789 return Heap::undefined_value();
9790 }
9791
9792 // Calculate the size of the result.
9793 int details_size = kScopeDetailsSize;
9794 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9795
9796 // Fill in scope details.
9797 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009798 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009799 RETURN_IF_EMPTY_HANDLE(scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009800 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009801
9802 return *Factory::NewJSArrayWithElements(details);
9803}
9804
9805
lrn@chromium.org303ada72010-10-27 09:33:13 +00009806static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009807 HandleScope scope;
9808 ASSERT(args.length() == 0);
9809
9810#ifdef DEBUG
9811 // Print the scopes for the top frame.
9812 StackFrameLocator locator;
9813 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9814 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9815 it.DebugPrint();
9816 }
9817#endif
9818 return Heap::undefined_value();
9819}
9820
9821
lrn@chromium.org303ada72010-10-27 09:33:13 +00009822static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009823 HandleScope scope;
9824 ASSERT(args.length() == 1);
9825
9826 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009827 Object* result;
9828 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9829 if (!maybe_result->ToObject(&result)) return maybe_result;
9830 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009831
9832 // Count all archived V8 threads.
9833 int n = 0;
9834 for (ThreadState* thread = ThreadState::FirstInUse();
9835 thread != NULL;
9836 thread = thread->Next()) {
9837 n++;
9838 }
9839
9840 // Total number of threads is current thread and archived threads.
9841 return Smi::FromInt(n + 1);
9842}
9843
9844
9845static const int kThreadDetailsCurrentThreadIndex = 0;
9846static const int kThreadDetailsThreadIdIndex = 1;
9847static const int kThreadDetailsSize = 2;
9848
9849// Return an array with thread details
9850// args[0]: number: break id
9851// args[1]: number: thread index
9852//
9853// The array returned contains the following information:
9854// 0: Is current thread?
9855// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009856static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009857 HandleScope scope;
9858 ASSERT(args.length() == 2);
9859
9860 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009861 Object* check;
9862 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9863 if (!maybe_check->ToObject(&check)) return maybe_check;
9864 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009865 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9866
9867 // Allocate array for result.
9868 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9869
9870 // Thread index 0 is current thread.
9871 if (index == 0) {
9872 // Fill the details.
9873 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9874 details->set(kThreadDetailsThreadIdIndex,
9875 Smi::FromInt(ThreadManager::CurrentId()));
9876 } else {
9877 // Find the thread with the requested index.
9878 int n = 1;
9879 ThreadState* thread = ThreadState::FirstInUse();
9880 while (index != n && thread != NULL) {
9881 thread = thread->Next();
9882 n++;
9883 }
9884 if (thread == NULL) {
9885 return Heap::undefined_value();
9886 }
9887
9888 // Fill the details.
9889 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9890 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9891 }
9892
9893 // Convert to JS array and return.
9894 return *Factory::NewJSArrayWithElements(details);
9895}
9896
9897
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009898// Sets the disable break state
9899// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009900static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009901 HandleScope scope;
9902 ASSERT(args.length() == 1);
9903 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9904 Debug::set_disable_break(disable_break);
9905 return Heap::undefined_value();
9906}
9907
9908
lrn@chromium.org303ada72010-10-27 09:33:13 +00009909static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009910 HandleScope scope;
9911 ASSERT(args.length() == 1);
9912
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009913 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9914 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009915 // Find the number of break points
9916 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9917 if (break_locations->IsUndefined()) return Heap::undefined_value();
9918 // Return array as JS array
9919 return *Factory::NewJSArrayWithElements(
9920 Handle<FixedArray>::cast(break_locations));
9921}
9922
9923
9924// Set a break point in a function
9925// args[0]: function
9926// args[1]: number: break source position (within the function source)
9927// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009928static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009929 HandleScope scope;
9930 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009931 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9932 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009933 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9934 RUNTIME_ASSERT(source_position >= 0);
9935 Handle<Object> break_point_object_arg = args.at<Object>(2);
9936
9937 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009938 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009939
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009940 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009941}
9942
9943
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009944Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9945 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009946 // Iterate the heap looking for SharedFunctionInfo generated from the
9947 // script. The inner most SharedFunctionInfo containing the source position
9948 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009949 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009950 // which is found is not compiled it is compiled and the heap is iterated
9951 // again as the compilation might create inner functions from the newly
9952 // compiled function and the actual requested break point might be in one of
9953 // these functions.
9954 bool done = false;
9955 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009956 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009957 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009958 while (!done) {
9959 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009960 for (HeapObject* obj = iterator.next();
9961 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009962 if (obj->IsSharedFunctionInfo()) {
9963 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9964 if (shared->script() == *script) {
9965 // If the SharedFunctionInfo found has the requested script data and
9966 // contains the source position it is a candidate.
9967 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009968 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009969 start_position = shared->start_position();
9970 }
9971 if (start_position <= position &&
9972 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009973 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009974 // candidate this is the new candidate.
9975 if (target.is_null()) {
9976 target_start_position = start_position;
9977 target = shared;
9978 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009979 if (target_start_position == start_position &&
9980 shared->end_position() == target->end_position()) {
9981 // If a top-level function contain only one function
9982 // declartion the source for the top-level and the function is
9983 // the same. In that case prefer the non top-level function.
9984 if (!shared->is_toplevel()) {
9985 target_start_position = start_position;
9986 target = shared;
9987 }
9988 } else if (target_start_position <= start_position &&
9989 shared->end_position() <= target->end_position()) {
9990 // This containment check includes equality as a function inside
9991 // a top-level function can share either start or end position
9992 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009993 target_start_position = start_position;
9994 target = shared;
9995 }
9996 }
9997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009998 }
9999 }
10000 }
10001
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010002 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010003 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010004 }
10005
10006 // If the candidate found is compiled we are done. NOTE: when lazy
10007 // compilation of inner functions is introduced some additional checking
10008 // needs to be done here to compile inner functions.
10009 done = target->is_compiled();
10010 if (!done) {
10011 // If the candidate is not compiled compile it to reveal any inner
10012 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010013 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010014 }
10015 }
10016
10017 return *target;
10018}
10019
10020
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010021// Changes the state of a break point in a script and returns source position
10022// where break point was set. NOTE: Regarding performance see the NOTE for
10023// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010024// args[0]: script to set break point in
10025// args[1]: number: break source position (within the script source)
10026// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +000010027static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010028 HandleScope scope;
10029 ASSERT(args.length() == 3);
10030 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10031 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10032 RUNTIME_ASSERT(source_position >= 0);
10033 Handle<Object> break_point_object_arg = args.at<Object>(2);
10034
10035 // Get the script from the script wrapper.
10036 RUNTIME_ASSERT(wrapper->value()->IsScript());
10037 Handle<Script> script(Script::cast(wrapper->value()));
10038
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010039 Object* result = Runtime::FindSharedFunctionInfoInScript(
10040 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010041 if (!result->IsUndefined()) {
10042 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10043 // Find position within function. The script position might be before the
10044 // source position of the first function.
10045 int position;
10046 if (shared->start_position() > source_position) {
10047 position = 0;
10048 } else {
10049 position = source_position - shared->start_position();
10050 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010051 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
10052 position += shared->start_position();
10053 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010054 }
10055 return Heap::undefined_value();
10056}
10057
10058
10059// Clear a break point
10060// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +000010061static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010062 HandleScope scope;
10063 ASSERT(args.length() == 1);
10064 Handle<Object> break_point_object_arg = args.at<Object>(0);
10065
10066 // Clear break point.
10067 Debug::ClearBreakPoint(break_point_object_arg);
10068
10069 return Heap::undefined_value();
10070}
10071
10072
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010073// Change the state of break on exceptions.
10074// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10075// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010076static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010077 HandleScope scope;
10078 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010079 RUNTIME_ASSERT(args[0]->IsNumber());
10080 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010081
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010082 // If the number doesn't match an enum value, the ChangeBreakOnException
10083 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010084 ExceptionBreakType type =
10085 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010086 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010087 Debug::ChangeBreakOnException(type, enable);
10088 return Heap::undefined_value();
10089}
10090
10091
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010092// Returns the state of break on exceptions
10093// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +000010094static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010095 HandleScope scope;
10096 ASSERT(args.length() == 1);
10097 RUNTIME_ASSERT(args[0]->IsNumber());
10098
10099 ExceptionBreakType type =
10100 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
10101 bool result = Debug::IsBreakOnException(type);
10102 return Smi::FromInt(result);
10103}
10104
10105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010106// Prepare for stepping
10107// args[0]: break id for checking execution state
10108// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010109// args[2]: number of times to perform the step, for step out it is the number
10110// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010111static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010112 HandleScope scope;
10113 ASSERT(args.length() == 3);
10114 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010115 Object* check;
10116 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
10117 if (!maybe_check->ToObject(&check)) return maybe_check;
10118 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010119 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
10120 return Top::Throw(Heap::illegal_argument_symbol());
10121 }
10122
10123 // Get the step action and check validity.
10124 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10125 if (step_action != StepIn &&
10126 step_action != StepNext &&
10127 step_action != StepOut &&
10128 step_action != StepInMin &&
10129 step_action != StepMin) {
10130 return Top::Throw(Heap::illegal_argument_symbol());
10131 }
10132
10133 // Get the number of steps.
10134 int step_count = NumberToInt32(args[2]);
10135 if (step_count < 1) {
10136 return Top::Throw(Heap::illegal_argument_symbol());
10137 }
10138
ager@chromium.orga1645e22009-09-09 19:27:10 +000010139 // Clear all current stepping setup.
10140 Debug::ClearStepping();
10141
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010142 // Prepare step.
10143 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
10144 return Heap::undefined_value();
10145}
10146
10147
10148// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010149static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010150 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010151 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010152 Debug::ClearStepping();
10153 return Heap::undefined_value();
10154}
10155
10156
10157// Creates a copy of the with context chain. The copy of the context chain is
10158// is linked to the function context supplied.
10159static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10160 Handle<Context> function_context) {
10161 // At the bottom of the chain. Return the function context to link to.
10162 if (context_chain->is_function_context()) {
10163 return function_context;
10164 }
10165
10166 // Recursively copy the with contexts.
10167 Handle<Context> previous(context_chain->previous());
10168 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010169 Handle<Context> context = CopyWithContextChain(function_context, previous);
10170 return Factory::NewWithContext(context,
10171 extension,
10172 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010173}
10174
10175
10176// Helper function to find or create the arguments object for
10177// Runtime_DebugEvaluate.
10178static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
10179 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010180 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010181 const ScopeInfo<>* sinfo,
10182 Handle<Context> function_context) {
10183 // Try to find the value of 'arguments' to pass as parameter. If it is not
10184 // found (that is the debugged function does not reference 'arguments' and
10185 // does not support eval) then create an 'arguments' object.
10186 int index;
10187 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010188 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010189 if (index != -1) {
10190 return Handle<Object>(frame->GetExpression(index));
10191 }
10192 }
10193
10194 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010195 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010196 if (index != -1) {
10197 return Handle<Object>(function_context->get(index));
10198 }
10199 }
10200
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010201 const int length = frame->ComputeParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010202 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
10203 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010204
10205 AssertNoAllocation no_gc;
10206 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010207 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010208 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010209 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010210 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010211 return arguments;
10212}
10213
10214
10215// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010216// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010217// extension part has all the parameters and locals of the function on the
10218// stack frame. A function which calls eval with the code to evaluate is then
10219// compiled in this context and called in this context. As this context
10220// replaces the context of the function on the stack frame a new (empty)
10221// function is created as well to be used as the closure for the context.
10222// This function and the context acts as replacements for the function on the
10223// stack frame presenting the same view of the values of parameters and
10224// local variables as if the piece of JavaScript was evaluated at the point
10225// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010226static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010227 HandleScope scope;
10228
10229 // Check the execution state and decode arguments frame and source to be
10230 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010231 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010232 Object* check_result;
10233 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10234 if (!maybe_check_result->ToObject(&check_result)) {
10235 return maybe_check_result;
10236 }
10237 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010238 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10239 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010240 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010241 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010242
10243 // Handle the processing of break.
10244 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245
10246 // Get the frame where the debugging is performed.
10247 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10248 JavaScriptFrameIterator it(id);
10249 JavaScriptFrame* frame = it.frame();
10250 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010251 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010252 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010253
10254 // Traverse the saved contexts chain to find the active context for the
10255 // selected frame.
10256 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010257 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010258 save = save->prev();
10259 }
10260 ASSERT(save != NULL);
10261 SaveContext savex;
10262 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010263
10264 // Create the (empty) function replacing the function on the stack frame for
10265 // the purpose of evaluating in the context created below. It is important
10266 // that this function does not describe any parameters and local variables
10267 // in the context. If it does then this will cause problems with the lookup
10268 // in Context::Lookup, where context slots for parameters and local variables
10269 // are looked at before the extension object.
10270 Handle<JSFunction> go_between =
10271 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
10272 go_between->set_context(function->context());
10273#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010274 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010275 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10276 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10277#endif
10278
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010279 // Materialize the content of the local scope into a JSObject.
10280 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010281 RETURN_IF_EMPTY_HANDLE(local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010282
10283 // Allocate a new context for the debug evaluation and set the extension
10284 // object build.
10285 Handle<Context> context =
10286 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010287 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010288 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010289 Handle<Context> frame_context(Context::cast(frame->context()));
10290 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010291 context = CopyWithContextChain(frame_context, context);
10292
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010293 if (additional_context->IsJSObject()) {
10294 context = Factory::NewWithContext(context,
10295 Handle<JSObject>::cast(additional_context), false);
10296 }
10297
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298 // Wrap the evaluation statement in a new function compiled in the newly
10299 // created context. The function has one parameter which has to be called
10300 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010301 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010302 // function(arguments,__source__) {return eval(__source__);}
10303 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010304 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010305 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010306 Handle<String> function_source =
10307 Factory::NewStringFromAscii(Vector<const char>(source_str,
10308 source_str_length));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010309
10310 // Currently, the eval code will be executed in non-strict mode,
10311 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010312 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010313 Compiler::CompileEval(function_source,
10314 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010315 context->IsGlobalContext(),
10316 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010317 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010318 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010319 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010320
10321 // Invoke the result of the compilation to get the evaluation function.
10322 bool has_pending_exception;
10323 Handle<Object> receiver(frame->receiver());
10324 Handle<Object> evaluation_function =
10325 Execution::Call(compiled_function, receiver, 0, NULL,
10326 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010327 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010328
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010329 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
10330 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010331
10332 // Invoke the evaluation function and return the result.
10333 const int argc = 2;
10334 Object** argv[argc] = { arguments.location(),
10335 Handle<Object>::cast(source).location() };
10336 Handle<Object> result =
10337 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10338 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010339 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010340
10341 // Skip the global proxy as it has no properties and always delegates to the
10342 // real global object.
10343 if (result->IsJSGlobalProxy()) {
10344 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10345 }
10346
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010347 return *result;
10348}
10349
10350
lrn@chromium.org303ada72010-10-27 09:33:13 +000010351static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010352 HandleScope scope;
10353
10354 // Check the execution state and decode arguments frame and source to be
10355 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010356 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010357 Object* check_result;
10358 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10359 if (!maybe_check_result->ToObject(&check_result)) {
10360 return maybe_check_result;
10361 }
10362 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010363 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010364 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010365 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010366
10367 // Handle the processing of break.
10368 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010369
10370 // Enter the top context from before the debugger was invoked.
10371 SaveContext save;
10372 SaveContext* top = &save;
10373 while (top != NULL && *top->context() == *Debug::debug_context()) {
10374 top = top->prev();
10375 }
10376 if (top != NULL) {
10377 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010378 }
10379
10380 // Get the global context now set to the top context from before the
10381 // debugger was invoked.
10382 Handle<Context> context = Top::global_context();
10383
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010384 bool is_global = true;
10385
10386 if (additional_context->IsJSObject()) {
10387 // Create a function context first, than put 'with' context on top of it.
10388 Handle<JSFunction> go_between = Factory::NewFunction(
10389 Factory::empty_string(), Factory::undefined_value());
10390 go_between->set_context(*context);
10391 context =
10392 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
10393 context->set_extension(JSObject::cast(*additional_context));
10394 is_global = false;
10395 }
10396
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010397 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010398 // Currently, the eval code will be executed in non-strict mode,
10399 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010400 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010401 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010402 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010403 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010404 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
10405 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010406
10407 // Invoke the result of the compilation to get the evaluation function.
10408 bool has_pending_exception;
10409 Handle<Object> receiver = Top::global();
10410 Handle<Object> result =
10411 Execution::Call(compiled_function, receiver, 0, NULL,
10412 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010413 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010414 return *result;
10415}
10416
10417
lrn@chromium.org303ada72010-10-27 09:33:13 +000010418static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010419 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010420 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010421
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010422 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010423 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010424
10425 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010426 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010427 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10428 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10429 // because using
10430 // instances->set(i, *GetScriptWrapper(script))
10431 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10432 // already have deferenced the instances handle.
10433 Handle<JSValue> wrapper = GetScriptWrapper(script);
10434 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010435 }
10436
10437 // Return result as a JS array.
10438 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
10439 Handle<JSArray>::cast(result)->SetContent(*instances);
10440 return *result;
10441}
10442
10443
10444// Helper function used by Runtime_DebugReferencedBy below.
10445static int DebugReferencedBy(JSObject* target,
10446 Object* instance_filter, int max_references,
10447 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010448 JSFunction* arguments_function) {
10449 NoHandleAllocation ha;
10450 AssertNoAllocation no_alloc;
10451
10452 // Iterate the heap.
10453 int count = 0;
10454 JSObject* last = NULL;
10455 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010456 HeapObject* heap_obj = NULL;
10457 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010458 (max_references == 0 || count < max_references)) {
10459 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010460 if (heap_obj->IsJSObject()) {
10461 // Skip context extension objects and argument arrays as these are
10462 // checked in the context of functions using them.
10463 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010464 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010465 obj->map()->constructor() == arguments_function) {
10466 continue;
10467 }
10468
10469 // Check if the JS object has a reference to the object looked for.
10470 if (obj->ReferencesObject(target)) {
10471 // Check instance filter if supplied. This is normally used to avoid
10472 // references from mirror objects (see Runtime_IsInPrototypeChain).
10473 if (!instance_filter->IsUndefined()) {
10474 Object* V = obj;
10475 while (true) {
10476 Object* prototype = V->GetPrototype();
10477 if (prototype->IsNull()) {
10478 break;
10479 }
10480 if (instance_filter == prototype) {
10481 obj = NULL; // Don't add this object.
10482 break;
10483 }
10484 V = prototype;
10485 }
10486 }
10487
10488 if (obj != NULL) {
10489 // Valid reference found add to instance array if supplied an update
10490 // count.
10491 if (instances != NULL && count < instances_size) {
10492 instances->set(count, obj);
10493 }
10494 last = obj;
10495 count++;
10496 }
10497 }
10498 }
10499 }
10500
10501 // Check for circular reference only. This can happen when the object is only
10502 // referenced from mirrors and has a circular reference in which case the
10503 // object is not really alive and would have been garbage collected if not
10504 // referenced from the mirror.
10505 if (count == 1 && last == target) {
10506 count = 0;
10507 }
10508
10509 // Return the number of referencing objects found.
10510 return count;
10511}
10512
10513
10514// Scan the heap for objects with direct references to an object
10515// args[0]: the object to find references to
10516// args[1]: constructor function for instances to exclude (Mirror)
10517// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010518static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010519 ASSERT(args.length() == 3);
10520
10521 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010522 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010523
10524 // Check parameters.
10525 CONVERT_CHECKED(JSObject, target, args[0]);
10526 Object* instance_filter = args[1];
10527 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10528 instance_filter->IsJSObject());
10529 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10530 RUNTIME_ASSERT(max_references >= 0);
10531
10532 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010533 JSObject* arguments_boilerplate =
10534 Top::context()->global_context()->arguments_boilerplate();
10535 JSFunction* arguments_function =
10536 JSFunction::cast(arguments_boilerplate->map()->constructor());
10537
10538 // Get the number of referencing objects.
10539 int count;
10540 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010541 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010542
10543 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010544 Object* object;
10545 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10546 if (!maybe_object->ToObject(&object)) return maybe_object;
10547 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010548 FixedArray* instances = FixedArray::cast(object);
10549
10550 // Fill the referencing objects.
10551 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010552 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010553
10554 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010555 Object* result;
10556 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10557 Top::context()->global_context()->array_function());
10558 if (!maybe_result->ToObject(&result)) return maybe_result;
10559 }
10560 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561 return result;
10562}
10563
10564
10565// Helper function used by Runtime_DebugConstructedBy below.
10566static int DebugConstructedBy(JSFunction* constructor, int max_references,
10567 FixedArray* instances, int instances_size) {
10568 AssertNoAllocation no_alloc;
10569
10570 // Iterate the heap.
10571 int count = 0;
10572 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010573 HeapObject* heap_obj = NULL;
10574 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010575 (max_references == 0 || count < max_references)) {
10576 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010577 if (heap_obj->IsJSObject()) {
10578 JSObject* obj = JSObject::cast(heap_obj);
10579 if (obj->map()->constructor() == constructor) {
10580 // Valid reference found add to instance array if supplied an update
10581 // count.
10582 if (instances != NULL && count < instances_size) {
10583 instances->set(count, obj);
10584 }
10585 count++;
10586 }
10587 }
10588 }
10589
10590 // Return the number of referencing objects found.
10591 return count;
10592}
10593
10594
10595// Scan the heap for objects constructed by a specific function.
10596// args[0]: the constructor to find instances of
10597// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010598static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010599 ASSERT(args.length() == 2);
10600
10601 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010602 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010603
10604 // Check parameters.
10605 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10606 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10607 RUNTIME_ASSERT(max_references >= 0);
10608
10609 // Get the number of referencing objects.
10610 int count;
10611 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10612
10613 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010614 Object* object;
10615 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10616 if (!maybe_object->ToObject(&object)) return maybe_object;
10617 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010618 FixedArray* instances = FixedArray::cast(object);
10619
10620 // Fill the referencing objects.
10621 count = DebugConstructedBy(constructor, max_references, instances, count);
10622
10623 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010624 Object* result;
10625 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10626 Top::context()->global_context()->array_function());
10627 if (!maybe_result->ToObject(&result)) return maybe_result;
10628 }
10629 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010630 return result;
10631}
10632
10633
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010634// Find the effective prototype object as returned by __proto__.
10635// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010636static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010637 ASSERT(args.length() == 1);
10638
10639 CONVERT_CHECKED(JSObject, obj, args[0]);
10640
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010641 // Use the __proto__ accessor.
10642 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010643}
10644
10645
lrn@chromium.org303ada72010-10-27 09:33:13 +000010646static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010647 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010648 CPU::DebugBreak();
10649 return Heap::undefined_value();
10650}
10651
10652
lrn@chromium.org303ada72010-10-27 09:33:13 +000010653static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010654#ifdef DEBUG
10655 HandleScope scope;
10656 ASSERT(args.length() == 1);
10657 // Get the function and make sure it is compiled.
10658 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010659 Handle<SharedFunctionInfo> shared(func->shared());
10660 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010661 return Failure::Exception();
10662 }
10663 func->code()->PrintLn();
10664#endif // DEBUG
10665 return Heap::undefined_value();
10666}
ager@chromium.org9085a012009-05-11 19:22:57 +000010667
10668
lrn@chromium.org303ada72010-10-27 09:33:13 +000010669static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010670#ifdef DEBUG
10671 HandleScope scope;
10672 ASSERT(args.length() == 1);
10673 // Get the function and make sure it is compiled.
10674 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010675 Handle<SharedFunctionInfo> shared(func->shared());
10676 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010677 return Failure::Exception();
10678 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010679 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010680#endif // DEBUG
10681 return Heap::undefined_value();
10682}
10683
10684
lrn@chromium.org303ada72010-10-27 09:33:13 +000010685static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010686 NoHandleAllocation ha;
10687 ASSERT(args.length() == 1);
10688
10689 CONVERT_CHECKED(JSFunction, f, args[0]);
10690 return f->shared()->inferred_name();
10691}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010692
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010693
10694static int FindSharedFunctionInfosForScript(Script* script,
10695 FixedArray* buffer) {
10696 AssertNoAllocation no_allocations;
10697
10698 int counter = 0;
10699 int buffer_size = buffer->length();
10700 HeapIterator iterator;
10701 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10702 ASSERT(obj != NULL);
10703 if (!obj->IsSharedFunctionInfo()) {
10704 continue;
10705 }
10706 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10707 if (shared->script() != script) {
10708 continue;
10709 }
10710 if (counter < buffer_size) {
10711 buffer->set(counter, shared);
10712 }
10713 counter++;
10714 }
10715 return counter;
10716}
10717
10718// For a script finds all SharedFunctionInfo's in the heap that points
10719// to this script. Returns JSArray of SharedFunctionInfo wrapped
10720// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010721static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010722 Arguments args) {
10723 ASSERT(args.length() == 1);
10724 HandleScope scope;
10725 CONVERT_CHECKED(JSValue, script_value, args[0]);
10726
10727 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10728
10729 const int kBufferSize = 32;
10730
10731 Handle<FixedArray> array;
10732 array = Factory::NewFixedArray(kBufferSize);
10733 int number = FindSharedFunctionInfosForScript(*script, *array);
10734 if (number > kBufferSize) {
10735 array = Factory::NewFixedArray(number);
10736 FindSharedFunctionInfosForScript(*script, *array);
10737 }
10738
10739 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10740 result->set_length(Smi::FromInt(number));
10741
10742 LiveEdit::WrapSharedFunctionInfos(result);
10743
10744 return *result;
10745}
10746
10747// For a script calculates compilation information about all its functions.
10748// The script source is explicitly specified by the second argument.
10749// The source of the actual script is not used, however it is important that
10750// all generated code keeps references to this particular instance of script.
10751// Returns a JSArray of compilation infos. The array is ordered so that
10752// each function with all its descendant is always stored in a continues range
10753// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010754static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010755 ASSERT(args.length() == 2);
10756 HandleScope scope;
10757 CONVERT_CHECKED(JSValue, script, args[0]);
10758 CONVERT_ARG_CHECKED(String, source, 1);
10759 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10760
10761 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10762
10763 if (Top::has_pending_exception()) {
10764 return Failure::Exception();
10765 }
10766
10767 return result;
10768}
10769
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010770// Changes the source of the script to a new_source.
10771// If old_script_name is provided (i.e. is a String), also creates a copy of
10772// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010773static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010774 ASSERT(args.length() == 3);
10775 HandleScope scope;
10776 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10777 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010778 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010779
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010780 CONVERT_CHECKED(Script, original_script_pointer,
10781 original_script_value->value());
10782 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010783
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010784 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10785 new_source,
10786 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010787
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010788 if (old_script->IsScript()) {
10789 Handle<Script> script_handle(Script::cast(old_script));
10790 return *(GetScriptWrapper(script_handle));
10791 } else {
10792 return Heap::null_value();
10793 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010794}
10795
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010796
10797static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10798 ASSERT(args.length() == 1);
10799 HandleScope scope;
10800 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10801 return LiveEdit::FunctionSourceUpdated(shared_info);
10802}
10803
10804
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010805// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010806static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010807 ASSERT(args.length() == 2);
10808 HandleScope scope;
10809 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10810 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10811
ager@chromium.orgac091b72010-05-05 07:34:42 +000010812 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010813}
10814
10815// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010816static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010817 ASSERT(args.length() == 2);
10818 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010819 Handle<Object> function_object(args[0]);
10820 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010821
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010822 if (function_object->IsJSValue()) {
10823 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10824 if (script_object->IsJSValue()) {
10825 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10826 script_object = Handle<Object>(script);
10827 }
10828
10829 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10830 } else {
10831 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10832 // and we check it in this function.
10833 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010834
10835 return Heap::undefined_value();
10836}
10837
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010838
10839// In a code of a parent function replaces original function as embedded object
10840// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010841static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010842 ASSERT(args.length() == 3);
10843 HandleScope scope;
10844
10845 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10846 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10847 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10848
10849 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10850 subst_wrapper);
10851
10852 return Heap::undefined_value();
10853}
10854
10855
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010856// Updates positions of a shared function info (first parameter) according
10857// to script source change. Text change is described in second parameter as
10858// array of groups of 3 numbers:
10859// (change_begin, change_end, change_end_new_position).
10860// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010861static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010862 ASSERT(args.length() == 2);
10863 HandleScope scope;
10864 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10865 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10866
ager@chromium.orgac091b72010-05-05 07:34:42 +000010867 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010868}
10869
10870
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010871// For array of SharedFunctionInfo's (each wrapped in JSValue)
10872// checks that none of them have activations on stacks (of any thread).
10873// Returns array of the same length with corresponding results of
10874// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010875static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010876 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010877 HandleScope scope;
10878 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010879 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010880
ager@chromium.org357bf652010-04-12 11:30:10 +000010881 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010882}
10883
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010884// Compares 2 strings line-by-line, then token-wise and returns diff in form
10885// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
10886// of diff chunks.
10887static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010888 ASSERT(args.length() == 2);
10889 HandleScope scope;
10890 CONVERT_ARG_CHECKED(String, s1, 0);
10891 CONVERT_ARG_CHECKED(String, s2, 1);
10892
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010893 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010894}
10895
10896
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010897
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010898// A testing entry. Returns statement position which is the closest to
10899// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010900static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010901 ASSERT(args.length() == 2);
10902 HandleScope scope;
10903 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10904 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10905
10906 Handle<Code> code(function->code());
10907
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010908 if (code->kind() != Code::FUNCTION &&
10909 code->kind() != Code::OPTIMIZED_FUNCTION) {
10910 return Heap::undefined_value();
10911 }
10912
10913 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010914 int closest_pc = 0;
10915 int distance = kMaxInt;
10916 while (!it.done()) {
10917 int statement_position = static_cast<int>(it.rinfo()->data());
10918 // Check if this break point is closer that what was previously found.
10919 if (source_position <= statement_position &&
10920 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010921 closest_pc =
10922 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010923 distance = statement_position - source_position;
10924 // Check whether we can't get any closer.
10925 if (distance == 0) break;
10926 }
10927 it.next();
10928 }
10929
10930 return Smi::FromInt(closest_pc);
10931}
10932
10933
ager@chromium.org357bf652010-04-12 11:30:10 +000010934// Calls specified function with or without entering the debugger.
10935// This is used in unit tests to run code as if debugger is entered or simply
10936// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010937static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010938 ASSERT(args.length() == 2);
10939 HandleScope scope;
10940 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10941 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10942
10943 Handle<Object> result;
10944 bool pending_exception;
10945 {
10946 if (without_debugger) {
10947 result = Execution::Call(function, Top::global(), 0, NULL,
10948 &pending_exception);
10949 } else {
10950 EnterDebugger enter_debugger;
10951 result = Execution::Call(function, Top::global(), 0, NULL,
10952 &pending_exception);
10953 }
10954 }
10955 if (!pending_exception) {
10956 return *result;
10957 } else {
10958 return Failure::Exception();
10959 }
10960}
10961
10962
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010963// Sets a v8 flag.
10964static MaybeObject* Runtime_SetFlags(Arguments args) {
10965 CONVERT_CHECKED(String, arg, args[0]);
10966 SmartPointer<char> flags =
10967 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10968 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10969 return Heap::undefined_value();
10970}
10971
10972
10973// Performs a GC.
10974// Presently, it only does a full GC.
10975static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10976 Heap::CollectAllGarbage(true);
10977 return Heap::undefined_value();
10978}
10979
10980
10981// Gets the current heap usage.
10982static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10983 int usage = static_cast<int>(Heap::SizeOfObjects());
10984 if (!Smi::IsValid(usage)) {
10985 return *Factory::NewNumberFromInt(usage);
10986 }
10987 return Smi::FromInt(usage);
10988}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010989
10990
10991// Captures a live object list from the present heap.
10992static MaybeObject* Runtime_HasLOLEnabled(Arguments args) {
10993#ifdef LIVE_OBJECT_LIST
10994 return Heap::true_value();
10995#else
10996 return Heap::false_value();
10997#endif
10998}
10999
11000
11001// Captures a live object list from the present heap.
11002static MaybeObject* Runtime_CaptureLOL(Arguments args) {
11003#ifdef LIVE_OBJECT_LIST
11004 return LiveObjectList::Capture();
11005#else
11006 return Heap::undefined_value();
11007#endif
11008}
11009
11010
11011// Deletes the specified live object list.
11012static MaybeObject* Runtime_DeleteLOL(Arguments args) {
11013#ifdef LIVE_OBJECT_LIST
11014 CONVERT_SMI_CHECKED(id, args[0]);
11015 bool success = LiveObjectList::Delete(id);
11016 return success ? Heap::true_value() : Heap::false_value();
11017#else
11018 return Heap::undefined_value();
11019#endif
11020}
11021
11022
11023// Generates the response to a debugger request for a dump of the objects
11024// contained in the difference between the captured live object lists
11025// specified by id1 and id2.
11026// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11027// dumped.
11028static MaybeObject* Runtime_DumpLOL(Arguments args) {
11029#ifdef LIVE_OBJECT_LIST
11030 HandleScope scope;
11031 CONVERT_SMI_CHECKED(id1, args[0]);
11032 CONVERT_SMI_CHECKED(id2, args[1]);
11033 CONVERT_SMI_CHECKED(start, args[2]);
11034 CONVERT_SMI_CHECKED(count, args[3]);
11035 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11036 EnterDebugger enter_debugger;
11037 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11038#else
11039 return Heap::undefined_value();
11040#endif
11041}
11042
11043
11044// Gets the specified object as requested by the debugger.
11045// This is only used for obj ids shown in live object lists.
11046static MaybeObject* Runtime_GetLOLObj(Arguments args) {
11047#ifdef LIVE_OBJECT_LIST
11048 CONVERT_SMI_CHECKED(obj_id, args[0]);
11049 Object* result = LiveObjectList::GetObj(obj_id);
11050 return result;
11051#else
11052 return Heap::undefined_value();
11053#endif
11054}
11055
11056
11057// Gets the obj id for the specified address if valid.
11058// This is only used for obj ids shown in live object lists.
11059static MaybeObject* Runtime_GetLOLObjId(Arguments args) {
11060#ifdef LIVE_OBJECT_LIST
11061 HandleScope scope;
11062 CONVERT_ARG_CHECKED(String, address, 0);
11063 Object* result = LiveObjectList::GetObjId(address);
11064 return result;
11065#else
11066 return Heap::undefined_value();
11067#endif
11068}
11069
11070
11071// Gets the retainers that references the specified object alive.
11072static MaybeObject* Runtime_GetLOLObjRetainers(Arguments args) {
11073#ifdef LIVE_OBJECT_LIST
11074 HandleScope scope;
11075 CONVERT_SMI_CHECKED(obj_id, args[0]);
11076 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11077 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11078 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11079 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11080 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11081
11082 Handle<JSObject> instance_filter;
11083 if (args[1]->IsJSObject()) {
11084 instance_filter = args.at<JSObject>(1);
11085 }
11086 bool verbose = false;
11087 if (args[2]->IsBoolean()) {
11088 verbose = args[2]->IsTrue();
11089 }
11090 int start = 0;
11091 if (args[3]->IsSmi()) {
11092 start = Smi::cast(args[3])->value();
11093 }
11094 int limit = Smi::kMaxValue;
11095 if (args[4]->IsSmi()) {
11096 limit = Smi::cast(args[4])->value();
11097 }
11098
11099 return LiveObjectList::GetObjRetainers(obj_id,
11100 instance_filter,
11101 verbose,
11102 start,
11103 limit,
11104 filter_obj);
11105#else
11106 return Heap::undefined_value();
11107#endif
11108}
11109
11110
11111// Gets the reference path between 2 objects.
11112static MaybeObject* Runtime_GetLOLPath(Arguments args) {
11113#ifdef LIVE_OBJECT_LIST
11114 HandleScope scope;
11115 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11116 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11117 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11118
11119 Handle<JSObject> instance_filter;
11120 if (args[2]->IsJSObject()) {
11121 instance_filter = args.at<JSObject>(2);
11122 }
11123
11124 Object* result =
11125 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11126 return result;
11127#else
11128 return Heap::undefined_value();
11129#endif
11130}
11131
11132
11133// Generates the response to a debugger request for a list of all
11134// previously captured live object lists.
11135static MaybeObject* Runtime_InfoLOL(Arguments args) {
11136#ifdef LIVE_OBJECT_LIST
11137 CONVERT_SMI_CHECKED(start, args[0]);
11138 CONVERT_SMI_CHECKED(count, args[1]);
11139 return LiveObjectList::Info(start, count);
11140#else
11141 return Heap::undefined_value();
11142#endif
11143}
11144
11145
11146// Gets a dump of the specified object as requested by the debugger.
11147// This is only used for obj ids shown in live object lists.
11148static MaybeObject* Runtime_PrintLOLObj(Arguments args) {
11149#ifdef LIVE_OBJECT_LIST
11150 HandleScope scope;
11151 CONVERT_SMI_CHECKED(obj_id, args[0]);
11152 Object* result = LiveObjectList::PrintObj(obj_id);
11153 return result;
11154#else
11155 return Heap::undefined_value();
11156#endif
11157}
11158
11159
11160// Resets and releases all previously captured live object lists.
11161static MaybeObject* Runtime_ResetLOL(Arguments args) {
11162#ifdef LIVE_OBJECT_LIST
11163 LiveObjectList::Reset();
11164 return Heap::undefined_value();
11165#else
11166 return Heap::undefined_value();
11167#endif
11168}
11169
11170
11171// Generates the response to a debugger request for a summary of the types
11172// of objects in the difference between the captured live object lists
11173// specified by id1 and id2.
11174// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11175// summarized.
11176static MaybeObject* Runtime_SummarizeLOL(Arguments args) {
11177#ifdef LIVE_OBJECT_LIST
11178 HandleScope scope;
11179 CONVERT_SMI_CHECKED(id1, args[0]);
11180 CONVERT_SMI_CHECKED(id2, args[1]);
11181 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11182
11183 EnterDebugger enter_debugger;
11184 return LiveObjectList::Summarize(id1, id2, filter_obj);
11185#else
11186 return Heap::undefined_value();
11187#endif
11188}
11189
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011190#endif // ENABLE_DEBUGGER_SUPPORT
11191
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011192
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011193#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000011194static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011195 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011196 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011197
11198 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011199 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11200 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011201 return Heap::undefined_value();
11202}
11203
11204
lrn@chromium.org303ada72010-10-27 09:33:13 +000011205static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011206 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011207 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011208
11209 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011210 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11211 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011212 return Heap::undefined_value();
11213}
11214
11215#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011216
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011217// Finds the script object from the script data. NOTE: This operation uses
11218// heap traversal to find the function generated for the source position
11219// for the requested break point. For lazily compiled functions several heap
11220// traversals might be required rendering this operation as a rather slow
11221// operation. However for setting break points which is normally done through
11222// some kind of user interaction the performance is not crucial.
11223static Handle<Object> Runtime_GetScriptFromScriptName(
11224 Handle<String> script_name) {
11225 // Scan the heap for Script objects to find the script with the requested
11226 // script data.
11227 Handle<Script> script;
11228 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011229 HeapObject* obj = NULL;
11230 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011231 // If a script is found check if it has the script data requested.
11232 if (obj->IsScript()) {
11233 if (Script::cast(obj)->name()->IsString()) {
11234 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11235 script = Handle<Script>(Script::cast(obj));
11236 }
11237 }
11238 }
11239 }
11240
11241 // If no script with the requested script data is found return undefined.
11242 if (script.is_null()) return Factory::undefined_value();
11243
11244 // Return the script found.
11245 return GetScriptWrapper(script);
11246}
11247
11248
11249// Get the script object from script data. NOTE: Regarding performance
11250// see the NOTE for GetScriptFromScriptData.
11251// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000011252static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011253 HandleScope scope;
11254
11255 ASSERT(args.length() == 1);
11256
11257 CONVERT_CHECKED(String, script_name, args[0]);
11258
11259 // Find the requested script.
11260 Handle<Object> result =
11261 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11262 return *result;
11263}
11264
11265
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011266// Determines whether the given stack frame should be displayed in
11267// a stack trace. The caller is the error constructor that asked
11268// for the stack trace to be collected. The first time a construct
11269// call to this function is encountered it is skipped. The seen_caller
11270// in/out parameter is used to remember if the caller has been seen
11271// yet.
11272static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11273 bool* seen_caller) {
11274 // Only display JS frames.
11275 if (!raw_frame->is_java_script())
11276 return false;
11277 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11278 Object* raw_fun = frame->function();
11279 // Not sure when this can happen but skip it just in case.
11280 if (!raw_fun->IsJSFunction())
11281 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011282 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011283 *seen_caller = true;
11284 return false;
11285 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011286 // Skip all frames until we've seen the caller. Also, skip the most
11287 // obvious builtin calls. Some builtin calls (such as Number.ADD
11288 // which is invoked using 'call') are very difficult to recognize
11289 // so we're leaving them in for now.
11290 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011291}
11292
11293
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011294// Collect the raw data for a stack trace. Returns an array of 4
11295// element segments each containing a receiver, function, code and
11296// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011297static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011298 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011299 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011300 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11301
11302 HandleScope scope;
11303
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011304 limit = Max(limit, 0); // Ensure that limit is not negative.
11305 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011306 Handle<FixedArray> elements =
11307 Factory::NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011308
11309 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011310 // If the caller parameter is a function we skip frames until we're
11311 // under it before starting to collect.
11312 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011313 int cursor = 0;
11314 int frames_seen = 0;
11315 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011316 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011317 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011318 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011319 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011320 List<FrameSummary> frames(3); // Max 2 levels of inlining.
11321 frame->Summarize(&frames);
11322 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011323 if (cursor + 4 > elements->length()) {
11324 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11325 Handle<FixedArray> new_elements =
11326 Factory::NewFixedArrayWithHoles(new_capacity);
11327 for (int i = 0; i < cursor; i++) {
11328 new_elements->set(i, elements->get(i));
11329 }
11330 elements = new_elements;
11331 }
11332 ASSERT(cursor + 4 <= elements->length());
11333
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011334 Handle<Object> recv = frames[i].receiver();
11335 Handle<JSFunction> fun = frames[i].function();
11336 Handle<Code> code = frames[i].code();
11337 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011338 elements->set(cursor++, *recv);
11339 elements->set(cursor++, *fun);
11340 elements->set(cursor++, *code);
11341 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011342 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011343 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011344 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011345 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011346 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011347 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011348 return *result;
11349}
11350
11351
ager@chromium.org3811b432009-10-28 14:53:37 +000011352// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011353static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011354 ASSERT_EQ(args.length(), 0);
11355
11356 NoHandleAllocation ha;
11357
11358 const char* version_string = v8::V8::GetVersion();
11359
11360 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
11361}
11362
11363
lrn@chromium.org303ada72010-10-27 09:33:13 +000011364static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011365 ASSERT(args.length() == 2);
11366 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11367 Smi::cast(args[1])->value());
11368 Top::PrintStack();
11369 OS::Abort();
11370 UNREACHABLE();
11371 return NULL;
11372}
11373
11374
lrn@chromium.org303ada72010-10-27 09:33:13 +000011375static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011376 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011377 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011378 Object* key = args[1];
11379
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011380 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011381 Object* o = cache->get(finger_index);
11382 if (o == key) {
11383 // The fastest case: hit the same place again.
11384 return cache->get(finger_index + 1);
11385 }
11386
11387 for (int i = finger_index - 2;
11388 i >= JSFunctionResultCache::kEntriesIndex;
11389 i -= 2) {
11390 o = cache->get(i);
11391 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011392 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011393 return cache->get(i + 1);
11394 }
11395 }
11396
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011397 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011398 ASSERT(size <= cache->length());
11399
11400 for (int i = size - 2; i > finger_index; i -= 2) {
11401 o = cache->get(i);
11402 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011403 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011404 return cache->get(i + 1);
11405 }
11406 }
11407
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011408 // There is no value in the cache. Invoke the function and cache result.
11409 HandleScope scope;
11410
11411 Handle<JSFunctionResultCache> cache_handle(cache);
11412 Handle<Object> key_handle(key);
11413 Handle<Object> value;
11414 {
11415 Handle<JSFunction> factory(JSFunction::cast(
11416 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11417 // TODO(antonm): consider passing a receiver when constructing a cache.
11418 Handle<Object> receiver(Top::global_context()->global());
11419 // This handle is nor shared, nor used later, so it's safe.
11420 Object** argv[] = { key_handle.location() };
11421 bool pending_exception = false;
11422 value = Execution::Call(factory,
11423 receiver,
11424 1,
11425 argv,
11426 &pending_exception);
11427 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011428 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011429
11430#ifdef DEBUG
11431 cache_handle->JSFunctionResultCacheVerify();
11432#endif
11433
11434 // Function invocation may have cleared the cache. Reread all the data.
11435 finger_index = cache_handle->finger_index();
11436 size = cache_handle->size();
11437
11438 // If we have spare room, put new data into it, otherwise evict post finger
11439 // entry which is likely to be the least recently used.
11440 int index = -1;
11441 if (size < cache_handle->length()) {
11442 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11443 index = size;
11444 } else {
11445 index = finger_index + JSFunctionResultCache::kEntrySize;
11446 if (index == cache_handle->length()) {
11447 index = JSFunctionResultCache::kEntriesIndex;
11448 }
11449 }
11450
11451 ASSERT(index % 2 == 0);
11452 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11453 ASSERT(index < cache_handle->length());
11454
11455 cache_handle->set(index, *key_handle);
11456 cache_handle->set(index + 1, *value);
11457 cache_handle->set_finger_index(index);
11458
11459#ifdef DEBUG
11460 cache_handle->JSFunctionResultCacheVerify();
11461#endif
11462
11463 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011464}
11465
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011466
11467static MaybeObject* Runtime_NewMessageObject(Arguments args) {
11468 HandleScope scope;
11469 CONVERT_ARG_CHECKED(String, type, 0);
11470 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
11471 return *Factory::NewJSMessageObject(type,
11472 arguments,
11473 0,
11474 0,
11475 Factory::undefined_value(),
11476 Factory::undefined_value(),
11477 Factory::undefined_value());
11478}
11479
11480
11481static MaybeObject* Runtime_MessageGetType(Arguments args) {
11482 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11483 return message->type();
11484}
11485
11486
11487static MaybeObject* Runtime_MessageGetArguments(Arguments args) {
11488 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11489 return message->arguments();
11490}
11491
11492
11493static MaybeObject* Runtime_MessageGetStartPosition(Arguments args) {
11494 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11495 return Smi::FromInt(message->start_position());
11496}
11497
11498
11499static MaybeObject* Runtime_MessageGetScript(Arguments args) {
11500 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11501 return message->script();
11502}
11503
11504
kasper.lund44510672008-07-25 07:37:58 +000011505#ifdef DEBUG
11506// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11507// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011508static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000011509 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011510 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011511#define COUNT_ENTRY(Name, argc, ressize) + 1
11512 int entry_count = 0
11513 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
11514 INLINE_FUNCTION_LIST(COUNT_ENTRY)
11515 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
11516#undef COUNT_ENTRY
11517 Handle<FixedArray> elements = Factory::NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011518 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011519 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011520#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011521 { \
11522 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011523 Handle<String> name; \
11524 /* Inline runtime functions have an underscore in front of the name. */ \
11525 if (inline_runtime_functions) { \
11526 name = Factory::NewStringFromAscii( \
11527 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11528 } else { \
11529 name = Factory::NewStringFromAscii( \
11530 Vector<const char>(#Name, StrLength(#Name))); \
11531 } \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011532 Handle<FixedArray> pair_elements = Factory::NewFixedArray(2); \
11533 pair_elements->set(0, *name); \
11534 pair_elements->set(1, Smi::FromInt(argc)); \
11535 Handle<JSArray> pair = Factory::NewJSArrayWithElements(pair_elements); \
11536 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011537 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011538 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011539 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011540 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011541 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011542 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011543#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011544 ASSERT_EQ(index, entry_count);
11545 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011546 return *result;
11547}
kasper.lund44510672008-07-25 07:37:58 +000011548#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011549
11550
lrn@chromium.org303ada72010-10-27 09:33:13 +000011551static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011552 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011553 CONVERT_CHECKED(String, format, args[0]);
11554 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011555 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011556 Logger::LogRuntime(chars, elms);
11557 return Heap::undefined_value();
11558}
11559
11560
lrn@chromium.org303ada72010-10-27 09:33:13 +000011561static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011562 UNREACHABLE(); // implemented as macro in the parser
11563 return NULL;
11564}
11565
11566
11567// ----------------------------------------------------------------------------
11568// Implementation of Runtime
11569
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011570#define F(name, number_of_args, result_size) \
11571 { Runtime::k##name, Runtime::RUNTIME, #name, \
11572 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011573
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011574
11575#define I(name, number_of_args, result_size) \
11576 { Runtime::kInline##name, Runtime::INLINE, \
11577 "_" #name, NULL, number_of_args, result_size },
11578
11579Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011580 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011581 INLINE_FUNCTION_LIST(I)
11582 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011583};
11584
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011585
lrn@chromium.org303ada72010-10-27 09:33:13 +000011586MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011587 ASSERT(dictionary != NULL);
11588 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11589 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011590 Object* name_symbol;
11591 { MaybeObject* maybe_name_symbol =
11592 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
11593 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11594 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011595 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011596 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11597 String::cast(name_symbol),
11598 Smi::FromInt(i),
11599 PropertyDetails(NONE, NORMAL));
11600 if (!maybe_dictionary->ToObject(&dictionary)) {
11601 // Non-recoverable failure. Calling code must restart heap
11602 // initialization.
11603 return maybe_dictionary;
11604 }
11605 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011606 }
11607 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011608}
11609
11610
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011611Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11612 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
11613 if (entry != kNotFound) {
11614 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
11615 int function_index = Smi::cast(smi_index)->value();
11616 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011617 }
11618 return NULL;
11619}
11620
11621
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011622Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
11623 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11624}
11625
11626
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011627void Runtime::PerformGC(Object* result) {
11628 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011629 if (failure->IsRetryAfterGC()) {
11630 // Try to do a garbage collection; ignore it if it fails. The C
11631 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000011632 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011633 } else {
11634 // Handle last resort GC and make sure to allow future allocations
11635 // to grow the heap without causing GCs (if possible).
11636 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000011637 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011638 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011639}
11640
11641
11642} } // namespace v8::internal