blob: ff0503718b5c93262a33eda9f7ab8d24a6d379a4 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
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) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000062 if (!(value)) return isolate->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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000104MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
105 JSObject* boilerplate) {
106 StackLimitCheck check(isolate);
107 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000109 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000110 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000112 if (!maybe_result->ToObject(&result)) return maybe_result;
113 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000114 JSObject* copy = JSObject::cast(result);
115
116 // Deep copy local properties.
117 if (copy->HasFastProperties()) {
118 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119 for (int i = 0; i < properties->length(); i++) {
120 Object* value = properties->get(i);
121 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000122 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000123 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000124 if (!maybe_result->ToObject(&result)) return maybe_result;
125 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000127 }
128 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000129 int nof = copy->map()->inobject_properties();
130 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000131 Object* value = copy->InObjectPropertyAt(i);
132 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000133 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000134 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000135 if (!maybe_result->ToObject(&result)) return maybe_result;
136 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000138 }
139 }
140 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000141 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000142 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 if (!maybe_result->ToObject(&result)) return maybe_result;
144 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 FixedArray* names = FixedArray::cast(result);
146 copy->GetLocalPropertyNames(names, 0);
147 for (int i = 0; i < names->length(); i++) {
148 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000149 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 // Only deep copy fields from the object literal expression.
153 // In particular, don't try to copy the length attribute of
154 // an array.
155 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 Object* value =
157 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
163 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000164 // Creating object copy for literals. No strict mode needed.
165 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000166 if (!maybe_result->ToObject(&result)) return maybe_result;
167 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000168 }
169 }
170 }
171
172 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000174 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000175 switch (copy->GetElementsKind()) {
176 case JSObject::FAST_ELEMENTS: {
177 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000178 if (elements->map() == heap->fixed_cow_array_map()) {
179 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000180#ifdef DEBUG
181 for (int i = 0; i < elements->length(); i++) {
182 ASSERT(!elements->get(i)->IsJSObject());
183 }
184#endif
185 } else {
186 for (int i = 0; i < elements->length(); i++) {
187 Object* value = elements->get(i);
188 if (value->IsJSObject()) {
189 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000190 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
191 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
210 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000211 if (!maybe_result->ToObject(&result)) return maybe_result;
212 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000213 element_dictionary->ValueAtPut(i, result);
214 }
215 }
216 }
217 break;
218 }
219 default:
220 UNREACHABLE();
221 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000222 }
223 return copy;
224}
225
226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000227RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000228 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230}
231
232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000233RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000234 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000235 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236}
237
238
ager@chromium.org236ad962008-09-25 09:45:57 +0000239static Handle<Map> ComputeObjectLiteralMap(
240 Handle<Context> context,
241 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000242 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000243 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 int properties_length = constant_properties->length();
245 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000246 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000247 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000249 for (int p = 0; p != properties_length; p += 2) {
250 Object* key = constant_properties->get(p);
251 uint32_t element_index = 0;
252 if (key->IsSymbol()) {
253 number_of_symbol_keys++;
254 } else if (key->ToArrayIndex(&element_index)) {
255 // An index key does not require space in the property backing store.
256 number_of_properties--;
257 } else {
258 // Bail out as a non-symbol non-index key makes caching impossible.
259 // ASSERT to make sure that the if condition after the loop is false.
260 ASSERT(number_of_symbol_keys != number_of_properties);
261 break;
262 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000263 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000264 // If we only have symbols and array indices among keys then we can
265 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000266 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000267 if ((number_of_symbol_keys == number_of_properties) &&
268 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000270 Handle<FixedArray> keys =
271 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000272 if (number_of_symbol_keys > 0) {
273 int index = 0;
274 for (int p = 0; p < properties_length; p += 2) {
275 Object* key = constant_properties->get(p);
276 if (key->IsSymbol()) {
277 keys->set(index++, key);
278 }
279 }
280 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000281 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000282 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000283 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 }
285 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000286 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000287 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000288 Handle<Map>(context->object_function()->initial_map()),
289 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000290}
291
292
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000293static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000294 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295 Handle<FixedArray> literals,
296 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000297
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000298
299static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000301 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000302 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 bool should_have_fast_elements,
304 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000305 // Get the global context from the literals array. This is the
306 // context in which the function was created and we use the object
307 // function from this context to create the object literal. We do
308 // not use the object function from the current global context
309 // because this might be the object function from another context
310 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000311 Handle<Context> context =
312 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 // In case we have function literals, we want the object to be in
315 // slow properties mode for now. We don't go in the map cache because
316 // maps with constant functions can't be shared if the functions are
317 // not the same (which is the common case).
318 bool is_result_from_cache = false;
319 Handle<Map> map = has_function_literal
320 ? Handle<Map>(context->object_function()->initial_map())
321 : ComputeObjectLiteralMap(context,
322 constant_properties,
323 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000326
327 // Normalize the elements of the boilerplate to save space if needed.
328 if (!should_have_fast_elements) NormalizeElements(boilerplate);
329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 // Add the constant properties to the boilerplate.
331 int length = constant_properties->length();
332 bool should_transform =
333 !is_result_from_cache && boilerplate->HasFastProperties();
334 if (should_transform || has_function_literal) {
335 // Normalize the properties of object to avoid n^2 behavior
336 // when extending the object multiple properties. Indicate the number of
337 // properties to be added.
338 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
339 }
340
341 for (int index = 0; index < length; index +=2) {
342 Handle<Object> key(constant_properties->get(index+0), isolate);
343 Handle<Object> value(constant_properties->get(index+1), isolate);
344 if (value->IsFixedArray()) {
345 // The value contains the constant_properties of a
346 // simple object or array literal.
347 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
348 value = CreateLiteralBoilerplate(isolate, literals, array);
349 if (value.is_null()) return value;
350 }
351 Handle<Object> result;
352 uint32_t element_index = 0;
353 if (key->IsSymbol()) {
354 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
355 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000356 result = SetOwnElement(boilerplate,
357 element_index,
358 value,
359 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 Handle<String> name(String::cast(*key));
362 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000363 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
364 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000366 } else if (key->ToArrayIndex(&element_index)) {
367 // Array index (uint32).
368 result = SetOwnElement(boilerplate,
369 element_index,
370 value,
371 kNonStrictMode);
372 } else {
373 // Non-uint32 number.
374 ASSERT(key->IsNumber());
375 double num = key->Number();
376 char arr[100];
377 Vector<char> buffer(arr, ARRAY_SIZE(arr));
378 const char* str = DoubleToCString(num, buffer);
379 Handle<String> name =
380 isolate->factory()->NewStringFromAscii(CStrVector(str));
381 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
382 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000384 // If setting the property on the boilerplate throws an
385 // exception, the exception is converted to an empty handle in
386 // the handle based operations. In that case, we need to
387 // convert back to an exception.
388 if (result.is_null()) return result;
389 }
390
391 // Transform to fast properties if necessary. For object literals with
392 // containing function literals we defer this operation until after all
393 // computed properties have been assigned so that we can generate
394 // constant function properties.
395 if (should_transform && !has_function_literal) {
396 TransformToFastProperties(boilerplate,
397 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 }
399
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000400 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000401}
402
403
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000404static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406 Handle<FixedArray> literals,
407 Handle<FixedArray> elements) {
408 // Create the JSArray.
409 Handle<JSFunction> constructor(
410 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 const bool is_cow =
414 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000415 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000416 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417
418 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000419 if (is_cow) {
420#ifdef DEBUG
421 // Copy-on-write arrays must be shallow (and simple).
422 for (int i = 0; i < content->length(); i++) {
423 ASSERT(!content->get(i)->IsFixedArray());
424 }
425#endif
426 } else {
427 for (int i = 0; i < content->length(); i++) {
428 if (content->get(i)->IsFixedArray()) {
429 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000430 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000431 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
432 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 if (result.is_null()) return result;
435 content->set(i, *result);
436 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000437 }
438 }
439
440 // Set the elements.
441 Handle<JSArray>::cast(object)->SetContent(*content);
442 return object;
443}
444
445
446static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000448 Handle<FixedArray> literals,
449 Handle<FixedArray> array) {
450 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000451 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000454 return CreateObjectLiteralBoilerplate(isolate,
455 literals,
456 elements,
457 true,
458 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000459 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000460 return CreateObjectLiteralBoilerplate(isolate,
461 literals,
462 elements,
463 false,
464 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000465 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 default:
468 UNREACHABLE();
469 return Handle<Object>::null();
470 }
471}
472
473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000474RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000475 // Takes a FixedArray of elements containing the literal elements of
476 // the array literal and produces JSArray with those elements.
477 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000478 // which contains the context from which to get the Array function
479 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000480 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481 ASSERT(args.length() == 3);
482 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
483 CONVERT_SMI_CHECKED(literals_index, args[1]);
484 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000486 Handle<Object> object =
487 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000488 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000490 // Update the functions literal and return the boilerplate.
491 literals->set(literals_index, *object);
492 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000493}
494
495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000496RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000497 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000498 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000499 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
500 CONVERT_SMI_CHECKED(literals_index, args[1]);
501 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 CONVERT_SMI_CHECKED(flags, args[3]);
503 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
504 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000505
506 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000507 Handle<Object> boilerplate(literals->get(literals_index), isolate);
508 if (*boilerplate == isolate->heap()->undefined_value()) {
509 boilerplate = CreateObjectLiteralBoilerplate(isolate,
510 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000511 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512 should_have_fast_elements,
513 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 if (boilerplate.is_null()) return Failure::Exception();
515 // Update the functions literal and return the boilerplate.
516 literals->set(literals_index, *boilerplate);
517 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000518 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000519}
520
521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000522RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000524 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000525 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
526 CONVERT_SMI_CHECKED(literals_index, args[1]);
527 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 CONVERT_SMI_CHECKED(flags, args[3]);
529 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
530 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531
532 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 Handle<Object> boilerplate(literals->get(literals_index), isolate);
534 if (*boilerplate == isolate->heap()->undefined_value()) {
535 boilerplate = CreateObjectLiteralBoilerplate(isolate,
536 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000537 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 should_have_fast_elements,
539 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540 if (boilerplate.is_null()) return Failure::Exception();
541 // Update the functions literal and return the boilerplate.
542 literals->set(literals_index, *boilerplate);
543 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000545}
546
547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000548RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 ASSERT(args.length() == 3);
551 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
552 CONVERT_SMI_CHECKED(literals_index, args[1]);
553 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
554
555 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 Handle<Object> boilerplate(literals->get(literals_index), isolate);
557 if (*boilerplate == isolate->heap()->undefined_value()) {
558 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000559 if (boilerplate.is_null()) return Failure::Exception();
560 // Update the functions literal and return the boilerplate.
561 literals->set(literals_index, *boilerplate);
562 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000564}
565
566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 ASSERT(args.length() == 3);
570 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
571 CONVERT_SMI_CHECKED(literals_index, args[1]);
572 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
573
574 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000575 Handle<Object> boilerplate(literals->get(literals_index), isolate);
576 if (*boilerplate == isolate->heap()->undefined_value()) {
577 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 if (boilerplate.is_null()) return Failure::Exception();
579 // Update the functions literal and return the boilerplate.
580 literals->set(literals_index, *boilerplate);
581 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000582 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000584 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000585 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000587}
588
589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000590RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000591 ASSERT(args.length() == 2);
592 CONVERT_CHECKED(String, key, args[0]);
593 Object* value = args[1];
594 // Create a catch context extension object.
595 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000596 isolate->context()->global_context()->
597 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000598 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000600 if (!maybe_object->ToObject(&object)) return maybe_object;
601 }
ager@chromium.org32912102009-01-16 10:38:43 +0000602 // Assign the exception value to the catch variable and make sure
603 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000604 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000605 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
606 JSObject::cast(object)->SetProperty(
607 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000608 if (!maybe_value->ToObject(&value)) return maybe_value;
609 }
ager@chromium.org32912102009-01-16 10:38:43 +0000610 return object;
611}
612
613
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000614RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615 NoHandleAllocation ha;
616 ASSERT(args.length() == 1);
617 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 return JSObject::cast(obj)->class_name();
620}
621
ager@chromium.org7c537e22008-10-16 08:43:32 +0000622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000623RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 NoHandleAllocation ha;
625 ASSERT(args.length() == 2);
626 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
627 Object* O = args[0];
628 Object* V = args[1];
629 while (true) {
630 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000631 if (prototype->IsNull()) return isolate->heap()->false_value();
632 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 V = prototype;
634 }
635}
636
637
ager@chromium.org9085a012009-05-11 19:22:57 +0000638// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 CONVERT_CHECKED(JSObject, jsobject, args[0]);
643 CONVERT_CHECKED(JSObject, proto, args[1]);
644
645 // Sanity checks. The old prototype (that we are replacing) could
646 // theoretically be null, but if it is not null then check that we
647 // didn't already install a hidden prototype here.
648 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
649 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
650 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
651
652 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000653 Object* map_or_failure;
654 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
655 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
656 return maybe_map_or_failure;
657 }
658 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000659 Map* new_proto_map = Map::cast(map_or_failure);
660
lrn@chromium.org303ada72010-10-27 09:33:13 +0000661 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
662 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
663 return maybe_map_or_failure;
664 }
665 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000666 Map* new_map = Map::cast(map_or_failure);
667
668 // Set proto's prototype to be the old prototype of the object.
669 new_proto_map->set_prototype(jsobject->GetPrototype());
670 proto->set_map(new_proto_map);
671 new_proto_map->set_is_hidden_prototype();
672
673 // Set the object's prototype to proto.
674 new_map->set_prototype(proto);
675 jsobject->set_map(new_map);
676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000677 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000678}
679
680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000681RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000682 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000683 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000684 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000685 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686}
687
688
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000689// Recursively traverses hidden prototypes if property is not found
690static void GetOwnPropertyImplementation(JSObject* obj,
691 String* name,
692 LookupResult* result) {
693 obj->LocalLookupRealNamedProperty(name, result);
694
695 if (!result->IsProperty()) {
696 Object* proto = obj->GetPrototype();
697 if (proto->IsJSObject() &&
698 JSObject::cast(proto)->map()->is_hidden_prototype())
699 GetOwnPropertyImplementation(JSObject::cast(proto),
700 name, result);
701 }
702}
703
704
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000705static bool CheckAccessException(LookupResult* result,
706 v8::AccessType access_type) {
707 if (result->type() == CALLBACKS) {
708 Object* callback = result->GetCallbackObject();
709 if (callback->IsAccessorInfo()) {
710 AccessorInfo* info = AccessorInfo::cast(callback);
711 bool can_access =
712 (access_type == v8::ACCESS_HAS &&
713 (info->all_can_read() || info->all_can_write())) ||
714 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
715 (access_type == v8::ACCESS_SET && info->all_can_write());
716 return can_access;
717 }
718 }
719
720 return false;
721}
722
723
724static bool CheckAccess(JSObject* obj,
725 String* name,
726 LookupResult* result,
727 v8::AccessType access_type) {
728 ASSERT(result->IsProperty());
729
730 JSObject* holder = result->holder();
731 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000732 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000733 while (true) {
734 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000735 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000736 // Access check callback denied the access, but some properties
737 // can have a special permissions which override callbacks descision
738 // (currently see v8::AccessControl).
739 break;
740 }
741
742 if (current == holder) {
743 return true;
744 }
745
746 current = JSObject::cast(current->GetPrototype());
747 }
748
749 // API callbacks can have per callback access exceptions.
750 switch (result->type()) {
751 case CALLBACKS: {
752 if (CheckAccessException(result, access_type)) {
753 return true;
754 }
755 break;
756 }
757 case INTERCEPTOR: {
758 // If the object has an interceptor, try real named properties.
759 // Overwrite the result to fetch the correct property later.
760 holder->LookupRealNamedProperty(name, result);
761 if (result->IsProperty()) {
762 if (CheckAccessException(result, access_type)) {
763 return true;
764 }
765 }
766 break;
767 }
768 default:
769 break;
770 }
771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000772 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000773 return false;
774}
775
776
777// TODO(1095): we should traverse hidden prototype hierachy as well.
778static bool CheckElementAccess(JSObject* obj,
779 uint32_t index,
780 v8::AccessType access_type) {
781 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000782 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000783 return false;
784 }
785
786 return true;
787}
788
789
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000790// Enumerator used as indices into the array returned from GetOwnProperty
791enum PropertyDescriptorIndices {
792 IS_ACCESSOR_INDEX,
793 VALUE_INDEX,
794 GETTER_INDEX,
795 SETTER_INDEX,
796 WRITABLE_INDEX,
797 ENUMERABLE_INDEX,
798 CONFIGURABLE_INDEX,
799 DESCRIPTOR_SIZE
800};
801
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000802// Returns an array with the property description:
803// if args[1] is not a property on args[0]
804// returns undefined
805// if args[1] is a data property on args[0]
806// [false, value, Writeable, Enumerable, Configurable]
807// if args[1] is an accessor on args[0]
808// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000809RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000810 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000811 Heap* heap = isolate->heap();
812 HandleScope scope(isolate);
813 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
814 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000815 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000816 CONVERT_ARG_CHECKED(JSObject, obj, 0);
817 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000818
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000819 // This could be an element.
820 uint32_t index;
821 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000822 switch (obj->HasLocalElement(index)) {
823 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000824 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000825
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000826 case JSObject::STRING_CHARACTER_ELEMENT: {
827 // Special handling of string objects according to ECMAScript 5
828 // 15.5.5.2. Note that this might be a string object with elements
829 // other than the actual string value. This is covered by the
830 // subsequent cases.
831 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
832 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000833 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000834
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000835 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000836 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000837 elms->set(WRITABLE_INDEX, heap->false_value());
838 elms->set(ENUMERABLE_INDEX, heap->false_value());
839 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000840 return *desc;
841 }
842
843 case JSObject::INTERCEPTED_ELEMENT:
844 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000845 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000846 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000847 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000848 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000849 elms->set(WRITABLE_INDEX, heap->true_value());
850 elms->set(ENUMERABLE_INDEX, heap->true_value());
851 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 return *desc;
853 }
854
855 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856 Handle<JSObject> holder = obj;
857 if (obj->IsJSGlobalProxy()) {
858 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000860 ASSERT(proto->IsJSGlobalObject());
861 holder = Handle<JSObject>(JSObject::cast(proto));
862 }
863 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000864 int entry = dictionary->FindEntry(index);
865 ASSERT(entry != NumberDictionary::kNotFound);
866 PropertyDetails details = dictionary->DetailsAt(entry);
867 switch (details.type()) {
868 case CALLBACKS: {
869 // This is an accessor property with getter and/or setter.
870 FixedArray* callbacks =
871 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000872 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000873 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
874 elms->set(GETTER_INDEX, callbacks->get(0));
875 }
876 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
877 elms->set(SETTER_INDEX, callbacks->get(1));
878 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000879 break;
880 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000881 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000882 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000884 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000885 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000886 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000887 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000888 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000889 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000890 default:
891 UNREACHABLE();
892 break;
893 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
895 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000896 return *desc;
897 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000898 }
899 }
900
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000901 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000902 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000903
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000904 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000906 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000907
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000908 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000910 }
911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000912 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
913 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000914
915 bool is_js_accessor = (result.type() == CALLBACKS) &&
916 (result.GetCallbackObject()->IsFixedArray());
917
918 if (is_js_accessor) {
919 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000920 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000921
922 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
923 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
924 elms->set(GETTER_INDEX, structure->get(0));
925 }
926 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
927 elms->set(SETTER_INDEX, structure->get(1));
928 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000929 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000930 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
931 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000932
933 PropertyAttributes attrs;
934 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000935 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000936 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
937 if (!maybe_value->ToObject(&value)) return maybe_value;
938 }
939 elms->set(VALUE_INDEX, value);
940 }
941
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000942 return *desc;
943}
944
945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000946RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000947 ASSERT(args.length() == 1);
948 CONVERT_CHECKED(JSObject, obj, args[0]);
949 return obj->PreventExtensions();
950}
951
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000953RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000954 ASSERT(args.length() == 1);
955 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000956 if (obj->IsJSGlobalProxy()) {
957 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000959 ASSERT(proto->IsJSGlobalObject());
960 obj = JSObject::cast(proto);
961 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000962 return obj->map()->is_extensible() ? isolate->heap()->true_value()
963 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000964}
965
966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000967RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000969 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000970 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
971 CONVERT_ARG_CHECKED(String, pattern, 1);
972 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000973 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
974 if (result.is_null()) return Failure::Exception();
975 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000976}
977
978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000979RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000982 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984}
985
986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000987RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 ASSERT(args.length() == 1);
989 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000990 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000991 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992}
993
994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000995RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996 ASSERT(args.length() == 2);
997 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000999 int index = field->value();
1000 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1001 InstanceType type = templ->map()->instance_type();
1002 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1003 type == OBJECT_TEMPLATE_INFO_TYPE);
1004 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001005 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001006 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1007 } else {
1008 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1009 }
1010 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011}
1012
1013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001014RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001015 ASSERT(args.length() == 1);
1016 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001017 Map* old_map = object->map();
1018 bool needs_access_checks = old_map->is_access_check_needed();
1019 if (needs_access_checks) {
1020 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001021 Object* new_map;
1022 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1023 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1024 }
ager@chromium.org32912102009-01-16 10:38:43 +00001025
1026 Map::cast(new_map)->set_is_access_check_needed(false);
1027 object->set_map(Map::cast(new_map));
1028 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001029 return needs_access_checks ? isolate->heap()->true_value()
1030 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001031}
1032
1033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001034RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001035 ASSERT(args.length() == 1);
1036 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001037 Map* old_map = object->map();
1038 if (!old_map->is_access_check_needed()) {
1039 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001040 Object* new_map;
1041 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1042 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1043 }
ager@chromium.org32912102009-01-16 10:38:43 +00001044
1045 Map::cast(new_map)->set_is_access_check_needed(true);
1046 object->set_map(Map::cast(new_map));
1047 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001048 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001049}
1050
1051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052static Failure* ThrowRedeclarationError(Isolate* isolate,
1053 const char* type,
1054 Handle<String> name) {
1055 HandleScope scope(isolate);
1056 Handle<Object> type_handle =
1057 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058 Handle<Object> args[2] = { type_handle, name };
1059 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1061 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062}
1063
1064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001065RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001066 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 HandleScope scope(isolate);
1068 Handle<GlobalObject> global = Handle<GlobalObject>(
1069 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001070
ager@chromium.org3811b432009-10-28 14:53:37 +00001071 Handle<Context> context = args.at<Context>(0);
1072 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001074 StrictModeFlag strict_mode =
1075 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1076 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077
1078 // Compute the property attributes. According to ECMA-262, section
1079 // 13, page 71, the property must be read-only and
1080 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1081 // property as read-only, so we don't either.
1082 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1083
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084 // Traverse the name/value pairs and set the properties.
1085 int length = pairs->length();
1086 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001090
1091 // We have to declare a global const property. To capture we only
1092 // assign to it when evaluating the assignment for "const x =
1093 // <expr>" the initial value is the hole.
1094 bool is_const_property = value->IsTheHole();
1095
1096 if (value->IsUndefined() || is_const_property) {
1097 // Lookup the property in the global object, and don't set the
1098 // value of the variable if the property is already there.
1099 LookupResult lookup;
1100 global->Lookup(*name, &lookup);
1101 if (lookup.IsProperty()) {
1102 // Determine if the property is local by comparing the holder
1103 // against the global object. The information will be used to
1104 // avoid throwing re-declaration errors when declaring
1105 // variables or constants that exist in the prototype chain.
1106 bool is_local = (*global == lookup.holder());
1107 // Get the property attributes and determine if the property is
1108 // read-only.
1109 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1110 bool is_read_only = (attributes & READ_ONLY) != 0;
1111 if (lookup.type() == INTERCEPTOR) {
1112 // If the interceptor says the property is there, we
1113 // just return undefined without overwriting the property.
1114 // Otherwise, we continue to setting the property.
1115 if (attributes != ABSENT) {
1116 // Check if the existing property conflicts with regards to const.
1117 if (is_local && (is_read_only || is_const_property)) {
1118 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001119 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120 };
1121 // The property already exists without conflicting: Go to
1122 // the next declaration.
1123 continue;
1124 }
1125 // Fall-through and introduce the absent property by using
1126 // SetProperty.
1127 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001128 // For const properties, we treat a callback with this name
1129 // even in the prototype as a conflicting declaration.
1130 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001131 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001132 }
1133 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 if (is_local && (is_read_only || is_const_property)) {
1135 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001136 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 }
1138 // The property already exists without conflicting: Go to
1139 // the next declaration.
1140 continue;
1141 }
1142 }
1143 } else {
1144 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001145 Handle<SharedFunctionInfo> shared =
1146 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1149 context,
1150 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 value = function;
1152 }
1153
1154 LookupResult lookup;
1155 global->LocalLookup(*name, &lookup);
1156
1157 PropertyAttributes attributes = is_const_property
1158 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1159 : base;
1160
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001161 // There's a local property that we need to overwrite because
1162 // we're either declaring a function or there's an interceptor
1163 // that claims the property is absent.
1164 //
1165 // Check for conflicting re-declarations. We cannot have
1166 // conflicting types in case of intercepted properties because
1167 // they are absent.
1168 if (lookup.IsProperty() &&
1169 (lookup.type() != INTERCEPTOR) &&
1170 (lookup.IsReadOnly() || is_const_property)) {
1171 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001173 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001175 // Safari does not allow the invocation of callback setters for
1176 // function declarations. To mimic this behavior, we do not allow
1177 // the invocation of setters for function values. This makes a
1178 // difference for global functions with the same names as event
1179 // handlers such as "function onload() {}". Firefox does call the
1180 // onload setter in those case and Safari does not. We follow
1181 // Safari for compatibility.
1182 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001183 // Do not change DONT_DELETE to false from true.
1184 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1185 attributes = static_cast<PropertyAttributes>(
1186 attributes | (lookup.GetAttributes() & DONT_DELETE));
1187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001188 RETURN_IF_EMPTY_HANDLE(isolate,
1189 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001190 name,
1191 value,
1192 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 RETURN_IF_EMPTY_HANDLE(isolate,
1195 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001196 name,
1197 value,
1198 attributes,
1199 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 }
1201 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001203 ASSERT(!isolate->has_pending_exception());
1204 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205}
1206
1207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001208RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001210 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211
ager@chromium.org7c537e22008-10-16 08:43:32 +00001212 CONVERT_ARG_CHECKED(Context, context, 0);
1213 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001215 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001216 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001217 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218
1219 // Declarations are always done in the function context.
1220 context = Handle<Context>(context->fcontext());
1221
1222 int index;
1223 PropertyAttributes attributes;
1224 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001225 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 context->Lookup(name, flags, &index, &attributes);
1227
1228 if (attributes != ABSENT) {
1229 // The name was declared before; check for conflicting
1230 // re-declarations: This is similar to the code in parser.cc in
1231 // the AstBuildingParser::Declare function.
1232 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1233 // Functions are not read-only.
1234 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1235 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001236 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237 }
1238
1239 // Initialize it if necessary.
1240 if (*initial_value != NULL) {
1241 if (index >= 0) {
1242 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001243 // the function context or the arguments object.
1244 if (holder->IsContext()) {
1245 ASSERT(holder.is_identical_to(context));
1246 if (((attributes & READ_ONLY) == 0) ||
1247 context->get(index)->IsTheHole()) {
1248 context->set(index, *initial_value);
1249 }
1250 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001251 // The holder is an arguments object.
1252 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001253 Handle<Object> result = SetElement(arguments, index, initial_value,
1254 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001255 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256 }
1257 } else {
1258 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001259 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001260 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001262 SetProperty(context_ext, name, initial_value,
1263 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264 }
1265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001268 // The property is not in the function context. It needs to be
1269 // "declared" in the function context's extension context, or in the
1270 // global context.
1271 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001272 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001273 // The function context's extension context exists - use it.
1274 context_ext = Handle<JSObject>(context->extension());
1275 } else {
1276 // The function context's extension context does not exists - allocate
1277 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001278 context_ext = isolate->factory()->NewJSObject(
1279 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001280 // And store it in the extension slot.
1281 context->set_extension(*context_ext);
1282 }
1283 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284
ager@chromium.org7c537e22008-10-16 08:43:32 +00001285 // Declare the property by setting it to the initial value if provided,
1286 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1287 // constant declarations).
1288 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001289 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001290 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001291 // Declaring a const context slot is a conflicting declaration if
1292 // there is a callback with that name in a prototype. It is
1293 // allowed to introduce const variables in
1294 // JSContextExtensionObjects. They are treated specially in
1295 // SetProperty and no setters are invoked for those since they are
1296 // not real JSObjects.
1297 if (initial_value->IsTheHole() &&
1298 !context_ext->IsJSContextExtensionObject()) {
1299 LookupResult lookup;
1300 context_ext->Lookup(*name, &lookup);
1301 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001303 }
1304 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001305 RETURN_IF_EMPTY_HANDLE(isolate,
1306 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001307 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001308 }
1309
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311}
1312
1313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001314RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001316 // args[0] == name
1317 // args[1] == strict_mode
1318 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
1320 // Determine if we need to assign to the variable if it already
1321 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001322 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1323 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324
1325 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001327 RUNTIME_ASSERT(args[1]->IsSmi());
1328 StrictModeFlag strict_mode =
1329 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1330 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331
1332 // According to ECMA-262, section 12.2, page 62, the property must
1333 // not be deletable.
1334 PropertyAttributes attributes = DONT_DELETE;
1335
1336 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001337 // there, there is a property with this name in the prototype chain.
1338 // We follow Safari and Firefox behavior and only set the property
1339 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001340 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001341 // Note that objects can have hidden prototypes, so we need to traverse
1342 // the whole chain of hidden prototypes to do a 'local' lookup.
1343 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001345 while (true) {
1346 real_holder->LocalLookup(*name, &lookup);
1347 if (lookup.IsProperty()) {
1348 // Determine if this is a redeclaration of something read-only.
1349 if (lookup.IsReadOnly()) {
1350 // If we found readonly property on one of hidden prototypes,
1351 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001352 if (real_holder != isolate->context()->global()) break;
1353 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001354 }
1355
1356 // Determine if this is a redeclaration of an intercepted read-only
1357 // property and figure out if the property exists at all.
1358 bool found = true;
1359 PropertyType type = lookup.type();
1360 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001361 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001362 Handle<JSObject> holder(real_holder);
1363 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1364 real_holder = *holder;
1365 if (intercepted == ABSENT) {
1366 // The interceptor claims the property isn't there. We need to
1367 // make sure to introduce it.
1368 found = false;
1369 } else if ((intercepted & READ_ONLY) != 0) {
1370 // The property is present, but read-only. Since we're trying to
1371 // overwrite it with a variable declaration we must throw a
1372 // re-declaration error. However if we found readonly property
1373 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 if (real_holder != isolate->context()->global()) break;
1375 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001376 }
1377 }
1378
1379 if (found && !assign) {
1380 // The global property is there and we're not assigning any value
1381 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001382 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001383 }
1384
1385 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001386 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001387 return real_holder->SetProperty(
1388 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001389 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001390
1391 Object* proto = real_holder->GetPrototype();
1392 if (!proto->IsJSObject())
1393 break;
1394
1395 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1396 break;
1397
1398 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 }
1400
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001401 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001402 if (assign) {
1403 return global->SetProperty(*name, args[2], attributes, strict_mode);
1404 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406}
1407
1408
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001409RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 // All constants are declared with an initial value. The name
1411 // of the constant is the first argument and the initial value
1412 // is the second.
1413 RUNTIME_ASSERT(args.length() == 2);
1414 CONVERT_ARG_CHECKED(String, name, 0);
1415 Handle<Object> value = args.at<Object>(1);
1416
1417 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419
1420 // According to ECMA-262, section 12.2, page 62, the property must
1421 // not be deletable. Since it's a const, it must be READ_ONLY too.
1422 PropertyAttributes attributes =
1423 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1424
1425 // Lookup the property locally in the global object. If it isn't
1426 // there, we add the property and take special precautions to always
1427 // add it as a local property even in case of callbacks in the
1428 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001429 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 LookupResult lookup;
1431 global->LocalLookup(*name, &lookup);
1432 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001433 return global->SetLocalPropertyIgnoreAttributes(*name,
1434 *value,
1435 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436 }
1437
1438 // Determine if this is a redeclaration of something not
1439 // read-only. In case the result is hidden behind an interceptor we
1440 // need to ask it for the property attributes.
1441 if (!lookup.IsReadOnly()) {
1442 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001443 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 }
1445
1446 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1447
1448 // Throw re-declaration error if the intercepted property is present
1449 // but not read-only.
1450 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001451 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452 }
1453
1454 // Restore global object from context (in case of GC) and continue
1455 // with setting the value because the property is either absent or
1456 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 HandleScope handle_scope(isolate);
1458 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001459
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001460 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461 // property through an interceptor and only do it if it's
1462 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 RETURN_IF_EMPTY_HANDLE(isolate,
1465 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001466 name,
1467 value,
1468 attributes,
1469 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470 return *value;
1471 }
1472
1473 // Set the value, but only we're assigning the initial value to a
1474 // constant. For now, we determine this by checking if the
1475 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001476 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477 PropertyType type = lookup.type();
1478 if (type == FIELD) {
1479 FixedArray* properties = global->properties();
1480 int index = lookup.GetFieldIndex();
1481 if (properties->get(index)->IsTheHole()) {
1482 properties->set(index, *value);
1483 }
1484 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001485 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1486 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487 }
1488 } else {
1489 // Ignore re-initialization of constants that have already been
1490 // assigned a function value.
1491 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1492 }
1493
1494 // Use the set value as the result of the operation.
1495 return *value;
1496}
1497
1498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001499RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001500 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 ASSERT(args.length() == 3);
1502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001503 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504 ASSERT(!value->IsTheHole());
1505 CONVERT_ARG_CHECKED(Context, context, 1);
1506 Handle<String> name(String::cast(args[2]));
1507
1508 // Initializations are always done in the function context.
1509 context = Handle<Context>(context->fcontext());
1510
1511 int index;
1512 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001513 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001514 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 context->Lookup(name, flags, &index, &attributes);
1516
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001517 // In most situations, the property introduced by the const
1518 // declaration should be present in the context extension object.
1519 // However, because declaration and initialization are separate, the
1520 // property might have been deleted (if it was introduced by eval)
1521 // before we reach the initialization point.
1522 //
1523 // Example:
1524 //
1525 // function f() { eval("delete x; const x;"); }
1526 //
1527 // In that case, the initialization behaves like a normal assignment
1528 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001530 // Property was found in a context.
1531 if (holder->IsContext()) {
1532 // The holder cannot be the function context. If it is, there
1533 // should have been a const redeclaration error when declaring
1534 // the const property.
1535 ASSERT(!holder.is_identical_to(context));
1536 if ((attributes & READ_ONLY) == 0) {
1537 Handle<Context>::cast(holder)->set(index, *value);
1538 }
1539 } else {
1540 // The holder is an arguments object.
1541 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001542 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001543 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001544 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001545 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001546 }
1547 return *value;
1548 }
1549
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001550 // The property could not be found, we introduce it in the global
1551 // context.
1552 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001553 Handle<JSObject> global = Handle<JSObject>(
1554 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001555 // Strict mode not needed (const disallowed in strict mode).
1556 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001557 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001558 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001559 return *value;
1560 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001562 // The property was present in a context extension object.
1563 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001565 if (*context_ext == context->extension()) {
1566 // This is the property that was introduced by the const
1567 // declaration. Set it if it hasn't been set before. NOTE: We
1568 // cannot use GetProperty() to get the current value as it
1569 // 'unholes' the value.
1570 LookupResult lookup;
1571 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1572 ASSERT(lookup.IsProperty()); // the property was declared
1573 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1574
1575 PropertyType type = lookup.type();
1576 if (type == FIELD) {
1577 FixedArray* properties = context_ext->properties();
1578 int index = lookup.GetFieldIndex();
1579 if (properties->get(index)->IsTheHole()) {
1580 properties->set(index, *value);
1581 }
1582 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001583 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1584 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001585 }
1586 } else {
1587 // We should not reach here. Any real, named property should be
1588 // either a field or a dictionary slot.
1589 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590 }
1591 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001592 // The property was found in a different context extension object.
1593 // Set it if it is not a read-only property.
1594 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001595 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001596 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001597 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001598 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001599 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001601
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 return *value;
1603}
1604
1605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001606RUNTIME_FUNCTION(MaybeObject*,
1607 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001608 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001609 ASSERT(args.length() == 2);
1610 CONVERT_ARG_CHECKED(JSObject, object, 0);
1611 CONVERT_SMI_CHECKED(properties, args[1]);
1612 if (object->HasFastProperties()) {
1613 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1614 }
1615 return *object;
1616}
1617
1618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001619RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001621 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001622 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1623 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001624 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001625 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001626 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001627 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001628 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001629 RUNTIME_ASSERT(index >= 0);
1630 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001631 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001632 Handle<Object> result = RegExpImpl::Exec(regexp,
1633 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001634 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001635 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001636 if (result.is_null()) return Failure::Exception();
1637 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638}
1639
1640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001641RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001642 ASSERT(args.length() == 3);
1643 CONVERT_SMI_CHECKED(elements_count, args[0]);
1644 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001646 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001647 Object* new_object;
1648 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001650 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1651 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001652 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001653 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1654 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001655 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1656 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001657 {
1658 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001659 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001660 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001661 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001662 }
1663 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001664 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001665 array->set_elements(elements);
1666 array->set_length(Smi::FromInt(elements_count));
1667 // Write in-object properties after the length of the array.
1668 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1669 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1670 return array;
1671}
1672
1673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001674RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001675 AssertNoAllocation no_alloc;
1676 ASSERT(args.length() == 5);
1677 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1678 CONVERT_CHECKED(String, source, args[1]);
1679
1680 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001682
1683 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001685
1686 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001687 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001688
1689 Map* map = regexp->map();
1690 Object* constructor = map->constructor();
1691 if (constructor->IsJSFunction() &&
1692 JSFunction::cast(constructor)->initial_map() == map) {
1693 // If we still have the original map, set in-object properties directly.
1694 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1695 // TODO(lrn): Consider skipping write barrier on booleans as well.
1696 // Both true and false should be in oldspace at all times.
1697 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1698 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1699 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1700 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1701 Smi::FromInt(0),
1702 SKIP_WRITE_BARRIER);
1703 return regexp;
1704 }
1705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001706 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001707 PropertyAttributes final =
1708 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1709 PropertyAttributes writable =
1710 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001711 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001712 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001713 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001714 source,
1715 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001716 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001718 global,
1719 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001720 ASSERT(!result->IsFailure());
1721 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001722 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001723 ignoreCase,
1724 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001725 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001727 multiline,
1728 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001729 ASSERT(!result->IsFailure());
1730 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001732 Smi::FromInt(0),
1733 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734 ASSERT(!result->IsFailure());
1735 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001736 return regexp;
1737}
1738
1739
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001740RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001742 ASSERT(args.length() == 1);
1743 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1744 // This is necessary to enable fast checks for absence of elements
1745 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001747 return Smi::FromInt(0);
1748}
1749
1750
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1752 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001753 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001754 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1756 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1757 Handle<JSFunction> optimized =
1758 isolate->factory()->NewFunction(key,
1759 JS_OBJECT_TYPE,
1760 JSObject::kHeaderSize,
1761 code,
1762 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001763 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001764 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001765 return optimized;
1766}
1767
1768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001769RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001771 ASSERT(args.length() == 1);
1772 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1773
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001774 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1775 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1776 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1777 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1778 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1779 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1780 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001781
1782 return *holder;
1783}
1784
1785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001786RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001787 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 Context* global_context =
1789 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001790 return global_context->global()->global_receiver();
1791}
1792
1793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001794RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001796 ASSERT(args.length() == 4);
1797 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1798 int index = Smi::cast(args[1])->value();
1799 Handle<String> pattern = args.at<String>(2);
1800 Handle<String> flags = args.at<String>(3);
1801
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001802 // Get the RegExp function from the context in the literals array.
1803 // This is the RegExp function from the context in which the
1804 // function was created. We do not use the RegExp function from the
1805 // current global context because this might be the RegExp function
1806 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001807 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001808 Handle<JSFunction>(
1809 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810 // Compute the regular expression literal.
1811 bool has_pending_exception;
1812 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001813 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1814 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001815 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 return Failure::Exception();
1818 }
1819 literals->set(index, *regexp);
1820 return *regexp;
1821}
1822
1823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001824RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001825 NoHandleAllocation ha;
1826 ASSERT(args.length() == 1);
1827
1828 CONVERT_CHECKED(JSFunction, f, args[0]);
1829 return f->shared()->name();
1830}
1831
1832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001833RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001834 NoHandleAllocation ha;
1835 ASSERT(args.length() == 2);
1836
1837 CONVERT_CHECKED(JSFunction, f, args[0]);
1838 CONVERT_CHECKED(String, name, args[1]);
1839 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001841}
1842
1843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001844RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001845 NoHandleAllocation ha;
1846 ASSERT(args.length() == 1);
1847
1848 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001849 Object* obj = f->RemovePrototype();
1850 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001851
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001852 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001853}
1854
1855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001856RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001858 ASSERT(args.length() == 1);
1859
1860 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1862 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001863
1864 return *GetScriptWrapper(Handle<Script>::cast(script));
1865}
1866
1867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001868RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 NoHandleAllocation ha;
1870 ASSERT(args.length() == 1);
1871
1872 CONVERT_CHECKED(JSFunction, f, args[0]);
1873 return f->shared()->GetSourceCode();
1874}
1875
1876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001877RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001878 NoHandleAllocation ha;
1879 ASSERT(args.length() == 1);
1880
1881 CONVERT_CHECKED(JSFunction, fun, args[0]);
1882 int pos = fun->shared()->start_position();
1883 return Smi::FromInt(pos);
1884}
1885
1886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001887RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001888 ASSERT(args.length() == 2);
1889
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001890 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001891 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1892
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001893 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1894
1895 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001896 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001897}
1898
1899
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001900RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001901 NoHandleAllocation ha;
1902 ASSERT(args.length() == 2);
1903
1904 CONVERT_CHECKED(JSFunction, fun, args[0]);
1905 CONVERT_CHECKED(String, name, args[1]);
1906 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001907 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001908}
1909
1910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001911RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912 NoHandleAllocation ha;
1913 ASSERT(args.length() == 2);
1914
1915 CONVERT_CHECKED(JSFunction, fun, args[0]);
1916 CONVERT_CHECKED(Smi, length, args[1]);
1917 fun->shared()->set_length(length->value());
1918 return length;
1919}
1920
1921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001922RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001923 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001924 ASSERT(args.length() == 2);
1925
1926 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001927 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001928 Object* obj;
1929 { MaybeObject* maybe_obj =
1930 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1931 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1932 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 return args[0]; // return TOS
1934}
1935
1936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001937RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001938 NoHandleAllocation ha;
1939 ASSERT(args.length() == 1);
1940
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001942 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1943 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001944}
1945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001947RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001948 NoHandleAllocation ha;
1949 ASSERT(args.length() == 1);
1950
1951 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001952 return f->IsBuiltin() ? isolate->heap()->true_value() :
1953 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001954}
1955
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001958 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001959 ASSERT(args.length() == 2);
1960
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001961 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 Handle<Object> code = args.at<Object>(1);
1963
1964 Handle<Context> context(target->context());
1965
1966 if (!code->IsNull()) {
1967 RUNTIME_ASSERT(code->IsJSFunction());
1968 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001969 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001970
1971 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001972 return Failure::Exception();
1973 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001974 // Since we don't store the source for this we should never
1975 // optimize this.
1976 shared->code()->set_optimizable(false);
1977
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001978 // Set the code, scope info, formal parameter count,
1979 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001980 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001981 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001982 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001983 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001984 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001985 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001986 // Set the source code of the target function to undefined.
1987 // SetCode is only used for built-in constructors like String,
1988 // Array, and Object, and some web code
1989 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001990 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001991 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001992 // Clear the optimization hints related to the compiled code as these are no
1993 // longer valid when the code is overwritten.
1994 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001995 context = Handle<Context>(fun->context());
1996
1997 // Make sure we get a fresh copy of the literal vector to avoid
1998 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001999 int number_of_literals = fun->NumberOfLiterals();
2000 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002001 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002002 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002003 // Insert the object, regexp and array functions in the literals
2004 // array prefix. These are the functions that will be used when
2005 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002006 literals->set(JSFunction::kLiteralGlobalContextIndex,
2007 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002008 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002009 // It's okay to skip the write barrier here because the literals
2010 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002011 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002012 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 }
2014
2015 target->set_context(*context);
2016 return *target;
2017}
2018
2019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002020RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002021 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002022 ASSERT(args.length() == 2);
2023 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2024 CONVERT_SMI_CHECKED(num, args[1]);
2025 RUNTIME_ASSERT(num >= 0);
2026 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002027 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002028}
2029
2030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002031MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2032 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002033 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002034 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002035 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002036 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002037 }
2038 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002039 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002040}
2041
2042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002043RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 NoHandleAllocation ha;
2045 ASSERT(args.length() == 2);
2046
2047 CONVERT_CHECKED(String, subject, args[0]);
2048 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002049 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002050
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002051 uint32_t i = 0;
2052 if (index->IsSmi()) {
2053 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002054 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002055 i = value;
2056 } else {
2057 ASSERT(index->IsHeapNumber());
2058 double value = HeapNumber::cast(index)->value();
2059 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002060 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002061
2062 // Flatten the string. If someone wants to get a char at an index
2063 // in a cons string, it is likely that more indices will be
2064 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002065 Object* flat;
2066 { MaybeObject* maybe_flat = subject->TryFlatten();
2067 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2068 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002069 subject = String::cast(flat);
2070
2071 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002072 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002073 }
2074
2075 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002076}
2077
2078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002079RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002080 NoHandleAllocation ha;
2081 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002082 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002083}
2084
lrn@chromium.org25156de2010-04-06 13:10:27 +00002085
2086class FixedArrayBuilder {
2087 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002088 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2089 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002090 length_(0) {
2091 // Require a non-zero initial size. Ensures that doubling the size to
2092 // extend the array will work.
2093 ASSERT(initial_capacity > 0);
2094 }
2095
2096 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2097 : array_(backing_store),
2098 length_(0) {
2099 // Require a non-zero initial size. Ensures that doubling the size to
2100 // extend the array will work.
2101 ASSERT(backing_store->length() > 0);
2102 }
2103
2104 bool HasCapacity(int elements) {
2105 int length = array_->length();
2106 int required_length = length_ + elements;
2107 return (length >= required_length);
2108 }
2109
2110 void EnsureCapacity(int elements) {
2111 int length = array_->length();
2112 int required_length = length_ + elements;
2113 if (length < required_length) {
2114 int new_length = length;
2115 do {
2116 new_length *= 2;
2117 } while (new_length < required_length);
2118 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002119 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002120 array_->CopyTo(0, *extended_array, 0, length_);
2121 array_ = extended_array;
2122 }
2123 }
2124
2125 void Add(Object* value) {
2126 ASSERT(length_ < capacity());
2127 array_->set(length_, value);
2128 length_++;
2129 }
2130
2131 void Add(Smi* value) {
2132 ASSERT(length_ < capacity());
2133 array_->set(length_, value);
2134 length_++;
2135 }
2136
2137 Handle<FixedArray> array() {
2138 return array_;
2139 }
2140
2141 int length() {
2142 return length_;
2143 }
2144
2145 int capacity() {
2146 return array_->length();
2147 }
2148
2149 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002150 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002151 result_array->set_length(Smi::FromInt(length_));
2152 return result_array;
2153 }
2154
2155 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2156 target_array->set_elements(*array_);
2157 target_array->set_length(Smi::FromInt(length_));
2158 return target_array;
2159 }
2160
2161 private:
2162 Handle<FixedArray> array_;
2163 int length_;
2164};
2165
2166
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002167// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002168const int kStringBuilderConcatHelperLengthBits = 11;
2169const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002170
2171template <typename schar>
2172static inline void StringBuilderConcatHelper(String*,
2173 schar*,
2174 FixedArray*,
2175 int);
2176
lrn@chromium.org25156de2010-04-06 13:10:27 +00002177typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2178 StringBuilderSubstringLength;
2179typedef BitField<int,
2180 kStringBuilderConcatHelperLengthBits,
2181 kStringBuilderConcatHelperPositionBits>
2182 StringBuilderSubstringPosition;
2183
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002184
2185class ReplacementStringBuilder {
2186 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002187 ReplacementStringBuilder(Heap* heap,
2188 Handle<String> subject,
2189 int estimated_part_count)
2190 : heap_(heap),
2191 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002192 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002193 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002194 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002195 // Require a non-zero initial size. Ensures that doubling the size to
2196 // extend the array will work.
2197 ASSERT(estimated_part_count > 0);
2198 }
2199
lrn@chromium.org25156de2010-04-06 13:10:27 +00002200 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2201 int from,
2202 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002203 ASSERT(from >= 0);
2204 int length = to - from;
2205 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002206 if (StringBuilderSubstringLength::is_valid(length) &&
2207 StringBuilderSubstringPosition::is_valid(from)) {
2208 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2209 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002210 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002211 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002212 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002213 builder->Add(Smi::FromInt(-length));
2214 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002215 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002216 }
2217
2218
2219 void EnsureCapacity(int elements) {
2220 array_builder_.EnsureCapacity(elements);
2221 }
2222
2223
2224 void AddSubjectSlice(int from, int to) {
2225 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002226 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002227 }
2228
2229
2230 void AddString(Handle<String> string) {
2231 int length = string->length();
2232 ASSERT(length > 0);
2233 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002234 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002235 is_ascii_ = false;
2236 }
2237 IncrementCharacterCount(length);
2238 }
2239
2240
2241 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002242 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002244 }
2245
2246 Handle<String> joined_string;
2247 if (is_ascii_) {
2248 joined_string = NewRawAsciiString(character_count_);
2249 AssertNoAllocation no_alloc;
2250 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2251 char* char_buffer = seq->GetChars();
2252 StringBuilderConcatHelper(*subject_,
2253 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002254 *array_builder_.array(),
2255 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002256 } else {
2257 // Non-ASCII.
2258 joined_string = NewRawTwoByteString(character_count_);
2259 AssertNoAllocation no_alloc;
2260 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2261 uc16* char_buffer = seq->GetChars();
2262 StringBuilderConcatHelper(*subject_,
2263 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002264 *array_builder_.array(),
2265 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002266 }
2267 return joined_string;
2268 }
2269
2270
2271 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002272 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002273 V8::FatalProcessOutOfMemory("String.replace result too large.");
2274 }
2275 character_count_ += by;
2276 }
2277
lrn@chromium.org25156de2010-04-06 13:10:27 +00002278 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002279 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002280 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002281
lrn@chromium.org25156de2010-04-06 13:10:27 +00002282 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002283 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002284 CALL_HEAP_FUNCTION(heap_->isolate(),
2285 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002286 }
2287
2288
2289 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002290 CALL_HEAP_FUNCTION(heap_->isolate(),
2291 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002292 }
2293
2294
2295 void AddElement(Object* element) {
2296 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002297 ASSERT(array_builder_.capacity() > array_builder_.length());
2298 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002299 }
2300
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002301 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002302 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002303 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002304 int character_count_;
2305 bool is_ascii_;
2306};
2307
2308
2309class CompiledReplacement {
2310 public:
2311 CompiledReplacement()
2312 : parts_(1), replacement_substrings_(0) {}
2313
2314 void Compile(Handle<String> replacement,
2315 int capture_count,
2316 int subject_length);
2317
2318 void Apply(ReplacementStringBuilder* builder,
2319 int match_from,
2320 int match_to,
2321 Handle<JSArray> last_match_info);
2322
2323 // Number of distinct parts of the replacement pattern.
2324 int parts() {
2325 return parts_.length();
2326 }
2327 private:
2328 enum PartType {
2329 SUBJECT_PREFIX = 1,
2330 SUBJECT_SUFFIX,
2331 SUBJECT_CAPTURE,
2332 REPLACEMENT_SUBSTRING,
2333 REPLACEMENT_STRING,
2334
2335 NUMBER_OF_PART_TYPES
2336 };
2337
2338 struct ReplacementPart {
2339 static inline ReplacementPart SubjectMatch() {
2340 return ReplacementPart(SUBJECT_CAPTURE, 0);
2341 }
2342 static inline ReplacementPart SubjectCapture(int capture_index) {
2343 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2344 }
2345 static inline ReplacementPart SubjectPrefix() {
2346 return ReplacementPart(SUBJECT_PREFIX, 0);
2347 }
2348 static inline ReplacementPart SubjectSuffix(int subject_length) {
2349 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2350 }
2351 static inline ReplacementPart ReplacementString() {
2352 return ReplacementPart(REPLACEMENT_STRING, 0);
2353 }
2354 static inline ReplacementPart ReplacementSubString(int from, int to) {
2355 ASSERT(from >= 0);
2356 ASSERT(to > from);
2357 return ReplacementPart(-from, to);
2358 }
2359
2360 // If tag <= 0 then it is the negation of a start index of a substring of
2361 // the replacement pattern, otherwise it's a value from PartType.
2362 ReplacementPart(int tag, int data)
2363 : tag(tag), data(data) {
2364 // Must be non-positive or a PartType value.
2365 ASSERT(tag < NUMBER_OF_PART_TYPES);
2366 }
2367 // Either a value of PartType or a non-positive number that is
2368 // the negation of an index into the replacement string.
2369 int tag;
2370 // The data value's interpretation depends on the value of tag:
2371 // tag == SUBJECT_PREFIX ||
2372 // tag == SUBJECT_SUFFIX: data is unused.
2373 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2374 // tag == REPLACEMENT_SUBSTRING ||
2375 // tag == REPLACEMENT_STRING: data is index into array of substrings
2376 // of the replacement string.
2377 // tag <= 0: Temporary representation of the substring of the replacement
2378 // string ranging over -tag .. data.
2379 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2380 // substring objects.
2381 int data;
2382 };
2383
2384 template<typename Char>
2385 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2386 Vector<Char> characters,
2387 int capture_count,
2388 int subject_length) {
2389 int length = characters.length();
2390 int last = 0;
2391 for (int i = 0; i < length; i++) {
2392 Char c = characters[i];
2393 if (c == '$') {
2394 int next_index = i + 1;
2395 if (next_index == length) { // No next character!
2396 break;
2397 }
2398 Char c2 = characters[next_index];
2399 switch (c2) {
2400 case '$':
2401 if (i > last) {
2402 // There is a substring before. Include the first "$".
2403 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2404 last = next_index + 1; // Continue after the second "$".
2405 } else {
2406 // Let the next substring start with the second "$".
2407 last = next_index;
2408 }
2409 i = next_index;
2410 break;
2411 case '`':
2412 if (i > last) {
2413 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2414 }
2415 parts->Add(ReplacementPart::SubjectPrefix());
2416 i = next_index;
2417 last = i + 1;
2418 break;
2419 case '\'':
2420 if (i > last) {
2421 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2422 }
2423 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2424 i = next_index;
2425 last = i + 1;
2426 break;
2427 case '&':
2428 if (i > last) {
2429 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2430 }
2431 parts->Add(ReplacementPart::SubjectMatch());
2432 i = next_index;
2433 last = i + 1;
2434 break;
2435 case '0':
2436 case '1':
2437 case '2':
2438 case '3':
2439 case '4':
2440 case '5':
2441 case '6':
2442 case '7':
2443 case '8':
2444 case '9': {
2445 int capture_ref = c2 - '0';
2446 if (capture_ref > capture_count) {
2447 i = next_index;
2448 continue;
2449 }
2450 int second_digit_index = next_index + 1;
2451 if (second_digit_index < length) {
2452 // Peek ahead to see if we have two digits.
2453 Char c3 = characters[second_digit_index];
2454 if ('0' <= c3 && c3 <= '9') { // Double digits.
2455 int double_digit_ref = capture_ref * 10 + c3 - '0';
2456 if (double_digit_ref <= capture_count) {
2457 next_index = second_digit_index;
2458 capture_ref = double_digit_ref;
2459 }
2460 }
2461 }
2462 if (capture_ref > 0) {
2463 if (i > last) {
2464 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2465 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002466 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002467 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2468 last = next_index + 1;
2469 }
2470 i = next_index;
2471 break;
2472 }
2473 default:
2474 i = next_index;
2475 break;
2476 }
2477 }
2478 }
2479 if (length > last) {
2480 if (last == 0) {
2481 parts->Add(ReplacementPart::ReplacementString());
2482 } else {
2483 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2484 }
2485 }
2486 }
2487
2488 ZoneList<ReplacementPart> parts_;
2489 ZoneList<Handle<String> > replacement_substrings_;
2490};
2491
2492
2493void CompiledReplacement::Compile(Handle<String> replacement,
2494 int capture_count,
2495 int subject_length) {
2496 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002497 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 AssertNoAllocation no_alloc;
2499 ParseReplacementPattern(&parts_,
2500 replacement->ToAsciiVector(),
2501 capture_count,
2502 subject_length);
2503 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002504 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002505 AssertNoAllocation no_alloc;
2506
2507 ParseReplacementPattern(&parts_,
2508 replacement->ToUC16Vector(),
2509 capture_count,
2510 subject_length);
2511 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002513 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002514 int substring_index = 0;
2515 for (int i = 0, n = parts_.length(); i < n; i++) {
2516 int tag = parts_[i].tag;
2517 if (tag <= 0) { // A replacement string slice.
2518 int from = -tag;
2519 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002520 replacement_substrings_.Add(
2521 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002522 parts_[i].tag = REPLACEMENT_SUBSTRING;
2523 parts_[i].data = substring_index;
2524 substring_index++;
2525 } else if (tag == REPLACEMENT_STRING) {
2526 replacement_substrings_.Add(replacement);
2527 parts_[i].data = substring_index;
2528 substring_index++;
2529 }
2530 }
2531}
2532
2533
2534void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2535 int match_from,
2536 int match_to,
2537 Handle<JSArray> last_match_info) {
2538 for (int i = 0, n = parts_.length(); i < n; i++) {
2539 ReplacementPart part = parts_[i];
2540 switch (part.tag) {
2541 case SUBJECT_PREFIX:
2542 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2543 break;
2544 case SUBJECT_SUFFIX: {
2545 int subject_length = part.data;
2546 if (match_to < subject_length) {
2547 builder->AddSubjectSlice(match_to, subject_length);
2548 }
2549 break;
2550 }
2551 case SUBJECT_CAPTURE: {
2552 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002553 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002554 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2555 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2556 if (from >= 0 && to > from) {
2557 builder->AddSubjectSlice(from, to);
2558 }
2559 break;
2560 }
2561 case REPLACEMENT_SUBSTRING:
2562 case REPLACEMENT_STRING:
2563 builder->AddString(replacement_substrings_[part.data]);
2564 break;
2565 default:
2566 UNREACHABLE();
2567 }
2568 }
2569}
2570
2571
2572
lrn@chromium.org303ada72010-10-27 09:33:13 +00002573MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002574 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002575 String* subject,
2576 JSRegExp* regexp,
2577 String* replacement,
2578 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002579 ASSERT(subject->IsFlat());
2580 ASSERT(replacement->IsFlat());
2581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002582 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002583
2584 int length = subject->length();
2585 Handle<String> subject_handle(subject);
2586 Handle<JSRegExp> regexp_handle(regexp);
2587 Handle<String> replacement_handle(replacement);
2588 Handle<JSArray> last_match_info_handle(last_match_info);
2589 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2590 subject_handle,
2591 0,
2592 last_match_info_handle);
2593 if (match.is_null()) {
2594 return Failure::Exception();
2595 }
2596 if (match->IsNull()) {
2597 return *subject_handle;
2598 }
2599
2600 int capture_count = regexp_handle->CaptureCount();
2601
2602 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002603 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002604 CompiledReplacement compiled_replacement;
2605 compiled_replacement.Compile(replacement_handle,
2606 capture_count,
2607 length);
2608
2609 bool is_global = regexp_handle->GetFlags().is_global();
2610
2611 // Guessing the number of parts that the final result string is built
2612 // from. Global regexps can match any number of times, so we guess
2613 // conservatively.
2614 int expected_parts =
2615 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002616 ReplacementStringBuilder builder(isolate->heap(),
2617 subject_handle,
2618 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002619
2620 // Index of end of last match.
2621 int prev = 0;
2622
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002623 // Number of parts added by compiled replacement plus preceeding
2624 // string and possibly suffix after last match. It is possible for
2625 // all components to use two elements when encoded as two smis.
2626 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002627 bool matched = true;
2628 do {
2629 ASSERT(last_match_info_handle->HasFastElements());
2630 // Increase the capacity of the builder before entering local handle-scope,
2631 // so its internal buffer can safely allocate a new handle if it grows.
2632 builder.EnsureCapacity(parts_added_per_loop);
2633
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002634 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002635 int start, end;
2636 {
2637 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002638 FixedArray* match_info_array =
2639 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002640
2641 ASSERT_EQ(capture_count * 2 + 2,
2642 RegExpImpl::GetLastCaptureCount(match_info_array));
2643 start = RegExpImpl::GetCapture(match_info_array, 0);
2644 end = RegExpImpl::GetCapture(match_info_array, 1);
2645 }
2646
2647 if (prev < start) {
2648 builder.AddSubjectSlice(prev, start);
2649 }
2650 compiled_replacement.Apply(&builder,
2651 start,
2652 end,
2653 last_match_info_handle);
2654 prev = end;
2655
2656 // Only continue checking for global regexps.
2657 if (!is_global) break;
2658
2659 // Continue from where the match ended, unless it was an empty match.
2660 int next = end;
2661 if (start == end) {
2662 next = end + 1;
2663 if (next > length) break;
2664 }
2665
2666 match = RegExpImpl::Exec(regexp_handle,
2667 subject_handle,
2668 next,
2669 last_match_info_handle);
2670 if (match.is_null()) {
2671 return Failure::Exception();
2672 }
2673 matched = !match->IsNull();
2674 } while (matched);
2675
2676 if (prev < length) {
2677 builder.AddSubjectSlice(prev, length);
2678 }
2679
2680 return *(builder.ToString());
2681}
2682
2683
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002684template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002685MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002686 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002687 String* subject,
2688 JSRegExp* regexp,
2689 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002690 ASSERT(subject->IsFlat());
2691
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002692 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002693
2694 Handle<String> subject_handle(subject);
2695 Handle<JSRegExp> regexp_handle(regexp);
2696 Handle<JSArray> last_match_info_handle(last_match_info);
2697 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2698 subject_handle,
2699 0,
2700 last_match_info_handle);
2701 if (match.is_null()) return Failure::Exception();
2702 if (match->IsNull()) return *subject_handle;
2703
2704 ASSERT(last_match_info_handle->HasFastElements());
2705
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002706 int start, end;
2707 {
2708 AssertNoAllocation match_info_array_is_not_in_a_handle;
2709 FixedArray* match_info_array =
2710 FixedArray::cast(last_match_info_handle->elements());
2711
2712 start = RegExpImpl::GetCapture(match_info_array, 0);
2713 end = RegExpImpl::GetCapture(match_info_array, 1);
2714 }
2715
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002716 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002717 int new_length = length - (end - start);
2718 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002719 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002720 }
2721 Handle<ResultSeqString> answer;
2722 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002723 answer = Handle<ResultSeqString>::cast(
2724 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002725 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002726 answer = Handle<ResultSeqString>::cast(
2727 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002728 }
2729
2730 // If the regexp isn't global, only match once.
2731 if (!regexp_handle->GetFlags().is_global()) {
2732 if (start > 0) {
2733 String::WriteToFlat(*subject_handle,
2734 answer->GetChars(),
2735 0,
2736 start);
2737 }
2738 if (end < length) {
2739 String::WriteToFlat(*subject_handle,
2740 answer->GetChars() + start,
2741 end,
2742 length);
2743 }
2744 return *answer;
2745 }
2746
2747 int prev = 0; // Index of end of last match.
2748 int next = 0; // Start of next search (prev unless last match was empty).
2749 int position = 0;
2750
2751 do {
2752 if (prev < start) {
2753 // Add substring subject[prev;start] to answer string.
2754 String::WriteToFlat(*subject_handle,
2755 answer->GetChars() + position,
2756 prev,
2757 start);
2758 position += start - prev;
2759 }
2760 prev = end;
2761 next = end;
2762 // Continue from where the match ended, unless it was an empty match.
2763 if (start == end) {
2764 next++;
2765 if (next > length) break;
2766 }
2767 match = RegExpImpl::Exec(regexp_handle,
2768 subject_handle,
2769 next,
2770 last_match_info_handle);
2771 if (match.is_null()) return Failure::Exception();
2772 if (match->IsNull()) break;
2773
2774 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002775 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002776 {
2777 AssertNoAllocation match_info_array_is_not_in_a_handle;
2778 FixedArray* match_info_array =
2779 FixedArray::cast(last_match_info_handle->elements());
2780 start = RegExpImpl::GetCapture(match_info_array, 0);
2781 end = RegExpImpl::GetCapture(match_info_array, 1);
2782 }
2783 } while (true);
2784
2785 if (prev < length) {
2786 // Add substring subject[prev;length] to answer string.
2787 String::WriteToFlat(*subject_handle,
2788 answer->GetChars() + position,
2789 prev,
2790 length);
2791 position += length - prev;
2792 }
2793
2794 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002795 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002796 }
2797
2798 // Shorten string and fill
2799 int string_size = ResultSeqString::SizeFor(position);
2800 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2801 int delta = allocated_string_size - string_size;
2802
2803 answer->set_length(position);
2804 if (delta == 0) return *answer;
2805
2806 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002807 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002808
2809 return *answer;
2810}
2811
2812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002813RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002814 ASSERT(args.length() == 4);
2815
2816 CONVERT_CHECKED(String, subject, args[0]);
2817 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002818 Object* flat_subject;
2819 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2820 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2821 return maybe_flat_subject;
2822 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002823 }
2824 subject = String::cast(flat_subject);
2825 }
2826
2827 CONVERT_CHECKED(String, replacement, args[2]);
2828 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002829 Object* flat_replacement;
2830 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2831 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2832 return maybe_flat_replacement;
2833 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002834 }
2835 replacement = String::cast(flat_replacement);
2836 }
2837
2838 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2839 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2840
2841 ASSERT(last_match_info->HasFastElements());
2842
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002843 if (replacement->length() == 0) {
2844 if (subject->HasOnlyAsciiChars()) {
2845 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002846 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002847 } else {
2848 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002849 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002850 }
2851 }
2852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002853 return StringReplaceRegExpWithString(isolate,
2854 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002855 regexp,
2856 replacement,
2857 last_match_info);
2858}
2859
2860
ager@chromium.org7c537e22008-10-16 08:43:32 +00002861// Perform string match of pattern on subject, starting at start index.
2862// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002863// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002864int Runtime::StringMatch(Isolate* isolate,
2865 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002866 Handle<String> pat,
2867 int start_index) {
2868 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002869 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002870
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002871 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002872 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002873
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002874 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002875 if (start_index + pattern_length > subject_length) return -1;
2876
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002877 if (!sub->IsFlat()) FlattenString(sub);
2878 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002879
ager@chromium.org7c537e22008-10-16 08:43:32 +00002880 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002881 // Extract flattened substrings of cons strings before determining asciiness.
2882 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002883 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002884 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002885 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002886
ager@chromium.org7c537e22008-10-16 08:43:32 +00002887 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002888 if (seq_pat->IsAsciiRepresentation()) {
2889 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2890 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002891 return SearchString(isolate,
2892 seq_sub->ToAsciiVector(),
2893 pat_vector,
2894 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002895 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002896 return SearchString(isolate,
2897 seq_sub->ToUC16Vector(),
2898 pat_vector,
2899 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002900 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002901 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2902 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002903 return SearchString(isolate,
2904 seq_sub->ToAsciiVector(),
2905 pat_vector,
2906 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002907 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002908 return SearchString(isolate,
2909 seq_sub->ToUC16Vector(),
2910 pat_vector,
2911 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002912}
2913
2914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002915RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002916 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002917 ASSERT(args.length() == 3);
2918
ager@chromium.org7c537e22008-10-16 08:43:32 +00002919 CONVERT_ARG_CHECKED(String, sub, 0);
2920 CONVERT_ARG_CHECKED(String, pat, 1);
2921
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002922 Object* index = args[2];
2923 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002924 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002925
ager@chromium.org870a0b62008-11-04 11:43:05 +00002926 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002927 int position =
2928 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002929 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002930}
2931
2932
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002933template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002934static int StringMatchBackwards(Vector<const schar> subject,
2935 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002936 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002937 int pattern_length = pattern.length();
2938 ASSERT(pattern_length >= 1);
2939 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002940
2941 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002942 for (int i = 0; i < pattern_length; i++) {
2943 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002944 if (c > String::kMaxAsciiCharCode) {
2945 return -1;
2946 }
2947 }
2948 }
2949
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002950 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002951 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002952 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002953 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002954 while (j < pattern_length) {
2955 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002956 break;
2957 }
2958 j++;
2959 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002960 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002961 return i;
2962 }
2963 }
2964 return -1;
2965}
2966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002968 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002969 ASSERT(args.length() == 3);
2970
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002971 CONVERT_ARG_CHECKED(String, sub, 0);
2972 CONVERT_ARG_CHECKED(String, pat, 1);
2973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002974 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002975 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002976 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002977
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002978 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002979 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002980
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002981 if (start_index + pat_length > sub_length) {
2982 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002984
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002985 if (pat_length == 0) {
2986 return Smi::FromInt(start_index);
2987 }
2988
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002989 if (!sub->IsFlat()) FlattenString(sub);
2990 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002991
2992 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2993
2994 int position = -1;
2995
2996 if (pat->IsAsciiRepresentation()) {
2997 Vector<const char> pat_vector = pat->ToAsciiVector();
2998 if (sub->IsAsciiRepresentation()) {
2999 position = StringMatchBackwards(sub->ToAsciiVector(),
3000 pat_vector,
3001 start_index);
3002 } else {
3003 position = StringMatchBackwards(sub->ToUC16Vector(),
3004 pat_vector,
3005 start_index);
3006 }
3007 } else {
3008 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3009 if (sub->IsAsciiRepresentation()) {
3010 position = StringMatchBackwards(sub->ToAsciiVector(),
3011 pat_vector,
3012 start_index);
3013 } else {
3014 position = StringMatchBackwards(sub->ToUC16Vector(),
3015 pat_vector,
3016 start_index);
3017 }
3018 }
3019
3020 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003021}
3022
3023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003024RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003025 NoHandleAllocation ha;
3026 ASSERT(args.length() == 2);
3027
3028 CONVERT_CHECKED(String, str1, args[0]);
3029 CONVERT_CHECKED(String, str2, args[1]);
3030
3031 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003032 int str1_length = str1->length();
3033 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003034
3035 // Decide trivial cases without flattening.
3036 if (str1_length == 0) {
3037 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3038 return Smi::FromInt(-str2_length);
3039 } else {
3040 if (str2_length == 0) return Smi::FromInt(str1_length);
3041 }
3042
3043 int end = str1_length < str2_length ? str1_length : str2_length;
3044
3045 // No need to flatten if we are going to find the answer on the first
3046 // character. At this point we know there is at least one character
3047 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003048 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003049 if (d != 0) return Smi::FromInt(d);
3050
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003051 str1->TryFlatten();
3052 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003053
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003054 StringInputBuffer& buf1 =
3055 *isolate->runtime_state()->string_locale_compare_buf1();
3056 StringInputBuffer& buf2 =
3057 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003058
3059 buf1.Reset(str1);
3060 buf2.Reset(str2);
3061
3062 for (int i = 0; i < end; i++) {
3063 uint16_t char1 = buf1.GetNext();
3064 uint16_t char2 = buf2.GetNext();
3065 if (char1 != char2) return Smi::FromInt(char1 - char2);
3066 }
3067
3068 return Smi::FromInt(str1_length - str2_length);
3069}
3070
3071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003072RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003073 NoHandleAllocation ha;
3074 ASSERT(args.length() == 3);
3075
3076 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003077 Object* from = args[1];
3078 Object* to = args[2];
3079 int start, end;
3080 // We have a fast integer-only case here to avoid a conversion to double in
3081 // the common case where from and to are Smis.
3082 if (from->IsSmi() && to->IsSmi()) {
3083 start = Smi::cast(from)->value();
3084 end = Smi::cast(to)->value();
3085 } else {
3086 CONVERT_DOUBLE_CHECKED(from_number, from);
3087 CONVERT_DOUBLE_CHECKED(to_number, to);
3088 start = FastD2I(from_number);
3089 end = FastD2I(to_number);
3090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003091 RUNTIME_ASSERT(end >= start);
3092 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003093 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003094 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003095 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003096}
3097
3098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003099RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003100 ASSERT_EQ(3, args.length());
3101
3102 CONVERT_ARG_CHECKED(String, subject, 0);
3103 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3104 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3105 HandleScope handles;
3106
3107 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3108
3109 if (match.is_null()) {
3110 return Failure::Exception();
3111 }
3112 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003113 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003114 }
3115 int length = subject->length();
3116
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003117 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003118 ZoneList<int> offsets(8);
3119 do {
3120 int start;
3121 int end;
3122 {
3123 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003124 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003125 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3126 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3127 }
3128 offsets.Add(start);
3129 offsets.Add(end);
3130 int index = start < end ? end : end + 1;
3131 if (index > length) break;
3132 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3133 if (match.is_null()) {
3134 return Failure::Exception();
3135 }
3136 } while (!match->IsNull());
3137 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003139 for (int i = 0; i < matches ; i++) {
3140 int from = offsets.at(i * 2);
3141 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003142 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003143 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003144 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003145 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003146 result->set_length(Smi::FromInt(matches));
3147 return *result;
3148}
3149
3150
lrn@chromium.org25156de2010-04-06 13:10:27 +00003151// Two smis before and after the match, for very long strings.
3152const int kMaxBuilderEntriesPerRegExpMatch = 5;
3153
3154
3155static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3156 Handle<JSArray> last_match_info,
3157 int match_start,
3158 int match_end) {
3159 // Fill last_match_info with a single capture.
3160 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3161 AssertNoAllocation no_gc;
3162 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3163 RegExpImpl::SetLastCaptureCount(elements, 2);
3164 RegExpImpl::SetLastInput(elements, *subject);
3165 RegExpImpl::SetLastSubject(elements, *subject);
3166 RegExpImpl::SetCapture(elements, 0, match_start);
3167 RegExpImpl::SetCapture(elements, 1, match_end);
3168}
3169
3170
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003171template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003172static bool SearchStringMultiple(Isolate* isolate,
3173 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003174 Vector<const PatternChar> pattern,
3175 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003176 FixedArrayBuilder* builder,
3177 int* match_pos) {
3178 int pos = *match_pos;
3179 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003180 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003181 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003182 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003183 while (pos <= max_search_start) {
3184 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3185 *match_pos = pos;
3186 return false;
3187 }
3188 // Position of end of previous match.
3189 int match_end = pos + pattern_length;
3190 int new_pos = search.Search(subject, match_end);
3191 if (new_pos >= 0) {
3192 // A match.
3193 if (new_pos > match_end) {
3194 ReplacementStringBuilder::AddSubjectSlice(builder,
3195 match_end,
3196 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003197 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003198 pos = new_pos;
3199 builder->Add(pattern_string);
3200 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003201 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003202 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003203 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003204
lrn@chromium.org25156de2010-04-06 13:10:27 +00003205 if (pos < max_search_start) {
3206 ReplacementStringBuilder::AddSubjectSlice(builder,
3207 pos + pattern_length,
3208 subject_length);
3209 }
3210 *match_pos = pos;
3211 return true;
3212}
3213
3214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003215static bool SearchStringMultiple(Isolate* isolate,
3216 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003217 Handle<String> pattern,
3218 Handle<JSArray> last_match_info,
3219 FixedArrayBuilder* builder) {
3220 ASSERT(subject->IsFlat());
3221 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003222
3223 // Treating as if a previous match was before first character.
3224 int match_pos = -pattern->length();
3225
3226 for (;;) { // Break when search complete.
3227 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3228 AssertNoAllocation no_gc;
3229 if (subject->IsAsciiRepresentation()) {
3230 Vector<const char> subject_vector = subject->ToAsciiVector();
3231 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003232 if (SearchStringMultiple(isolate,
3233 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003234 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003235 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003236 builder,
3237 &match_pos)) break;
3238 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003239 if (SearchStringMultiple(isolate,
3240 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003241 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003242 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003243 builder,
3244 &match_pos)) break;
3245 }
3246 } else {
3247 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3248 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003249 if (SearchStringMultiple(isolate,
3250 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003251 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003252 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003253 builder,
3254 &match_pos)) break;
3255 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003256 if (SearchStringMultiple(isolate,
3257 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003258 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003259 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003260 builder,
3261 &match_pos)) break;
3262 }
3263 }
3264 }
3265
3266 if (match_pos >= 0) {
3267 SetLastMatchInfoNoCaptures(subject,
3268 last_match_info,
3269 match_pos,
3270 match_pos + pattern->length());
3271 return true;
3272 }
3273 return false; // No matches at all.
3274}
3275
3276
3277static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003278 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003279 Handle<String> subject,
3280 Handle<JSRegExp> regexp,
3281 Handle<JSArray> last_match_array,
3282 FixedArrayBuilder* builder) {
3283 ASSERT(subject->IsFlat());
3284 int match_start = -1;
3285 int match_end = 0;
3286 int pos = 0;
3287 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3288 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3289
3290 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003291 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003292 int subject_length = subject->length();
3293
3294 for (;;) { // Break on failure, return on exception.
3295 RegExpImpl::IrregexpResult result =
3296 RegExpImpl::IrregexpExecOnce(regexp,
3297 subject,
3298 pos,
3299 register_vector);
3300 if (result == RegExpImpl::RE_SUCCESS) {
3301 match_start = register_vector[0];
3302 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3303 if (match_end < match_start) {
3304 ReplacementStringBuilder::AddSubjectSlice(builder,
3305 match_end,
3306 match_start);
3307 }
3308 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003309 HandleScope loop_scope(isolate);
3310 builder->Add(*isolate->factory()->NewSubString(subject,
3311 match_start,
3312 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003313 if (match_start != match_end) {
3314 pos = match_end;
3315 } else {
3316 pos = match_end + 1;
3317 if (pos > subject_length) break;
3318 }
3319 } else if (result == RegExpImpl::RE_FAILURE) {
3320 break;
3321 } else {
3322 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3323 return result;
3324 }
3325 }
3326
3327 if (match_start >= 0) {
3328 if (match_end < subject_length) {
3329 ReplacementStringBuilder::AddSubjectSlice(builder,
3330 match_end,
3331 subject_length);
3332 }
3333 SetLastMatchInfoNoCaptures(subject,
3334 last_match_array,
3335 match_start,
3336 match_end);
3337 return RegExpImpl::RE_SUCCESS;
3338 } else {
3339 return RegExpImpl::RE_FAILURE; // No matches at all.
3340 }
3341}
3342
3343
3344static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003345 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003346 Handle<String> subject,
3347 Handle<JSRegExp> regexp,
3348 Handle<JSArray> last_match_array,
3349 FixedArrayBuilder* builder) {
3350
3351 ASSERT(subject->IsFlat());
3352 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3353 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3354
3355 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003356 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003357
3358 RegExpImpl::IrregexpResult result =
3359 RegExpImpl::IrregexpExecOnce(regexp,
3360 subject,
3361 0,
3362 register_vector);
3363
3364 int capture_count = regexp->CaptureCount();
3365 int subject_length = subject->length();
3366
3367 // Position to search from.
3368 int pos = 0;
3369 // End of previous match. Differs from pos if match was empty.
3370 int match_end = 0;
3371 if (result == RegExpImpl::RE_SUCCESS) {
3372 // Need to keep a copy of the previous match for creating last_match_info
3373 // at the end, so we have two vectors that we swap between.
3374 OffsetsVector registers2(required_registers);
3375 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3376
3377 do {
3378 int match_start = register_vector[0];
3379 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3380 if (match_end < match_start) {
3381 ReplacementStringBuilder::AddSubjectSlice(builder,
3382 match_end,
3383 match_start);
3384 }
3385 match_end = register_vector[1];
3386
3387 {
3388 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003389 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003390 // Arguments array to replace function is match, captures, index and
3391 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003392 Handle<FixedArray> elements =
3393 isolate->factory()->NewFixedArray(3 + capture_count);
3394 Handle<String> match = isolate->factory()->NewSubString(subject,
3395 match_start,
3396 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003397 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003398 for (int i = 1; i <= capture_count; i++) {
3399 int start = register_vector[i * 2];
3400 if (start >= 0) {
3401 int end = register_vector[i * 2 + 1];
3402 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003403 Handle<String> substring = isolate->factory()->NewSubString(subject,
3404 start,
3405 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003406 elements->set(i, *substring);
3407 } else {
3408 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003409 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003410 }
3411 }
3412 elements->set(capture_count + 1, Smi::FromInt(match_start));
3413 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003414 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003415 }
3416 // Swap register vectors, so the last successful match is in
3417 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003418 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003419 prev_register_vector = register_vector;
3420 register_vector = tmp;
3421
3422 if (match_end > match_start) {
3423 pos = match_end;
3424 } else {
3425 pos = match_end + 1;
3426 if (pos > subject_length) {
3427 break;
3428 }
3429 }
3430
3431 result = RegExpImpl::IrregexpExecOnce(regexp,
3432 subject,
3433 pos,
3434 register_vector);
3435 } while (result == RegExpImpl::RE_SUCCESS);
3436
3437 if (result != RegExpImpl::RE_EXCEPTION) {
3438 // Finished matching, with at least one match.
3439 if (match_end < subject_length) {
3440 ReplacementStringBuilder::AddSubjectSlice(builder,
3441 match_end,
3442 subject_length);
3443 }
3444
3445 int last_match_capture_count = (capture_count + 1) * 2;
3446 int last_match_array_size =
3447 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3448 last_match_array->EnsureSize(last_match_array_size);
3449 AssertNoAllocation no_gc;
3450 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3451 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3452 RegExpImpl::SetLastSubject(elements, *subject);
3453 RegExpImpl::SetLastInput(elements, *subject);
3454 for (int i = 0; i < last_match_capture_count; i++) {
3455 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3456 }
3457 return RegExpImpl::RE_SUCCESS;
3458 }
3459 }
3460 // No matches at all, return failure or exception result directly.
3461 return result;
3462}
3463
3464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003465RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003466 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003467 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003468
3469 CONVERT_ARG_CHECKED(String, subject, 1);
3470 if (!subject->IsFlat()) { FlattenString(subject); }
3471 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3472 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3473 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3474
3475 ASSERT(last_match_info->HasFastElements());
3476 ASSERT(regexp->GetFlags().is_global());
3477 Handle<FixedArray> result_elements;
3478 if (result_array->HasFastElements()) {
3479 result_elements =
3480 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3481 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003482 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003483 }
3484 FixedArrayBuilder builder(result_elements);
3485
3486 if (regexp->TypeTag() == JSRegExp::ATOM) {
3487 Handle<String> pattern(
3488 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003489 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003490 if (SearchStringMultiple(isolate, subject, pattern,
3491 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003492 return *builder.ToJSArray(result_array);
3493 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003494 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003495 }
3496
3497 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3498
3499 RegExpImpl::IrregexpResult result;
3500 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003501 result = SearchRegExpNoCaptureMultiple(isolate,
3502 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003503 regexp,
3504 last_match_info,
3505 &builder);
3506 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003507 result = SearchRegExpMultiple(isolate,
3508 subject,
3509 regexp,
3510 last_match_info,
3511 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003512 }
3513 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003514 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003515 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3516 return Failure::Exception();
3517}
3518
3519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003520RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003521 NoHandleAllocation ha;
3522 ASSERT(args.length() == 2);
3523
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003524 // Fast case where the result is a one character string.
3525 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3526 int value = Smi::cast(args[0])->value();
3527 int radix = Smi::cast(args[1])->value();
3528 if (value >= 0 && value < radix) {
3529 RUNTIME_ASSERT(radix <= 36);
3530 // Character array used for conversion.
3531 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003532 return isolate->heap()->
3533 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003534 }
3535 }
3536
3537 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003538 CONVERT_DOUBLE_CHECKED(value, args[0]);
3539 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003540 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003541 }
3542 if (isinf(value)) {
3543 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003544 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003546 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003547 }
3548 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3549 int radix = FastD2I(radix_number);
3550 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3551 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003552 MaybeObject* result =
3553 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554 DeleteArray(str);
3555 return result;
3556}
3557
3558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003559RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003560 NoHandleAllocation ha;
3561 ASSERT(args.length() == 2);
3562
3563 CONVERT_DOUBLE_CHECKED(value, args[0]);
3564 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003566 }
3567 if (isinf(value)) {
3568 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003569 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003571 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003572 }
3573 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3574 int f = FastD2I(f_number);
3575 RUNTIME_ASSERT(f >= 0);
3576 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003577 MaybeObject* res =
3578 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003580 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581}
3582
3583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003584RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003585 NoHandleAllocation ha;
3586 ASSERT(args.length() == 2);
3587
3588 CONVERT_DOUBLE_CHECKED(value, args[0]);
3589 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003590 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 }
3592 if (isinf(value)) {
3593 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003596 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 }
3598 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3599 int f = FastD2I(f_number);
3600 RUNTIME_ASSERT(f >= -1 && f <= 20);
3601 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 MaybeObject* res =
3603 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003604 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606}
3607
3608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003609RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610 NoHandleAllocation ha;
3611 ASSERT(args.length() == 2);
3612
3613 CONVERT_DOUBLE_CHECKED(value, args[0]);
3614 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003615 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 }
3617 if (isinf(value)) {
3618 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 }
3623 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3624 int f = FastD2I(f_number);
3625 RUNTIME_ASSERT(f >= 1 && f <= 21);
3626 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 MaybeObject* res =
3628 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003630 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631}
3632
3633
3634// Returns a single character string where first character equals
3635// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003636static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003637 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003638 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003639 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003640 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003642 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643}
3644
3645
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003646MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3647 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003648 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003649 // Handle [] indexing on Strings
3650 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003651 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3652 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 }
3654
3655 // Handle [] indexing on String objects
3656 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003657 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3658 Handle<Object> result =
3659 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3660 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 }
3662
3663 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003664 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003665 return prototype->GetElement(index);
3666 }
3667
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003668 return GetElement(object, index);
3669}
3670
3671
lrn@chromium.org303ada72010-10-27 09:33:13 +00003672MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003673 return object->GetElement(index);
3674}
3675
3676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003677MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3678 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003679 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003680 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003681
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003682 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003683 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003684 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685 isolate->factory()->NewTypeError("non_object_property_load",
3686 HandleVector(args, 2));
3687 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 }
3689
3690 // Check if the given key is an array index.
3691 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003692 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003693 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003694 }
3695
3696 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003697 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003699 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003700 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003701 bool has_pending_exception = false;
3702 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003703 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003704 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003705 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003706 }
3707
ager@chromium.org32912102009-01-16 10:38:43 +00003708 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003709 // the element if so.
3710 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003711 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 } else {
3713 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003714 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 }
3716}
3717
3718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003719RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720 NoHandleAllocation ha;
3721 ASSERT(args.length() == 2);
3722
3723 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003724 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003726 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003727}
3728
3729
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003730// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003731RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003732 NoHandleAllocation ha;
3733 ASSERT(args.length() == 2);
3734
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003735 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003736 // itself.
3737 //
3738 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003739 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003740 // global proxy object never has properties. This is the case
3741 // because the global proxy object forwards everything to its hidden
3742 // prototype including local lookups.
3743 //
3744 // Additionally, we need to make sure that we do not cache results
3745 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003746 if (args[0]->IsJSObject() &&
3747 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003748 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003749 args[1]->IsString()) {
3750 JSObject* receiver = JSObject::cast(args[0]);
3751 String* key = String::cast(args[1]);
3752 if (receiver->HasFastProperties()) {
3753 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003754 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003755 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3756 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003757 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003758 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003759 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003760 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003761 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003762 LookupResult result;
3763 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003764 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003765 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003766 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003767 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003768 }
3769 } else {
3770 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003771 StringDictionary* dictionary = receiver->property_dictionary();
3772 int entry = dictionary->FindEntry(key);
3773 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003774 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003775 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003776 if (!receiver->IsGlobalObject()) return value;
3777 value = JSGlobalPropertyCell::cast(value)->value();
3778 if (!value->IsTheHole()) return value;
3779 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003780 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003781 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003782 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3783 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003784 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003785 Handle<String> str = args.at<String>(0);
3786 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003787 if (index >= 0 && index < str->length()) {
3788 Handle<Object> result = GetCharAt(str, index);
3789 return *result;
3790 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003791 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003792
3793 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 return Runtime::GetObjectProperty(isolate,
3795 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003796 args.at<Object>(1));
3797}
3798
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003799// Implements part of 8.12.9 DefineOwnProperty.
3800// There are 3 cases that lead here:
3801// Step 4b - define a new accessor property.
3802// Steps 9c & 12 - replace an existing data property with an accessor property.
3803// Step 12 - update an existing accessor property with an accessor or generic
3804// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003805RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003806 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003807 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003808 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3809 CONVERT_CHECKED(String, name, args[1]);
3810 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003811 Object* fun = args[3];
3812 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003813 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3814 int unchecked = flag_attr->value();
3815 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3816 RUNTIME_ASSERT(!obj->IsNull());
3817 LookupResult result;
3818 obj->LocalLookupRealNamedProperty(name, &result);
3819
3820 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3821 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3822 // delete it to avoid running into trouble in DefineAccessor, which
3823 // handles this incorrectly if the property is readonly (does nothing)
3824 if (result.IsProperty() &&
3825 (result.type() == FIELD || result.type() == NORMAL
3826 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003827 Object* ok;
3828 { MaybeObject* maybe_ok =
3829 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3830 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3831 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003832 }
3833 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3834}
3835
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003836// Implements part of 8.12.9 DefineOwnProperty.
3837// There are 3 cases that lead here:
3838// Step 4a - define a new data property.
3839// Steps 9b & 12 - replace an existing accessor property with a data property.
3840// Step 12 - update an existing data property with a data or generic
3841// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003842RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003843 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003844 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003845 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3846 CONVERT_ARG_CHECKED(String, name, 1);
3847 Handle<Object> obj_value = args.at<Object>(2);
3848
3849 CONVERT_CHECKED(Smi, flag, args[3]);
3850 int unchecked = flag->value();
3851 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3852
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003853 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3854
3855 // Check if this is an element.
3856 uint32_t index;
3857 bool is_element = name->AsArrayIndex(&index);
3858
3859 // Special case for elements if any of the flags are true.
3860 // If elements are in fast case we always implicitly assume that:
3861 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3862 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3863 is_element) {
3864 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003865 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003866 // We do not need to do access checks here since these has already
3867 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003868 Handle<Object> proto(js_object->GetPrototype());
3869 // If proxy is detached, ignore the assignment. Alternatively,
3870 // we could throw an exception.
3871 if (proto->IsNull()) return *obj_value;
3872 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003873 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003874 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003875 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003876 // Make sure that we never go back to fast case.
3877 dictionary->set_requires_slow_elements();
3878 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003879 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003880 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003881 }
3882
ager@chromium.org5c838252010-02-19 08:53:10 +00003883 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003884 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003885
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003886 // To be compatible with safari we do not change the value on API objects
3887 // in defineProperty. Firefox disagrees here, and actually changes the value.
3888 if (result.IsProperty() &&
3889 (result.type() == CALLBACKS) &&
3890 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003891 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003892 }
3893
ager@chromium.org5c838252010-02-19 08:53:10 +00003894 // Take special care when attributes are different and there is already
3895 // a property. For simplicity we normalize the property which enables us
3896 // to not worry about changing the instance_descriptor and creating a new
3897 // map. The current version of SetObjectProperty does not handle attributes
3898 // correctly in the case where a property is a field and is reset with
3899 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003900 if (result.IsProperty() &&
3901 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003902 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003903 if (js_object->IsJSGlobalProxy()) {
3904 // Since the result is a property, the prototype will exist so
3905 // we don't have to check for null.
3906 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003907 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003908 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003909 // Use IgnoreAttributes version since a readonly property may be
3910 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003911 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3912 *obj_value,
3913 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003914 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003916 return Runtime::ForceSetObjectProperty(isolate,
3917 js_object,
3918 name,
3919 obj_value,
3920 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003921}
3922
3923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003924MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3925 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003926 Handle<Object> key,
3927 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003928 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003929 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003930 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003931
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003932 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003933 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003934 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003935 isolate->factory()->NewTypeError("non_object_property_store",
3936 HandleVector(args, 2));
3937 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003938 }
3939
3940 // If the object isn't a JavaScript object, we ignore the store.
3941 if (!object->IsJSObject()) return *value;
3942
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003943 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3944
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003945 // Check if the given key is an array index.
3946 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003947 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3949 // of a string using [] notation. We need to support this too in
3950 // JavaScript.
3951 // In the case of a String object we just need to redirect the assignment to
3952 // the underlying string if the index is in range. Since the underlying
3953 // string does nothing with the assignment then we can ignore such
3954 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003955 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003957 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003958
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003959 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003960 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003961 return *value;
3962 }
3963
3964 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003965 Handle<Object> result;
3966 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003967 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003969 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003970 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003971 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003973 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 return *value;
3975 }
3976
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 bool has_pending_exception = false;
3979 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3980 if (has_pending_exception) return Failure::Exception();
3981 Handle<String> name = Handle<String>::cast(converted);
3982
3983 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003984 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003986 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987 }
3988}
3989
3990
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003991MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
3992 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003993 Handle<Object> key,
3994 Handle<Object> value,
3995 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003997
3998 // Check if the given key is an array index.
3999 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004000 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004001 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4002 // of a string using [] notation. We need to support this too in
4003 // JavaScript.
4004 // In the case of a String object we just need to redirect the assignment to
4005 // the underlying string if the index is in range. Since the underlying
4006 // string does nothing with the assignment then we can ignore such
4007 // assignments.
4008 if (js_object->IsStringObjectWithCharacterAt(index)) {
4009 return *value;
4010 }
4011
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004012 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004013 }
4014
4015 if (key->IsString()) {
4016 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004017 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004018 } else {
4019 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004020 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004021 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4022 *value,
4023 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004024 }
4025 }
4026
4027 // Call-back into JavaScript to convert the key to a string.
4028 bool has_pending_exception = false;
4029 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4030 if (has_pending_exception) return Failure::Exception();
4031 Handle<String> name = Handle<String>::cast(converted);
4032
4033 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004034 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004035 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004036 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004037 }
4038}
4039
4040
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004041MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4042 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004043 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004044 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004045
4046 // Check if the given key is an array index.
4047 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004048 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004049 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4050 // characters of a string using [] notation. In the case of a
4051 // String object we just need to redirect the deletion to the
4052 // underlying string if the index is in range. Since the
4053 // underlying string does nothing with the deletion, we can ignore
4054 // such deletions.
4055 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004056 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004057 }
4058
4059 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4060 }
4061
4062 Handle<String> key_string;
4063 if (key->IsString()) {
4064 key_string = Handle<String>::cast(key);
4065 } else {
4066 // Call-back into JavaScript to convert the key to a string.
4067 bool has_pending_exception = false;
4068 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4069 if (has_pending_exception) return Failure::Exception();
4070 key_string = Handle<String>::cast(converted);
4071 }
4072
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004073 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004074 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4075}
4076
4077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004078RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004080 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081
4082 Handle<Object> object = args.at<Object>(0);
4083 Handle<Object> key = args.at<Object>(1);
4084 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004085 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4086 RUNTIME_ASSERT(
4087 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004089 PropertyAttributes attributes =
4090 static_cast<PropertyAttributes>(unchecked_attributes);
4091
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004092 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004093 if (args.length() == 5) {
4094 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4095 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4096 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004097 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004100 return Runtime::SetObjectProperty(isolate,
4101 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004102 key,
4103 value,
4104 attributes,
4105 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106}
4107
4108
4109// Set a local property, even if it is READ_ONLY. If the property does not
4110// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004111RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004113 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 CONVERT_CHECKED(JSObject, object, args[0]);
4115 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004116 // Compute attributes.
4117 PropertyAttributes attributes = NONE;
4118 if (args.length() == 4) {
4119 CONVERT_CHECKED(Smi, value_obj, args[3]);
4120 int unchecked_value = value_obj->value();
4121 // Only attribute bits should be set.
4122 RUNTIME_ASSERT(
4123 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4124 attributes = static_cast<PropertyAttributes>(unchecked_value);
4125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004127 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004128 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004129}
4130
4131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004132RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004133 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004134 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135
4136 CONVERT_CHECKED(JSObject, object, args[0]);
4137 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004138 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004139 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004140 ? JSObject::STRICT_DELETION
4141 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142}
4143
4144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004145static Object* HasLocalPropertyImplementation(Isolate* isolate,
4146 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004147 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004148 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004149 // Handle hidden prototypes. If there's a hidden prototype above this thing
4150 // then we have to check it for properties, because they are supposed to
4151 // look like they are on this object.
4152 Handle<Object> proto(object->GetPrototype());
4153 if (proto->IsJSObject() &&
4154 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004155 return HasLocalPropertyImplementation(isolate,
4156 Handle<JSObject>::cast(proto),
4157 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004158 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004159 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004160}
4161
4162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004163RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 NoHandleAllocation ha;
4165 ASSERT(args.length() == 2);
4166 CONVERT_CHECKED(String, key, args[1]);
4167
ager@chromium.org9085a012009-05-11 19:22:57 +00004168 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004170 if (obj->IsJSObject()) {
4171 JSObject* object = JSObject::cast(obj);
4172 // Fast case - no interceptors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004173 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004174 // Slow case. Either it's not there or we have an interceptor. We should
4175 // have handles for this kind of deal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176 HandleScope scope(isolate);
4177 return HasLocalPropertyImplementation(isolate,
4178 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004179 Handle<String>(key));
4180 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 // Well, there is one exception: Handle [] on strings.
4182 uint32_t index;
4183 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004184 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004185 if (index < static_cast<uint32_t>(string->length()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004186 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 }
4188 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004189 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190}
4191
4192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004193RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 NoHandleAllocation na;
4195 ASSERT(args.length() == 2);
4196
4197 // Only JS objects can have properties.
4198 if (args[0]->IsJSObject()) {
4199 JSObject* object = JSObject::cast(args[0]);
4200 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004201 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004203 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004204}
4205
4206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004207RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 NoHandleAllocation na;
4209 ASSERT(args.length() == 2);
4210
4211 // Only JS objects can have elements.
4212 if (args[0]->IsJSObject()) {
4213 JSObject* object = JSObject::cast(args[0]);
4214 CONVERT_CHECKED(Smi, index_obj, args[1]);
4215 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004216 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004217 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004218 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219}
4220
4221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004222RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223 NoHandleAllocation ha;
4224 ASSERT(args.length() == 2);
4225
4226 CONVERT_CHECKED(JSObject, object, args[0]);
4227 CONVERT_CHECKED(String, key, args[1]);
4228
4229 uint32_t index;
4230 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232 }
4233
ager@chromium.org870a0b62008-11-04 11:43:05 +00004234 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004235 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004236}
4237
4238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004239RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004240 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004242 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004243 return *GetKeysFor(object);
4244}
4245
4246
4247// Returns either a FixedArray as Runtime_GetPropertyNames,
4248// or, if the given object has an enum cache that contains
4249// all enumerable properties of the object and its prototypes
4250// have none, the map of the object. This is used to speed up
4251// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004252RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 ASSERT(args.length() == 1);
4254
4255 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4256
4257 if (raw_object->IsSimpleEnum()) return raw_object->map();
4258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004259 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004260 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004261 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4262 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004263
4264 // Test again, since cache may have been built by preceding call.
4265 if (object->IsSimpleEnum()) return object->map();
4266
4267 return *content;
4268}
4269
4270
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004271// Find the length of the prototype chain that is to to handled as one. If a
4272// prototype object is hidden it is to be viewed as part of the the object it
4273// is prototype for.
4274static int LocalPrototypeChainLength(JSObject* obj) {
4275 int count = 1;
4276 Object* proto = obj->GetPrototype();
4277 while (proto->IsJSObject() &&
4278 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4279 count++;
4280 proto = JSObject::cast(proto)->GetPrototype();
4281 }
4282 return count;
4283}
4284
4285
4286// Return the names of the local named properties.
4287// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004288RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004289 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004290 ASSERT(args.length() == 1);
4291 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004292 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004293 }
4294 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4295
4296 // Skip the global proxy as it has no properties and always delegates to the
4297 // real global object.
4298 if (obj->IsJSGlobalProxy()) {
4299 // Only collect names if access is permitted.
4300 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004301 !isolate->MayNamedAccess(*obj,
4302 isolate->heap()->undefined_value(),
4303 v8::ACCESS_KEYS)) {
4304 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4305 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004306 }
4307 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4308 }
4309
4310 // Find the number of objects making up this.
4311 int length = LocalPrototypeChainLength(*obj);
4312
4313 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004314 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004315 int total_property_count = 0;
4316 Handle<JSObject> jsproto = obj;
4317 for (int i = 0; i < length; i++) {
4318 // Only collect names if access is permitted.
4319 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004320 !isolate->MayNamedAccess(*jsproto,
4321 isolate->heap()->undefined_value(),
4322 v8::ACCESS_KEYS)) {
4323 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4324 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004325 }
4326 int n;
4327 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4328 local_property_count[i] = n;
4329 total_property_count += n;
4330 if (i < length - 1) {
4331 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4332 }
4333 }
4334
4335 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004336 Handle<FixedArray> names =
4337 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004338
4339 // Get the property names.
4340 jsproto = obj;
4341 int proto_with_hidden_properties = 0;
4342 for (int i = 0; i < length; i++) {
4343 jsproto->GetLocalPropertyNames(*names,
4344 i == 0 ? 0 : local_property_count[i - 1]);
4345 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4346 proto_with_hidden_properties++;
4347 }
4348 if (i < length - 1) {
4349 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4350 }
4351 }
4352
4353 // Filter out name of hidden propeties object.
4354 if (proto_with_hidden_properties > 0) {
4355 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004356 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004357 names->length() - proto_with_hidden_properties);
4358 int dest_pos = 0;
4359 for (int i = 0; i < total_property_count; i++) {
4360 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004361 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004362 continue;
4363 }
4364 names->set(dest_pos++, name);
4365 }
4366 }
4367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004368 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004369}
4370
4371
4372// Return the names of the local indexed properties.
4373// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004374RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004375 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004376 ASSERT(args.length() == 1);
4377 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004378 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004379 }
4380 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4381
4382 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004383 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004384 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004385 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004386}
4387
4388
4389// Return information on whether an object has a named or indexed interceptor.
4390// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004391RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004392 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004393 ASSERT(args.length() == 1);
4394 if (!args[0]->IsJSObject()) {
4395 return Smi::FromInt(0);
4396 }
4397 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4398
4399 int result = 0;
4400 if (obj->HasNamedInterceptor()) result |= 2;
4401 if (obj->HasIndexedInterceptor()) result |= 1;
4402
4403 return Smi::FromInt(result);
4404}
4405
4406
4407// Return property names from named interceptor.
4408// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004409RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004410 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004411 ASSERT(args.length() == 1);
4412 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4413
4414 if (obj->HasNamedInterceptor()) {
4415 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4416 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004418 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004419}
4420
4421
4422// Return element names from indexed interceptor.
4423// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004424RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004425 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004426 ASSERT(args.length() == 1);
4427 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4428
4429 if (obj->HasIndexedInterceptor()) {
4430 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4431 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4432 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004433 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004434}
4435
4436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004437RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004438 ASSERT_EQ(args.length(), 1);
4439 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004440 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004441 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004442
4443 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004444 // Do access checks before going to the global object.
4445 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004446 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004447 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004448 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4449 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004450 }
4451
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004452 Handle<Object> proto(object->GetPrototype());
4453 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004454 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004455 object = Handle<JSObject>::cast(proto);
4456 }
4457
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004458 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4459 LOCAL_ONLY);
4460 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4461 // property array and since the result is mutable we have to create
4462 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004463 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004464 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004465 for (int i = 0; i < length; i++) {
4466 Object* entry = contents->get(i);
4467 if (entry->IsString()) {
4468 copy->set(i, entry);
4469 } else {
4470 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004471 HandleScope scope(isolate);
4472 Handle<Object> entry_handle(entry, isolate);
4473 Handle<Object> entry_str =
4474 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004475 copy->set(i, *entry_str);
4476 }
4477 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004478 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004479}
4480
4481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004482RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 NoHandleAllocation ha;
4484 ASSERT(args.length() == 1);
4485
4486 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004487 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 it.AdvanceToArgumentsFrame();
4489 JavaScriptFrame* frame = it.frame();
4490
4491 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004492 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493
4494 // Try to convert the key to an index. If successful and within
4495 // index return the the argument from the frame.
4496 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004497 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004498 return frame->GetParameter(index);
4499 }
4500
4501 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004502 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503 bool exception = false;
4504 Handle<Object> converted =
4505 Execution::ToString(args.at<Object>(0), &exception);
4506 if (exception) return Failure::Exception();
4507 Handle<String> key = Handle<String>::cast(converted);
4508
4509 // Try to convert the string key into an array index.
4510 if (key->AsArrayIndex(&index)) {
4511 if (index < n) {
4512 return frame->GetParameter(index);
4513 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004514 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004515 }
4516 }
4517
4518 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004519 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4520 if (key->Equals(isolate->heap()->callee_symbol())) {
4521 Object* function = frame->function();
4522 if (function->IsJSFunction() &&
4523 JSFunction::cast(function)->shared()->strict_mode()) {
4524 return isolate->Throw(*isolate->factory()->NewTypeError(
4525 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4526 }
4527 return function;
4528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004529
4530 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004531 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004532}
4533
4534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004535RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004536 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004537
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004538 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004539 Handle<Object> object = args.at<Object>(0);
4540 if (object->IsJSObject()) {
4541 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004542 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004543 MaybeObject* ok = js_object->TransformToFastProperties(0);
4544 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004545 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004546 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004547 return *object;
4548}
4549
4550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004551RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004552 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004553
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004554 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004555 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004556 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004557 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004558 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004559 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004560 return *object;
4561}
4562
4563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004564RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004565 NoHandleAllocation ha;
4566 ASSERT(args.length() == 1);
4567
4568 return args[0]->ToBoolean();
4569}
4570
4571
4572// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4573// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004574RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004575 NoHandleAllocation ha;
4576
4577 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004579 HeapObject* heap_obj = HeapObject::cast(obj);
4580
4581 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582 if (heap_obj->map()->is_undetectable()) {
4583 return isolate->heap()->undefined_symbol();
4584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004585
4586 InstanceType instance_type = heap_obj->map()->instance_type();
4587 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004588 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004589 }
4590
4591 switch (instance_type) {
4592 case ODDBALL_TYPE:
4593 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004594 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004595 }
4596 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004597 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004598 }
4599 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004600 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004601 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004602 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 default:
4604 // For any kind of object not handled above, the spec rule for
4605 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004606 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004607 }
4608}
4609
4610
lrn@chromium.org25156de2010-04-06 13:10:27 +00004611static bool AreDigits(const char*s, int from, int to) {
4612 for (int i = from; i < to; i++) {
4613 if (s[i] < '0' || s[i] > '9') return false;
4614 }
4615
4616 return true;
4617}
4618
4619
4620static int ParseDecimalInteger(const char*s, int from, int to) {
4621 ASSERT(to - from < 10); // Overflow is not possible.
4622 ASSERT(from < to);
4623 int d = s[from] - '0';
4624
4625 for (int i = from + 1; i < to; i++) {
4626 d = 10 * d + (s[i] - '0');
4627 }
4628
4629 return d;
4630}
4631
4632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004633RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634 NoHandleAllocation ha;
4635 ASSERT(args.length() == 1);
4636 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004637 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004638
4639 // Fast case: short integer or some sorts of junk values.
4640 int len = subject->length();
4641 if (subject->IsSeqAsciiString()) {
4642 if (len == 0) return Smi::FromInt(0);
4643
4644 char const* data = SeqAsciiString::cast(subject)->GetChars();
4645 bool minus = (data[0] == '-');
4646 int start_pos = (minus ? 1 : 0);
4647
4648 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004649 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004650 } else if (data[start_pos] > '9') {
4651 // Fast check for a junk value. A valid string may start from a
4652 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4653 // the 'I' character ('Infinity'). All of that have codes not greater than
4654 // '9' except 'I'.
4655 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004656 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004657 }
4658 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4659 // The maximal/minimal smi has 10 digits. If the string has less digits we
4660 // know it will fit into the smi-data type.
4661 int d = ParseDecimalInteger(data, start_pos, len);
4662 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004663 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004664 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004665 } else if (!subject->HasHashCode() &&
4666 len <= String::kMaxArrayIndexSize &&
4667 (len == 1 || data[0] != '0')) {
4668 // String hash is not calculated yet but all the data are present.
4669 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004670 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004671#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004672 subject->Hash(); // Force hash calculation.
4673 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4674 static_cast<int>(hash));
4675#endif
4676 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004677 }
4678 return Smi::FromInt(d);
4679 }
4680 }
4681
4682 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004683 return isolate->heap()->NumberFromDouble(
4684 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004685}
4686
4687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004688RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004689 NoHandleAllocation ha;
4690 ASSERT(args.length() == 1);
4691
4692 CONVERT_CHECKED(JSArray, codes, args[0]);
4693 int length = Smi::cast(codes->length())->value();
4694
4695 // Check if the string can be ASCII.
4696 int i;
4697 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004698 Object* element;
4699 { MaybeObject* maybe_element = codes->GetElement(i);
4700 // We probably can't get an exception here, but just in order to enforce
4701 // the checking of inputs in the runtime calls we check here.
4702 if (!maybe_element->ToObject(&element)) return maybe_element;
4703 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004704 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4705 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4706 break;
4707 }
4708
lrn@chromium.org303ada72010-10-27 09:33:13 +00004709 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004711 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004712 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004713 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004714 }
4715
lrn@chromium.org303ada72010-10-27 09:33:13 +00004716 Object* object = NULL;
4717 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718 String* result = String::cast(object);
4719 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004720 Object* element;
4721 { MaybeObject* maybe_element = codes->GetElement(i);
4722 if (!maybe_element->ToObject(&element)) return maybe_element;
4723 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004725 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004726 }
4727 return result;
4728}
4729
4730
4731// kNotEscaped is generated by the following:
4732//
4733// #!/bin/perl
4734// for (my $i = 0; $i < 256; $i++) {
4735// print "\n" if $i % 16 == 0;
4736// my $c = chr($i);
4737// my $escaped = 1;
4738// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4739// print $escaped ? "0, " : "1, ";
4740// }
4741
4742
4743static bool IsNotEscaped(uint16_t character) {
4744 // Only for 8 bit characters, the rest are always escaped (in a different way)
4745 ASSERT(character < 256);
4746 static const char kNotEscaped[256] = {
4747 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4748 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4749 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4750 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4751 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4752 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4753 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4754 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4755 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4756 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4757 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4758 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4759 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4760 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4761 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4762 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4763 };
4764 return kNotEscaped[character] != 0;
4765}
4766
4767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004768RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769 const char hex_chars[] = "0123456789ABCDEF";
4770 NoHandleAllocation ha;
4771 ASSERT(args.length() == 1);
4772 CONVERT_CHECKED(String, source, args[0]);
4773
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004774 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004775
4776 int escaped_length = 0;
4777 int length = source->length();
4778 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004779 Access<StringInputBuffer> buffer(
4780 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781 buffer->Reset(source);
4782 while (buffer->has_more()) {
4783 uint16_t character = buffer->GetNext();
4784 if (character >= 256) {
4785 escaped_length += 6;
4786 } else if (IsNotEscaped(character)) {
4787 escaped_length++;
4788 } else {
4789 escaped_length += 3;
4790 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004791 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004792 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004793 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004794 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004795 return Failure::OutOfMemoryException();
4796 }
4797 }
4798 }
4799 // No length change implies no change. Return original string if no change.
4800 if (escaped_length == length) {
4801 return source;
4802 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004803 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004804 { MaybeObject* maybe_o =
4805 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004806 if (!maybe_o->ToObject(&o)) return maybe_o;
4807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004808 String* destination = String::cast(o);
4809 int dest_position = 0;
4810
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004811 Access<StringInputBuffer> buffer(
4812 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004813 buffer->Rewind();
4814 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004815 uint16_t chr = buffer->GetNext();
4816 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004817 destination->Set(dest_position, '%');
4818 destination->Set(dest_position+1, 'u');
4819 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4820 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4821 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4822 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004824 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004825 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004826 dest_position++;
4827 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004828 destination->Set(dest_position, '%');
4829 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4830 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 dest_position += 3;
4832 }
4833 }
4834 return destination;
4835}
4836
4837
4838static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4839 static const signed char kHexValue['g'] = {
4840 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4841 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4842 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4843 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4844 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4845 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4846 -1, 10, 11, 12, 13, 14, 15 };
4847
4848 if (character1 > 'f') return -1;
4849 int hi = kHexValue[character1];
4850 if (hi == -1) return -1;
4851 if (character2 > 'f') return -1;
4852 int lo = kHexValue[character2];
4853 if (lo == -1) return -1;
4854 return (hi << 4) + lo;
4855}
4856
4857
ager@chromium.org870a0b62008-11-04 11:43:05 +00004858static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004859 int i,
4860 int length,
4861 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004862 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004863 int32_t hi = 0;
4864 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004865 if (character == '%' &&
4866 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004867 source->Get(i + 1) == 'u' &&
4868 (hi = TwoDigitHex(source->Get(i + 2),
4869 source->Get(i + 3))) != -1 &&
4870 (lo = TwoDigitHex(source->Get(i + 4),
4871 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872 *step = 6;
4873 return (hi << 8) + lo;
4874 } else if (character == '%' &&
4875 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004876 (lo = TwoDigitHex(source->Get(i + 1),
4877 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004878 *step = 3;
4879 return lo;
4880 } else {
4881 *step = 1;
4882 return character;
4883 }
4884}
4885
4886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004887RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888 NoHandleAllocation ha;
4889 ASSERT(args.length() == 1);
4890 CONVERT_CHECKED(String, source, args[0]);
4891
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004892 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893
4894 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004895 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004896
4897 int unescaped_length = 0;
4898 for (int i = 0; i < length; unescaped_length++) {
4899 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004900 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004901 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004902 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004903 i += step;
4904 }
4905
4906 // No length change implies no change. Return original string if no change.
4907 if (unescaped_length == length)
4908 return source;
4909
lrn@chromium.org303ada72010-10-27 09:33:13 +00004910 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004911 { MaybeObject* maybe_o =
4912 ascii ?
4913 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4914 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004915 if (!maybe_o->ToObject(&o)) return maybe_o;
4916 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004917 String* destination = String::cast(o);
4918
4919 int dest_position = 0;
4920 for (int i = 0; i < length; dest_position++) {
4921 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004922 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004923 i += step;
4924 }
4925 return destination;
4926}
4927
4928
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004929static const unsigned int kQuoteTableLength = 128u;
4930
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004931static const int kJsonQuotesCharactersPerEntry = 8;
4932static const char* const JsonQuotes =
4933 "\\u0000 \\u0001 \\u0002 \\u0003 "
4934 "\\u0004 \\u0005 \\u0006 \\u0007 "
4935 "\\b \\t \\n \\u000b "
4936 "\\f \\r \\u000e \\u000f "
4937 "\\u0010 \\u0011 \\u0012 \\u0013 "
4938 "\\u0014 \\u0015 \\u0016 \\u0017 "
4939 "\\u0018 \\u0019 \\u001a \\u001b "
4940 "\\u001c \\u001d \\u001e \\u001f "
4941 " ! \\\" # "
4942 "$ % & ' "
4943 "( ) * + "
4944 ", - . / "
4945 "0 1 2 3 "
4946 "4 5 6 7 "
4947 "8 9 : ; "
4948 "< = > ? "
4949 "@ A B C "
4950 "D E F G "
4951 "H I J K "
4952 "L M N O "
4953 "P Q R S "
4954 "T U V W "
4955 "X Y Z [ "
4956 "\\\\ ] ^ _ "
4957 "` a b c "
4958 "d e f g "
4959 "h i j k "
4960 "l m n o "
4961 "p q r s "
4962 "t u v w "
4963 "x y z { "
4964 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004965
4966
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004967// For a string that is less than 32k characters it should always be
4968// possible to allocate it in new space.
4969static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4970
4971
4972// Doing JSON quoting cannot make the string more than this many times larger.
4973static const int kJsonQuoteWorstCaseBlowup = 6;
4974
4975
4976// Covers the entire ASCII range (all other characters are unchanged by JSON
4977// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004978static const byte JsonQuoteLengths[kQuoteTableLength] = {
4979 6, 6, 6, 6, 6, 6, 6, 6,
4980 2, 2, 2, 6, 2, 2, 6, 6,
4981 6, 6, 6, 6, 6, 6, 6, 6,
4982 6, 6, 6, 6, 6, 6, 6, 6,
4983 1, 1, 2, 1, 1, 1, 1, 1,
4984 1, 1, 1, 1, 1, 1, 1, 1,
4985 1, 1, 1, 1, 1, 1, 1, 1,
4986 1, 1, 1, 1, 1, 1, 1, 1,
4987 1, 1, 1, 1, 1, 1, 1, 1,
4988 1, 1, 1, 1, 1, 1, 1, 1,
4989 1, 1, 1, 1, 1, 1, 1, 1,
4990 1, 1, 1, 1, 2, 1, 1, 1,
4991 1, 1, 1, 1, 1, 1, 1, 1,
4992 1, 1, 1, 1, 1, 1, 1, 1,
4993 1, 1, 1, 1, 1, 1, 1, 1,
4994 1, 1, 1, 1, 1, 1, 1, 1,
4995};
4996
4997
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004998template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004999MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005000
5001
5002template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005003MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5004 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005005}
5006
5007
5008template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005009MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5010 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005011}
5012
5013
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005014template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005015static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5016 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005017 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005018 const Char* read_cursor = characters.start();
5019 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005020 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005021 int quoted_length = kSpaceForQuotes;
5022 while (read_cursor < end) {
5023 Char c = *(read_cursor++);
5024 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5025 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005026 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005027 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005028 }
5029 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005030 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5031 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005032 Object* new_object;
5033 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005034 return new_alloc;
5035 }
5036 StringType* new_string = StringType::cast(new_object);
5037
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005038 Char* write_cursor = reinterpret_cast<Char*>(
5039 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005040 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005041 *(write_cursor++) = '"';
5042
5043 read_cursor = characters.start();
5044 while (read_cursor < end) {
5045 Char c = *(read_cursor++);
5046 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5047 *(write_cursor++) = c;
5048 } else {
5049 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5050 const char* replacement = JsonQuotes +
5051 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5052 for (int i = 0; i < len; i++) {
5053 *write_cursor++ = *replacement++;
5054 }
5055 }
5056 }
5057 *(write_cursor++) = '"';
5058 return new_string;
5059}
5060
5061
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005062template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005063static MaybeObject* QuoteJsonString(Isolate* isolate,
5064 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005065 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005066 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005067 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005068 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5069 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005070 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005071 }
5072
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005073 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5074 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005075 Object* new_object;
5076 if (!new_alloc->ToObject(&new_object)) {
5077 return new_alloc;
5078 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005079 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005080 // Even if our string is small enough to fit in new space we still have to
5081 // handle it being allocated in old space as may happen in the third
5082 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5083 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005084 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005085 }
5086 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005087 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005088
5089 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5090 Char* write_cursor = reinterpret_cast<Char*>(
5091 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005092 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005093 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005094
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005095 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005096 const Char* end = read_cursor + length;
5097 while (read_cursor < end) {
5098 Char c = *(read_cursor++);
5099 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5100 *(write_cursor++) = c;
5101 } else {
5102 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5103 const char* replacement = JsonQuotes +
5104 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5105 write_cursor[0] = replacement[0];
5106 if (len > 1) {
5107 write_cursor[1] = replacement[1];
5108 if (len > 2) {
5109 ASSERT(len == 6);
5110 write_cursor[2] = replacement[2];
5111 write_cursor[3] = replacement[3];
5112 write_cursor[4] = replacement[4];
5113 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005114 }
5115 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005116 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005117 }
5118 }
5119 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005120
5121 int final_length = static_cast<int>(
5122 write_cursor - reinterpret_cast<Char*>(
5123 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005124 isolate->heap()->new_space()->
5125 template ShrinkStringAtAllocationBoundary<StringType>(
5126 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005127 return new_string;
5128}
5129
5130
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005131RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005132 NoHandleAllocation ha;
5133 CONVERT_CHECKED(String, str, args[0]);
5134 if (!str->IsFlat()) {
5135 MaybeObject* try_flatten = str->TryFlatten();
5136 Object* flat;
5137 if (!try_flatten->ToObject(&flat)) {
5138 return try_flatten;
5139 }
5140 str = String::cast(flat);
5141 ASSERT(str->IsFlat());
5142 }
5143 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005144 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5145 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005146 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005147 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5148 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005149 }
5150}
5151
5152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005153RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005154 NoHandleAllocation ha;
5155 CONVERT_CHECKED(String, str, args[0]);
5156 if (!str->IsFlat()) {
5157 MaybeObject* try_flatten = str->TryFlatten();
5158 Object* flat;
5159 if (!try_flatten->ToObject(&flat)) {
5160 return try_flatten;
5161 }
5162 str = String::cast(flat);
5163 ASSERT(str->IsFlat());
5164 }
5165 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005166 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5167 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005168 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005169 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5170 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005171 }
5172}
5173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005174RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005175 NoHandleAllocation ha;
5176
5177 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005178 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005179
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005180 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181
lrn@chromium.org25156de2010-04-06 13:10:27 +00005182 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005183 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005184 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005185}
5186
5187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005188RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005189 NoHandleAllocation ha;
5190 CONVERT_CHECKED(String, str, args[0]);
5191
5192 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005193 double value = StringToDouble(isolate->unicode_cache(),
5194 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195
5196 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005197 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198}
5199
5200
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005202MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005203 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005204 String* s,
5205 int length,
5206 int input_string_length,
5207 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005208 // We try this twice, once with the assumption that the result is no longer
5209 // than the input and, if that assumption breaks, again with the exact
5210 // length. This may not be pretty, but it is nicer than what was here before
5211 // and I hereby claim my vaffel-is.
5212 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005213 // Allocate the resulting string.
5214 //
5215 // NOTE: This assumes that the upper/lower case of an ascii
5216 // character is also ascii. This is currently the case, but it
5217 // might break in the future if we implement more context and locale
5218 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005219 Object* o;
5220 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005221 ? isolate->heap()->AllocateRawAsciiString(length)
5222 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005223 if (!maybe_o->ToObject(&o)) return maybe_o;
5224 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005225 String* result = String::cast(o);
5226 bool has_changed_character = false;
5227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 // Convert all characters to upper case, assuming that they will fit
5229 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005230 Access<StringInputBuffer> buffer(
5231 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005232 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005233 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005234 // We can assume that the string is not empty
5235 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005236 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005237 bool has_next = buffer->has_more();
5238 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005239 int char_length = mapping->get(current, next, chars);
5240 if (char_length == 0) {
5241 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005242 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005243 i++;
5244 } else if (char_length == 1) {
5245 // Common case: converting the letter resulted in one character.
5246 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005247 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005248 has_changed_character = true;
5249 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005250 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251 // We've assumed that the result would be as long as the
5252 // input but here is a character that converts to several
5253 // characters. No matter, we calculate the exact length
5254 // of the result and try the whole thing again.
5255 //
5256 // Note that this leaves room for optimization. We could just
5257 // memcpy what we already have to the result string. Also,
5258 // the result string is the last object allocated we could
5259 // "realloc" it and probably, in the vast majority of cases,
5260 // extend the existing string to be able to hold the full
5261 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005262 int next_length = 0;
5263 if (has_next) {
5264 next_length = mapping->get(next, 0, chars);
5265 if (next_length == 0) next_length = 1;
5266 }
5267 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005268 while (buffer->has_more()) {
5269 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005270 // NOTE: we use 0 as the next character here because, while
5271 // the next character may affect what a character converts to,
5272 // it does not in any case affect the length of what it convert
5273 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005274 int char_length = mapping->get(current, 0, chars);
5275 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005276 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005277 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005278 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005279 return Failure::OutOfMemoryException();
5280 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005281 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005282 // Try again with the real length.
5283 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005284 } else {
5285 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005286 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005287 i++;
5288 }
5289 has_changed_character = true;
5290 }
5291 current = next;
5292 }
5293 if (has_changed_character) {
5294 return result;
5295 } else {
5296 // If we didn't actually change anything in doing the conversion
5297 // we simple return the result and let the converted string
5298 // become garbage; there is no reason to keep two identical strings
5299 // alive.
5300 return s;
5301 }
5302}
5303
5304
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005305namespace {
5306
lrn@chromium.org303ada72010-10-27 09:33:13 +00005307static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5308
5309
5310// Given a word and two range boundaries returns a word with high bit
5311// set in every byte iff the corresponding input byte was strictly in
5312// the range (m, n). All the other bits in the result are cleared.
5313// This function is only useful when it can be inlined and the
5314// boundaries are statically known.
5315// Requires: all bytes in the input word and the boundaries must be
5316// ascii (less than 0x7F).
5317static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5318 // Every byte in an ascii string is less than or equal to 0x7F.
5319 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5320 // Use strict inequalities since in edge cases the function could be
5321 // further simplified.
5322 ASSERT(0 < m && m < n && n < 0x7F);
5323 // Has high bit set in every w byte less than n.
5324 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5325 // Has high bit set in every w byte greater than m.
5326 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5327 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5328}
5329
5330
5331enum AsciiCaseConversion {
5332 ASCII_TO_LOWER,
5333 ASCII_TO_UPPER
5334};
5335
5336
5337template <AsciiCaseConversion dir>
5338struct FastAsciiConverter {
5339 static bool Convert(char* dst, char* src, int length) {
5340#ifdef DEBUG
5341 char* saved_dst = dst;
5342 char* saved_src = src;
5343#endif
5344 // We rely on the distance between upper and lower case letters
5345 // being a known power of 2.
5346 ASSERT('a' - 'A' == (1 << 5));
5347 // Boundaries for the range of input characters than require conversion.
5348 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5349 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5350 bool changed = false;
5351 char* const limit = src + length;
5352#ifdef V8_HOST_CAN_READ_UNALIGNED
5353 // Process the prefix of the input that requires no conversion one
5354 // (machine) word at a time.
5355 while (src <= limit - sizeof(uintptr_t)) {
5356 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5357 if (AsciiRangeMask(w, lo, hi) != 0) {
5358 changed = true;
5359 break;
5360 }
5361 *reinterpret_cast<uintptr_t*>(dst) = w;
5362 src += sizeof(uintptr_t);
5363 dst += sizeof(uintptr_t);
5364 }
5365 // Process the remainder of the input performing conversion when
5366 // required one word at a time.
5367 while (src <= limit - sizeof(uintptr_t)) {
5368 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5369 uintptr_t m = AsciiRangeMask(w, lo, hi);
5370 // The mask has high (7th) bit set in every byte that needs
5371 // conversion and we know that the distance between cases is
5372 // 1 << 5.
5373 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5374 src += sizeof(uintptr_t);
5375 dst += sizeof(uintptr_t);
5376 }
5377#endif
5378 // Process the last few bytes of the input (or the whole input if
5379 // unaligned access is not supported).
5380 while (src < limit) {
5381 char c = *src;
5382 if (lo < c && c < hi) {
5383 c ^= (1 << 5);
5384 changed = true;
5385 }
5386 *dst = c;
5387 ++src;
5388 ++dst;
5389 }
5390#ifdef DEBUG
5391 CheckConvert(saved_dst, saved_src, length, changed);
5392#endif
5393 return changed;
5394 }
5395
5396#ifdef DEBUG
5397 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5398 bool expected_changed = false;
5399 for (int i = 0; i < length; i++) {
5400 if (dst[i] == src[i]) continue;
5401 expected_changed = true;
5402 if (dir == ASCII_TO_LOWER) {
5403 ASSERT('A' <= src[i] && src[i] <= 'Z');
5404 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5405 } else {
5406 ASSERT(dir == ASCII_TO_UPPER);
5407 ASSERT('a' <= src[i] && src[i] <= 'z');
5408 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5409 }
5410 }
5411 ASSERT(expected_changed == changed);
5412 }
5413#endif
5414};
5415
5416
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005417struct ToLowerTraits {
5418 typedef unibrow::ToLowercase UnibrowConverter;
5419
lrn@chromium.org303ada72010-10-27 09:33:13 +00005420 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005421};
5422
5423
5424struct ToUpperTraits {
5425 typedef unibrow::ToUppercase UnibrowConverter;
5426
lrn@chromium.org303ada72010-10-27 09:33:13 +00005427 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005428};
5429
5430} // namespace
5431
5432
5433template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005434MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005435 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005436 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005437 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005438 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005439 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005440 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005441
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005442 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005443 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005444 if (length == 0) return s;
5445
5446 // Simpler handling of ascii strings.
5447 //
5448 // NOTE: This assumes that the upper/lower case of an ascii
5449 // character is also ascii. This is currently the case, but it
5450 // might break in the future if we implement more context and locale
5451 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005452 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005453 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005454 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005455 if (!maybe_o->ToObject(&o)) return maybe_o;
5456 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005457 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005458 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005459 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005460 return has_changed_character ? result : s;
5461 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005462
lrn@chromium.org303ada72010-10-27 09:33:13 +00005463 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005464 { MaybeObject* maybe_answer =
5465 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005466 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5467 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005468 if (answer->IsSmi()) {
5469 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005470 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005471 ConvertCaseHelper(isolate,
5472 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005473 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5474 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005475 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005476 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005477}
5478
5479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005480RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005481 return ConvertCase<ToLowerTraits>(
5482 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005483}
5484
5485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005486RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005487 return ConvertCase<ToUpperTraits>(
5488 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489}
5490
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005491
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005492static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5493 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5494}
5495
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005497RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005498 NoHandleAllocation ha;
5499 ASSERT(args.length() == 3);
5500
5501 CONVERT_CHECKED(String, s, args[0]);
5502 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5503 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5504
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005505 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005506 int length = s->length();
5507
5508 int left = 0;
5509 if (trimLeft) {
5510 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5511 left++;
5512 }
5513 }
5514
5515 int right = length;
5516 if (trimRight) {
5517 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5518 right--;
5519 }
5520 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005521 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005522}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005523
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005524
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005525template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005526void FindStringIndices(Isolate* isolate,
5527 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005528 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005529 ZoneList<int>* indices,
5530 unsigned int limit) {
5531 ASSERT(limit > 0);
5532 // Collect indices of pattern in subject, and the end-of-string index.
5533 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005534 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005535 int pattern_length = pattern.length();
5536 int index = 0;
5537 while (limit > 0) {
5538 index = search.Search(subject, index);
5539 if (index < 0) return;
5540 indices->Add(index);
5541 index += pattern_length;
5542 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005543 }
5544}
5545
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005547RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005548 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005549 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005550 CONVERT_ARG_CHECKED(String, subject, 0);
5551 CONVERT_ARG_CHECKED(String, pattern, 1);
5552 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5553
5554 int subject_length = subject->length();
5555 int pattern_length = pattern->length();
5556 RUNTIME_ASSERT(pattern_length > 0);
5557
5558 // The limit can be very large (0xffffffffu), but since the pattern
5559 // isn't empty, we can never create more parts than ~half the length
5560 // of the subject.
5561
5562 if (!subject->IsFlat()) FlattenString(subject);
5563
5564 static const int kMaxInitialListCapacity = 16;
5565
5566 ZoneScope scope(DELETE_ON_EXIT);
5567
5568 // Find (up to limit) indices of separator and end-of-string in subject
5569 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5570 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005571 if (!pattern->IsFlat()) FlattenString(pattern);
5572
5573 // No allocation block.
5574 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005575 AssertNoAllocation nogc;
5576 if (subject->IsAsciiRepresentation()) {
5577 Vector<const char> subject_vector = subject->ToAsciiVector();
5578 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005579 FindStringIndices(isolate,
5580 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005581 pattern->ToAsciiVector(),
5582 &indices,
5583 limit);
5584 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005585 FindStringIndices(isolate,
5586 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005587 pattern->ToUC16Vector(),
5588 &indices,
5589 limit);
5590 }
5591 } else {
5592 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5593 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005594 FindStringIndices(isolate,
5595 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005596 pattern->ToAsciiVector(),
5597 &indices,
5598 limit);
5599 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005600 FindStringIndices(isolate,
5601 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005602 pattern->ToUC16Vector(),
5603 &indices,
5604 limit);
5605 }
5606 }
5607 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005608
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005609 if (static_cast<uint32_t>(indices.length()) < limit) {
5610 indices.Add(subject_length);
5611 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005612
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005613 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005614
5615 // Create JSArray of substrings separated by separator.
5616 int part_count = indices.length();
5617
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005618 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005619 result->set_length(Smi::FromInt(part_count));
5620
5621 ASSERT(result->HasFastElements());
5622
5623 if (part_count == 1 && indices.at(0) == subject_length) {
5624 FixedArray::cast(result->elements())->set(0, *subject);
5625 return *result;
5626 }
5627
5628 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5629 int part_start = 0;
5630 for (int i = 0; i < part_count; i++) {
5631 HandleScope local_loop_handle;
5632 int part_end = indices.at(i);
5633 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005634 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005635 elements->set(i, *substring);
5636 part_start = part_end + pattern_length;
5637 }
5638
5639 return *result;
5640}
5641
5642
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005643// Copies ascii characters to the given fixed array looking up
5644// one-char strings in the cache. Gives up on the first char that is
5645// not in the cache and fills the remainder with smi zeros. Returns
5646// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005647static int CopyCachedAsciiCharsToArray(Heap* heap,
5648 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005649 FixedArray* elements,
5650 int length) {
5651 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005652 FixedArray* ascii_cache = heap->single_character_string_cache();
5653 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005654 int i;
5655 for (i = 0; i < length; ++i) {
5656 Object* value = ascii_cache->get(chars[i]);
5657 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005658 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005659 elements->set(i, value, SKIP_WRITE_BARRIER);
5660 }
5661 if (i < length) {
5662 ASSERT(Smi::FromInt(0) == 0);
5663 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5664 }
5665#ifdef DEBUG
5666 for (int j = 0; j < length; ++j) {
5667 Object* element = elements->get(j);
5668 ASSERT(element == Smi::FromInt(0) ||
5669 (element->IsString() && String::cast(element)->LooksValid()));
5670 }
5671#endif
5672 return i;
5673}
5674
5675
5676// Converts a String to JSArray.
5677// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005678RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005679 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005680 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005681 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005682 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005683
5684 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005685 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005686
5687 Handle<FixedArray> elements;
5688 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005689 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005690 { MaybeObject* maybe_obj =
5691 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005692 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5693 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005694 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005695
5696 Vector<const char> chars = s->ToAsciiVector();
5697 // Note, this will initialize all elements (not only the prefix)
5698 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005699 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5700 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005701 *elements,
5702 length);
5703
5704 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005705 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5706 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005707 }
5708 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005709 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005710 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005711 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5712 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005713 }
5714 }
5715
5716#ifdef DEBUG
5717 for (int i = 0; i < length; ++i) {
5718 ASSERT(String::cast(elements->get(i))->length() == 1);
5719 }
5720#endif
5721
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005722 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005723}
5724
5725
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005726RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005727 NoHandleAllocation ha;
5728 ASSERT(args.length() == 1);
5729 CONVERT_CHECKED(String, value, args[0]);
5730 return value->ToObject();
5731}
5732
5733
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005734bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005735 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005737 return char_length == 0;
5738}
5739
5740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005741RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005742 NoHandleAllocation ha;
5743 ASSERT(args.length() == 1);
5744
5745 Object* number = args[0];
5746 RUNTIME_ASSERT(number->IsNumber());
5747
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005748 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005749}
5750
5751
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005752RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005753 NoHandleAllocation ha;
5754 ASSERT(args.length() == 1);
5755
5756 Object* number = args[0];
5757 RUNTIME_ASSERT(number->IsNumber());
5758
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005759 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005760}
5761
5762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005763RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005764 NoHandleAllocation ha;
5765 ASSERT(args.length() == 1);
5766
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005767 CONVERT_DOUBLE_CHECKED(number, args[0]);
5768
5769 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5770 if (number > 0 && number <= Smi::kMaxValue) {
5771 return Smi::FromInt(static_cast<int>(number));
5772 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005773 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005774}
5775
5776
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005777RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005778 NoHandleAllocation ha;
5779 ASSERT(args.length() == 1);
5780
5781 CONVERT_DOUBLE_CHECKED(number, args[0]);
5782
5783 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5784 if (number > 0 && number <= Smi::kMaxValue) {
5785 return Smi::FromInt(static_cast<int>(number));
5786 }
5787
5788 double double_value = DoubleToInteger(number);
5789 // Map both -0 and +0 to +0.
5790 if (double_value == 0) double_value = 0;
5791
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005792 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005793}
5794
5795
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005796RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005797 NoHandleAllocation ha;
5798 ASSERT(args.length() == 1);
5799
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005800 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005801 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005802}
5803
5804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005805RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005806 NoHandleAllocation ha;
5807 ASSERT(args.length() == 1);
5808
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005809 CONVERT_DOUBLE_CHECKED(number, args[0]);
5810
5811 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5812 if (number > 0 && number <= Smi::kMaxValue) {
5813 return Smi::FromInt(static_cast<int>(number));
5814 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005815 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005816}
5817
5818
ager@chromium.org870a0b62008-11-04 11:43:05 +00005819// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5820// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005821RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005822 NoHandleAllocation ha;
5823 ASSERT(args.length() == 1);
5824
5825 Object* obj = args[0];
5826 if (obj->IsSmi()) {
5827 return obj;
5828 }
5829 if (obj->IsHeapNumber()) {
5830 double value = HeapNumber::cast(obj)->value();
5831 int int_value = FastD2I(value);
5832 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5833 return Smi::FromInt(int_value);
5834 }
5835 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005836 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005837}
5838
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005840RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005841 NoHandleAllocation ha;
5842 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005843 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005844}
5845
5846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005847RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005848 NoHandleAllocation ha;
5849 ASSERT(args.length() == 2);
5850
5851 CONVERT_DOUBLE_CHECKED(x, args[0]);
5852 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005853 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005854}
5855
5856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005857RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005858 NoHandleAllocation ha;
5859 ASSERT(args.length() == 2);
5860
5861 CONVERT_DOUBLE_CHECKED(x, args[0]);
5862 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005863 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005864}
5865
5866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005867RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005868 NoHandleAllocation ha;
5869 ASSERT(args.length() == 2);
5870
5871 CONVERT_DOUBLE_CHECKED(x, args[0]);
5872 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005873 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005874}
5875
5876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005877RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005878 NoHandleAllocation ha;
5879 ASSERT(args.length() == 1);
5880
5881 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005882 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005883}
5884
5885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005886RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005887 NoHandleAllocation ha;
5888 ASSERT(args.length() == 0);
5889
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005890 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005891}
5892
5893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005894RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005895 NoHandleAllocation ha;
5896 ASSERT(args.length() == 2);
5897
5898 CONVERT_DOUBLE_CHECKED(x, args[0]);
5899 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005900 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005901}
5902
5903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005904RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005905 NoHandleAllocation ha;
5906 ASSERT(args.length() == 2);
5907
5908 CONVERT_DOUBLE_CHECKED(x, args[0]);
5909 CONVERT_DOUBLE_CHECKED(y, args[1]);
5910
ager@chromium.org3811b432009-10-28 14:53:37 +00005911 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005912 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005913 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914}
5915
5916
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005917RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918 NoHandleAllocation ha;
5919 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920 CONVERT_CHECKED(String, str1, args[0]);
5921 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005922 isolate->counters()->string_add_runtime()->Increment();
5923 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924}
5925
5926
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005927template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005928static inline void StringBuilderConcatHelper(String* special,
5929 sinkchar* sink,
5930 FixedArray* fixed_array,
5931 int array_length) {
5932 int position = 0;
5933 for (int i = 0; i < array_length; i++) {
5934 Object* element = fixed_array->get(i);
5935 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005936 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005937 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005938 int pos;
5939 int len;
5940 if (encoded_slice > 0) {
5941 // Position and length encoded in one smi.
5942 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5943 len = StringBuilderSubstringLength::decode(encoded_slice);
5944 } else {
5945 // Position and length encoded in two smis.
5946 Object* obj = fixed_array->get(++i);
5947 ASSERT(obj->IsSmi());
5948 pos = Smi::cast(obj)->value();
5949 len = -encoded_slice;
5950 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005951 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005952 sink + position,
5953 pos,
5954 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005955 position += len;
5956 } else {
5957 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005958 int element_length = string->length();
5959 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005960 position += element_length;
5961 }
5962 }
5963}
5964
5965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005966RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005967 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005968 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005970 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005971 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005972 return Failure::OutOfMemoryException();
5973 }
5974 int array_length = Smi::cast(args[1])->value();
5975 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005976
5977 // This assumption is used by the slice encoding in one or two smis.
5978 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5979
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005980 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005982 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005983 }
5984 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005985 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005987 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988
5989 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005990 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005991 } else if (array_length == 1) {
5992 Object* first = fixed_array->get(0);
5993 if (first->IsString()) return first;
5994 }
5995
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005996 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005997 int position = 0;
5998 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005999 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000 Object* elt = fixed_array->get(i);
6001 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006002 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006003 int smi_value = Smi::cast(elt)->value();
6004 int pos;
6005 int len;
6006 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006007 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006008 pos = StringBuilderSubstringPosition::decode(smi_value);
6009 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006010 } else {
6011 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006012 len = -smi_value;
6013 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006014 i++;
6015 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006016 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006017 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006018 Object* next_smi = fixed_array->get(i);
6019 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006020 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006021 }
6022 pos = Smi::cast(next_smi)->value();
6023 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006024 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006025 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006027 ASSERT(pos >= 0);
6028 ASSERT(len >= 0);
6029 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006030 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006031 }
6032 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006033 } else if (elt->IsString()) {
6034 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006035 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006036 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006037 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006039 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006041 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006042 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006043 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006044 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006045 return Failure::OutOfMemoryException();
6046 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006047 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006048 }
6049
6050 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006051 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006052
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006054 { MaybeObject* maybe_object =
6055 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006056 if (!maybe_object->ToObject(&object)) return maybe_object;
6057 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006058 SeqAsciiString* answer = SeqAsciiString::cast(object);
6059 StringBuilderConcatHelper(special,
6060 answer->GetChars(),
6061 fixed_array,
6062 array_length);
6063 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006064 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006065 { MaybeObject* maybe_object =
6066 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006067 if (!maybe_object->ToObject(&object)) return maybe_object;
6068 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006069 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6070 StringBuilderConcatHelper(special,
6071 answer->GetChars(),
6072 fixed_array,
6073 array_length);
6074 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006075 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006076}
6077
6078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006079RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006080 NoHandleAllocation ha;
6081 ASSERT(args.length() == 3);
6082 CONVERT_CHECKED(JSArray, array, args[0]);
6083 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006084 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006085 return Failure::OutOfMemoryException();
6086 }
6087 int array_length = Smi::cast(args[1])->value();
6088 CONVERT_CHECKED(String, separator, args[2]);
6089
6090 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006091 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006092 }
6093 FixedArray* fixed_array = FixedArray::cast(array->elements());
6094 if (fixed_array->length() < array_length) {
6095 array_length = fixed_array->length();
6096 }
6097
6098 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006099 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006100 } else if (array_length == 1) {
6101 Object* first = fixed_array->get(0);
6102 if (first->IsString()) return first;
6103 }
6104
6105 int separator_length = separator->length();
6106 int max_nof_separators =
6107 (String::kMaxLength + separator_length - 1) / separator_length;
6108 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006109 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006110 return Failure::OutOfMemoryException();
6111 }
6112 int length = (array_length - 1) * separator_length;
6113 for (int i = 0; i < array_length; i++) {
6114 Object* element_obj = fixed_array->get(i);
6115 if (!element_obj->IsString()) {
6116 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006117 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006118 }
6119 String* element = String::cast(element_obj);
6120 int increment = element->length();
6121 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006122 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006123 return Failure::OutOfMemoryException();
6124 }
6125 length += increment;
6126 }
6127
6128 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006129 { MaybeObject* maybe_object =
6130 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006131 if (!maybe_object->ToObject(&object)) return maybe_object;
6132 }
6133 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6134
6135 uc16* sink = answer->GetChars();
6136#ifdef DEBUG
6137 uc16* end = sink + length;
6138#endif
6139
6140 String* first = String::cast(fixed_array->get(0));
6141 int first_length = first->length();
6142 String::WriteToFlat(first, sink, 0, first_length);
6143 sink += first_length;
6144
6145 for (int i = 1; i < array_length; i++) {
6146 ASSERT(sink + separator_length <= end);
6147 String::WriteToFlat(separator, sink, 0, separator_length);
6148 sink += separator_length;
6149
6150 String* element = String::cast(fixed_array->get(i));
6151 int element_length = element->length();
6152 ASSERT(sink + element_length <= end);
6153 String::WriteToFlat(element, sink, 0, element_length);
6154 sink += element_length;
6155 }
6156 ASSERT(sink == end);
6157
6158 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6159 return answer;
6160}
6161
6162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006163RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006164 NoHandleAllocation ha;
6165 ASSERT(args.length() == 2);
6166
6167 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6168 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006169 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006170}
6171
6172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006173RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006174 NoHandleAllocation ha;
6175 ASSERT(args.length() == 2);
6176
6177 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6178 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006179 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006180}
6181
6182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006183RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006184 NoHandleAllocation ha;
6185 ASSERT(args.length() == 2);
6186
6187 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6188 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006189 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006190}
6191
6192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006193RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006194 NoHandleAllocation ha;
6195 ASSERT(args.length() == 1);
6196
6197 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006198 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006199}
6200
6201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006202RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203 NoHandleAllocation ha;
6204 ASSERT(args.length() == 2);
6205
6206 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6207 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006208 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006209}
6210
6211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006212RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006213 NoHandleAllocation ha;
6214 ASSERT(args.length() == 2);
6215
6216 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6217 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006218 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006219}
6220
6221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006222RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006223 NoHandleAllocation ha;
6224 ASSERT(args.length() == 2);
6225
6226 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6227 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006228 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006229}
6230
6231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006232RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006233 NoHandleAllocation ha;
6234 ASSERT(args.length() == 2);
6235
6236 CONVERT_DOUBLE_CHECKED(x, args[0]);
6237 CONVERT_DOUBLE_CHECKED(y, args[1]);
6238 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6239 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6240 if (x == y) return Smi::FromInt(EQUAL);
6241 Object* result;
6242 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6243 result = Smi::FromInt(EQUAL);
6244 } else {
6245 result = Smi::FromInt(NOT_EQUAL);
6246 }
6247 return result;
6248}
6249
6250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006251RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252 NoHandleAllocation ha;
6253 ASSERT(args.length() == 2);
6254
6255 CONVERT_CHECKED(String, x, args[0]);
6256 CONVERT_CHECKED(String, y, args[1]);
6257
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006258 bool not_equal = !x->Equals(y);
6259 // This is slightly convoluted because the value that signifies
6260 // equality is 0 and inequality is 1 so we have to negate the result
6261 // from String::Equals.
6262 ASSERT(not_equal == 0 || not_equal == 1);
6263 STATIC_CHECK(EQUAL == 0);
6264 STATIC_CHECK(NOT_EQUAL == 1);
6265 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006266}
6267
6268
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006269RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006270 NoHandleAllocation ha;
6271 ASSERT(args.length() == 3);
6272
6273 CONVERT_DOUBLE_CHECKED(x, args[0]);
6274 CONVERT_DOUBLE_CHECKED(y, args[1]);
6275 if (isnan(x) || isnan(y)) return args[2];
6276 if (x == y) return Smi::FromInt(EQUAL);
6277 if (isless(x, y)) return Smi::FromInt(LESS);
6278 return Smi::FromInt(GREATER);
6279}
6280
6281
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006282// Compare two Smis as if they were converted to strings and then
6283// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006284RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006285 NoHandleAllocation ha;
6286 ASSERT(args.length() == 2);
6287
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006288 // Extract the integer values from the Smis.
6289 CONVERT_CHECKED(Smi, x, args[0]);
6290 CONVERT_CHECKED(Smi, y, args[1]);
6291 int x_value = x->value();
6292 int y_value = y->value();
6293
6294 // If the integers are equal so are the string representations.
6295 if (x_value == y_value) return Smi::FromInt(EQUAL);
6296
6297 // If one of the integers are zero the normal integer order is the
6298 // same as the lexicographic order of the string representations.
6299 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6300
ager@chromium.org32912102009-01-16 10:38:43 +00006301 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006302 // smallest because the char code of '-' is less than the char code
6303 // of any digit. Otherwise, we make both values positive.
6304 if (x_value < 0 || y_value < 0) {
6305 if (y_value >= 0) return Smi::FromInt(LESS);
6306 if (x_value >= 0) return Smi::FromInt(GREATER);
6307 x_value = -x_value;
6308 y_value = -y_value;
6309 }
6310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006311 // Arrays for the individual characters of the two Smis. Smis are
6312 // 31 bit integers and 10 decimal digits are therefore enough.
6313 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6314 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6315 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6316
6317
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006318 // Convert the integers to arrays of their decimal digits.
6319 int x_index = 0;
6320 int y_index = 0;
6321 while (x_value > 0) {
6322 x_elms[x_index++] = x_value % 10;
6323 x_value /= 10;
6324 }
6325 while (y_value > 0) {
6326 y_elms[y_index++] = y_value % 10;
6327 y_value /= 10;
6328 }
6329
6330 // Loop through the arrays of decimal digits finding the first place
6331 // where they differ.
6332 while (--x_index >= 0 && --y_index >= 0) {
6333 int diff = x_elms[x_index] - y_elms[y_index];
6334 if (diff != 0) return Smi::FromInt(diff);
6335 }
6336
6337 // If one array is a suffix of the other array, the longest array is
6338 // the representation of the largest of the Smis in the
6339 // lexicographic ordering.
6340 return Smi::FromInt(x_index - y_index);
6341}
6342
6343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006344static Object* StringInputBufferCompare(RuntimeState* state,
6345 String* x,
6346 String* y) {
6347 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6348 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006349 bufx.Reset(x);
6350 bufy.Reset(y);
6351 while (bufx.has_more() && bufy.has_more()) {
6352 int d = bufx.GetNext() - bufy.GetNext();
6353 if (d < 0) return Smi::FromInt(LESS);
6354 else if (d > 0) return Smi::FromInt(GREATER);
6355 }
6356
6357 // x is (non-trivial) prefix of y:
6358 if (bufy.has_more()) return Smi::FromInt(LESS);
6359 // y is prefix of x:
6360 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6361}
6362
6363
6364static Object* FlatStringCompare(String* x, String* y) {
6365 ASSERT(x->IsFlat());
6366 ASSERT(y->IsFlat());
6367 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6368 int prefix_length = x->length();
6369 if (y->length() < prefix_length) {
6370 prefix_length = y->length();
6371 equal_prefix_result = Smi::FromInt(GREATER);
6372 } else if (y->length() > prefix_length) {
6373 equal_prefix_result = Smi::FromInt(LESS);
6374 }
6375 int r;
6376 if (x->IsAsciiRepresentation()) {
6377 Vector<const char> x_chars = x->ToAsciiVector();
6378 if (y->IsAsciiRepresentation()) {
6379 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006380 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006381 } else {
6382 Vector<const uc16> y_chars = y->ToUC16Vector();
6383 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6384 }
6385 } else {
6386 Vector<const uc16> x_chars = x->ToUC16Vector();
6387 if (y->IsAsciiRepresentation()) {
6388 Vector<const char> y_chars = y->ToAsciiVector();
6389 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6390 } else {
6391 Vector<const uc16> y_chars = y->ToUC16Vector();
6392 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6393 }
6394 }
6395 Object* result;
6396 if (r == 0) {
6397 result = equal_prefix_result;
6398 } else {
6399 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6400 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006401 ASSERT(result ==
6402 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006403 return result;
6404}
6405
6406
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006407RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006408 NoHandleAllocation ha;
6409 ASSERT(args.length() == 2);
6410
6411 CONVERT_CHECKED(String, x, args[0]);
6412 CONVERT_CHECKED(String, y, args[1]);
6413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006414 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006415
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006416 // A few fast case tests before we flatten.
6417 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006418 if (y->length() == 0) {
6419 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006420 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006421 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006422 return Smi::FromInt(LESS);
6423 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006424
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006425 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006426 if (d < 0) return Smi::FromInt(LESS);
6427 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006428
lrn@chromium.org303ada72010-10-27 09:33:13 +00006429 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006430 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006431 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6432 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006433 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006434 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6435 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006436
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006437 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006438 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006439}
6440
6441
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006442RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006443 NoHandleAllocation ha;
6444 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006445 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006446
6447 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006448 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006449}
6450
6451
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006452RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453 NoHandleAllocation ha;
6454 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006455 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006456
6457 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006458 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006459}
6460
6461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006462RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006463 NoHandleAllocation ha;
6464 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006465 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006466
6467 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006468 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006469}
6470
6471
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006472static const double kPiDividedBy4 = 0.78539816339744830962;
6473
6474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006475RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006476 NoHandleAllocation ha;
6477 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006478 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006479
6480 CONVERT_DOUBLE_CHECKED(x, args[0]);
6481 CONVERT_DOUBLE_CHECKED(y, args[1]);
6482 double result;
6483 if (isinf(x) && isinf(y)) {
6484 // Make sure that the result in case of two infinite arguments
6485 // is a multiple of Pi / 4. The sign of the result is determined
6486 // by the first argument (x) and the sign of the second argument
6487 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006488 int multiplier = (x < 0) ? -1 : 1;
6489 if (y < 0) multiplier *= 3;
6490 result = multiplier * kPiDividedBy4;
6491 } else {
6492 result = atan2(x, y);
6493 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006494 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006495}
6496
6497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006498RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006499 NoHandleAllocation ha;
6500 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006502
6503 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006504 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505}
6506
6507
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006508RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006509 NoHandleAllocation ha;
6510 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006511 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006512
6513 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006514 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515}
6516
6517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006518RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006519 NoHandleAllocation ha;
6520 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006521 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006522
6523 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006524 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525}
6526
6527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006528RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006529 NoHandleAllocation ha;
6530 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006531 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006532
6533 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006534 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006535}
6536
6537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006538RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006539 NoHandleAllocation ha;
6540 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006541 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006542
6543 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006544 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006545}
6546
6547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006548RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006549 NoHandleAllocation ha;
6550 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006551 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006552
6553 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006554
6555 // If the second argument is a smi, it is much faster to call the
6556 // custom powi() function than the generic pow().
6557 if (args[1]->IsSmi()) {
6558 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006559 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006560 }
6561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006562 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006563 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006564}
6565
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006566// Fast version of Math.pow if we know that y is not an integer and
6567// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006568RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006569 NoHandleAllocation ha;
6570 ASSERT(args.length() == 2);
6571 CONVERT_DOUBLE_CHECKED(x, args[0]);
6572 CONVERT_DOUBLE_CHECKED(y, args[1]);
6573 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006574 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006575 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006576 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006577 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006578 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006579 }
6580}
6581
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006583RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006584 NoHandleAllocation ha;
6585 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006586 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006588 if (!args[0]->IsHeapNumber()) {
6589 // Must be smi. Return the argument unchanged for all the other types
6590 // to make fuzz-natives test happy.
6591 return args[0];
6592 }
6593
6594 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6595
6596 double value = number->value();
6597 int exponent = number->get_exponent();
6598 int sign = number->get_sign();
6599
danno@chromium.org160a7b02011-04-18 15:51:38 +00006600 if (exponent < -1) {
6601 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6602 if (sign) return isolate->heap()->minus_zero_value();
6603 return Smi::FromInt(0);
6604 }
6605
6606 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6607 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6608 // agument holds for 32-bit smis).
6609 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006610 return Smi::FromInt(static_cast<int>(value + 0.5));
6611 }
6612
6613 // If the magnitude is big enough, there's no place for fraction part. If we
6614 // try to add 0.5 to this number, 1.0 will be added instead.
6615 if (exponent >= 52) {
6616 return number;
6617 }
6618
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006619 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006620
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006621 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006622 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623}
6624
6625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006626RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006627 NoHandleAllocation ha;
6628 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006629 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006630
6631 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006632 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633}
6634
6635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006636RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006637 NoHandleAllocation ha;
6638 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006639 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006640
6641 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006642 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006643}
6644
6645
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006646RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006647 NoHandleAllocation ha;
6648 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006649 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006650
6651 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006652 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006653}
6654
6655
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006656static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006657 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6658 181, 212, 243, 273, 304, 334};
6659 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6660 182, 213, 244, 274, 305, 335};
6661
6662 year += month / 12;
6663 month %= 12;
6664 if (month < 0) {
6665 year--;
6666 month += 12;
6667 }
6668
6669 ASSERT(month >= 0);
6670 ASSERT(month < 12);
6671
6672 // year_delta is an arbitrary number such that:
6673 // a) year_delta = -1 (mod 400)
6674 // b) year + year_delta > 0 for years in the range defined by
6675 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6676 // Jan 1 1970. This is required so that we don't run into integer
6677 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006678 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006679 // operations.
6680 static const int year_delta = 399999;
6681 static const int base_day = 365 * (1970 + year_delta) +
6682 (1970 + year_delta) / 4 -
6683 (1970 + year_delta) / 100 +
6684 (1970 + year_delta) / 400;
6685
6686 int year1 = year + year_delta;
6687 int day_from_year = 365 * year1 +
6688 year1 / 4 -
6689 year1 / 100 +
6690 year1 / 400 -
6691 base_day;
6692
6693 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006694 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006695 }
6696
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006697 return day_from_year + day_from_month_leap[month] + day - 1;
6698}
6699
6700
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006701RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006702 NoHandleAllocation ha;
6703 ASSERT(args.length() == 3);
6704
6705 CONVERT_SMI_CHECKED(year, args[0]);
6706 CONVERT_SMI_CHECKED(month, args[1]);
6707 CONVERT_SMI_CHECKED(date, args[2]);
6708
6709 return Smi::FromInt(MakeDay(year, month, date));
6710}
6711
6712
6713static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6714static const int kDaysIn4Years = 4 * 365 + 1;
6715static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6716static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6717static const int kDays1970to2000 = 30 * 365 + 7;
6718static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6719 kDays1970to2000;
6720static const int kYearsOffset = 400000;
6721
6722static const char kDayInYear[] = {
6723 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6724 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6725 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6726 22, 23, 24, 25, 26, 27, 28,
6727 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6728 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6729 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6730 22, 23, 24, 25, 26, 27, 28, 29, 30,
6731 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6732 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6733 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6734 22, 23, 24, 25, 26, 27, 28, 29, 30,
6735 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6736 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6737 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6738 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6739 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6740 22, 23, 24, 25, 26, 27, 28, 29, 30,
6741 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6742 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6743 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6744 22, 23, 24, 25, 26, 27, 28, 29, 30,
6745 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6746 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6747
6748 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6749 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6750 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6751 22, 23, 24, 25, 26, 27, 28,
6752 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6753 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6754 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6755 22, 23, 24, 25, 26, 27, 28, 29, 30,
6756 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6757 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6758 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6759 22, 23, 24, 25, 26, 27, 28, 29, 30,
6760 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6761 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6762 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6763 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6764 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6765 22, 23, 24, 25, 26, 27, 28, 29, 30,
6766 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6767 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6768 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6769 22, 23, 24, 25, 26, 27, 28, 29, 30,
6770 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6771 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6772
6773 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6774 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6775 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6776 22, 23, 24, 25, 26, 27, 28, 29,
6777 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6778 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6779 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6780 22, 23, 24, 25, 26, 27, 28, 29, 30,
6781 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6782 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6783 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6784 22, 23, 24, 25, 26, 27, 28, 29, 30,
6785 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6786 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6787 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6788 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6789 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6790 22, 23, 24, 25, 26, 27, 28, 29, 30,
6791 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6792 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6793 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6794 22, 23, 24, 25, 26, 27, 28, 29, 30,
6795 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6796 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6797
6798 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6799 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6800 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6801 22, 23, 24, 25, 26, 27, 28,
6802 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6803 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6804 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6805 22, 23, 24, 25, 26, 27, 28, 29, 30,
6806 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6807 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6808 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6809 22, 23, 24, 25, 26, 27, 28, 29, 30,
6810 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6811 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6812 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6813 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6814 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6815 22, 23, 24, 25, 26, 27, 28, 29, 30,
6816 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6817 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6818 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6819 22, 23, 24, 25, 26, 27, 28, 29, 30,
6820 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6821 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6822
6823static const char kMonthInYear[] = {
6824 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,
6825 0, 0, 0, 0, 0, 0,
6826 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,
6827 1, 1, 1,
6828 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,
6829 2, 2, 2, 2, 2, 2,
6830 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,
6831 3, 3, 3, 3, 3,
6832 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,
6833 4, 4, 4, 4, 4, 4,
6834 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,
6835 5, 5, 5, 5, 5,
6836 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,
6837 6, 6, 6, 6, 6, 6,
6838 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,
6839 7, 7, 7, 7, 7, 7,
6840 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,
6841 8, 8, 8, 8, 8,
6842 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,
6843 9, 9, 9, 9, 9, 9,
6844 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6845 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6846 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6847 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6848
6849 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,
6850 0, 0, 0, 0, 0, 0,
6851 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,
6852 1, 1, 1,
6853 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,
6854 2, 2, 2, 2, 2, 2,
6855 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,
6856 3, 3, 3, 3, 3,
6857 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,
6858 4, 4, 4, 4, 4, 4,
6859 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,
6860 5, 5, 5, 5, 5,
6861 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,
6862 6, 6, 6, 6, 6, 6,
6863 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,
6864 7, 7, 7, 7, 7, 7,
6865 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,
6866 8, 8, 8, 8, 8,
6867 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,
6868 9, 9, 9, 9, 9, 9,
6869 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6870 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6871 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6872 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6873
6874 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,
6875 0, 0, 0, 0, 0, 0,
6876 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,
6877 1, 1, 1, 1,
6878 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,
6879 2, 2, 2, 2, 2, 2,
6880 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,
6881 3, 3, 3, 3, 3,
6882 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,
6883 4, 4, 4, 4, 4, 4,
6884 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,
6885 5, 5, 5, 5, 5,
6886 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,
6887 6, 6, 6, 6, 6, 6,
6888 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,
6889 7, 7, 7, 7, 7, 7,
6890 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,
6891 8, 8, 8, 8, 8,
6892 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,
6893 9, 9, 9, 9, 9, 9,
6894 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6895 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6896 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6897 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6898
6899 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,
6900 0, 0, 0, 0, 0, 0,
6901 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,
6902 1, 1, 1,
6903 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,
6904 2, 2, 2, 2, 2, 2,
6905 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,
6906 3, 3, 3, 3, 3,
6907 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,
6908 4, 4, 4, 4, 4, 4,
6909 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,
6910 5, 5, 5, 5, 5,
6911 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,
6912 6, 6, 6, 6, 6, 6,
6913 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,
6914 7, 7, 7, 7, 7, 7,
6915 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,
6916 8, 8, 8, 8, 8,
6917 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,
6918 9, 9, 9, 9, 9, 9,
6919 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6920 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6921 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6922 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6923
6924
6925// This function works for dates from 1970 to 2099.
6926static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006927 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006928#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006929 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006930#endif
6931
6932 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6933 date %= kDaysIn4Years;
6934
6935 month = kMonthInYear[date];
6936 day = kDayInYear[date];
6937
6938 ASSERT(MakeDay(year, month, day) == save_date);
6939}
6940
6941
6942static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006943 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006944#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006945 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006946#endif
6947
6948 date += kDaysOffset;
6949 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6950 date %= kDaysIn400Years;
6951
6952 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6953
6954 date--;
6955 int yd1 = date / kDaysIn100Years;
6956 date %= kDaysIn100Years;
6957 year += 100 * yd1;
6958
6959 date++;
6960 int yd2 = date / kDaysIn4Years;
6961 date %= kDaysIn4Years;
6962 year += 4 * yd2;
6963
6964 date--;
6965 int yd3 = date / 365;
6966 date %= 365;
6967 year += yd3;
6968
6969 bool is_leap = (!yd1 || yd2) && !yd3;
6970
6971 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006972 ASSERT(is_leap || (date >= 0));
6973 ASSERT((date < 365) || (is_leap && (date < 366)));
6974 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6975 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6976 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006977
6978 if (is_leap) {
6979 day = kDayInYear[2*365 + 1 + date];
6980 month = kMonthInYear[2*365 + 1 + date];
6981 } else {
6982 day = kDayInYear[date];
6983 month = kMonthInYear[date];
6984 }
6985
6986 ASSERT(MakeDay(year, month, day) == save_date);
6987}
6988
6989
6990static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006991 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006992 if (date >= 0 && date < 32 * kDaysIn4Years) {
6993 DateYMDFromTimeAfter1970(date, year, month, day);
6994 } else {
6995 DateYMDFromTimeSlow(date, year, month, day);
6996 }
6997}
6998
6999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007000RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007001 NoHandleAllocation ha;
7002 ASSERT(args.length() == 2);
7003
7004 CONVERT_DOUBLE_CHECKED(t, args[0]);
7005 CONVERT_CHECKED(JSArray, res_array, args[1]);
7006
7007 int year, month, day;
7008 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7009
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007010 RUNTIME_ASSERT(res_array->elements()->map() ==
7011 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007012 FixedArray* elms = FixedArray::cast(res_array->elements());
7013 RUNTIME_ASSERT(elms->length() == 3);
7014
7015 elms->set(0, Smi::FromInt(year));
7016 elms->set(1, Smi::FromInt(month));
7017 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007019 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007020}
7021
7022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007023RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007024 NoHandleAllocation ha;
7025 ASSERT(args.length() == 3);
7026
7027 JSFunction* callee = JSFunction::cast(args[0]);
7028 Object** parameters = reinterpret_cast<Object**>(args[1]);
7029 const int length = Smi::cast(args[2])->value();
7030
lrn@chromium.org303ada72010-10-27 09:33:13 +00007031 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007032 { MaybeObject* maybe_result =
7033 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007034 if (!maybe_result->ToObject(&result)) return maybe_result;
7035 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007036 // Allocate the elements if needed.
7037 if (length > 0) {
7038 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007039 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007040 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007041 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7042 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007043
7044 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007045 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007046 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007047 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007048
7049 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007050 for (int i = 0; i < length; i++) {
7051 array->set(i, *--parameters, mode);
7052 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007053 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007054 }
7055 return result;
7056}
7057
7058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007059RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007060 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007061 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007062 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007063 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007064 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007065
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007066 // Allocate global closures in old space and allocate local closures
7067 // in new space. Additionally pretenure closures that are assigned
7068 // directly to properties.
7069 pretenure = pretenure || (context->global_context() == *context);
7070 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007072 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7073 context,
7074 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007075 return *result;
7076}
7077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007078
7079static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7080 int* total_argc) {
7081 // Find frame containing arguments passed to the caller.
7082 JavaScriptFrameIterator it;
7083 JavaScriptFrame* frame = it.frame();
7084 List<JSFunction*> functions(2);
7085 frame->GetFunctions(&functions);
7086 if (functions.length() > 1) {
7087 int inlined_frame_index = functions.length() - 1;
7088 JSFunction* inlined_function = functions[inlined_frame_index];
7089 int args_count = inlined_function->shared()->formal_parameter_count();
7090 ScopedVector<SlotRef> args_slots(args_count);
7091 SlotRef::ComputeSlotMappingForArguments(frame,
7092 inlined_frame_index,
7093 &args_slots);
7094
7095 *total_argc = bound_argc + args_count;
7096 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7097 for (int i = 0; i < args_count; i++) {
7098 Handle<Object> val = args_slots[i].GetValue();
7099 param_data[bound_argc + i] = val.location();
7100 }
7101 return param_data;
7102 } else {
7103 it.AdvanceToArgumentsFrame();
7104 frame = it.frame();
7105 int args_count = frame->ComputeParametersCount();
7106
7107 *total_argc = bound_argc + args_count;
7108 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7109 for (int i = 0; i < args_count; i++) {
7110 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7111 param_data[bound_argc + i] = val.location();
7112 }
7113 return param_data;
7114 }
7115}
7116
7117
7118RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007119 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007120 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007121 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007122 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007123
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007124 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007125 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007126 int bound_argc = 0;
7127 if (!args[1]->IsNull()) {
7128 CONVERT_ARG_CHECKED(JSArray, params, 1);
7129 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007130 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007131 bound_argc = Smi::cast(params->length())->value();
7132 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007134 int total_argc = 0;
7135 SmartPointer<Object**> param_data =
7136 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007137 for (int i = 0; i < bound_argc; i++) {
7138 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007139 param_data[i] = val.location();
7140 }
7141
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007142 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007143 Handle<Object> result =
7144 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007145 if (exception) {
7146 return Failure::Exception();
7147 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007148
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007149 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007150 return *result;
7151}
7152
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007153
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007154static void TrySettingInlineConstructStub(Isolate* isolate,
7155 Handle<JSFunction> function) {
7156 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007157 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007158 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007159 }
7160 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007161 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007162 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007163 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007164 function->shared()->set_construct_stub(
7165 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007166 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007167 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007168}
7169
7170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007171RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007172 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007173 ASSERT(args.length() == 1);
7174
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007175 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007176
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007177 // If the constructor isn't a proper function we throw a type error.
7178 if (!constructor->IsJSFunction()) {
7179 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7180 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007181 isolate->factory()->NewTypeError("not_constructor", arguments);
7182 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007183 }
7184
7185 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007186
7187 // If function should not have prototype, construction is not allowed. In this
7188 // case generated code bailouts here, since function has no initial_map.
7189 if (!function->should_have_prototype()) {
7190 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7191 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007192 isolate->factory()->NewTypeError("not_constructor", arguments);
7193 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007194 }
7195
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007196#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007197 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007198 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007199 if (debug->StepInActive()) {
7200 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007201 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007202#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007203
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007204 if (function->has_initial_map()) {
7205 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007206 // The 'Function' function ignores the receiver object when
7207 // called using 'new' and creates a new JSFunction object that
7208 // is returned. The receiver object is only used for error
7209 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007210 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007211 // allocate JSFunctions since it does not properly initialize
7212 // the shared part of the function. Since the receiver is
7213 // ignored anyway, we use the global object as the receiver
7214 // instead of a new JSFunction object. This way, errors are
7215 // reported the same way whether or not 'Function' is called
7216 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007217 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007218 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007219 }
7220
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007221 // The function should be compiled for the optimization hints to be
7222 // available. We cannot use EnsureCompiled because that forces a
7223 // compilation through the shared function info which makes it
7224 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007225 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007226 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007227
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007228 if (!function->has_initial_map() &&
7229 shared->IsInobjectSlackTrackingInProgress()) {
7230 // The tracking is already in progress for another function. We can only
7231 // track one initial_map at a time, so we force the completion before the
7232 // function is called as a constructor for the first time.
7233 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007234 }
7235
7236 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007237 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7238 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007239 // Delay setting the stub if inobject slack tracking is in progress.
7240 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007241 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007242 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007244 isolate->counters()->constructed_objects()->Increment();
7245 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007246
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007247 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007248}
7249
7250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007251RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007252 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007253 ASSERT(args.length() == 1);
7254
7255 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7256 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007257 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007259 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007260}
7261
7262
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007263RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007264 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007265 ASSERT(args.length() == 1);
7266
7267 Handle<JSFunction> function = args.at<JSFunction>(0);
7268#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007269 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007270 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007271 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007272 PrintF("]\n");
7273 }
7274#endif
7275
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007276 // Compile the target function. Here we compile using CompileLazyInLoop in
7277 // order to get the optimized version. This helps code like delta-blue
7278 // that calls performance-critical routines through constructors. A
7279 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7280 // direct call. Since the in-loop tracking takes place through CallICs
7281 // this means that things called through constructors are never known to
7282 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007284 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007285 return Failure::Exception();
7286 }
7287
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007288 // All done. Return the compiled code.
7289 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007290 return function->code();
7291}
7292
7293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007294RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007295 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007296 ASSERT(args.length() == 1);
7297 Handle<JSFunction> function = args.at<JSFunction>(0);
7298 // If the function is not optimizable or debugger is active continue using the
7299 // code from the full compiler.
7300 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007301 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007302 if (FLAG_trace_opt) {
7303 PrintF("[failed to optimize ");
7304 function->PrintName();
7305 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7306 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007307 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007308 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007309 function->ReplaceCode(function->shared()->code());
7310 return function->code();
7311 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007312 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007313 return function->code();
7314 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007315 if (FLAG_trace_opt) {
7316 PrintF("[failed to optimize ");
7317 function->PrintName();
7318 PrintF(": optimized compilation failed]\n");
7319 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007320 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007321 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007322}
7323
7324
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007325RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007326 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007327 ASSERT(args.length() == 1);
7328 RUNTIME_ASSERT(args[0]->IsSmi());
7329 Deoptimizer::BailoutType type =
7330 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007331 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7332 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007333 int frames = deoptimizer->output_count();
7334
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007335 deoptimizer->MaterializeHeapNumbers();
7336 delete deoptimizer;
7337
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007338 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007339 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007340 for (int i = 0; i < frames - 1; i++) it.Advance();
7341 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007342
7343 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007344 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007345 Handle<Object> arguments;
7346 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007347 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007348 if (arguments.is_null()) {
7349 // FunctionGetArguments can't throw an exception, so cast away the
7350 // doubt with an assert.
7351 arguments = Handle<Object>(
7352 Accessors::FunctionGetArguments(*function,
7353 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007354 ASSERT(*arguments != isolate->heap()->null_value());
7355 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007356 }
7357 frame->SetExpression(i, *arguments);
7358 }
7359 }
7360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007361 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007362 if (type == Deoptimizer::EAGER) {
7363 RUNTIME_ASSERT(function->IsOptimized());
7364 } else {
7365 RUNTIME_ASSERT(!function->IsOptimized());
7366 }
7367
7368 // Avoid doing too much work when running with --always-opt and keep
7369 // the optimized code around.
7370 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007371 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007372 }
7373
7374 // Count the number of optimized activations of the function.
7375 int activations = 0;
7376 while (!it.done()) {
7377 JavaScriptFrame* frame = it.frame();
7378 if (frame->is_optimized() && frame->function() == *function) {
7379 activations++;
7380 }
7381 it.Advance();
7382 }
7383
7384 // TODO(kasperl): For now, we cannot support removing the optimized
7385 // code when we have recursive invocations of the same function.
7386 if (activations == 0) {
7387 if (FLAG_trace_deopt) {
7388 PrintF("[removing optimized code for: ");
7389 function->PrintName();
7390 PrintF("]\n");
7391 }
7392 function->ReplaceCode(function->shared()->code());
7393 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007395}
7396
7397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007398RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007400 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007401 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007402}
7403
7404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007405RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007406 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007407 ASSERT(args.length() == 1);
7408 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007409 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007410
7411 Deoptimizer::DeoptimizeFunction(*function);
7412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007413 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007414}
7415
7416
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007417RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7418 HandleScope scope(isolate);
7419 ASSERT(args.length() == 1);
7420 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7421 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7422 function->MarkForLazyRecompilation();
7423 return isolate->heap()->undefined_value();
7424}
7425
7426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007427RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007428 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007429 ASSERT(args.length() == 1);
7430 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7431
7432 // We're not prepared to handle a function with arguments object.
7433 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7434
7435 // We have hit a back edge in an unoptimized frame for a function that was
7436 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007437 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007438 // Keep track of whether we've succeeded in optimizing.
7439 bool succeeded = unoptimized->optimizable();
7440 if (succeeded) {
7441 // If we are trying to do OSR when there are already optimized
7442 // activations of the function, it means (a) the function is directly or
7443 // indirectly recursive and (b) an optimized invocation has been
7444 // deoptimized so that we are currently in an unoptimized activation.
7445 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007446 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007447 while (succeeded && !it.done()) {
7448 JavaScriptFrame* frame = it.frame();
7449 succeeded = !frame->is_optimized() || frame->function() != *function;
7450 it.Advance();
7451 }
7452 }
7453
7454 int ast_id = AstNode::kNoNumber;
7455 if (succeeded) {
7456 // The top JS function is this one, the PC is somewhere in the
7457 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007458 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007459 JavaScriptFrame* frame = it.frame();
7460 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007461 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007462 ASSERT(unoptimized->contains(frame->pc()));
7463
7464 // Use linear search of the unoptimized code's stack check table to find
7465 // the AST id matching the PC.
7466 Address start = unoptimized->instruction_start();
7467 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007468 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007469 uint32_t table_length = Memory::uint32_at(table_cursor);
7470 table_cursor += kIntSize;
7471 for (unsigned i = 0; i < table_length; ++i) {
7472 // Table entries are (AST id, pc offset) pairs.
7473 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7474 if (pc_offset == target_pc_offset) {
7475 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7476 break;
7477 }
7478 table_cursor += 2 * kIntSize;
7479 }
7480 ASSERT(ast_id != AstNode::kNoNumber);
7481 if (FLAG_trace_osr) {
7482 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7483 function->PrintName();
7484 PrintF("]\n");
7485 }
7486
7487 // Try to compile the optimized code. A true return value from
7488 // CompileOptimized means that compilation succeeded, not necessarily
7489 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007490 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7491 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007492 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7493 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007494 if (data->OsrPcOffset()->value() >= 0) {
7495 if (FLAG_trace_osr) {
7496 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007497 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007498 }
7499 ASSERT(data->OsrAstId()->value() == ast_id);
7500 } else {
7501 // We may never generate the desired OSR entry if we emit an
7502 // early deoptimize.
7503 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007504 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007505 } else {
7506 succeeded = false;
7507 }
7508 }
7509
7510 // Revert to the original stack checks in the original unoptimized code.
7511 if (FLAG_trace_osr) {
7512 PrintF("[restoring original stack checks in ");
7513 function->PrintName();
7514 PrintF("]\n");
7515 }
7516 StackCheckStub check_stub;
7517 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007518 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007519 Deoptimizer::RevertStackCheckCode(*unoptimized,
7520 *check_code,
7521 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007522
7523 // Allow OSR only at nesting level zero again.
7524 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7525
7526 // If the optimization attempt succeeded, return the AST id tagged as a
7527 // smi. This tells the builtin that we need to translate the unoptimized
7528 // frame to an optimized one.
7529 if (succeeded) {
7530 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7531 return Smi::FromInt(ast_id);
7532 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007533 if (function->IsMarkedForLazyRecompilation()) {
7534 function->ReplaceCode(function->shared()->code());
7535 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007536 return Smi::FromInt(-1);
7537 }
7538}
7539
7540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007541RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007542 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007543 ASSERT(args.length() == 1);
7544 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7545 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7546}
7547
7548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007549RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007550 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007551 ASSERT(args.length() == 1);
7552 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7553 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7554}
7555
7556
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007557RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007558 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007559 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007560
kasper.lund7276f142008-07-30 08:49:36 +00007561 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007562 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007563 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007564 { MaybeObject* maybe_result =
7565 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007566 if (!maybe_result->ToObject(&result)) return maybe_result;
7567 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007568
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007569 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007570
kasper.lund7276f142008-07-30 08:49:36 +00007571 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007572}
7573
lrn@chromium.org303ada72010-10-27 09:33:13 +00007574
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007575MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7576 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007577 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007578 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007579 Object* js_object = object;
7580 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007581 MaybeObject* maybe_js_object = js_object->ToObject();
7582 if (!maybe_js_object->ToObject(&js_object)) {
7583 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7584 return maybe_js_object;
7585 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007586 HandleScope scope(isolate);
7587 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007588 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007589 isolate->factory()->NewTypeError("with_expression",
7590 HandleVector(&handle, 1));
7591 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007592 }
7593 }
7594
lrn@chromium.org303ada72010-10-27 09:33:13 +00007595 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007596 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7597 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007598 if (!maybe_result->ToObject(&result)) return maybe_result;
7599 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007600
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007601 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007602 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007603
kasper.lund7276f142008-07-30 08:49:36 +00007604 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007605}
7606
7607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007608RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007609 NoHandleAllocation ha;
7610 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007611 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007612}
7613
7614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007615RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007616 NoHandleAllocation ha;
7617 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007618 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007619}
7620
7621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007622RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007623 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007624 ASSERT(args.length() == 2);
7625
7626 CONVERT_ARG_CHECKED(Context, context, 0);
7627 CONVERT_ARG_CHECKED(String, name, 1);
7628
7629 int index;
7630 PropertyAttributes attributes;
7631 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007632 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007633
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007634 // If the slot was not found the result is true.
7635 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007636 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007637 }
7638
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007639 // If the slot was found in a context, it should be DONT_DELETE.
7640 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007641 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007642 }
7643
7644 // The slot was found in a JSObject, either a context extension object,
7645 // the global object, or an arguments object. Try to delete it
7646 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7647 // which allows deleting all parameters in functions that mention
7648 // 'arguments', we do this even for the case of slots found on an
7649 // arguments object. The slot was found on an arguments object if the
7650 // index is non-negative.
7651 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7652 if (index >= 0) {
7653 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7654 } else {
7655 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7656 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007657}
7658
7659
ager@chromium.orga1645e22009-09-09 19:27:10 +00007660// A mechanism to return a pair of Object pointers in registers (if possible).
7661// How this is achieved is calling convention-dependent.
7662// All currently supported x86 compiles uses calling conventions that are cdecl
7663// variants where a 64-bit value is returned in two 32-bit registers
7664// (edx:eax on ia32, r1:r0 on ARM).
7665// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7666// In Win64 calling convention, a struct of two pointers is returned in memory,
7667// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007668#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007669struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007670 MaybeObject* x;
7671 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007672};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007673
lrn@chromium.org303ada72010-10-27 09:33:13 +00007674static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007675 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007676 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7677 // In Win64 they are assigned to a hidden first argument.
7678 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007679}
7680#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007681typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007682static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007683 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007684 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007685}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007686#endif
7687
7688
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007689static inline MaybeObject* Unhole(Heap* heap,
7690 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007691 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007692 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7693 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007694 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007695}
7696
7697
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007698static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7699 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007700 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007701 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007702 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007703 JSFunction* context_extension_function =
7704 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007705 // If the holder isn't a context extension object, we just return it
7706 // as the receiver. This allows arguments objects to be used as
7707 // receivers, but only if they are put in the context scope chain
7708 // explicitly via a with-statement.
7709 Object* constructor = holder->map()->constructor();
7710 if (constructor != context_extension_function) return holder;
7711 // Fall back to using the global object as the receiver if the
7712 // property turns out to be a local variable allocated in a context
7713 // extension object - introduced via eval.
7714 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007715}
7716
7717
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007718static ObjectPair LoadContextSlotHelper(Arguments args,
7719 Isolate* isolate,
7720 bool throw_error) {
7721 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007722 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007723
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007724 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007725 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007726 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007727 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007728 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007729
7730 int index;
7731 PropertyAttributes attributes;
7732 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007733 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007734
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007735 // If the index is non-negative, the slot has been found in a local
7736 // variable or a parameter. Read it from the context object or the
7737 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007738 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007739 // If the "property" we were looking for is a local variable or an
7740 // argument in a context, the receiver is the global object; see
7741 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007742 JSObject* receiver =
7743 isolate->context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007744 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007745 ? Context::cast(*holder)->get(index)
7746 : JSObject::cast(*holder)->GetElement(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007747 return MakePair(Unhole(isolate->heap(), value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748 }
7749
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007750 // If the holder is found, we read the property from it.
7751 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007752 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007753 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007754 JSObject* receiver;
7755 if (object->IsGlobalObject()) {
7756 receiver = GlobalObject::cast(object)->global_receiver();
7757 } else if (context->is_exception_holder(*holder)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007758 receiver = isolate->context()->global()->global_receiver();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007759 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007760 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007761 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007762 // No need to unhole the value here. This is taken care of by the
7763 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007764 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007765 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007766 }
7767
7768 if (throw_error) {
7769 // The property doesn't exist - throw exception.
7770 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007771 isolate->factory()->NewReferenceError("not_defined",
7772 HandleVector(&name, 1));
7773 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007774 } else {
7775 // The property doesn't exist - return undefined
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007776 return MakePair(isolate->heap()->undefined_value(),
7777 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007778 }
7779}
7780
7781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007782RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007783 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007784}
7785
7786
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007787RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007788 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007789}
7790
7791
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007792RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007793 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007794 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007795
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007796 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007797 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007798 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007799 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7800 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7801 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007802 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007803
7804 int index;
7805 PropertyAttributes attributes;
7806 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007807 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007808
7809 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007810 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007811 // Ignore if read_only variable.
7812 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007813 // Context is a fixed array and set cannot fail.
7814 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007815 } else if (strict_mode == kStrictMode) {
7816 // Setting read only property in strict mode.
7817 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007818 isolate->factory()->NewTypeError("strict_cannot_assign",
7819 HandleVector(&name, 1));
7820 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007821 }
7822 } else {
7823 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007824 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007825 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007826 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007827 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007828 return Failure::Exception();
7829 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007830 }
7831 return *value;
7832 }
7833
7834 // Slow case: The property is not in a FixedArray context.
7835 // It is either in an JSObject extension context or it was not found.
7836 Handle<JSObject> context_ext;
7837
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007838 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007839 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007840 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007841 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007842 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007843 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007844
7845 if (strict_mode == kStrictMode) {
7846 // Throw in strict mode (assignment to undefined variable).
7847 Handle<Object> error =
7848 isolate->factory()->NewReferenceError(
7849 "not_defined", HandleVector(&name, 1));
7850 return isolate->Throw(*error);
7851 }
7852 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007853 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007854 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007855 }
7856
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007857 // Set the property, but ignore if read_only variable on the context
7858 // extension object itself.
7859 if ((attributes & READ_ONLY) == 0 ||
7860 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007861 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007862 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007863 SetProperty(context_ext, name, value, NONE, strict_mode));
7864 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007865 // Setting read only property in strict mode.
7866 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007867 isolate->factory()->NewTypeError(
7868 "strict_cannot_assign", HandleVector(&name, 1));
7869 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007870 }
7871 return *value;
7872}
7873
7874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007875RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007876 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007877 ASSERT(args.length() == 1);
7878
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007879 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007880}
7881
7882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007883RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007884 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007885 ASSERT(args.length() == 1);
7886
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007887 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007888}
7889
7890
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007891RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007892 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007893 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007894}
7895
7896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007897RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007898 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007899 ASSERT(args.length() == 1);
7900
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007901 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007902 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007903 isolate->factory()->NewReferenceError("not_defined",
7904 HandleVector(&name, 1));
7905 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007906}
7907
7908
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007909RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007910 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007911
7912 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007913 if (isolate->stack_guard()->IsStackOverflow()) {
7914 NoHandleAllocation na;
7915 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007916 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007917
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007918 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007919}
7920
7921
7922// NOTE: These PrintXXX functions are defined for all builds (not just
7923// DEBUG builds) because we may want to be able to trace function
7924// calls in all modes.
7925static void PrintString(String* str) {
7926 // not uncommon to have empty strings
7927 if (str->length() > 0) {
7928 SmartPointer<char> s =
7929 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7930 PrintF("%s", *s);
7931 }
7932}
7933
7934
7935static void PrintObject(Object* obj) {
7936 if (obj->IsSmi()) {
7937 PrintF("%d", Smi::cast(obj)->value());
7938 } else if (obj->IsString() || obj->IsSymbol()) {
7939 PrintString(String::cast(obj));
7940 } else if (obj->IsNumber()) {
7941 PrintF("%g", obj->Number());
7942 } else if (obj->IsFailure()) {
7943 PrintF("<failure>");
7944 } else if (obj->IsUndefined()) {
7945 PrintF("<undefined>");
7946 } else if (obj->IsNull()) {
7947 PrintF("<null>");
7948 } else if (obj->IsTrue()) {
7949 PrintF("<true>");
7950 } else if (obj->IsFalse()) {
7951 PrintF("<false>");
7952 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007953 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007954 }
7955}
7956
7957
7958static int StackSize() {
7959 int n = 0;
7960 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7961 return n;
7962}
7963
7964
7965static void PrintTransition(Object* result) {
7966 // indentation
7967 { const int nmax = 80;
7968 int n = StackSize();
7969 if (n <= nmax)
7970 PrintF("%4d:%*s", n, n, "");
7971 else
7972 PrintF("%4d:%*s", n, nmax, "...");
7973 }
7974
7975 if (result == NULL) {
7976 // constructor calls
7977 JavaScriptFrameIterator it;
7978 JavaScriptFrame* frame = it.frame();
7979 if (frame->IsConstructor()) PrintF("new ");
7980 // function name
7981 Object* fun = frame->function();
7982 if (fun->IsJSFunction()) {
7983 PrintObject(JSFunction::cast(fun)->shared()->name());
7984 } else {
7985 PrintObject(fun);
7986 }
7987 // function arguments
7988 // (we are intentionally only printing the actually
7989 // supplied parameters, not all parameters required)
7990 PrintF("(this=");
7991 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007992 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007993 for (int i = 0; i < length; i++) {
7994 PrintF(", ");
7995 PrintObject(frame->GetParameter(i));
7996 }
7997 PrintF(") {\n");
7998
7999 } else {
8000 // function result
8001 PrintF("} -> ");
8002 PrintObject(result);
8003 PrintF("\n");
8004 }
8005}
8006
8007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008008RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008009 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008010 NoHandleAllocation ha;
8011 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008012 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008013}
8014
8015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008016RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008017 NoHandleAllocation ha;
8018 PrintTransition(args[0]);
8019 return args[0]; // return TOS
8020}
8021
8022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008023RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008024 NoHandleAllocation ha;
8025 ASSERT(args.length() == 1);
8026
8027#ifdef DEBUG
8028 if (args[0]->IsString()) {
8029 // If we have a string, assume it's a code "marker"
8030 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008031 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008032 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008033 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8034 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008035 } else {
8036 PrintF("DebugPrint: ");
8037 }
8038 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008039 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008040 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008041 HeapObject::cast(args[0])->map()->Print();
8042 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008043#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008044 // ShortPrint is available in release mode. Print is not.
8045 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008046#endif
8047 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008048 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008049
8050 return args[0]; // return TOS
8051}
8052
8053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008054RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008055 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008056 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008057 isolate->PrintStack();
8058 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008059}
8060
8061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008062RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008063 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008064 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008065
8066 // According to ECMA-262, section 15.9.1, page 117, the precision of
8067 // the number in a Date object representing a particular instant in
8068 // time is milliseconds. Therefore, we floor the result of getting
8069 // the OS time.
8070 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008071 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008072}
8073
8074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008075RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008076 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008077 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008078
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008079 CONVERT_ARG_CHECKED(String, str, 0);
8080 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008081
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008082 CONVERT_ARG_CHECKED(JSArray, output, 1);
8083 RUNTIME_ASSERT(output->HasFastElements());
8084
8085 AssertNoAllocation no_allocation;
8086
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008087 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008088 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8089 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008090 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008091 result = DateParser::Parse(str->ToAsciiVector(),
8092 output_array,
8093 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008094 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008095 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008096 result = DateParser::Parse(str->ToUC16Vector(),
8097 output_array,
8098 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008099 }
8100
8101 if (result) {
8102 return *output;
8103 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008104 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008105 }
8106}
8107
8108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008109RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008110 NoHandleAllocation ha;
8111 ASSERT(args.length() == 1);
8112
8113 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008114 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008115 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008116}
8117
8118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008119RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008120 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008121 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008123 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008124}
8125
8126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008127RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008128 NoHandleAllocation ha;
8129 ASSERT(args.length() == 1);
8130
8131 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008132 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008133}
8134
8135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008136RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008137 ASSERT(args.length() == 1);
8138 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008139 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008140 return JSGlobalObject::cast(global)->global_receiver();
8141}
8142
8143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008144RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008145 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008146 ASSERT_EQ(1, args.length());
8147 CONVERT_ARG_CHECKED(String, source, 0);
8148
8149 Handle<Object> result = JsonParser::Parse(source);
8150 if (result.is_null()) {
8151 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008152 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008153 return Failure::Exception();
8154 }
8155 return *result;
8156}
8157
8158
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008159RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008160 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008161 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008162 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008163
ager@chromium.org381abbb2009-02-25 13:23:22 +00008164 // Compile source string in the global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008165 Handle<Context> context(isolate->context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008166 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8167 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008168 true,
8169 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008170 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008171 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008172 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8173 context,
8174 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008175 return *fun;
8176}
8177
8178
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008179static ObjectPair CompileGlobalEval(Isolate* isolate,
8180 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008181 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008182 StrictModeFlag strict_mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008183 // Deal with a normal eval call with a string argument. Compile it
8184 // and return the compiled function bound in the local context.
8185 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8186 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008187 Handle<Context>(isolate->context()),
8188 isolate->context()->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008189 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008190 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008191 Handle<JSFunction> compiled =
8192 isolate->factory()->NewFunctionFromSharedFunctionInfo(
8193 shared, Handle<Context>(isolate->context()), NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008194 return MakePair(*compiled, *receiver);
8195}
8196
8197
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008198RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008199 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008200
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008201 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008202 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008203 Handle<Object> receiver; // Will be overwritten.
8204
8205 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008206 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008207#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008208 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008209 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008210 StackFrameLocator locator;
8211 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008212 ASSERT(Context::cast(frame->context()) == *context);
8213#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008214
8215 // Find where the 'eval' symbol is bound. It is unaliased only if
8216 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008217 int index = -1;
8218 PropertyAttributes attributes = ABSENT;
8219 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008220 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8221 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008222 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008223 // Stop search when eval is found or when the global context is
8224 // reached.
8225 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008226 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008227 context = Handle<Context>(Context::cast(context->closure()->context()),
8228 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008229 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008230 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008231 }
8232 }
8233
iposva@chromium.org245aa852009-02-10 00:49:54 +00008234 // If eval could not be resolved, it has been deleted and we need to
8235 // throw a reference error.
8236 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008237 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008238 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008239 isolate->factory()->NewReferenceError("not_defined",
8240 HandleVector(&name, 1));
8241 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008242 }
8243
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008244 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008245 // 'eval' is not bound in the global context. Just call the function
8246 // with the given arguments. This is not necessarily the global eval.
8247 if (receiver->IsContext()) {
8248 context = Handle<Context>::cast(receiver);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008249 receiver = Handle<Object>(context->get(index), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008250 } else if (receiver->IsJSContextExtensionObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008251 receiver = Handle<JSObject>(
8252 isolate->context()->global()->global_receiver(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008253 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008254 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008255 }
8256
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008257 // 'eval' is bound in the global context, but it may have been overwritten.
8258 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008259 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008260 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008261 return MakePair(*callee,
8262 isolate->context()->global()->global_receiver());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008263 }
8264
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008265 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008266 return CompileGlobalEval(isolate,
8267 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008268 args.at<Object>(2),
8269 static_cast<StrictModeFlag>(
8270 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008271}
8272
8273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008274RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008275 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008276
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008277 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008278 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008279
8280 // 'eval' is bound in the global context, but it may have been overwritten.
8281 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008282 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008283 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008284 return MakePair(*callee,
8285 isolate->context()->global()->global_receiver());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008286 }
8287
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008288 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008289 return CompileGlobalEval(isolate,
8290 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008291 args.at<Object>(2),
8292 static_cast<StrictModeFlag>(
8293 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008294}
8295
8296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008297RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008298 // This utility adjusts the property attributes for newly created Function
8299 // object ("new Function(...)") by changing the map.
8300 // All it does is changing the prototype property to enumerable
8301 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008302 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008303 ASSERT(args.length() == 1);
8304 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008305
8306 Handle<Map> map = func->shared()->strict_mode()
8307 ? isolate->strict_mode_function_instance_map()
8308 : isolate->function_instance_map();
8309
8310 ASSERT(func->map()->instance_type() == map->instance_type());
8311 ASSERT(func->map()->instance_size() == map->instance_size());
8312 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008313 return *func;
8314}
8315
8316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008317RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008318 // Allocate a block of memory in NewSpace (filled with a filler).
8319 // Use as fallback for allocation in generated code when NewSpace
8320 // is full.
8321 ASSERT(args.length() == 1);
8322 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8323 int size = size_smi->value();
8324 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8325 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008326 Heap* heap = isolate->heap();
8327 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008328 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008329 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008330 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008331 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008332 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008333 }
8334 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008335 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008336}
8337
8338
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008339// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008340// array. Returns true if the element was pushed on the stack and
8341// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008342RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008343 ASSERT(args.length() == 2);
8344 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008345 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008346 RUNTIME_ASSERT(array->HasFastElements());
8347 int length = Smi::cast(array->length())->value();
8348 FixedArray* elements = FixedArray::cast(array->elements());
8349 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008350 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008351 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008352 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008353 // Strict not needed. Used for cycle detection in Array join implementation.
8354 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8355 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008356 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8357 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008358 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008359}
8360
8361
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008362/**
8363 * A simple visitor visits every element of Array's.
8364 * The backend storage can be a fixed array for fast elements case,
8365 * or a dictionary for sparse array. Since Dictionary is a subtype
8366 * of FixedArray, the class can be used by both fast and slow cases.
8367 * The second parameter of the constructor, fast_elements, specifies
8368 * whether the storage is a FixedArray or Dictionary.
8369 *
8370 * An index limit is used to deal with the situation that a result array
8371 * length overflows 32-bit non-negative integer.
8372 */
8373class ArrayConcatVisitor {
8374 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008375 ArrayConcatVisitor(Isolate* isolate,
8376 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008377 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008378 isolate_(isolate),
8379 storage_(Handle<FixedArray>::cast(
8380 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008381 index_offset_(0u),
8382 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008383
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008384 ~ArrayConcatVisitor() {
8385 clear_storage();
8386 }
8387
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008388 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008389 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008390 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008391
8392 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008393 if (index < static_cast<uint32_t>(storage_->length())) {
8394 storage_->set(index, *elm);
8395 return;
8396 }
8397 // Our initial estimate of length was foiled, possibly by
8398 // getters on the arrays increasing the length of later arrays
8399 // during iteration.
8400 // This shouldn't happen in anything but pathological cases.
8401 SetDictionaryMode(index);
8402 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008403 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008404 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008405 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008406 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008407 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008408 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008409 // Dictionary needed to grow.
8410 clear_storage();
8411 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008412 }
8413}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008414
8415 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008416 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8417 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008418 } else {
8419 index_offset_ += delta;
8420 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008421 }
8422
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008423 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008424 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008425 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008426 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008427 Handle<Map> map;
8428 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008429 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008430 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008431 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008432 }
8433 array->set_map(*map);
8434 array->set_length(*length);
8435 array->set_elements(*storage_);
8436 return array;
8437 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008438
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008439 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008440 // Convert storage to dictionary mode.
8441 void SetDictionaryMode(uint32_t index) {
8442 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008443 Handle<FixedArray> current_storage(*storage_);
8444 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008445 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008446 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8447 for (uint32_t i = 0; i < current_length; i++) {
8448 HandleScope loop_scope;
8449 Handle<Object> element(current_storage->get(i));
8450 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008451 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008452 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008453 if (!new_storage.is_identical_to(slow_storage)) {
8454 slow_storage = loop_scope.CloseAndEscape(new_storage);
8455 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008456 }
8457 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008458 clear_storage();
8459 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008460 fast_elements_ = false;
8461 }
8462
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008463 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008464 isolate_->global_handles()->Destroy(
8465 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008466 }
8467
8468 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008469 storage_ = Handle<FixedArray>::cast(
8470 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008471 }
8472
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008473 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008474 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008475 // Index after last seen index. Always less than or equal to
8476 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008477 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008478 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008479};
8480
8481
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008482static uint32_t EstimateElementCount(Handle<JSArray> array) {
8483 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8484 int element_count = 0;
8485 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008486 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008487 // Fast elements can't have lengths that are not representable by
8488 // a 32-bit signed integer.
8489 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8490 int fast_length = static_cast<int>(length);
8491 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8492 for (int i = 0; i < fast_length; i++) {
8493 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008494 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008495 break;
8496 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008497 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008498 Handle<NumberDictionary> dictionary(
8499 NumberDictionary::cast(array->elements()));
8500 int capacity = dictionary->Capacity();
8501 for (int i = 0; i < capacity; i++) {
8502 Handle<Object> key(dictionary->KeyAt(i));
8503 if (dictionary->IsKey(*key)) {
8504 element_count++;
8505 }
8506 }
8507 break;
8508 }
8509 default:
8510 // External arrays are always dense.
8511 return length;
8512 }
8513 // As an estimate, we assume that the prototype doesn't contain any
8514 // inherited elements.
8515 return element_count;
8516}
8517
8518
8519
8520template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008521static void IterateExternalArrayElements(Isolate* isolate,
8522 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008523 bool elements_are_ints,
8524 bool elements_are_guaranteed_smis,
8525 ArrayConcatVisitor* visitor) {
8526 Handle<ExternalArrayClass> array(
8527 ExternalArrayClass::cast(receiver->elements()));
8528 uint32_t len = static_cast<uint32_t>(array->length());
8529
8530 ASSERT(visitor != NULL);
8531 if (elements_are_ints) {
8532 if (elements_are_guaranteed_smis) {
8533 for (uint32_t j = 0; j < len; j++) {
8534 HandleScope loop_scope;
8535 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8536 visitor->visit(j, e);
8537 }
8538 } else {
8539 for (uint32_t j = 0; j < len; j++) {
8540 HandleScope loop_scope;
8541 int64_t val = static_cast<int64_t>(array->get(j));
8542 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8543 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8544 visitor->visit(j, e);
8545 } else {
8546 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008547 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008548 visitor->visit(j, e);
8549 }
8550 }
8551 }
8552 } else {
8553 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008554 HandleScope loop_scope(isolate);
8555 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008556 visitor->visit(j, e);
8557 }
8558 }
8559}
8560
8561
8562// Used for sorting indices in a List<uint32_t>.
8563static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8564 uint32_t a = *ap;
8565 uint32_t b = *bp;
8566 return (a == b) ? 0 : (a < b) ? -1 : 1;
8567}
8568
8569
8570static void CollectElementIndices(Handle<JSObject> object,
8571 uint32_t range,
8572 List<uint32_t>* indices) {
8573 JSObject::ElementsKind kind = object->GetElementsKind();
8574 switch (kind) {
8575 case JSObject::FAST_ELEMENTS: {
8576 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8577 uint32_t length = static_cast<uint32_t>(elements->length());
8578 if (range < length) length = range;
8579 for (uint32_t i = 0; i < length; i++) {
8580 if (!elements->get(i)->IsTheHole()) {
8581 indices->Add(i);
8582 }
8583 }
8584 break;
8585 }
8586 case JSObject::DICTIONARY_ELEMENTS: {
8587 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008588 uint32_t capacity = dict->Capacity();
8589 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008590 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008591 Handle<Object> k(dict->KeyAt(j));
8592 if (dict->IsKey(*k)) {
8593 ASSERT(k->IsNumber());
8594 uint32_t index = static_cast<uint32_t>(k->Number());
8595 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008596 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008597 }
8598 }
8599 }
8600 break;
8601 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008602 default: {
8603 int dense_elements_length;
8604 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008605 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008606 dense_elements_length =
8607 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008608 break;
8609 }
8610 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008611 dense_elements_length =
8612 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008613 break;
8614 }
8615 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008616 dense_elements_length =
8617 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008618 break;
8619 }
8620 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008621 dense_elements_length =
8622 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008623 break;
8624 }
8625 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008626 dense_elements_length =
8627 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008628 break;
8629 }
8630 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008631 dense_elements_length =
8632 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008633 break;
8634 }
8635 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008636 dense_elements_length =
8637 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008638 break;
8639 }
8640 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008641 dense_elements_length =
8642 ExternalFloatArray::cast(object->elements())->length();
8643 break;
8644 }
8645 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8646 dense_elements_length =
8647 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008648 break;
8649 }
8650 default:
8651 UNREACHABLE();
8652 dense_elements_length = 0;
8653 break;
8654 }
8655 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8656 if (range <= length) {
8657 length = range;
8658 // We will add all indices, so we might as well clear it first
8659 // and avoid duplicates.
8660 indices->Clear();
8661 }
8662 for (uint32_t i = 0; i < length; i++) {
8663 indices->Add(i);
8664 }
8665 if (length == range) return; // All indices accounted for already.
8666 break;
8667 }
8668 }
8669
8670 Handle<Object> prototype(object->GetPrototype());
8671 if (prototype->IsJSObject()) {
8672 // The prototype will usually have no inherited element indices,
8673 // but we have to check.
8674 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8675 }
8676}
8677
8678
8679/**
8680 * A helper function that visits elements of a JSArray in numerical
8681 * order.
8682 *
8683 * The visitor argument called for each existing element in the array
8684 * with the element index and the element's value.
8685 * Afterwards it increments the base-index of the visitor by the array
8686 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008687 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008688 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008689static bool IterateElements(Isolate* isolate,
8690 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008691 ArrayConcatVisitor* visitor) {
8692 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8693 switch (receiver->GetElementsKind()) {
8694 case JSObject::FAST_ELEMENTS: {
8695 // Run through the elements FixedArray and use HasElement and GetElement
8696 // to check the prototype for missing elements.
8697 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8698 int fast_length = static_cast<int>(length);
8699 ASSERT(fast_length <= elements->length());
8700 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008701 HandleScope loop_scope(isolate);
8702 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008703 if (!element_value->IsTheHole()) {
8704 visitor->visit(j, element_value);
8705 } else if (receiver->HasElement(j)) {
8706 // Call GetElement on receiver, not its prototype, or getters won't
8707 // have the correct receiver.
8708 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008709 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008710 visitor->visit(j, element_value);
8711 }
8712 }
8713 break;
8714 }
8715 case JSObject::DICTIONARY_ELEMENTS: {
8716 Handle<NumberDictionary> dict(receiver->element_dictionary());
8717 List<uint32_t> indices(dict->Capacity() / 2);
8718 // Collect all indices in the object and the prototypes less
8719 // than length. This might introduce duplicates in the indices list.
8720 CollectElementIndices(receiver, length, &indices);
8721 indices.Sort(&compareUInt32);
8722 int j = 0;
8723 int n = indices.length();
8724 while (j < n) {
8725 HandleScope loop_scope;
8726 uint32_t index = indices[j];
8727 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008728 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008729 visitor->visit(index, element);
8730 // Skip to next different index (i.e., omit duplicates).
8731 do {
8732 j++;
8733 } while (j < n && indices[j] == index);
8734 }
8735 break;
8736 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008737 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8738 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8739 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008740 for (uint32_t j = 0; j < length; j++) {
8741 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8742 visitor->visit(j, e);
8743 }
8744 break;
8745 }
8746 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8747 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008748 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008749 break;
8750 }
8751 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8752 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008753 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008754 break;
8755 }
8756 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8757 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008758 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008759 break;
8760 }
8761 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8762 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008763 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008764 break;
8765 }
8766 case JSObject::EXTERNAL_INT_ELEMENTS: {
8767 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008768 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008769 break;
8770 }
8771 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8772 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008773 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008774 break;
8775 }
8776 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8777 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008778 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008779 break;
8780 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008781 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8782 IterateExternalArrayElements<ExternalDoubleArray, double>(
8783 isolate, receiver, false, false, visitor);
8784 break;
8785 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008786 default:
8787 UNREACHABLE();
8788 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008789 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008790 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008791 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008792}
8793
8794
8795/**
8796 * Array::concat implementation.
8797 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008798 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008799 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008800 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008801RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008802 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008803 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008804
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008805 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8806 int argument_count = static_cast<int>(arguments->length()->Number());
8807 RUNTIME_ASSERT(arguments->HasFastElements());
8808 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008809
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008810 // Pass 1: estimate the length and number of elements of the result.
8811 // The actual length can be larger if any of the arguments have getters
8812 // that mutate other arguments (but will otherwise be precise).
8813 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008814
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008815 uint32_t estimate_result_length = 0;
8816 uint32_t estimate_nof_elements = 0;
8817 {
8818 for (int i = 0; i < argument_count; i++) {
8819 HandleScope loop_scope;
8820 Handle<Object> obj(elements->get(i));
8821 uint32_t length_estimate;
8822 uint32_t element_estimate;
8823 if (obj->IsJSArray()) {
8824 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8825 length_estimate =
8826 static_cast<uint32_t>(array->length()->Number());
8827 element_estimate =
8828 EstimateElementCount(array);
8829 } else {
8830 length_estimate = 1;
8831 element_estimate = 1;
8832 }
8833 // Avoid overflows by capping at kMaxElementCount.
8834 if (JSObject::kMaxElementCount - estimate_result_length <
8835 length_estimate) {
8836 estimate_result_length = JSObject::kMaxElementCount;
8837 } else {
8838 estimate_result_length += length_estimate;
8839 }
8840 if (JSObject::kMaxElementCount - estimate_nof_elements <
8841 element_estimate) {
8842 estimate_nof_elements = JSObject::kMaxElementCount;
8843 } else {
8844 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008845 }
8846 }
8847 }
8848
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008849 // If estimated number of elements is more than half of length, a
8850 // fixed array (fast case) is more time and space-efficient than a
8851 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008852 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008853
8854 Handle<FixedArray> storage;
8855 if (fast_case) {
8856 // The backing storage array must have non-existing elements to
8857 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008858 storage = isolate->factory()->NewFixedArrayWithHoles(
8859 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008860 } else {
8861 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8862 uint32_t at_least_space_for = estimate_nof_elements +
8863 (estimate_nof_elements >> 2);
8864 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008865 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008866 }
8867
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008868 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008869
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008870 for (int i = 0; i < argument_count; i++) {
8871 Handle<Object> obj(elements->get(i));
8872 if (obj->IsJSArray()) {
8873 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008874 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008875 return Failure::Exception();
8876 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008877 } else {
8878 visitor.visit(0, obj);
8879 visitor.increase_index_offset(1);
8880 }
8881 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008882
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008883 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008884}
8885
8886
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008887// This will not allocate (flatten the string), but it may run
8888// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008889RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008890 NoHandleAllocation ha;
8891 ASSERT(args.length() == 1);
8892
8893 CONVERT_CHECKED(String, string, args[0]);
8894 StringInputBuffer buffer(string);
8895 while (buffer.has_more()) {
8896 uint16_t character = buffer.GetNext();
8897 PrintF("%c", character);
8898 }
8899 return string;
8900}
8901
ager@chromium.org5ec48922009-05-05 07:25:34 +00008902// Moves all own elements of an object, that are below a limit, to positions
8903// starting at zero. All undefined values are placed after non-undefined values,
8904// and are followed by non-existing element. Does not change the length
8905// property.
8906// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008907RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008908 ASSERT(args.length() == 2);
8909 CONVERT_CHECKED(JSObject, object, args[0]);
8910 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8911 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008912}
8913
8914
8915// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008916RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008917 ASSERT(args.length() == 2);
8918 CONVERT_CHECKED(JSArray, from, args[0]);
8919 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008920 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008921 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008922 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
8923 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008924 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008925 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008926 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008927 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008928 Object* new_map;
8929 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008930 to->set_map(Map::cast(new_map));
8931 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008932 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008933 Object* obj;
8934 { MaybeObject* maybe_obj = from->ResetElements();
8935 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8936 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008937 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008938 return to;
8939}
8940
8941
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008942// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008943RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008944 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008945 CONVERT_CHECKED(JSObject, object, args[0]);
8946 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008947 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008948 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008949 } else if (object->IsJSArray()) {
8950 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008951 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008952 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008953 }
8954}
8955
8956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008957RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008958 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008959
8960 ASSERT_EQ(3, args.length());
8961
ager@chromium.orgac091b72010-05-05 07:34:42 +00008962 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008963 Handle<Object> key1 = args.at<Object>(1);
8964 Handle<Object> key2 = args.at<Object>(2);
8965
8966 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008967 if (!key1->ToArrayIndex(&index1)
8968 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008969 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008970 }
8971
ager@chromium.orgac091b72010-05-05 07:34:42 +00008972 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8973 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008974 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008975 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008976 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008977
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008978 RETURN_IF_EMPTY_HANDLE(isolate,
8979 SetElement(jsobject, index1, tmp2, kStrictMode));
8980 RETURN_IF_EMPTY_HANDLE(isolate,
8981 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00008982
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008983 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008984}
8985
8986
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008987// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008988// might have elements. Can either return keys (positive integers) or
8989// intervals (pair of a negative integer (-start-1) followed by a
8990// positive (length)) or undefined values.
8991// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008992RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008993 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008994 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00008995 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008996 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008997 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008998 // Create an array and get all the keys into it, then remove all the
8999 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009000 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009001 int keys_length = keys->length();
9002 for (int i = 0; i < keys_length; i++) {
9003 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009004 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009005 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009006 // Zap invalid keys.
9007 keys->set_undefined(i);
9008 }
9009 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009010 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009011 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009012 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009013 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009014 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009015 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009016 uint32_t actual_length =
9017 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009018 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009020 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009021 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009022 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009023 }
9024}
9025
9026
9027// DefineAccessor takes an optional final argument which is the
9028// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9029// to the way accessors are implemented, it is set for both the getter
9030// and setter on the first call to DefineAccessor and ignored on
9031// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009032RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009033 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9034 // Compute attributes.
9035 PropertyAttributes attributes = NONE;
9036 if (args.length() == 5) {
9037 CONVERT_CHECKED(Smi, attrs, args[4]);
9038 int value = attrs->value();
9039 // Only attribute bits should be set.
9040 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9041 attributes = static_cast<PropertyAttributes>(value);
9042 }
9043
9044 CONVERT_CHECKED(JSObject, obj, args[0]);
9045 CONVERT_CHECKED(String, name, args[1]);
9046 CONVERT_CHECKED(Smi, flag, args[2]);
9047 CONVERT_CHECKED(JSFunction, fun, args[3]);
9048 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9049}
9050
9051
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009052RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053 ASSERT(args.length() == 3);
9054 CONVERT_CHECKED(JSObject, obj, args[0]);
9055 CONVERT_CHECKED(String, name, args[1]);
9056 CONVERT_CHECKED(Smi, flag, args[2]);
9057 return obj->LookupAccessor(name, flag->value() == 0);
9058}
9059
9060
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009061#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009062RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009063 ASSERT(args.length() == 0);
9064 return Execution::DebugBreakHelper();
9065}
9066
9067
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068// Helper functions for wrapping and unwrapping stack frame ids.
9069static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009070 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009071 return Smi::FromInt(id >> 2);
9072}
9073
9074
9075static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9076 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9077}
9078
9079
9080// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009081// args[0]: debug event listener function to set or null or undefined for
9082// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009083// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009084RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009085 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009086 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9087 args[0]->IsUndefined() ||
9088 args[0]->IsNull());
9089 Handle<Object> callback = args.at<Object>(0);
9090 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009091 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009092
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009093 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009094}
9095
9096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009097RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009098 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009099 isolate->stack_guard()->DebugBreak();
9100 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009101}
9102
9103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009104static MaybeObject* DebugLookupResultValue(Heap* heap,
9105 Object* receiver,
9106 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009107 LookupResult* result,
9108 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009109 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009110 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009111 case NORMAL:
9112 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009113 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009114 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009115 }
9116 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009117 case FIELD:
9118 value =
9119 JSObject::cast(
9120 result->holder())->FastPropertyAt(result->GetFieldIndex());
9121 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009122 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009123 }
9124 return value;
9125 case CONSTANT_FUNCTION:
9126 return result->GetConstantFunction();
9127 case CALLBACKS: {
9128 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009129 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009130 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009131 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009132 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009133 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009134 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009135 maybe_value = heap->isolate()->pending_exception();
9136 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009137 if (caught_exception != NULL) {
9138 *caught_exception = true;
9139 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009140 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009141 }
9142 return value;
9143 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009144 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009145 }
9146 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009147 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009148 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009149 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009150 case CONSTANT_TRANSITION:
9151 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009152 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009153 default:
9154 UNREACHABLE();
9155 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009156 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009157 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009158}
9159
9160
ager@chromium.org32912102009-01-16 10:38:43 +00009161// Get debugger related details for an object property.
9162// args[0]: object holding property
9163// args[1]: name of the property
9164//
9165// The array returned contains the following information:
9166// 0: Property value
9167// 1: Property details
9168// 2: Property value is exception
9169// 3: Getter function if defined
9170// 4: Setter function if defined
9171// Items 2-4 are only filled if the property has either a getter or a setter
9172// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009173RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009174 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009175
9176 ASSERT(args.length() == 2);
9177
9178 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9179 CONVERT_ARG_CHECKED(String, name, 1);
9180
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009181 // Make sure to set the current context to the context before the debugger was
9182 // entered (if the debugger is entered). The reason for switching context here
9183 // is that for some property lookups (accessors and interceptors) callbacks
9184 // into the embedding application can occour, and the embedding application
9185 // could have the assumption that its own global context is the current
9186 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009187 SaveContext save(isolate);
9188 if (isolate->debug()->InDebugger()) {
9189 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009190 }
9191
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009192 // Skip the global proxy as it has no properties and always delegates to the
9193 // real global object.
9194 if (obj->IsJSGlobalProxy()) {
9195 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9196 }
9197
9198
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009199 // Check if the name is trivially convertible to an index and get the element
9200 // if so.
9201 uint32_t index;
9202 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009203 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009204 Object* element_or_char;
9205 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009206 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009207 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9208 return maybe_element_or_char;
9209 }
9210 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009211 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009212 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009213 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009214 }
9215
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009216 // Find the number of objects making up this.
9217 int length = LocalPrototypeChainLength(*obj);
9218
9219 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009220 Handle<JSObject> jsproto = obj;
9221 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009222 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009223 jsproto->LocalLookup(*name, &result);
9224 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009225 // LookupResult is not GC safe as it holds raw object pointers.
9226 // GC can happen later in this code so put the required fields into
9227 // local variables using handles when required for later use.
9228 PropertyType result_type = result.type();
9229 Handle<Object> result_callback_obj;
9230 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009231 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9232 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009233 }
9234 Smi* property_details = result.GetPropertyDetails().AsSmi();
9235 // DebugLookupResultValue can cause GC so details from LookupResult needs
9236 // to be copied to handles before this.
9237 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009238 Object* raw_value;
9239 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009240 DebugLookupResultValue(isolate->heap(), *obj, *name,
9241 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009242 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9243 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009244 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009245
9246 // If the callback object is a fixed array then it contains JavaScript
9247 // getter and/or setter.
9248 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9249 result_callback_obj->IsFixedArray();
9250 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009251 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009252 details->set(0, *value);
9253 details->set(1, property_details);
9254 if (hasJavaScriptAccessors) {
9255 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009256 caught_exception ? isolate->heap()->true_value()
9257 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009258 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9259 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9260 }
9261
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009262 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009263 }
9264 if (i < length - 1) {
9265 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9266 }
9267 }
9268
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009269 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009270}
9271
9272
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009273RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009274 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009275
9276 ASSERT(args.length() == 2);
9277
9278 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9279 CONVERT_ARG_CHECKED(String, name, 1);
9280
9281 LookupResult result;
9282 obj->Lookup(*name, &result);
9283 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009284 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009285 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009286 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009287}
9288
9289
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009290// Return the property type calculated from the property details.
9291// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009292RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009293 ASSERT(args.length() == 1);
9294 CONVERT_CHECKED(Smi, details, args[0]);
9295 PropertyType type = PropertyDetails(details).type();
9296 return Smi::FromInt(static_cast<int>(type));
9297}
9298
9299
9300// Return the property attribute calculated from the property details.
9301// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009302RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009303 ASSERT(args.length() == 1);
9304 CONVERT_CHECKED(Smi, details, args[0]);
9305 PropertyAttributes attributes = PropertyDetails(details).attributes();
9306 return Smi::FromInt(static_cast<int>(attributes));
9307}
9308
9309
9310// Return the property insertion index calculated from the property details.
9311// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009312RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009313 ASSERT(args.length() == 1);
9314 CONVERT_CHECKED(Smi, details, args[0]);
9315 int index = PropertyDetails(details).index();
9316 return Smi::FromInt(index);
9317}
9318
9319
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009320// Return property value from named interceptor.
9321// args[0]: object
9322// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009323RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009324 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009325 ASSERT(args.length() == 2);
9326 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9327 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9328 CONVERT_ARG_CHECKED(String, name, 1);
9329
9330 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009331 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332}
9333
9334
9335// Return element value from indexed interceptor.
9336// args[0]: object
9337// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009338RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009339 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009340 ASSERT(args.length() == 2);
9341 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9342 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9343 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9344
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009345 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009346}
9347
9348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009349RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009350 ASSERT(args.length() >= 1);
9351 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009352 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009353 if (isolate->debug()->break_id() == 0 ||
9354 break_id != isolate->debug()->break_id()) {
9355 return isolate->Throw(
9356 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009357 }
9358
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009359 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009360}
9361
9362
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009363RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009364 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009365 ASSERT(args.length() == 1);
9366
9367 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009368 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009369 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9370 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009371 if (!maybe_result->ToObject(&result)) return maybe_result;
9372 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009373
9374 // Count all frames which are relevant to debugging stack trace.
9375 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009376 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009377 if (id == StackFrame::NO_ID) {
9378 // If there is no JavaScript stack frame count is 0.
9379 return Smi::FromInt(0);
9380 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009381 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009382 return Smi::FromInt(n);
9383}
9384
9385
9386static const int kFrameDetailsFrameIdIndex = 0;
9387static const int kFrameDetailsReceiverIndex = 1;
9388static const int kFrameDetailsFunctionIndex = 2;
9389static const int kFrameDetailsArgumentCountIndex = 3;
9390static const int kFrameDetailsLocalCountIndex = 4;
9391static const int kFrameDetailsSourcePositionIndex = 5;
9392static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009393static const int kFrameDetailsAtReturnIndex = 7;
9394static const int kFrameDetailsDebuggerFrameIndex = 8;
9395static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009396
9397// Return an array with frame details
9398// args[0]: number: break id
9399// args[1]: number: frame index
9400//
9401// The array returned contains the following information:
9402// 0: Frame id
9403// 1: Receiver
9404// 2: Function
9405// 3: Argument count
9406// 4: Local count
9407// 5: Source position
9408// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009409// 7: Is at return
9410// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009411// Arguments name, value
9412// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009413// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009414RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009415 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009416 ASSERT(args.length() == 2);
9417
9418 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009419 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009420 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9421 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009422 if (!maybe_check->ToObject(&check)) return maybe_check;
9423 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009424 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009425 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009426
9427 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009428 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009429 if (id == StackFrame::NO_ID) {
9430 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009431 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009432 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009433 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009434 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009435 for (; !it.done(); it.Advance()) {
9436 if (count == index) break;
9437 count++;
9438 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009439 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009440
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009441 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009442 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009443
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009444 // Traverse the saved contexts chain to find the active context for the
9445 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009446 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009447 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009448 save = save->prev();
9449 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009450 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009451
9452 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009453 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009454
9455 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009456 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009457 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009458
9459 // Check for constructor frame.
9460 bool constructor = it.frame()->IsConstructor();
9461
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009462 // Get scope info and read from it for local variable information.
9463 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009464 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009465 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009466
9467 // Get the context.
9468 Handle<Context> context(Context::cast(it.frame()->context()));
9469
9470 // Get the locals names and values into a temporary array.
9471 //
9472 // TODO(1240907): Hide compiler-introduced stack variables
9473 // (e.g. .result)? For users of the debugger, they will probably be
9474 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009475 Handle<FixedArray> locals =
9476 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009477
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009478 // Fill in the names of the locals.
9479 for (int i = 0; i < info.NumberOfLocals(); i++) {
9480 locals->set(i * 2, *info.LocalName(i));
9481 }
9482
9483 // Fill in the values of the locals.
9484 for (int i = 0; i < info.NumberOfLocals(); i++) {
9485 if (is_optimized_frame) {
9486 // If we are inspecting an optimized frame use undefined as the
9487 // value for all locals.
9488 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009489 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009490 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009491 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009492 } else if (i < info.number_of_stack_slots()) {
9493 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009494 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9495 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009496 // Traverse the context chain to the function context as all local
9497 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009498 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009499 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009500 context = Handle<Context>(context->previous());
9501 }
9502 ASSERT(context->is_function_context());
9503 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009504 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009505 }
9506 }
9507
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009508 // Check whether this frame is positioned at return. If not top
9509 // frame or if the frame is optimized it cannot be at a return.
9510 bool at_return = false;
9511 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009512 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009513 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009514
9515 // If positioned just before return find the value to be returned and add it
9516 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009517 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009518 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009519 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009520 Address internal_frame_sp = NULL;
9521 while (!it2.done()) {
9522 if (it2.frame()->is_internal()) {
9523 internal_frame_sp = it2.frame()->sp();
9524 } else {
9525 if (it2.frame()->is_java_script()) {
9526 if (it2.frame()->id() == it.frame()->id()) {
9527 // The internal frame just before the JavaScript frame contains the
9528 // value to return on top. A debug break at return will create an
9529 // internal frame to store the return value (eax/rax/r0) before
9530 // entering the debug break exit frame.
9531 if (internal_frame_sp != NULL) {
9532 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009533 Handle<Object>(Memory::Object_at(internal_frame_sp),
9534 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009535 break;
9536 }
9537 }
9538 }
9539
9540 // Indicate that the previous frame was not an internal frame.
9541 internal_frame_sp = NULL;
9542 }
9543 it2.Advance();
9544 }
9545 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009546
9547 // Now advance to the arguments adapter frame (if any). It contains all
9548 // the provided parameters whereas the function frame always have the number
9549 // of arguments matching the functions parameters. The rest of the
9550 // information (except for what is collected above) is the same.
9551 it.AdvanceToArgumentsFrame();
9552
9553 // Find the number of arguments to fill. At least fill the number of
9554 // parameters for the function and fill more if more parameters are provided.
9555 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009556 if (argument_count < it.frame()->ComputeParametersCount()) {
9557 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009558 }
9559
9560 // Calculate the size of the result.
9561 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009562 2 * (argument_count + info.NumberOfLocals()) +
9563 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009564 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009565
9566 // Add the frame id.
9567 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9568
9569 // Add the function (same as in function frame).
9570 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9571
9572 // Add the arguments count.
9573 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9574
9575 // Add the locals count
9576 details->set(kFrameDetailsLocalCountIndex,
9577 Smi::FromInt(info.NumberOfLocals()));
9578
9579 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009580 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009581 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9582 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009583 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009584 }
9585
9586 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009587 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009588
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009589 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009590 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009591
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009592 // Add information on whether this frame is invoked in the debugger context.
9593 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009594 heap->ToBoolean(*save->context() ==
9595 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009596
9597 // Fill the dynamic part.
9598 int details_index = kFrameDetailsFirstDynamicIndex;
9599
9600 // Add arguments name and value.
9601 for (int i = 0; i < argument_count; i++) {
9602 // Name of the argument.
9603 if (i < info.number_of_parameters()) {
9604 details->set(details_index++, *info.parameter_name(i));
9605 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009606 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009607 }
9608
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009609 // Parameter value. If we are inspecting an optimized frame, use
9610 // undefined as the value.
9611 //
9612 // TODO(3141533): We should be able to get the actual parameter
9613 // value for optimized frames.
9614 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009615 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009616 details->set(details_index++, it.frame()->GetParameter(i));
9617 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009618 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009619 }
9620 }
9621
9622 // Add locals name and value from the temporary copy from the function frame.
9623 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9624 details->set(details_index++, locals->get(i));
9625 }
9626
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009627 // Add the value being returned.
9628 if (at_return) {
9629 details->set(details_index++, *return_value);
9630 }
9631
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009632 // Add the receiver (same as in function frame).
9633 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9634 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009635 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009636 if (!receiver->IsJSObject()) {
9637 // If the receiver is NOT a JSObject we have hit an optimization
9638 // where a value object is not converted into a wrapped JS objects.
9639 // To hide this optimization from the debugger, we wrap the receiver
9640 // by creating correct wrapper object based on the calling frame's
9641 // global context.
9642 it.Advance();
9643 Handle<Context> calling_frames_global_context(
9644 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009645 receiver =
9646 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009647 }
9648 details->set(kFrameDetailsReceiverIndex, *receiver);
9649
9650 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009651 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009652}
9653
9654
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009655// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009656static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009657 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009658 Handle<SerializedScopeInfo> serialized_scope_info,
9659 ScopeInfo<>& scope_info,
9660 Handle<Context> context,
9661 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009662 // Fill all context locals to the context extension.
9663 for (int i = Context::MIN_CONTEXT_SLOTS;
9664 i < scope_info.number_of_context_slots();
9665 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009666 int context_index = serialized_scope_info->ContextSlotIndex(
9667 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009668
9669 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009670 if (*scope_info.context_slot_name(i) !=
9671 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009672 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009673 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009674 SetProperty(scope_object,
9675 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009676 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009677 NONE,
9678 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009679 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009680 }
9681 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009682
9683 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009684}
9685
9686
9687// Create a plain JSObject which materializes the local scope for the specified
9688// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009689static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9690 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009691 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009692 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009693 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9694 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009695
9696 // Allocate and initialize a JSObject with all the arguments, stack locals
9697 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009698 Handle<JSObject> local_scope =
9699 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009700
9701 // First fill all parameters.
9702 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009703 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009704 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009705 SetProperty(local_scope,
9706 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009707 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009708 NONE,
9709 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009710 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009711 }
9712
9713 // Second fill all stack locals.
9714 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009715 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009716 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009717 SetProperty(local_scope,
9718 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009719 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009720 NONE,
9721 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009722 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009723 }
9724
9725 // Third fill all context locals.
9726 Handle<Context> frame_context(Context::cast(frame->context()));
9727 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009728 if (!CopyContextLocalsToScopeObject(isolate,
9729 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009730 function_context, local_scope)) {
9731 return Handle<JSObject>();
9732 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009733
9734 // Finally copy any properties from the function context extension. This will
9735 // be variables introduced by eval.
9736 if (function_context->closure() == *function) {
9737 if (function_context->has_extension() &&
9738 !function_context->IsGlobalContext()) {
9739 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009740 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009741 for (int i = 0; i < keys->length(); i++) {
9742 // Names of variables introduced by eval are strings.
9743 ASSERT(keys->get(i)->IsString());
9744 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009745 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009746 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009747 SetProperty(local_scope,
9748 key,
9749 GetProperty(ext, key),
9750 NONE,
9751 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009752 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009753 }
9754 }
9755 }
9756 return local_scope;
9757}
9758
9759
9760// Create a plain JSObject which materializes the closure content for the
9761// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009762static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9763 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009764 ASSERT(context->is_function_context());
9765
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009766 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009767 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9768 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009769
9770 // Allocate and initialize a JSObject with all the content of theis function
9771 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009772 Handle<JSObject> closure_scope =
9773 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009774
9775 // Check whether the arguments shadow object exists.
9776 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009777 shared->scope_info()->ContextSlotIndex(
9778 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009779 if (arguments_shadow_index >= 0) {
9780 // In this case all the arguments are available in the arguments shadow
9781 // object.
9782 Handle<JSObject> arguments_shadow(
9783 JSObject::cast(context->get(arguments_shadow_index)));
9784 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009785 // We don't expect exception-throwing getters on the arguments shadow.
9786 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009787 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009788 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009789 SetProperty(closure_scope,
9790 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009791 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009792 NONE,
9793 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009794 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009795 }
9796 }
9797
9798 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009799 if (!CopyContextLocalsToScopeObject(isolate,
9800 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009801 context, closure_scope)) {
9802 return Handle<JSObject>();
9803 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009804
9805 // Finally copy any properties from the function context extension. This will
9806 // be variables introduced by eval.
9807 if (context->has_extension()) {
9808 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009809 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009810 for (int i = 0; i < keys->length(); i++) {
9811 // Names of variables introduced by eval are strings.
9812 ASSERT(keys->get(i)->IsString());
9813 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009814 RETURN_IF_EMPTY_HANDLE_VALUE(
9815 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009816 SetProperty(closure_scope,
9817 key,
9818 GetProperty(ext, key),
9819 NONE,
9820 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009821 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009822 }
9823 }
9824
9825 return closure_scope;
9826}
9827
9828
9829// Iterate over the actual scopes visible from a stack frame. All scopes are
9830// backed by an actual context except the local scope, which is inserted
9831// "artifically" in the context chain.
9832class ScopeIterator {
9833 public:
9834 enum ScopeType {
9835 ScopeTypeGlobal = 0,
9836 ScopeTypeLocal,
9837 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009838 ScopeTypeClosure,
9839 // Every catch block contains an implicit with block (its parameter is
9840 // a JSContextExtensionObject) that extends current scope with a variable
9841 // holding exception object. Such with blocks are treated as scopes of their
9842 // own type.
9843 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009844 };
9845
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009846 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
9847 : isolate_(isolate),
9848 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009849 function_(JSFunction::cast(frame->function())),
9850 context_(Context::cast(frame->context())),
9851 local_done_(false),
9852 at_local_(false) {
9853
9854 // Check whether the first scope is actually a local scope.
9855 if (context_->IsGlobalContext()) {
9856 // If there is a stack slot for .result then this local scope has been
9857 // created for evaluating top level code and it is not a real local scope.
9858 // Checking for the existence of .result seems fragile, but the scope info
9859 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009860 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009861 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009862 at_local_ = index < 0;
9863 } else if (context_->is_function_context()) {
9864 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009865 } else if (context_->closure() != *function_) {
9866 // The context_ is a with block from the outer function.
9867 ASSERT(context_->has_extension());
9868 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009869 }
9870 }
9871
9872 // More scopes?
9873 bool Done() { return context_.is_null(); }
9874
9875 // Move to the next scope.
9876 void Next() {
9877 // If at a local scope mark the local scope as passed.
9878 if (at_local_) {
9879 at_local_ = false;
9880 local_done_ = true;
9881
9882 // If the current context is not associated with the local scope the
9883 // current context is the next real scope, so don't move to the next
9884 // context in this case.
9885 if (context_->closure() != *function_) {
9886 return;
9887 }
9888 }
9889
9890 // The global scope is always the last in the chain.
9891 if (context_->IsGlobalContext()) {
9892 context_ = Handle<Context>();
9893 return;
9894 }
9895
9896 // Move to the next context.
9897 if (context_->is_function_context()) {
9898 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9899 } else {
9900 context_ = Handle<Context>(context_->previous());
9901 }
9902
9903 // If passing the local scope indicate that the current scope is now the
9904 // local scope.
9905 if (!local_done_ &&
9906 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9907 at_local_ = true;
9908 }
9909 }
9910
9911 // Return the type of the current scope.
9912 int Type() {
9913 if (at_local_) {
9914 return ScopeTypeLocal;
9915 }
9916 if (context_->IsGlobalContext()) {
9917 ASSERT(context_->global()->IsGlobalObject());
9918 return ScopeTypeGlobal;
9919 }
9920 if (context_->is_function_context()) {
9921 return ScopeTypeClosure;
9922 }
9923 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009924 // Current scope is either an explicit with statement or a with statement
9925 // implicitely generated for a catch block.
9926 // If the extension object here is a JSContextExtensionObject then
9927 // current with statement is one frome a catch block otherwise it's a
9928 // regular with statement.
9929 if (context_->extension()->IsJSContextExtensionObject()) {
9930 return ScopeTypeCatch;
9931 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009932 return ScopeTypeWith;
9933 }
9934
9935 // Return the JavaScript object with the content of the current scope.
9936 Handle<JSObject> ScopeObject() {
9937 switch (Type()) {
9938 case ScopeIterator::ScopeTypeGlobal:
9939 return Handle<JSObject>(CurrentContext()->global());
9940 break;
9941 case ScopeIterator::ScopeTypeLocal:
9942 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009943 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009944 break;
9945 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009946 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009947 // Return the with object.
9948 return Handle<JSObject>(CurrentContext()->extension());
9949 break;
9950 case ScopeIterator::ScopeTypeClosure:
9951 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009952 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009953 break;
9954 }
9955 UNREACHABLE();
9956 return Handle<JSObject>();
9957 }
9958
9959 // Return the context for this scope. For the local context there might not
9960 // be an actual context.
9961 Handle<Context> CurrentContext() {
9962 if (at_local_ && context_->closure() != *function_) {
9963 return Handle<Context>();
9964 }
9965 return context_;
9966 }
9967
9968#ifdef DEBUG
9969 // Debug print of the content of the current scope.
9970 void DebugPrint() {
9971 switch (Type()) {
9972 case ScopeIterator::ScopeTypeGlobal:
9973 PrintF("Global:\n");
9974 CurrentContext()->Print();
9975 break;
9976
9977 case ScopeIterator::ScopeTypeLocal: {
9978 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009979 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009980 scope_info.Print();
9981 if (!CurrentContext().is_null()) {
9982 CurrentContext()->Print();
9983 if (CurrentContext()->has_extension()) {
9984 Handle<JSObject> extension =
9985 Handle<JSObject>(CurrentContext()->extension());
9986 if (extension->IsJSContextExtensionObject()) {
9987 extension->Print();
9988 }
9989 }
9990 }
9991 break;
9992 }
9993
9994 case ScopeIterator::ScopeTypeWith: {
9995 PrintF("With:\n");
9996 Handle<JSObject> extension =
9997 Handle<JSObject>(CurrentContext()->extension());
9998 extension->Print();
9999 break;
10000 }
10001
ager@chromium.orga1645e22009-09-09 19:27:10 +000010002 case ScopeIterator::ScopeTypeCatch: {
10003 PrintF("Catch:\n");
10004 Handle<JSObject> extension =
10005 Handle<JSObject>(CurrentContext()->extension());
10006 extension->Print();
10007 break;
10008 }
10009
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010010 case ScopeIterator::ScopeTypeClosure: {
10011 PrintF("Closure:\n");
10012 CurrentContext()->Print();
10013 if (CurrentContext()->has_extension()) {
10014 Handle<JSObject> extension =
10015 Handle<JSObject>(CurrentContext()->extension());
10016 if (extension->IsJSContextExtensionObject()) {
10017 extension->Print();
10018 }
10019 }
10020 break;
10021 }
10022
10023 default:
10024 UNREACHABLE();
10025 }
10026 PrintF("\n");
10027 }
10028#endif
10029
10030 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010031 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010032 JavaScriptFrame* frame_;
10033 Handle<JSFunction> function_;
10034 Handle<Context> context_;
10035 bool local_done_;
10036 bool at_local_;
10037
10038 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10039};
10040
10041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010042RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010043 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010044 ASSERT(args.length() == 2);
10045
10046 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010047 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010048 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10049 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010050 if (!maybe_check->ToObject(&check)) return maybe_check;
10051 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010052 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10053
10054 // Get the frame where the debugging is performed.
10055 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010056 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010057 JavaScriptFrame* frame = it.frame();
10058
10059 // Count the visible scopes.
10060 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010061 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010062 n++;
10063 }
10064
10065 return Smi::FromInt(n);
10066}
10067
10068
10069static const int kScopeDetailsTypeIndex = 0;
10070static const int kScopeDetailsObjectIndex = 1;
10071static const int kScopeDetailsSize = 2;
10072
10073// Return an array with scope details
10074// args[0]: number: break id
10075// args[1]: number: frame index
10076// args[2]: number: scope index
10077//
10078// The array returned contains the following information:
10079// 0: Scope type
10080// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010081RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010082 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010083 ASSERT(args.length() == 3);
10084
10085 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010086 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010087 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10088 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010089 if (!maybe_check->ToObject(&check)) return maybe_check;
10090 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010091 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10092 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10093
10094 // Get the frame where the debugging is performed.
10095 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010096 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010097 JavaScriptFrame* frame = frame_it.frame();
10098
10099 // Find the requested scope.
10100 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010101 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010102 for (; !it.Done() && n < index; it.Next()) {
10103 n++;
10104 }
10105 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010106 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010107 }
10108
10109 // Calculate the size of the result.
10110 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010111 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010112
10113 // Fill in scope details.
10114 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010115 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010116 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010117 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010118
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010119 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010120}
10121
10122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010123RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010124 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010125 ASSERT(args.length() == 0);
10126
10127#ifdef DEBUG
10128 // Print the scopes for the top frame.
10129 StackFrameLocator locator;
10130 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010131 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010132 it.DebugPrint();
10133 }
10134#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010135 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010136}
10137
10138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010139RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010140 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010141 ASSERT(args.length() == 1);
10142
10143 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010144 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010145 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10146 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010147 if (!maybe_result->ToObject(&result)) return maybe_result;
10148 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010149
10150 // Count all archived V8 threads.
10151 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010152 for (ThreadState* thread =
10153 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010154 thread != NULL;
10155 thread = thread->Next()) {
10156 n++;
10157 }
10158
10159 // Total number of threads is current thread and archived threads.
10160 return Smi::FromInt(n + 1);
10161}
10162
10163
10164static const int kThreadDetailsCurrentThreadIndex = 0;
10165static const int kThreadDetailsThreadIdIndex = 1;
10166static const int kThreadDetailsSize = 2;
10167
10168// Return an array with thread details
10169// args[0]: number: break id
10170// args[1]: number: thread index
10171//
10172// The array returned contains the following information:
10173// 0: Is current thread?
10174// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010175RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010176 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010177 ASSERT(args.length() == 2);
10178
10179 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010180 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010181 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10182 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010183 if (!maybe_check->ToObject(&check)) return maybe_check;
10184 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010185 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10186
10187 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010188 Handle<FixedArray> details =
10189 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010190
10191 // Thread index 0 is current thread.
10192 if (index == 0) {
10193 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010194 details->set(kThreadDetailsCurrentThreadIndex,
10195 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010196 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010197 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010198 } else {
10199 // Find the thread with the requested index.
10200 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010201 ThreadState* thread =
10202 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010203 while (index != n && thread != NULL) {
10204 thread = thread->Next();
10205 n++;
10206 }
10207 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010208 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010209 }
10210
10211 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010212 details->set(kThreadDetailsCurrentThreadIndex,
10213 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010214 details->set(kThreadDetailsThreadIdIndex,
10215 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010216 }
10217
10218 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010219 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010220}
10221
10222
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010223// Sets the disable break state
10224// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010225RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010226 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010227 ASSERT(args.length() == 1);
10228 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010229 isolate->debug()->set_disable_break(disable_break);
10230 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010231}
10232
10233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010234RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010235 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010236 ASSERT(args.length() == 1);
10237
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010238 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10239 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240 // Find the number of break points
10241 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010242 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010243 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010244 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245 Handle<FixedArray>::cast(break_locations));
10246}
10247
10248
10249// Set a break point in a function
10250// args[0]: function
10251// args[1]: number: break source position (within the function source)
10252// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010253RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010254 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010255 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010256 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10257 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010258 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10259 RUNTIME_ASSERT(source_position >= 0);
10260 Handle<Object> break_point_object_arg = args.at<Object>(2);
10261
10262 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010263 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10264 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010265
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010266 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010267}
10268
10269
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010270Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10271 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010272 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010273 // Iterate the heap looking for SharedFunctionInfo generated from the
10274 // script. The inner most SharedFunctionInfo containing the source position
10275 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010276 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010277 // which is found is not compiled it is compiled and the heap is iterated
10278 // again as the compilation might create inner functions from the newly
10279 // compiled function and the actual requested break point might be in one of
10280 // these functions.
10281 bool done = false;
10282 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010283 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010285 while (!done) {
10286 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010287 for (HeapObject* obj = iterator.next();
10288 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010289 if (obj->IsSharedFunctionInfo()) {
10290 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10291 if (shared->script() == *script) {
10292 // If the SharedFunctionInfo found has the requested script data and
10293 // contains the source position it is a candidate.
10294 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010295 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010296 start_position = shared->start_position();
10297 }
10298 if (start_position <= position &&
10299 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010300 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010301 // candidate this is the new candidate.
10302 if (target.is_null()) {
10303 target_start_position = start_position;
10304 target = shared;
10305 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010306 if (target_start_position == start_position &&
10307 shared->end_position() == target->end_position()) {
10308 // If a top-level function contain only one function
10309 // declartion the source for the top-level and the function is
10310 // the same. In that case prefer the non top-level function.
10311 if (!shared->is_toplevel()) {
10312 target_start_position = start_position;
10313 target = shared;
10314 }
10315 } else if (target_start_position <= start_position &&
10316 shared->end_position() <= target->end_position()) {
10317 // This containment check includes equality as a function inside
10318 // a top-level function can share either start or end position
10319 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010320 target_start_position = start_position;
10321 target = shared;
10322 }
10323 }
10324 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325 }
10326 }
10327 }
10328
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010329 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010330 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010331 }
10332
10333 // If the candidate found is compiled we are done. NOTE: when lazy
10334 // compilation of inner functions is introduced some additional checking
10335 // needs to be done here to compile inner functions.
10336 done = target->is_compiled();
10337 if (!done) {
10338 // If the candidate is not compiled compile it to reveal any inner
10339 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010340 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010341 }
10342 }
10343
10344 return *target;
10345}
10346
10347
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010348// Changes the state of a break point in a script and returns source position
10349// where break point was set. NOTE: Regarding performance see the NOTE for
10350// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010351// args[0]: script to set break point in
10352// args[1]: number: break source position (within the script source)
10353// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010354RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010355 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010356 ASSERT(args.length() == 3);
10357 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10358 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10359 RUNTIME_ASSERT(source_position >= 0);
10360 Handle<Object> break_point_object_arg = args.at<Object>(2);
10361
10362 // Get the script from the script wrapper.
10363 RUNTIME_ASSERT(wrapper->value()->IsScript());
10364 Handle<Script> script(Script::cast(wrapper->value()));
10365
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010366 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010367 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010368 if (!result->IsUndefined()) {
10369 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10370 // Find position within function. The script position might be before the
10371 // source position of the first function.
10372 int position;
10373 if (shared->start_position() > source_position) {
10374 position = 0;
10375 } else {
10376 position = source_position - shared->start_position();
10377 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010378 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010379 position += shared->start_position();
10380 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010381 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010382 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010383}
10384
10385
10386// Clear a break point
10387// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010388RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010389 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010390 ASSERT(args.length() == 1);
10391 Handle<Object> break_point_object_arg = args.at<Object>(0);
10392
10393 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010394 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010395
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010396 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010397}
10398
10399
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010400// Change the state of break on exceptions.
10401// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10402// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010403RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010404 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010405 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010406 RUNTIME_ASSERT(args[0]->IsNumber());
10407 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010408
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010409 // If the number doesn't match an enum value, the ChangeBreakOnException
10410 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010411 ExceptionBreakType type =
10412 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010413 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010414 isolate->debug()->ChangeBreakOnException(type, enable);
10415 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010416}
10417
10418
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010419// Returns the state of break on exceptions
10420// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010421RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010422 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010423 ASSERT(args.length() == 1);
10424 RUNTIME_ASSERT(args[0]->IsNumber());
10425
10426 ExceptionBreakType type =
10427 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010428 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010429 return Smi::FromInt(result);
10430}
10431
10432
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010433// Prepare for stepping
10434// args[0]: break id for checking execution state
10435// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010436// args[2]: number of times to perform the step, for step out it is the number
10437// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010438RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010439 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010440 ASSERT(args.length() == 3);
10441 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010442 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010443 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10444 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010445 if (!maybe_check->ToObject(&check)) return maybe_check;
10446 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010447 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010448 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010449 }
10450
10451 // Get the step action and check validity.
10452 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10453 if (step_action != StepIn &&
10454 step_action != StepNext &&
10455 step_action != StepOut &&
10456 step_action != StepInMin &&
10457 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010458 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010459 }
10460
10461 // Get the number of steps.
10462 int step_count = NumberToInt32(args[2]);
10463 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010464 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010465 }
10466
ager@chromium.orga1645e22009-09-09 19:27:10 +000010467 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010468 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010469
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010470 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010471 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10472 step_count);
10473 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010474}
10475
10476
10477// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010478RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010479 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010480 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010481 isolate->debug()->ClearStepping();
10482 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010483}
10484
10485
10486// Creates a copy of the with context chain. The copy of the context chain is
10487// is linked to the function context supplied.
10488static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10489 Handle<Context> function_context) {
10490 // At the bottom of the chain. Return the function context to link to.
10491 if (context_chain->is_function_context()) {
10492 return function_context;
10493 }
10494
10495 // Recursively copy the with contexts.
10496 Handle<Context> previous(context_chain->previous());
10497 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
danno@chromium.org160a7b02011-04-18 15:51:38 +000010498 Handle<Context> context = CopyWithContextChain(previous, function_context);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010499 return context->GetIsolate()->factory()->NewWithContext(
10500 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010501}
10502
10503
10504// Helper function to find or create the arguments object for
10505// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010506static Handle<Object> GetArgumentsObject(Isolate* isolate,
10507 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010508 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010509 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010510 const ScopeInfo<>* sinfo,
10511 Handle<Context> function_context) {
10512 // Try to find the value of 'arguments' to pass as parameter. If it is not
10513 // found (that is the debugged function does not reference 'arguments' and
10514 // does not support eval) then create an 'arguments' object.
10515 int index;
10516 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010517 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010518 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010519 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010520 }
10521 }
10522
10523 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010524 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10525 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010526 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010527 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010528 }
10529 }
10530
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010531 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010532 Handle<JSObject> arguments =
10533 isolate->factory()->NewArgumentsObject(function, length);
10534 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010535
10536 AssertNoAllocation no_gc;
10537 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010538 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010539 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010540 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010541 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010542 return arguments;
10543}
10544
10545
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010546static const char kSourceStr[] =
10547 "(function(arguments,__source__){return eval(__source__);})";
10548
10549
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010550// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010551// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010552// extension part has all the parameters and locals of the function on the
10553// stack frame. A function which calls eval with the code to evaluate is then
10554// compiled in this context and called in this context. As this context
10555// replaces the context of the function on the stack frame a new (empty)
10556// function is created as well to be used as the closure for the context.
10557// This function and the context acts as replacements for the function on the
10558// stack frame presenting the same view of the values of parameters and
10559// local variables as if the piece of JavaScript was evaluated at the point
10560// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010561RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010562 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010563
10564 // Check the execution state and decode arguments frame and source to be
10565 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010566 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010567 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010568 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10569 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010570 if (!maybe_check_result->ToObject(&check_result)) {
10571 return maybe_check_result;
10572 }
10573 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10575 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010576 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010577 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010578
10579 // Handle the processing of break.
10580 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010581
10582 // Get the frame where the debugging is performed.
10583 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010584 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010585 JavaScriptFrame* frame = it.frame();
10586 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010587 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010588 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010589
10590 // Traverse the saved contexts chain to find the active context for the
10591 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010592 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010593 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594 save = save->prev();
10595 }
10596 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010597 SaveContext savex(isolate);
10598 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010599
10600 // Create the (empty) function replacing the function on the stack frame for
10601 // the purpose of evaluating in the context created below. It is important
10602 // that this function does not describe any parameters and local variables
10603 // in the context. If it does then this will cause problems with the lookup
10604 // in Context::Lookup, where context slots for parameters and local variables
10605 // are looked at before the extension object.
10606 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10608 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609 go_between->set_context(function->context());
10610#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010611 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10613 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10614#endif
10615
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010616 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010617 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10618 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010619
10620 // Allocate a new context for the debug evaluation and set the extension
10621 // object build.
10622 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010623 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10624 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010625 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010626 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010627 Handle<Context> frame_context(Context::cast(frame->context()));
10628 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010629 context = CopyWithContextChain(frame_context, context);
10630
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010631 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010632 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010633 Handle<JSObject>::cast(additional_context), false);
10634 }
10635
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010636 // Wrap the evaluation statement in a new function compiled in the newly
10637 // created context. The function has one parameter which has to be called
10638 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010639 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010640 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010641
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010642 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010643 isolate->factory()->NewStringFromAscii(
10644 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010645
10646 // Currently, the eval code will be executed in non-strict mode,
10647 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010648 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010649 Compiler::CompileEval(function_source,
10650 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010651 context->IsGlobalContext(),
10652 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010653 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010654 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010655 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010656
10657 // Invoke the result of the compilation to get the evaluation function.
10658 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010659 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010660 Handle<Object> evaluation_function =
10661 Execution::Call(compiled_function, receiver, 0, NULL,
10662 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010663 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010665 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10666 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010667 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010668
10669 // Invoke the evaluation function and return the result.
10670 const int argc = 2;
10671 Object** argv[argc] = { arguments.location(),
10672 Handle<Object>::cast(source).location() };
10673 Handle<Object> result =
10674 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10675 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010676 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010677
10678 // Skip the global proxy as it has no properties and always delegates to the
10679 // real global object.
10680 if (result->IsJSGlobalProxy()) {
10681 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10682 }
10683
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010684 return *result;
10685}
10686
10687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010688RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010689 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690
10691 // Check the execution state and decode arguments frame and source to be
10692 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010693 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010694 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010695 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10696 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010697 if (!maybe_check_result->ToObject(&check_result)) {
10698 return maybe_check_result;
10699 }
10700 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010701 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010702 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010703 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010704
10705 // Handle the processing of break.
10706 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010707
10708 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010709 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010710 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010711 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010712 top = top->prev();
10713 }
10714 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010715 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010716 }
10717
10718 // Get the global context now set to the top context from before the
10719 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010720 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010721
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010722 bool is_global = true;
10723
10724 if (additional_context->IsJSObject()) {
10725 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010726 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10727 isolate->factory()->empty_string(),
10728 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010729 go_between->set_context(*context);
10730 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010731 isolate->factory()->NewFunctionContext(
10732 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010733 context->set_extension(JSObject::cast(*additional_context));
10734 is_global = false;
10735 }
10736
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010737 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010738 // Currently, the eval code will be executed in non-strict mode,
10739 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010740 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010741 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010742 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010743 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010744 Handle<JSFunction>(
10745 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10746 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010747
10748 // Invoke the result of the compilation to get the evaluation function.
10749 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010750 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010751 Handle<Object> result =
10752 Execution::Call(compiled_function, receiver, 0, NULL,
10753 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010754 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010755 return *result;
10756}
10757
10758
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010759RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010760 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010761 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010763 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010764 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010765
10766 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010767 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010768 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10769 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10770 // because using
10771 // instances->set(i, *GetScriptWrapper(script))
10772 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10773 // already have deferenced the instances handle.
10774 Handle<JSValue> wrapper = GetScriptWrapper(script);
10775 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010776 }
10777
10778 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010779 Handle<JSObject> result =
10780 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010781 Handle<JSArray>::cast(result)->SetContent(*instances);
10782 return *result;
10783}
10784
10785
10786// Helper function used by Runtime_DebugReferencedBy below.
10787static int DebugReferencedBy(JSObject* target,
10788 Object* instance_filter, int max_references,
10789 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010790 JSFunction* arguments_function) {
10791 NoHandleAllocation ha;
10792 AssertNoAllocation no_alloc;
10793
10794 // Iterate the heap.
10795 int count = 0;
10796 JSObject* last = NULL;
10797 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010798 HeapObject* heap_obj = NULL;
10799 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010800 (max_references == 0 || count < max_references)) {
10801 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010802 if (heap_obj->IsJSObject()) {
10803 // Skip context extension objects and argument arrays as these are
10804 // checked in the context of functions using them.
10805 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010806 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010807 obj->map()->constructor() == arguments_function) {
10808 continue;
10809 }
10810
10811 // Check if the JS object has a reference to the object looked for.
10812 if (obj->ReferencesObject(target)) {
10813 // Check instance filter if supplied. This is normally used to avoid
10814 // references from mirror objects (see Runtime_IsInPrototypeChain).
10815 if (!instance_filter->IsUndefined()) {
10816 Object* V = obj;
10817 while (true) {
10818 Object* prototype = V->GetPrototype();
10819 if (prototype->IsNull()) {
10820 break;
10821 }
10822 if (instance_filter == prototype) {
10823 obj = NULL; // Don't add this object.
10824 break;
10825 }
10826 V = prototype;
10827 }
10828 }
10829
10830 if (obj != NULL) {
10831 // Valid reference found add to instance array if supplied an update
10832 // count.
10833 if (instances != NULL && count < instances_size) {
10834 instances->set(count, obj);
10835 }
10836 last = obj;
10837 count++;
10838 }
10839 }
10840 }
10841 }
10842
10843 // Check for circular reference only. This can happen when the object is only
10844 // referenced from mirrors and has a circular reference in which case the
10845 // object is not really alive and would have been garbage collected if not
10846 // referenced from the mirror.
10847 if (count == 1 && last == target) {
10848 count = 0;
10849 }
10850
10851 // Return the number of referencing objects found.
10852 return count;
10853}
10854
10855
10856// Scan the heap for objects with direct references to an object
10857// args[0]: the object to find references to
10858// args[1]: constructor function for instances to exclude (Mirror)
10859// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010860RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010861 ASSERT(args.length() == 3);
10862
10863 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010864 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010865
10866 // Check parameters.
10867 CONVERT_CHECKED(JSObject, target, args[0]);
10868 Object* instance_filter = args[1];
10869 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10870 instance_filter->IsJSObject());
10871 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10872 RUNTIME_ASSERT(max_references >= 0);
10873
10874 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010875 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010876 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010877 JSFunction* arguments_function =
10878 JSFunction::cast(arguments_boilerplate->map()->constructor());
10879
10880 // Get the number of referencing objects.
10881 int count;
10882 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010883 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010884
10885 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010886 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010887 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010888 if (!maybe_object->ToObject(&object)) return maybe_object;
10889 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890 FixedArray* instances = FixedArray::cast(object);
10891
10892 // Fill the referencing objects.
10893 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010894 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010895
10896 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010897 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010898 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
10899 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010900 if (!maybe_result->ToObject(&result)) return maybe_result;
10901 }
10902 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010903 return result;
10904}
10905
10906
10907// Helper function used by Runtime_DebugConstructedBy below.
10908static int DebugConstructedBy(JSFunction* constructor, int max_references,
10909 FixedArray* instances, int instances_size) {
10910 AssertNoAllocation no_alloc;
10911
10912 // Iterate the heap.
10913 int count = 0;
10914 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010915 HeapObject* heap_obj = NULL;
10916 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010917 (max_references == 0 || count < max_references)) {
10918 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010919 if (heap_obj->IsJSObject()) {
10920 JSObject* obj = JSObject::cast(heap_obj);
10921 if (obj->map()->constructor() == constructor) {
10922 // Valid reference found add to instance array if supplied an update
10923 // count.
10924 if (instances != NULL && count < instances_size) {
10925 instances->set(count, obj);
10926 }
10927 count++;
10928 }
10929 }
10930 }
10931
10932 // Return the number of referencing objects found.
10933 return count;
10934}
10935
10936
10937// Scan the heap for objects constructed by a specific function.
10938// args[0]: the constructor to find instances of
10939// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010940RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010941 ASSERT(args.length() == 2);
10942
10943 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010944 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010945
10946 // Check parameters.
10947 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10948 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10949 RUNTIME_ASSERT(max_references >= 0);
10950
10951 // Get the number of referencing objects.
10952 int count;
10953 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10954
10955 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010956 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010957 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010958 if (!maybe_object->ToObject(&object)) return maybe_object;
10959 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010960 FixedArray* instances = FixedArray::cast(object);
10961
10962 // Fill the referencing objects.
10963 count = DebugConstructedBy(constructor, max_references, instances, count);
10964
10965 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010966 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010967 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
10968 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010969 if (!maybe_result->ToObject(&result)) return maybe_result;
10970 }
10971 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010972 return result;
10973}
10974
10975
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010976// Find the effective prototype object as returned by __proto__.
10977// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010978RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010979 ASSERT(args.length() == 1);
10980
10981 CONVERT_CHECKED(JSObject, obj, args[0]);
10982
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010983 // Use the __proto__ accessor.
10984 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010985}
10986
10987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010988RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000010989 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010990 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010991 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010992}
10993
10994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010995RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010996#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010997 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010998 ASSERT(args.length() == 1);
10999 // Get the function and make sure it is compiled.
11000 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011001 Handle<SharedFunctionInfo> shared(func->shared());
11002 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011003 return Failure::Exception();
11004 }
11005 func->code()->PrintLn();
11006#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011007 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011008}
ager@chromium.org9085a012009-05-11 19:22:57 +000011009
11010
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011011RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011012#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011013 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011014 ASSERT(args.length() == 1);
11015 // Get the function and make sure it is compiled.
11016 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011017 Handle<SharedFunctionInfo> shared(func->shared());
11018 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011019 return Failure::Exception();
11020 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011021 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011022#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011023 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011024}
11025
11026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011027RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011028 NoHandleAllocation ha;
11029 ASSERT(args.length() == 1);
11030
11031 CONVERT_CHECKED(JSFunction, f, args[0]);
11032 return f->shared()->inferred_name();
11033}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011034
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011035
11036static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011037 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011038 AssertNoAllocation no_allocations;
11039
11040 int counter = 0;
11041 int buffer_size = buffer->length();
11042 HeapIterator iterator;
11043 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11044 ASSERT(obj != NULL);
11045 if (!obj->IsSharedFunctionInfo()) {
11046 continue;
11047 }
11048 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11049 if (shared->script() != script) {
11050 continue;
11051 }
11052 if (counter < buffer_size) {
11053 buffer->set(counter, shared);
11054 }
11055 counter++;
11056 }
11057 return counter;
11058}
11059
11060// For a script finds all SharedFunctionInfo's in the heap that points
11061// to this script. Returns JSArray of SharedFunctionInfo wrapped
11062// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011063RUNTIME_FUNCTION(MaybeObject*,
11064 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011065 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011066 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011067 CONVERT_CHECKED(JSValue, script_value, args[0]);
11068
11069 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11070
11071 const int kBufferSize = 32;
11072
11073 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011074 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011075 int number = FindSharedFunctionInfosForScript(*script, *array);
11076 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011077 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011078 FindSharedFunctionInfosForScript(*script, *array);
11079 }
11080
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011081 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011082 result->set_length(Smi::FromInt(number));
11083
11084 LiveEdit::WrapSharedFunctionInfos(result);
11085
11086 return *result;
11087}
11088
11089// For a script calculates compilation information about all its functions.
11090// The script source is explicitly specified by the second argument.
11091// The source of the actual script is not used, however it is important that
11092// all generated code keeps references to this particular instance of script.
11093// Returns a JSArray of compilation infos. The array is ordered so that
11094// each function with all its descendant is always stored in a continues range
11095// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011096RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011097 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011098 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011099 CONVERT_CHECKED(JSValue, script, args[0]);
11100 CONVERT_ARG_CHECKED(String, source, 1);
11101 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11102
11103 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011105 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011106 return Failure::Exception();
11107 }
11108
11109 return result;
11110}
11111
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011112// Changes the source of the script to a new_source.
11113// If old_script_name is provided (i.e. is a String), also creates a copy of
11114// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011115RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011116 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011117 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011118 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11119 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011120 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011121
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011122 CONVERT_CHECKED(Script, original_script_pointer,
11123 original_script_value->value());
11124 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011125
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011126 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11127 new_source,
11128 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011129
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011130 if (old_script->IsScript()) {
11131 Handle<Script> script_handle(Script::cast(old_script));
11132 return *(GetScriptWrapper(script_handle));
11133 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011134 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011135 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011136}
11137
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011139RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011140 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011141 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011142 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11143 return LiveEdit::FunctionSourceUpdated(shared_info);
11144}
11145
11146
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011147// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011148RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011149 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011150 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011151 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11152 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11153
ager@chromium.orgac091b72010-05-05 07:34:42 +000011154 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011155}
11156
11157// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011158RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011159 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011160 HandleScope scope(isolate);
11161 Handle<Object> function_object(args[0], isolate);
11162 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011163
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011164 if (function_object->IsJSValue()) {
11165 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11166 if (script_object->IsJSValue()) {
11167 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011168 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011169 }
11170
11171 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11172 } else {
11173 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11174 // and we check it in this function.
11175 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011176
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011177 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011178}
11179
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011180
11181// In a code of a parent function replaces original function as embedded object
11182// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011183RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011184 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011185 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011186
11187 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11188 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11189 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11190
11191 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11192 subst_wrapper);
11193
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011194 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011195}
11196
11197
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011198// Updates positions of a shared function info (first parameter) according
11199// to script source change. Text change is described in second parameter as
11200// array of groups of 3 numbers:
11201// (change_begin, change_end, change_end_new_position).
11202// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011203RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011204 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011205 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011206 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11207 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11208
ager@chromium.orgac091b72010-05-05 07:34:42 +000011209 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011210}
11211
11212
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011213// For array of SharedFunctionInfo's (each wrapped in JSValue)
11214// checks that none of them have activations on stacks (of any thread).
11215// Returns array of the same length with corresponding results of
11216// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011217RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011218 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011219 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011220 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011221 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011222
ager@chromium.org357bf652010-04-12 11:30:10 +000011223 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011224}
11225
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011226// Compares 2 strings line-by-line, then token-wise and returns diff in form
11227// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11228// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011229RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011230 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011231 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011232 CONVERT_ARG_CHECKED(String, s1, 0);
11233 CONVERT_ARG_CHECKED(String, s2, 1);
11234
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011235 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011236}
11237
11238
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011239// A testing entry. Returns statement position which is the closest to
11240// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011241RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011242 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011243 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011244 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11245 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11246
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011247 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011248
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011249 if (code->kind() != Code::FUNCTION &&
11250 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011251 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011252 }
11253
11254 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011255 int closest_pc = 0;
11256 int distance = kMaxInt;
11257 while (!it.done()) {
11258 int statement_position = static_cast<int>(it.rinfo()->data());
11259 // Check if this break point is closer that what was previously found.
11260 if (source_position <= statement_position &&
11261 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011262 closest_pc =
11263 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011264 distance = statement_position - source_position;
11265 // Check whether we can't get any closer.
11266 if (distance == 0) break;
11267 }
11268 it.next();
11269 }
11270
11271 return Smi::FromInt(closest_pc);
11272}
11273
11274
ager@chromium.org357bf652010-04-12 11:30:10 +000011275// Calls specified function with or without entering the debugger.
11276// This is used in unit tests to run code as if debugger is entered or simply
11277// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011278RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011279 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011280 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011281 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11282 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11283
11284 Handle<Object> result;
11285 bool pending_exception;
11286 {
11287 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011288 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011289 &pending_exception);
11290 } else {
11291 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011292 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011293 &pending_exception);
11294 }
11295 }
11296 if (!pending_exception) {
11297 return *result;
11298 } else {
11299 return Failure::Exception();
11300 }
11301}
11302
11303
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011304// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011305RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011306 CONVERT_CHECKED(String, arg, args[0]);
11307 SmartPointer<char> flags =
11308 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11309 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011310 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011311}
11312
11313
11314// Performs a GC.
11315// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011316RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011317 isolate->heap()->CollectAllGarbage(true);
11318 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011319}
11320
11321
11322// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011323RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011324 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011325 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011326 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011327 }
11328 return Smi::FromInt(usage);
11329}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011330
11331
11332// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011333RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011334#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011335 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011336#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011337 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011338#endif
11339}
11340
11341
11342// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011343RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011344#ifdef LIVE_OBJECT_LIST
11345 return LiveObjectList::Capture();
11346#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011347 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011348#endif
11349}
11350
11351
11352// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011353RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011354#ifdef LIVE_OBJECT_LIST
11355 CONVERT_SMI_CHECKED(id, args[0]);
11356 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011357 return success ? isolate->heap()->true_value() :
11358 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011359#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011360 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011361#endif
11362}
11363
11364
11365// Generates the response to a debugger request for a dump of the objects
11366// contained in the difference between the captured live object lists
11367// specified by id1 and id2.
11368// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11369// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011370RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011371#ifdef LIVE_OBJECT_LIST
11372 HandleScope scope;
11373 CONVERT_SMI_CHECKED(id1, args[0]);
11374 CONVERT_SMI_CHECKED(id2, args[1]);
11375 CONVERT_SMI_CHECKED(start, args[2]);
11376 CONVERT_SMI_CHECKED(count, args[3]);
11377 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11378 EnterDebugger enter_debugger;
11379 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11380#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011381 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011382#endif
11383}
11384
11385
11386// Gets the specified object as requested by the debugger.
11387// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011388RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011389#ifdef LIVE_OBJECT_LIST
11390 CONVERT_SMI_CHECKED(obj_id, args[0]);
11391 Object* result = LiveObjectList::GetObj(obj_id);
11392 return result;
11393#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011394 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011395#endif
11396}
11397
11398
11399// Gets the obj id for the specified address if valid.
11400// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011401RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011402#ifdef LIVE_OBJECT_LIST
11403 HandleScope scope;
11404 CONVERT_ARG_CHECKED(String, address, 0);
11405 Object* result = LiveObjectList::GetObjId(address);
11406 return result;
11407#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011408 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011409#endif
11410}
11411
11412
11413// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011414RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011415#ifdef LIVE_OBJECT_LIST
11416 HandleScope scope;
11417 CONVERT_SMI_CHECKED(obj_id, args[0]);
11418 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11419 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11420 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11421 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11422 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11423
11424 Handle<JSObject> instance_filter;
11425 if (args[1]->IsJSObject()) {
11426 instance_filter = args.at<JSObject>(1);
11427 }
11428 bool verbose = false;
11429 if (args[2]->IsBoolean()) {
11430 verbose = args[2]->IsTrue();
11431 }
11432 int start = 0;
11433 if (args[3]->IsSmi()) {
11434 start = Smi::cast(args[3])->value();
11435 }
11436 int limit = Smi::kMaxValue;
11437 if (args[4]->IsSmi()) {
11438 limit = Smi::cast(args[4])->value();
11439 }
11440
11441 return LiveObjectList::GetObjRetainers(obj_id,
11442 instance_filter,
11443 verbose,
11444 start,
11445 limit,
11446 filter_obj);
11447#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011448 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011449#endif
11450}
11451
11452
11453// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011454RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011455#ifdef LIVE_OBJECT_LIST
11456 HandleScope scope;
11457 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11458 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11459 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11460
11461 Handle<JSObject> instance_filter;
11462 if (args[2]->IsJSObject()) {
11463 instance_filter = args.at<JSObject>(2);
11464 }
11465
11466 Object* result =
11467 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11468 return result;
11469#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011470 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011471#endif
11472}
11473
11474
11475// Generates the response to a debugger request for a list of all
11476// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011477RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011478#ifdef LIVE_OBJECT_LIST
11479 CONVERT_SMI_CHECKED(start, args[0]);
11480 CONVERT_SMI_CHECKED(count, args[1]);
11481 return LiveObjectList::Info(start, count);
11482#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011483 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011484#endif
11485}
11486
11487
11488// Gets a dump of the specified object as requested by the debugger.
11489// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011490RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011491#ifdef LIVE_OBJECT_LIST
11492 HandleScope scope;
11493 CONVERT_SMI_CHECKED(obj_id, args[0]);
11494 Object* result = LiveObjectList::PrintObj(obj_id);
11495 return result;
11496#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011497 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011498#endif
11499}
11500
11501
11502// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011503RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011504#ifdef LIVE_OBJECT_LIST
11505 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011506 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011507#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011508 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011509#endif
11510}
11511
11512
11513// Generates the response to a debugger request for a summary of the types
11514// of objects in the difference between the captured live object lists
11515// specified by id1 and id2.
11516// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11517// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011518RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011519#ifdef LIVE_OBJECT_LIST
11520 HandleScope scope;
11521 CONVERT_SMI_CHECKED(id1, args[0]);
11522 CONVERT_SMI_CHECKED(id2, args[1]);
11523 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11524
11525 EnterDebugger enter_debugger;
11526 return LiveObjectList::Summarize(id1, id2, filter_obj);
11527#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011528 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011529#endif
11530}
11531
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011532#endif // ENABLE_DEBUGGER_SUPPORT
11533
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011534
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011535#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011536RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011537 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011538 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011539
11540 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011541 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11542 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011543 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011544}
11545
11546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011547RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011548 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011549 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011550
11551 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011552 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11553 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011554 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011555}
11556
11557#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011558
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011559// Finds the script object from the script data. NOTE: This operation uses
11560// heap traversal to find the function generated for the source position
11561// for the requested break point. For lazily compiled functions several heap
11562// traversals might be required rendering this operation as a rather slow
11563// operation. However for setting break points which is normally done through
11564// some kind of user interaction the performance is not crucial.
11565static Handle<Object> Runtime_GetScriptFromScriptName(
11566 Handle<String> script_name) {
11567 // Scan the heap for Script objects to find the script with the requested
11568 // script data.
11569 Handle<Script> script;
11570 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011571 HeapObject* obj = NULL;
11572 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011573 // If a script is found check if it has the script data requested.
11574 if (obj->IsScript()) {
11575 if (Script::cast(obj)->name()->IsString()) {
11576 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11577 script = Handle<Script>(Script::cast(obj));
11578 }
11579 }
11580 }
11581 }
11582
11583 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011584 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011585
11586 // Return the script found.
11587 return GetScriptWrapper(script);
11588}
11589
11590
11591// Get the script object from script data. NOTE: Regarding performance
11592// see the NOTE for GetScriptFromScriptData.
11593// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011594RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011595 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011596
11597 ASSERT(args.length() == 1);
11598
11599 CONVERT_CHECKED(String, script_name, args[0]);
11600
11601 // Find the requested script.
11602 Handle<Object> result =
11603 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11604 return *result;
11605}
11606
11607
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011608// Determines whether the given stack frame should be displayed in
11609// a stack trace. The caller is the error constructor that asked
11610// for the stack trace to be collected. The first time a construct
11611// call to this function is encountered it is skipped. The seen_caller
11612// in/out parameter is used to remember if the caller has been seen
11613// yet.
11614static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11615 bool* seen_caller) {
11616 // Only display JS frames.
11617 if (!raw_frame->is_java_script())
11618 return false;
11619 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11620 Object* raw_fun = frame->function();
11621 // Not sure when this can happen but skip it just in case.
11622 if (!raw_fun->IsJSFunction())
11623 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011624 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011625 *seen_caller = true;
11626 return false;
11627 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011628 // Skip all frames until we've seen the caller. Also, skip the most
11629 // obvious builtin calls. Some builtin calls (such as Number.ADD
11630 // which is invoked using 'call') are very difficult to recognize
11631 // so we're leaving them in for now.
11632 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011633}
11634
11635
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011636// Collect the raw data for a stack trace. Returns an array of 4
11637// element segments each containing a receiver, function, code and
11638// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011639RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011640 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011641 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011642 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11643
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011644 HandleScope scope(isolate);
11645 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011646
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011647 limit = Max(limit, 0); // Ensure that limit is not negative.
11648 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011649 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011650 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011651
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011652 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011653 // If the caller parameter is a function we skip frames until we're
11654 // under it before starting to collect.
11655 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011656 int cursor = 0;
11657 int frames_seen = 0;
11658 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011659 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011660 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011661 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011662 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011663 // Set initial size to the maximum inlining level + 1 for the outermost
11664 // function.
11665 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011666 frame->Summarize(&frames);
11667 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011668 if (cursor + 4 > elements->length()) {
11669 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11670 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011671 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011672 for (int i = 0; i < cursor; i++) {
11673 new_elements->set(i, elements->get(i));
11674 }
11675 elements = new_elements;
11676 }
11677 ASSERT(cursor + 4 <= elements->length());
11678
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011679 Handle<Object> recv = frames[i].receiver();
11680 Handle<JSFunction> fun = frames[i].function();
11681 Handle<Code> code = frames[i].code();
11682 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011683 elements->set(cursor++, *recv);
11684 elements->set(cursor++, *fun);
11685 elements->set(cursor++, *code);
11686 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011687 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011688 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011689 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011690 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011691 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011692 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011693 return *result;
11694}
11695
11696
ager@chromium.org3811b432009-10-28 14:53:37 +000011697// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011698RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011699 ASSERT_EQ(args.length(), 0);
11700
11701 NoHandleAllocation ha;
11702
11703 const char* version_string = v8::V8::GetVersion();
11704
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011705 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11706 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011707}
11708
11709
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011710RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011711 ASSERT(args.length() == 2);
11712 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11713 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011714 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011715 OS::Abort();
11716 UNREACHABLE();
11717 return NULL;
11718}
11719
11720
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011721RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011722 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011723 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011724 Object* key = args[1];
11725
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011726 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011727 Object* o = cache->get(finger_index);
11728 if (o == key) {
11729 // The fastest case: hit the same place again.
11730 return cache->get(finger_index + 1);
11731 }
11732
11733 for (int i = finger_index - 2;
11734 i >= JSFunctionResultCache::kEntriesIndex;
11735 i -= 2) {
11736 o = cache->get(i);
11737 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011738 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011739 return cache->get(i + 1);
11740 }
11741 }
11742
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011743 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011744 ASSERT(size <= cache->length());
11745
11746 for (int i = size - 2; i > finger_index; i -= 2) {
11747 o = cache->get(i);
11748 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011749 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011750 return cache->get(i + 1);
11751 }
11752 }
11753
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011754 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011755 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011756
11757 Handle<JSFunctionResultCache> cache_handle(cache);
11758 Handle<Object> key_handle(key);
11759 Handle<Object> value;
11760 {
11761 Handle<JSFunction> factory(JSFunction::cast(
11762 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11763 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011764 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011765 // This handle is nor shared, nor used later, so it's safe.
11766 Object** argv[] = { key_handle.location() };
11767 bool pending_exception = false;
11768 value = Execution::Call(factory,
11769 receiver,
11770 1,
11771 argv,
11772 &pending_exception);
11773 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011774 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011775
11776#ifdef DEBUG
11777 cache_handle->JSFunctionResultCacheVerify();
11778#endif
11779
11780 // Function invocation may have cleared the cache. Reread all the data.
11781 finger_index = cache_handle->finger_index();
11782 size = cache_handle->size();
11783
11784 // If we have spare room, put new data into it, otherwise evict post finger
11785 // entry which is likely to be the least recently used.
11786 int index = -1;
11787 if (size < cache_handle->length()) {
11788 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11789 index = size;
11790 } else {
11791 index = finger_index + JSFunctionResultCache::kEntrySize;
11792 if (index == cache_handle->length()) {
11793 index = JSFunctionResultCache::kEntriesIndex;
11794 }
11795 }
11796
11797 ASSERT(index % 2 == 0);
11798 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11799 ASSERT(index < cache_handle->length());
11800
11801 cache_handle->set(index, *key_handle);
11802 cache_handle->set(index + 1, *value);
11803 cache_handle->set_finger_index(index);
11804
11805#ifdef DEBUG
11806 cache_handle->JSFunctionResultCacheVerify();
11807#endif
11808
11809 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011810}
11811
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011813RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011814 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011815 CONVERT_ARG_CHECKED(String, type, 0);
11816 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011817 return *isolate->factory()->NewJSMessageObject(
11818 type,
11819 arguments,
11820 0,
11821 0,
11822 isolate->factory()->undefined_value(),
11823 isolate->factory()->undefined_value(),
11824 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011825}
11826
11827
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011828RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011829 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11830 return message->type();
11831}
11832
11833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011834RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011835 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11836 return message->arguments();
11837}
11838
11839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011840RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011841 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11842 return Smi::FromInt(message->start_position());
11843}
11844
11845
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011846RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011847 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11848 return message->script();
11849}
11850
11851
kasper.lund44510672008-07-25 07:37:58 +000011852#ifdef DEBUG
11853// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11854// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011855RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000011856 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011857 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011858#define COUNT_ENTRY(Name, argc, ressize) + 1
11859 int entry_count = 0
11860 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
11861 INLINE_FUNCTION_LIST(COUNT_ENTRY)
11862 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
11863#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011864 Factory* factory = isolate->factory();
11865 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011866 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011867 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011868#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011869 { \
11870 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011871 Handle<String> name; \
11872 /* Inline runtime functions have an underscore in front of the name. */ \
11873 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011874 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011875 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11876 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011877 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011878 Vector<const char>(#Name, StrLength(#Name))); \
11879 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011880 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011881 pair_elements->set(0, *name); \
11882 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011883 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011884 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011885 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011886 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011887 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011888 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011889 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011890 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011891#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011892 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011893 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011894 return *result;
11895}
kasper.lund44510672008-07-25 07:37:58 +000011896#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011897
11898
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011899RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011900 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011901 CONVERT_CHECKED(String, format, args[0]);
11902 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011903 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011904 LOGGER->LogRuntime(chars, elms);
11905 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011906}
11907
11908
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011909RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011910 UNREACHABLE(); // implemented as macro in the parser
11911 return NULL;
11912}
11913
11914
11915// ----------------------------------------------------------------------------
11916// Implementation of Runtime
11917
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011918#define F(name, number_of_args, result_size) \
11919 { Runtime::k##name, Runtime::RUNTIME, #name, \
11920 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011921
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011922
11923#define I(name, number_of_args, result_size) \
11924 { Runtime::kInline##name, Runtime::INLINE, \
11925 "_" #name, NULL, number_of_args, result_size },
11926
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011927static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011928 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011929 INLINE_FUNCTION_LIST(I)
11930 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011931};
11932
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011933
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011934MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
11935 Object* dictionary) {
11936 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011937 ASSERT(dictionary != NULL);
11938 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11939 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011940 Object* name_symbol;
11941 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011942 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011943 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11944 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011945 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011946 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11947 String::cast(name_symbol),
11948 Smi::FromInt(i),
11949 PropertyDetails(NONE, NORMAL));
11950 if (!maybe_dictionary->ToObject(&dictionary)) {
11951 // Non-recoverable failure. Calling code must restart heap
11952 // initialization.
11953 return maybe_dictionary;
11954 }
11955 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011956 }
11957 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011958}
11959
11960
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011961const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11962 Heap* heap = name->GetHeap();
11963 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011964 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011965 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011966 int function_index = Smi::cast(smi_index)->value();
11967 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011968 }
11969 return NULL;
11970}
11971
11972
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011973const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011974 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11975}
11976
11977
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011978void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011979 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011980 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011981 if (failure->IsRetryAfterGC()) {
11982 // Try to do a garbage collection; ignore it if it fails. The C
11983 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011984 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011985 } else {
11986 // Handle last resort GC and make sure to allow future allocations
11987 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011988 isolate->counters()->gc_last_resort_from_js()->Increment();
11989 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011990 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011991}
11992
11993
11994} } // namespace v8::internal