blob: 82733a7c1d35ea4d65646f3e33fc31fca3f5e3bb [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"
danno@chromium.org40cb8782011-05-25 07:58:50 +000045#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000046#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000047#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000048#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000049#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000052#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000054#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000056#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000057#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000058#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
kasperl@chromium.org71affb52009-05-26 05:44:31 +000060namespace v8 {
61namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
63
ager@chromium.org3e875802009-06-29 08:26:34 +000064#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000065 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066
67// Cast the given object to a value of the specified type and store
68// it in a variable with the given name. If the object is not of the
69// expected type call IllegalOperation and return.
70#define CONVERT_CHECKED(Type, name, obj) \
71 RUNTIME_ASSERT(obj->Is##Type()); \
72 Type* name = Type::cast(obj);
73
74#define CONVERT_ARG_CHECKED(Type, name, index) \
75 RUNTIME_ASSERT(args[index]->Is##Type()); \
76 Handle<Type> name = args.at<Type>(index);
77
kasper.lundbd3ec4e2008-07-09 11:06:54 +000078// Cast the given object to a boolean and store it in a variable with
79// the given name. If the object is not a boolean call IllegalOperation
80// and return.
81#define CONVERT_BOOLEAN_CHECKED(name, obj) \
82 RUNTIME_ASSERT(obj->IsBoolean()); \
83 bool name = (obj)->IsTrue();
84
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000085// Cast the given argument to a Smi and store its value in an int variable
86// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000087// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000088#define CONVERT_SMI_ARG_CHECKED(name, index) \
89 RUNTIME_ASSERT(args[index]->IsSmi()); \
90 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000091
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000092// Cast the given argument to a double and store it in a variable with
93// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000094// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000095#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
96 RUNTIME_ASSERT(args[index]->IsNumber()); \
97 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098
99// Call the specified converter on the object *comand store the result in
100// a variable of the specified type with the given name. If the
101// object is not a Number call IllegalOperation and return.
102#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
103 RUNTIME_ASSERT(obj->IsNumber()); \
104 type name = NumberTo##Type(obj);
105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000107MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
108 JSObject* boilerplate) {
109 StackLimitCheck check(isolate);
110 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000113 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000115 if (!maybe_result->ToObject(&result)) return maybe_result;
116 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000117 JSObject* copy = JSObject::cast(result);
118
119 // Deep copy local properties.
120 if (copy->HasFastProperties()) {
121 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000122 for (int i = 0; i < properties->length(); i++) {
123 Object* value = properties->get(i);
124 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000127 if (!maybe_result->ToObject(&result)) return maybe_result;
128 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000129 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 }
131 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000132 int nof = copy->map()->inobject_properties();
133 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 Object* value = copy->InObjectPropertyAt(i);
135 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000140 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000141 }
142 }
143 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 if (!maybe_result->ToObject(&result)) return maybe_result;
147 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 FixedArray* names = FixedArray::cast(result);
149 copy->GetLocalPropertyNames(names, 0);
150 for (int i = 0; i < names->length(); i++) {
151 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000154 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000155 // Only deep copy fields from the object literal expression.
156 // In particular, don't try to copy the length attribute of
157 // an array.
158 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 Object* value =
160 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000161 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000162 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000163 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
166 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000167 // Creating object copy for literals. No strict mode needed.
168 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 }
172 }
173 }
174
175 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000176 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000177 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000178 switch (copy->GetElementsKind()) {
179 case JSObject::FAST_ELEMENTS: {
180 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000181 if (elements->map() == heap->fixed_cow_array_map()) {
182 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000183#ifdef DEBUG
184 for (int i = 0; i < elements->length(); i++) {
185 ASSERT(!elements->get(i)->IsJSObject());
186 }
187#endif
188 } else {
189 for (int i = 0; i < elements->length(); i++) {
190 Object* value = elements->get(i);
191 if (value->IsJSObject()) {
192 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000193 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
194 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000195 if (!maybe_result->ToObject(&result)) return maybe_result;
196 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000197 elements->set(i, result);
198 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
200 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000202 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000203 case JSObject::DICTIONARY_ELEMENTS: {
204 NumberDictionary* element_dictionary = copy->element_dictionary();
205 int capacity = element_dictionary->Capacity();
206 for (int i = 0; i < capacity; i++) {
207 Object* k = element_dictionary->KeyAt(i);
208 if (element_dictionary->IsKey(k)) {
209 Object* value = element_dictionary->ValueAt(i);
210 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000211 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000212 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
213 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000214 if (!maybe_result->ToObject(&result)) return maybe_result;
215 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000216 element_dictionary->ValueAtPut(i, result);
217 }
218 }
219 }
220 break;
221 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000222 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
223 UNIMPLEMENTED();
224 break;
225 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
226 case JSObject::EXTERNAL_BYTE_ELEMENTS:
227 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
228 case JSObject::EXTERNAL_SHORT_ELEMENTS:
229 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
230 case JSObject::EXTERNAL_INT_ELEMENTS:
231 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
232 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
233 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
234 case JSObject::FAST_DOUBLE_ELEMENTS:
235 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000236 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000237 }
238 return copy;
239}
240
241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000242RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000243 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000244 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000245}
246
247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000248RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000249 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000250 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251}
252
253
ager@chromium.org236ad962008-09-25 09:45:57 +0000254static Handle<Map> ComputeObjectLiteralMap(
255 Handle<Context> context,
256 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000257 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000258 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000259 int properties_length = constant_properties->length();
260 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000262 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000263 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000264 for (int p = 0; p != properties_length; p += 2) {
265 Object* key = constant_properties->get(p);
266 uint32_t element_index = 0;
267 if (key->IsSymbol()) {
268 number_of_symbol_keys++;
269 } else if (key->ToArrayIndex(&element_index)) {
270 // An index key does not require space in the property backing store.
271 number_of_properties--;
272 } else {
273 // Bail out as a non-symbol non-index key makes caching impossible.
274 // ASSERT to make sure that the if condition after the loop is false.
275 ASSERT(number_of_symbol_keys != number_of_properties);
276 break;
277 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000279 // If we only have symbols and array indices among keys then we can
280 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000281 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000282 if ((number_of_symbol_keys == number_of_properties) &&
283 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000285 Handle<FixedArray> keys =
286 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000287 if (number_of_symbol_keys > 0) {
288 int index = 0;
289 for (int p = 0; p < properties_length; p += 2) {
290 Object* key = constant_properties->get(p);
291 if (key->IsSymbol()) {
292 keys->set(index++, key);
293 }
294 }
295 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000297 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000298 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 }
300 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000301 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000303 Handle<Map>(context->object_function()->initial_map()),
304 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000305}
306
307
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000308static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000309 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000310 Handle<FixedArray> literals,
311 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000312
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000313
314static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000316 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000317 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 bool should_have_fast_elements,
319 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000320 // Get the global context from the literals array. This is the
321 // context in which the function was created and we use the object
322 // function from this context to create the object literal. We do
323 // not use the object function from the current global context
324 // because this might be the object function from another context
325 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000326 Handle<Context> context =
327 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
328
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000329 // In case we have function literals, we want the object to be in
330 // slow properties mode for now. We don't go in the map cache because
331 // maps with constant functions can't be shared if the functions are
332 // not the same (which is the common case).
333 bool is_result_from_cache = false;
334 Handle<Map> map = has_function_literal
335 ? Handle<Map>(context->object_function()->initial_map())
336 : ComputeObjectLiteralMap(context,
337 constant_properties,
338 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000341
342 // Normalize the elements of the boilerplate to save space if needed.
343 if (!should_have_fast_elements) NormalizeElements(boilerplate);
344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 // Add the constant properties to the boilerplate.
346 int length = constant_properties->length();
347 bool should_transform =
348 !is_result_from_cache && boilerplate->HasFastProperties();
349 if (should_transform || has_function_literal) {
350 // Normalize the properties of object to avoid n^2 behavior
351 // when extending the object multiple properties. Indicate the number of
352 // properties to be added.
353 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
354 }
355
356 for (int index = 0; index < length; index +=2) {
357 Handle<Object> key(constant_properties->get(index+0), isolate);
358 Handle<Object> value(constant_properties->get(index+1), isolate);
359 if (value->IsFixedArray()) {
360 // The value contains the constant_properties of a
361 // simple object or array literal.
362 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
363 value = CreateLiteralBoilerplate(isolate, literals, array);
364 if (value.is_null()) return value;
365 }
366 Handle<Object> result;
367 uint32_t element_index = 0;
368 if (key->IsSymbol()) {
369 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
370 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000371 result = SetOwnElement(boilerplate,
372 element_index,
373 value,
374 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000375 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000376 Handle<String> name(String::cast(*key));
377 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000378 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
379 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000380 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000381 } else if (key->ToArrayIndex(&element_index)) {
382 // Array index (uint32).
383 result = SetOwnElement(boilerplate,
384 element_index,
385 value,
386 kNonStrictMode);
387 } else {
388 // Non-uint32 number.
389 ASSERT(key->IsNumber());
390 double num = key->Number();
391 char arr[100];
392 Vector<char> buffer(arr, ARRAY_SIZE(arr));
393 const char* str = DoubleToCString(num, buffer);
394 Handle<String> name =
395 isolate->factory()->NewStringFromAscii(CStrVector(str));
396 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
397 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000399 // If setting the property on the boilerplate throws an
400 // exception, the exception is converted to an empty handle in
401 // the handle based operations. In that case, we need to
402 // convert back to an exception.
403 if (result.is_null()) return result;
404 }
405
406 // Transform to fast properties if necessary. For object literals with
407 // containing function literals we defer this operation until after all
408 // computed properties have been assigned so that we can generate
409 // constant function properties.
410 if (should_transform && !has_function_literal) {
411 TransformToFastProperties(boilerplate,
412 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 }
414
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000415 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000416}
417
418
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000419static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000420 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000421 Handle<FixedArray> literals,
422 Handle<FixedArray> elements) {
423 // Create the JSArray.
424 Handle<JSFunction> constructor(
425 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000426 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000428 const bool is_cow =
429 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000430 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432
433 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 if (is_cow) {
435#ifdef DEBUG
436 // Copy-on-write arrays must be shallow (and simple).
437 for (int i = 0; i < content->length(); i++) {
438 ASSERT(!content->get(i)->IsFixedArray());
439 }
440#endif
441 } else {
442 for (int i = 0; i < content->length(); i++) {
443 if (content->get(i)->IsFixedArray()) {
444 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000445 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000446 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
447 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000448 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000449 if (result.is_null()) return result;
450 content->set(i, *result);
451 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 }
453 }
454
455 // Set the elements.
456 Handle<JSArray>::cast(object)->SetContent(*content);
457 return object;
458}
459
460
461static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000463 Handle<FixedArray> literals,
464 Handle<FixedArray> array) {
465 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000468 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000469 return CreateObjectLiteralBoilerplate(isolate,
470 literals,
471 elements,
472 true,
473 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000474 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000475 return CreateObjectLiteralBoilerplate(isolate,
476 literals,
477 elements,
478 false,
479 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000480 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000481 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000482 default:
483 UNREACHABLE();
484 return Handle<Object>::null();
485 }
486}
487
488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000489RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000490 // Takes a FixedArray of elements containing the literal elements of
491 // the array literal and produces JSArray with those elements.
492 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000493 // which contains the context from which to get the Array function
494 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000495 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000496 ASSERT(args.length() == 3);
497 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000498 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000499 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000501 Handle<Object> object =
502 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000503 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000505 // Update the functions literal and return the boilerplate.
506 literals->set(literals_index, *object);
507 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508}
509
510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000511RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000513 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000515 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000517 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000518 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
519 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000520
521 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000522 Handle<Object> boilerplate(literals->get(literals_index), isolate);
523 if (*boilerplate == isolate->heap()->undefined_value()) {
524 boilerplate = CreateObjectLiteralBoilerplate(isolate,
525 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000526 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000527 should_have_fast_elements,
528 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000529 if (boilerplate.is_null()) return Failure::Exception();
530 // Update the functions literal and return the boilerplate.
531 literals->set(literals_index, *boilerplate);
532 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000534}
535
536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000537RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000539 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000541 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000542 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000543 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
545 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000546
547 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000548 Handle<Object> boilerplate(literals->get(literals_index), isolate);
549 if (*boilerplate == isolate->heap()->undefined_value()) {
550 boilerplate = CreateObjectLiteralBoilerplate(isolate,
551 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000552 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000553 should_have_fast_elements,
554 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000555 if (boilerplate.is_null()) return Failure::Exception();
556 // Update the functions literal and return the boilerplate.
557 literals->set(literals_index, *boilerplate);
558 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000559 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000560}
561
562
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000563RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565 ASSERT(args.length() == 3);
566 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000567 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000568 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
569
570 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 Handle<Object> boilerplate(literals->get(literals_index), isolate);
572 if (*boilerplate == isolate->heap()->undefined_value()) {
573 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574 if (boilerplate.is_null()) return Failure::Exception();
575 // Update the functions literal and return the boilerplate.
576 literals->set(literals_index, *boilerplate);
577 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579}
580
581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000582RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584 ASSERT(args.length() == 3);
585 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000586 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000587 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
588
589 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000590 Handle<Object> boilerplate(literals->get(literals_index), isolate);
591 if (*boilerplate == isolate->heap()->undefined_value()) {
592 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593 if (boilerplate.is_null()) return Failure::Exception();
594 // Update the functions literal and return the boilerplate.
595 literals->set(literals_index, *boilerplate);
596 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000597 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000599 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000600 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000601 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602}
603
604
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000605RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
606 ASSERT(args.length() == 2);
607 Object* handler = args[0];
608 Object* prototype = args[1];
609 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000610 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000611 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
612}
613
614
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000615RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
616 ASSERT(args.length() == 1);
617 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000618 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000619}
620
621
622RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
623 ASSERT(args.length() == 1);
624 CONVERT_CHECKED(JSProxy, proxy, args[0]);
625 return proxy->handler();
626}
627
628
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000629RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
630 ASSERT(args.length() == 1);
631 CONVERT_CHECKED(JSProxy, proxy, args[0]);
632 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000633 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000634}
635
636
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000637RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
638 HandleScope scope(isolate);
639 ASSERT(args.length() == 1);
640 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
641 ASSERT(weakmap->map()->inobject_properties() == 0);
642 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
643 weakmap->set_table(*table);
644 weakmap->set_next(Smi::FromInt(0));
645 return *weakmap;
646}
647
648
649RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
650 NoHandleAllocation ha;
651 ASSERT(args.length() == 2);
652 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
653 // TODO(mstarzinger): Currently we cannot use JSProxy objects as keys
654 // because they cannot be cast to JSObject to get an identity hash code.
655 CONVERT_ARG_CHECKED(JSObject, key, 1);
656 return weakmap->table()->Lookup(*key);
657}
658
659
660RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
661 HandleScope scope(isolate);
662 ASSERT(args.length() == 3);
663 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
664 // TODO(mstarzinger): See Runtime_WeakMapGet above.
665 CONVERT_ARG_CHECKED(JSObject, key, 1);
666 Handle<Object> value(args[2]);
667 Handle<ObjectHashTable> table(weakmap->table());
668 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
669 weakmap->set_table(*new_table);
670 return *value;
671}
672
673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675 NoHandleAllocation ha;
676 ASSERT(args.length() == 1);
677 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000678 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000679 return JSObject::cast(obj)->class_name();
680}
681
ager@chromium.org7c537e22008-10-16 08:43:32 +0000682
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000683RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
684 NoHandleAllocation ha;
685 ASSERT(args.length() == 1);
686 Object* obj = args[0];
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000687 do {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000688 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000689 } while (obj->IsJSObject() &&
690 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691 return obj;
692}
693
694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000695RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 NoHandleAllocation ha;
697 ASSERT(args.length() == 2);
698 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
699 Object* O = args[0];
700 Object* V = args[1];
701 while (true) {
702 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000703 if (prototype->IsNull()) return isolate->heap()->false_value();
704 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000705 V = prototype;
706 }
707}
708
709
ager@chromium.org9085a012009-05-11 19:22:57 +0000710// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000711RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000712 NoHandleAllocation ha;
713 ASSERT(args.length() == 2);
714 CONVERT_CHECKED(JSObject, jsobject, args[0]);
715 CONVERT_CHECKED(JSObject, proto, args[1]);
716
717 // Sanity checks. The old prototype (that we are replacing) could
718 // theoretically be null, but if it is not null then check that we
719 // didn't already install a hidden prototype here.
720 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
721 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
722 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
723
724 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000725 Object* map_or_failure;
726 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
727 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
728 return maybe_map_or_failure;
729 }
730 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000731 Map* new_proto_map = Map::cast(map_or_failure);
732
lrn@chromium.org303ada72010-10-27 09:33:13 +0000733 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
734 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
735 return maybe_map_or_failure;
736 }
737 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000738 Map* new_map = Map::cast(map_or_failure);
739
740 // Set proto's prototype to be the old prototype of the object.
741 new_proto_map->set_prototype(jsobject->GetPrototype());
742 proto->set_map(new_proto_map);
743 new_proto_map->set_is_hidden_prototype();
744
745 // Set the object's prototype to proto.
746 new_map->set_prototype(proto);
747 jsobject->set_map(new_map);
748
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000749 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000750}
751
752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000753RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000754 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000755 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000756 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000757 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000758}
759
760
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000761// Recursively traverses hidden prototypes if property is not found
762static void GetOwnPropertyImplementation(JSObject* obj,
763 String* name,
764 LookupResult* result) {
765 obj->LocalLookupRealNamedProperty(name, result);
766
767 if (!result->IsProperty()) {
768 Object* proto = obj->GetPrototype();
769 if (proto->IsJSObject() &&
770 JSObject::cast(proto)->map()->is_hidden_prototype())
771 GetOwnPropertyImplementation(JSObject::cast(proto),
772 name, result);
773 }
774}
775
776
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000777static bool CheckAccessException(LookupResult* result,
778 v8::AccessType access_type) {
779 if (result->type() == CALLBACKS) {
780 Object* callback = result->GetCallbackObject();
781 if (callback->IsAccessorInfo()) {
782 AccessorInfo* info = AccessorInfo::cast(callback);
783 bool can_access =
784 (access_type == v8::ACCESS_HAS &&
785 (info->all_can_read() || info->all_can_write())) ||
786 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
787 (access_type == v8::ACCESS_SET && info->all_can_write());
788 return can_access;
789 }
790 }
791
792 return false;
793}
794
795
796static bool CheckAccess(JSObject* obj,
797 String* name,
798 LookupResult* result,
799 v8::AccessType access_type) {
800 ASSERT(result->IsProperty());
801
802 JSObject* holder = result->holder();
803 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000804 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000805 while (true) {
806 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000807 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000808 // Access check callback denied the access, but some properties
809 // can have a special permissions which override callbacks descision
810 // (currently see v8::AccessControl).
811 break;
812 }
813
814 if (current == holder) {
815 return true;
816 }
817
818 current = JSObject::cast(current->GetPrototype());
819 }
820
821 // API callbacks can have per callback access exceptions.
822 switch (result->type()) {
823 case CALLBACKS: {
824 if (CheckAccessException(result, access_type)) {
825 return true;
826 }
827 break;
828 }
829 case INTERCEPTOR: {
830 // If the object has an interceptor, try real named properties.
831 // Overwrite the result to fetch the correct property later.
832 holder->LookupRealNamedProperty(name, result);
833 if (result->IsProperty()) {
834 if (CheckAccessException(result, access_type)) {
835 return true;
836 }
837 }
838 break;
839 }
840 default:
841 break;
842 }
843
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000845 return false;
846}
847
848
849// TODO(1095): we should traverse hidden prototype hierachy as well.
850static bool CheckElementAccess(JSObject* obj,
851 uint32_t index,
852 v8::AccessType access_type) {
853 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000855 return false;
856 }
857
858 return true;
859}
860
861
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000862// Enumerator used as indices into the array returned from GetOwnProperty
863enum PropertyDescriptorIndices {
864 IS_ACCESSOR_INDEX,
865 VALUE_INDEX,
866 GETTER_INDEX,
867 SETTER_INDEX,
868 WRITABLE_INDEX,
869 ENUMERABLE_INDEX,
870 CONFIGURABLE_INDEX,
871 DESCRIPTOR_SIZE
872};
873
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000874// Returns an array with the property description:
875// if args[1] is not a property on args[0]
876// returns undefined
877// if args[1] is a data property on args[0]
878// [false, value, Writeable, Enumerable, Configurable]
879// if args[1] is an accessor on args[0]
880// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000881RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000882 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 Heap* heap = isolate->heap();
884 HandleScope scope(isolate);
885 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
886 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000887 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000888 CONVERT_ARG_CHECKED(JSObject, obj, 0);
889 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000890
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000891 // This could be an element.
892 uint32_t index;
893 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000894 switch (obj->HasLocalElement(index)) {
895 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000896 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000897
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000898 case JSObject::STRING_CHARACTER_ELEMENT: {
899 // Special handling of string objects according to ECMAScript 5
900 // 15.5.5.2. Note that this might be a string object with elements
901 // other than the actual string value. This is covered by the
902 // subsequent cases.
903 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
904 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000905 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000907 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000908 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 elms->set(WRITABLE_INDEX, heap->false_value());
910 elms->set(ENUMERABLE_INDEX, heap->false_value());
911 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000912 return *desc;
913 }
914
915 case JSObject::INTERCEPTED_ELEMENT:
916 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000917 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000918 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000919 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000920 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000921 elms->set(WRITABLE_INDEX, heap->true_value());
922 elms->set(ENUMERABLE_INDEX, heap->true_value());
923 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000924 return *desc;
925 }
926
927 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000928 Handle<JSObject> holder = obj;
929 if (obj->IsJSGlobalProxy()) {
930 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000932 ASSERT(proto->IsJSGlobalObject());
933 holder = Handle<JSObject>(JSObject::cast(proto));
934 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000935 FixedArray* elements = FixedArray::cast(holder->elements());
936 NumberDictionary* dictionary = NULL;
937 if (elements->map() == heap->non_strict_arguments_elements_map()) {
938 dictionary = NumberDictionary::cast(elements->get(1));
939 } else {
940 dictionary = NumberDictionary::cast(elements);
941 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000942 int entry = dictionary->FindEntry(index);
943 ASSERT(entry != NumberDictionary::kNotFound);
944 PropertyDetails details = dictionary->DetailsAt(entry);
945 switch (details.type()) {
946 case CALLBACKS: {
947 // This is an accessor property with getter and/or setter.
948 FixedArray* callbacks =
949 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000950 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000951 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
952 elms->set(GETTER_INDEX, callbacks->get(0));
953 }
954 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
955 elms->set(SETTER_INDEX, callbacks->get(1));
956 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000957 break;
958 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000959 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000960 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000961 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000962 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000963 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000964 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000965 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000966 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000967 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000968 default:
969 UNREACHABLE();
970 break;
971 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
973 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000974 return *desc;
975 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000976 }
977 }
978
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000979 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000980 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000981
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000982 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000984 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000985
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000986 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000987 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000988 }
989
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000990 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
991 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000992
993 bool is_js_accessor = (result.type() == CALLBACKS) &&
994 (result.GetCallbackObject()->IsFixedArray());
995
996 if (is_js_accessor) {
997 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000999
1000 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1001 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1002 elms->set(GETTER_INDEX, structure->get(0));
1003 }
1004 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1005 elms->set(SETTER_INDEX, structure->get(1));
1006 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001007 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001008 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1009 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001010
1011 PropertyAttributes attrs;
1012 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001013 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001014 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1015 if (!maybe_value->ToObject(&value)) return maybe_value;
1016 }
1017 elms->set(VALUE_INDEX, value);
1018 }
1019
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001020 return *desc;
1021}
1022
1023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001024RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001025 ASSERT(args.length() == 1);
1026 CONVERT_CHECKED(JSObject, obj, args[0]);
1027 return obj->PreventExtensions();
1028}
1029
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001031RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001032 ASSERT(args.length() == 1);
1033 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001034 if (obj->IsJSGlobalProxy()) {
1035 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001036 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001037 ASSERT(proto->IsJSGlobalObject());
1038 obj = JSObject::cast(proto);
1039 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001040 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001041}
1042
1043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001044RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001045 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001047 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1048 CONVERT_ARG_CHECKED(String, pattern, 1);
1049 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001050 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1051 if (result.is_null()) return Failure::Exception();
1052 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001053}
1054
1055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001056RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001057 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001059 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001061}
1062
1063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001064RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065 ASSERT(args.length() == 1);
1066 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001067 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001068 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069}
1070
1071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001072RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 ASSERT(args.length() == 2);
1074 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001076 int index = field->value();
1077 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1078 InstanceType type = templ->map()->instance_type();
1079 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1080 type == OBJECT_TEMPLATE_INFO_TYPE);
1081 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001082 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001083 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1084 } else {
1085 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1086 }
1087 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088}
1089
1090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001091RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001092 ASSERT(args.length() == 1);
1093 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001094 Map* old_map = object->map();
1095 bool needs_access_checks = old_map->is_access_check_needed();
1096 if (needs_access_checks) {
1097 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001098 Object* new_map;
1099 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1100 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1101 }
ager@chromium.org32912102009-01-16 10:38:43 +00001102
1103 Map::cast(new_map)->set_is_access_check_needed(false);
1104 object->set_map(Map::cast(new_map));
1105 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001106 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001107}
1108
1109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001110RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001111 ASSERT(args.length() == 1);
1112 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001113 Map* old_map = object->map();
1114 if (!old_map->is_access_check_needed()) {
1115 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001116 Object* new_map;
1117 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1118 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1119 }
ager@chromium.org32912102009-01-16 10:38:43 +00001120
1121 Map::cast(new_map)->set_is_access_check_needed(true);
1122 object->set_map(Map::cast(new_map));
1123 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001124 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001125}
1126
1127
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001128static Failure* ThrowRedeclarationError(Isolate* isolate,
1129 const char* type,
1130 Handle<String> name) {
1131 HandleScope scope(isolate);
1132 Handle<Object> type_handle =
1133 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 Handle<Object> args[2] = { type_handle, name };
1135 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001136 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1137 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138}
1139
1140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001141RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001142 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001143 HandleScope scope(isolate);
1144 Handle<GlobalObject> global = Handle<GlobalObject>(
1145 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146
ager@chromium.org3811b432009-10-28 14:53:37 +00001147 Handle<Context> context = args.at<Context>(0);
1148 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001149 bool is_eval = args.smi_at(2) == 1;
1150 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001151 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001152
1153 // Compute the property attributes. According to ECMA-262, section
1154 // 13, page 71, the property must be read-only and
1155 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1156 // property as read-only, so we don't either.
1157 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1158
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001159 // Traverse the name/value pairs and set the properties.
1160 int length = pairs->length();
1161 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001162 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001164 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165
1166 // We have to declare a global const property. To capture we only
1167 // assign to it when evaluating the assignment for "const x =
1168 // <expr>" the initial value is the hole.
1169 bool is_const_property = value->IsTheHole();
1170
1171 if (value->IsUndefined() || is_const_property) {
1172 // Lookup the property in the global object, and don't set the
1173 // value of the variable if the property is already there.
1174 LookupResult lookup;
1175 global->Lookup(*name, &lookup);
1176 if (lookup.IsProperty()) {
1177 // Determine if the property is local by comparing the holder
1178 // against the global object. The information will be used to
1179 // avoid throwing re-declaration errors when declaring
1180 // variables or constants that exist in the prototype chain.
1181 bool is_local = (*global == lookup.holder());
1182 // Get the property attributes and determine if the property is
1183 // read-only.
1184 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1185 bool is_read_only = (attributes & READ_ONLY) != 0;
1186 if (lookup.type() == INTERCEPTOR) {
1187 // If the interceptor says the property is there, we
1188 // just return undefined without overwriting the property.
1189 // Otherwise, we continue to setting the property.
1190 if (attributes != ABSENT) {
1191 // Check if the existing property conflicts with regards to const.
1192 if (is_local && (is_read_only || is_const_property)) {
1193 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195 };
1196 // The property already exists without conflicting: Go to
1197 // the next declaration.
1198 continue;
1199 }
1200 // Fall-through and introduce the absent property by using
1201 // SetProperty.
1202 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001203 // For const properties, we treat a callback with this name
1204 // even in the prototype as a conflicting declaration.
1205 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001206 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001207 }
1208 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001209 if (is_local && (is_read_only || is_const_property)) {
1210 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001211 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212 }
1213 // The property already exists without conflicting: Go to
1214 // the next declaration.
1215 continue;
1216 }
1217 }
1218 } else {
1219 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001220 Handle<SharedFunctionInfo> shared =
1221 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001223 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1224 context,
1225 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 value = function;
1227 }
1228
1229 LookupResult lookup;
1230 global->LocalLookup(*name, &lookup);
1231
1232 PropertyAttributes attributes = is_const_property
1233 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1234 : base;
1235
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001236 // There's a local property that we need to overwrite because
1237 // we're either declaring a function or there's an interceptor
1238 // that claims the property is absent.
1239 //
1240 // Check for conflicting re-declarations. We cannot have
1241 // conflicting types in case of intercepted properties because
1242 // they are absent.
1243 if (lookup.IsProperty() &&
1244 (lookup.type() != INTERCEPTOR) &&
1245 (lookup.IsReadOnly() || is_const_property)) {
1246 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001248 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001250 // Safari does not allow the invocation of callback setters for
1251 // function declarations. To mimic this behavior, we do not allow
1252 // the invocation of setters for function values. This makes a
1253 // difference for global functions with the same names as event
1254 // handlers such as "function onload() {}". Firefox does call the
1255 // onload setter in those case and Safari does not. We follow
1256 // Safari for compatibility.
1257 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001258 // Do not change DONT_DELETE to false from true.
1259 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1260 attributes = static_cast<PropertyAttributes>(
1261 attributes | (lookup.GetAttributes() & DONT_DELETE));
1262 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001263 RETURN_IF_EMPTY_HANDLE(isolate,
1264 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001265 name,
1266 value,
1267 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001269 RETURN_IF_EMPTY_HANDLE(isolate,
1270 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001271 name,
1272 value,
1273 attributes,
1274 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001275 }
1276 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001277
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001278 ASSERT(!isolate->has_pending_exception());
1279 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280}
1281
1282
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001283RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001284 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001285 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286
ager@chromium.org7c537e22008-10-16 08:43:32 +00001287 CONVERT_ARG_CHECKED(Context, context, 0);
1288 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001289 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001290 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001291 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001293 // Declarations are always done in a function or global context.
1294 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295
1296 int index;
1297 PropertyAttributes attributes;
1298 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001299 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 context->Lookup(name, flags, &index, &attributes);
1301
1302 if (attributes != ABSENT) {
1303 // The name was declared before; check for conflicting
1304 // re-declarations: This is similar to the code in parser.cc in
1305 // the AstBuildingParser::Declare function.
1306 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1307 // Functions are not read-only.
1308 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1309 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 }
1312
1313 // Initialize it if necessary.
1314 if (*initial_value != NULL) {
1315 if (index >= 0) {
1316 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001317 // the function context or the arguments object.
1318 if (holder->IsContext()) {
1319 ASSERT(holder.is_identical_to(context));
1320 if (((attributes & READ_ONLY) == 0) ||
1321 context->get(index)->IsTheHole()) {
1322 context->set(index, *initial_value);
1323 }
1324 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001325 // The holder is an arguments object.
1326 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001327 Handle<Object> result = SetElement(arguments, index, initial_value,
1328 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001329 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330 }
1331 } else {
1332 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001333 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001334 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001335 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001336 SetProperty(context_ext, name, initial_value,
1337 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 }
1339 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001342 // The property is not in the function context. It needs to be
1343 // "declared" in the function context's extension context, or in the
1344 // global context.
1345 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001346 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001347 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001348 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001349 } else {
1350 // The function context's extension context does not exists - allocate
1351 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001352 context_ext = isolate->factory()->NewJSObject(
1353 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001354 // And store it in the extension slot.
1355 context->set_extension(*context_ext);
1356 }
1357 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
ager@chromium.org7c537e22008-10-16 08:43:32 +00001359 // Declare the property by setting it to the initial value if provided,
1360 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1361 // constant declarations).
1362 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001363 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001364 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001365 // Declaring a const context slot is a conflicting declaration if
1366 // there is a callback with that name in a prototype. It is
1367 // allowed to introduce const variables in
1368 // JSContextExtensionObjects. They are treated specially in
1369 // SetProperty and no setters are invoked for those since they are
1370 // not real JSObjects.
1371 if (initial_value->IsTheHole() &&
1372 !context_ext->IsJSContextExtensionObject()) {
1373 LookupResult lookup;
1374 context_ext->Lookup(*name, &lookup);
1375 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001376 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001377 }
1378 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001379 RETURN_IF_EMPTY_HANDLE(isolate,
1380 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001381 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001382 }
1383
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001384 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385}
1386
1387
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001388RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001390 // args[0] == name
1391 // args[1] == strict_mode
1392 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393
1394 // Determine if we need to assign to the variable if it already
1395 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001396 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1397 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398
1399 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001400 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001401 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001402 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001403 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404
1405 // According to ECMA-262, section 12.2, page 62, the property must
1406 // not be deletable.
1407 PropertyAttributes attributes = DONT_DELETE;
1408
1409 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001410 // there, there is a property with this name in the prototype chain.
1411 // We follow Safari and Firefox behavior and only set the property
1412 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001413 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001414 // Note that objects can have hidden prototypes, so we need to traverse
1415 // the whole chain of hidden prototypes to do a 'local' lookup.
1416 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001418 while (true) {
1419 real_holder->LocalLookup(*name, &lookup);
1420 if (lookup.IsProperty()) {
1421 // Determine if this is a redeclaration of something read-only.
1422 if (lookup.IsReadOnly()) {
1423 // If we found readonly property on one of hidden prototypes,
1424 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 if (real_holder != isolate->context()->global()) break;
1426 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001427 }
1428
1429 // Determine if this is a redeclaration of an intercepted read-only
1430 // property and figure out if the property exists at all.
1431 bool found = true;
1432 PropertyType type = lookup.type();
1433 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001434 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001435 Handle<JSObject> holder(real_holder);
1436 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1437 real_holder = *holder;
1438 if (intercepted == ABSENT) {
1439 // The interceptor claims the property isn't there. We need to
1440 // make sure to introduce it.
1441 found = false;
1442 } else if ((intercepted & READ_ONLY) != 0) {
1443 // The property is present, but read-only. Since we're trying to
1444 // overwrite it with a variable declaration we must throw a
1445 // re-declaration error. However if we found readonly property
1446 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001447 if (real_holder != isolate->context()->global()) break;
1448 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001449 }
1450 }
1451
1452 if (found && !assign) {
1453 // The global property is there and we're not assigning any value
1454 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001455 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001456 }
1457
1458 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001459 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001460 return real_holder->SetProperty(
1461 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001462 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001463
1464 Object* proto = real_holder->GetPrototype();
1465 if (!proto->IsJSObject())
1466 break;
1467
1468 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1469 break;
1470
1471 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 }
1473
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001474 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001475 if (assign) {
1476 return global->SetProperty(*name, args[2], attributes, strict_mode);
1477 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001478 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479}
1480
1481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001482RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 // All constants are declared with an initial value. The name
1484 // of the constant is the first argument and the initial value
1485 // is the second.
1486 RUNTIME_ASSERT(args.length() == 2);
1487 CONVERT_ARG_CHECKED(String, name, 0);
1488 Handle<Object> value = args.at<Object>(1);
1489
1490 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001491 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001492
1493 // According to ECMA-262, section 12.2, page 62, the property must
1494 // not be deletable. Since it's a const, it must be READ_ONLY too.
1495 PropertyAttributes attributes =
1496 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1497
1498 // Lookup the property locally in the global object. If it isn't
1499 // there, we add the property and take special precautions to always
1500 // add it as a local property even in case of callbacks in the
1501 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001502 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001503 LookupResult lookup;
1504 global->LocalLookup(*name, &lookup);
1505 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001506 return global->SetLocalPropertyIgnoreAttributes(*name,
1507 *value,
1508 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509 }
1510
1511 // Determine if this is a redeclaration of something not
1512 // read-only. In case the result is hidden behind an interceptor we
1513 // need to ask it for the property attributes.
1514 if (!lookup.IsReadOnly()) {
1515 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001516 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001517 }
1518
1519 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1520
1521 // Throw re-declaration error if the intercepted property is present
1522 // but not read-only.
1523 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001524 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001525 }
1526
1527 // Restore global object from context (in case of GC) and continue
1528 // with setting the value because the property is either absent or
1529 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001530 HandleScope handle_scope(isolate);
1531 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001532
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001533 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 // property through an interceptor and only do it if it's
1535 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001536 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001537 RETURN_IF_EMPTY_HANDLE(isolate,
1538 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001539 name,
1540 value,
1541 attributes,
1542 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 return *value;
1544 }
1545
1546 // Set the value, but only we're assigning the initial value to a
1547 // constant. For now, we determine this by checking if the
1548 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001549 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550 PropertyType type = lookup.type();
1551 if (type == FIELD) {
1552 FixedArray* properties = global->properties();
1553 int index = lookup.GetFieldIndex();
1554 if (properties->get(index)->IsTheHole()) {
1555 properties->set(index, *value);
1556 }
1557 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001558 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1559 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 }
1561 } else {
1562 // Ignore re-initialization of constants that have already been
1563 // assigned a function value.
1564 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1565 }
1566
1567 // Use the set value as the result of the operation.
1568 return *value;
1569}
1570
1571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001572RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001573 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 ASSERT(args.length() == 3);
1575
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001576 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577 ASSERT(!value->IsTheHole());
1578 CONVERT_ARG_CHECKED(Context, context, 1);
1579 Handle<String> name(String::cast(args[2]));
1580
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001581 // Initializations are always done in a function or global context.
1582 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583
1584 int index;
1585 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001586 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001587 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 context->Lookup(name, flags, &index, &attributes);
1589
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001590 // In most situations, the property introduced by the const
1591 // declaration should be present in the context extension object.
1592 // However, because declaration and initialization are separate, the
1593 // property might have been deleted (if it was introduced by eval)
1594 // before we reach the initialization point.
1595 //
1596 // Example:
1597 //
1598 // function f() { eval("delete x; const x;"); }
1599 //
1600 // In that case, the initialization behaves like a normal assignment
1601 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001603 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001604 // Property was found in a context. Perform the assignment if we
1605 // found some non-constant or an uninitialized constant.
1606 Handle<Context> context = Handle<Context>::cast(holder);
1607 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1608 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001609 }
1610 } else {
1611 // The holder is an arguments object.
1612 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001613 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001614 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001615 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001616 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617 }
1618 return *value;
1619 }
1620
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001621 // The property could not be found, we introduce it in the global
1622 // context.
1623 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001624 Handle<JSObject> global = Handle<JSObject>(
1625 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001626 // Strict mode not needed (const disallowed in strict mode).
1627 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001628 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001629 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001630 return *value;
1631 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001633 // The property was present in a context extension object.
1634 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001636 if (*context_ext == context->extension()) {
1637 // This is the property that was introduced by the const
1638 // declaration. Set it if it hasn't been set before. NOTE: We
1639 // cannot use GetProperty() to get the current value as it
1640 // 'unholes' the value.
1641 LookupResult lookup;
1642 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1643 ASSERT(lookup.IsProperty()); // the property was declared
1644 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1645
1646 PropertyType type = lookup.type();
1647 if (type == FIELD) {
1648 FixedArray* properties = context_ext->properties();
1649 int index = lookup.GetFieldIndex();
1650 if (properties->get(index)->IsTheHole()) {
1651 properties->set(index, *value);
1652 }
1653 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001654 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1655 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001656 }
1657 } else {
1658 // We should not reach here. Any real, named property should be
1659 // either a field or a dictionary slot.
1660 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001661 }
1662 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001663 // The property was found in a different context extension object.
1664 // Set it if it is not a read-only property.
1665 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001666 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001667 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001668 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001669 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001670 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001671 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001672
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673 return *value;
1674}
1675
1676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001677RUNTIME_FUNCTION(MaybeObject*,
1678 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001679 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001680 ASSERT(args.length() == 2);
1681 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001682 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001683 if (object->HasFastProperties()) {
1684 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1685 }
1686 return *object;
1687}
1688
1689
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001690RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001691 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001692 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001693 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1694 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001695 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001696 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001697 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001698 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001699 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001700 RUNTIME_ASSERT(index >= 0);
1701 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001702 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001703 Handle<Object> result = RegExpImpl::Exec(regexp,
1704 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001705 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001706 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001707 if (result.is_null()) return Failure::Exception();
1708 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001709}
1710
1711
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001712RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001713 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001714 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001715 if (elements_count < 0 ||
1716 elements_count > FixedArray::kMaxLength ||
1717 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001718 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001719 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001720 Object* new_object;
1721 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001722 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001723 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1724 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001725 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1727 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001728 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1729 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001730 {
1731 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001732 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001733 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001734 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001735 }
1736 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001738 array->set_elements(elements);
1739 array->set_length(Smi::FromInt(elements_count));
1740 // Write in-object properties after the length of the array.
1741 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1742 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1743 return array;
1744}
1745
1746
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001747RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001748 AssertNoAllocation no_alloc;
1749 ASSERT(args.length() == 5);
1750 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1751 CONVERT_CHECKED(String, source, args[1]);
1752
1753 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001754 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001755
1756 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001757 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001758
1759 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001760 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001761
1762 Map* map = regexp->map();
1763 Object* constructor = map->constructor();
1764 if (constructor->IsJSFunction() &&
1765 JSFunction::cast(constructor)->initial_map() == map) {
1766 // If we still have the original map, set in-object properties directly.
1767 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1768 // TODO(lrn): Consider skipping write barrier on booleans as well.
1769 // Both true and false should be in oldspace at all times.
1770 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1771 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1772 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1773 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1774 Smi::FromInt(0),
1775 SKIP_WRITE_BARRIER);
1776 return regexp;
1777 }
1778
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001779 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001780 PropertyAttributes final =
1781 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1782 PropertyAttributes writable =
1783 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001784 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001785 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001786 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001787 source,
1788 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001789 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001790 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001791 global,
1792 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001793 ASSERT(!result->IsFailure());
1794 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001796 ignoreCase,
1797 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001798 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001799 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001800 multiline,
1801 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001802 ASSERT(!result->IsFailure());
1803 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001804 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001805 Smi::FromInt(0),
1806 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001807 ASSERT(!result->IsFailure());
1808 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001809 return regexp;
1810}
1811
1812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001813RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001815 ASSERT(args.length() == 1);
1816 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1817 // This is necessary to enable fast checks for absence of elements
1818 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001819 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001820 return Smi::FromInt(0);
1821}
1822
1823
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001824static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1825 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001826 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001827 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001828 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1829 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1830 Handle<JSFunction> optimized =
1831 isolate->factory()->NewFunction(key,
1832 JS_OBJECT_TYPE,
1833 JSObject::kHeaderSize,
1834 code,
1835 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001836 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001837 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001838 return optimized;
1839}
1840
1841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001842RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001843 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001844 ASSERT(args.length() == 1);
1845 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1846
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001847 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1848 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1849 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1850 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1851 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1852 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1853 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001854
1855 return *holder;
1856}
1857
1858
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001859RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001860 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 Context* global_context =
1862 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001863 return global_context->global()->global_receiver();
1864}
1865
1866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001867RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001868 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 ASSERT(args.length() == 4);
1870 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001871 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872 Handle<String> pattern = args.at<String>(2);
1873 Handle<String> flags = args.at<String>(3);
1874
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001875 // Get the RegExp function from the context in the literals array.
1876 // This is the RegExp function from the context in which the
1877 // function was created. We do not use the RegExp function from the
1878 // current global context because this might be the RegExp function
1879 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001880 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001881 Handle<JSFunction>(
1882 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001883 // Compute the regular expression literal.
1884 bool has_pending_exception;
1885 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001886 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1887 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001888 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 return Failure::Exception();
1891 }
1892 literals->set(index, *regexp);
1893 return *regexp;
1894}
1895
1896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001897RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001898 NoHandleAllocation ha;
1899 ASSERT(args.length() == 1);
1900
1901 CONVERT_CHECKED(JSFunction, f, args[0]);
1902 return f->shared()->name();
1903}
1904
1905
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001906RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001907 NoHandleAllocation ha;
1908 ASSERT(args.length() == 2);
1909
1910 CONVERT_CHECKED(JSFunction, f, args[0]);
1911 CONVERT_CHECKED(String, name, args[1]);
1912 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001913 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001914}
1915
1916
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001917RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1918 NoHandleAllocation ha;
1919 ASSERT(args.length() == 1);
1920 CONVERT_CHECKED(JSFunction, f, args[0]);
1921 return isolate->heap()->ToBoolean(
1922 f->shared()->name_should_print_as_anonymous());
1923}
1924
1925
1926RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1927 NoHandleAllocation ha;
1928 ASSERT(args.length() == 1);
1929 CONVERT_CHECKED(JSFunction, f, args[0]);
1930 f->shared()->set_name_should_print_as_anonymous(true);
1931 return isolate->heap()->undefined_value();
1932}
1933
1934
whesse@chromium.org7b260152011-06-20 15:33:18 +00001935RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1936 HandleScope scope(isolate);
1937 ASSERT(args.length() == 1);
1938
1939 CONVERT_CHECKED(JSFunction, fun, args[0]);
1940 fun->shared()->set_bound(true);
1941 return isolate->heap()->undefined_value();
1942}
1943
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001944RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001945 NoHandleAllocation ha;
1946 ASSERT(args.length() == 1);
1947
1948 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001949 Object* obj = f->RemovePrototype();
1950 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001951
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001952 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001953}
1954
1955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001956RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001957 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958 ASSERT(args.length() == 1);
1959
1960 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001961 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1962 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001963
1964 return *GetScriptWrapper(Handle<Script>::cast(script));
1965}
1966
1967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001968RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001969 NoHandleAllocation ha;
1970 ASSERT(args.length() == 1);
1971
1972 CONVERT_CHECKED(JSFunction, f, args[0]);
1973 return f->shared()->GetSourceCode();
1974}
1975
1976
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001977RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001978 NoHandleAllocation ha;
1979 ASSERT(args.length() == 1);
1980
1981 CONVERT_CHECKED(JSFunction, fun, args[0]);
1982 int pos = fun->shared()->start_position();
1983 return Smi::FromInt(pos);
1984}
1985
1986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001987RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001988 ASSERT(args.length() == 2);
1989
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001990 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001991 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1992
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001993 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1994
1995 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001996 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001997}
1998
1999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002000RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002001 NoHandleAllocation ha;
2002 ASSERT(args.length() == 2);
2003
2004 CONVERT_CHECKED(JSFunction, fun, args[0]);
2005 CONVERT_CHECKED(String, name, args[1]);
2006 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002007 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002008}
2009
2010
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002011RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002012 NoHandleAllocation ha;
2013 ASSERT(args.length() == 2);
2014
2015 CONVERT_CHECKED(JSFunction, fun, args[0]);
2016 CONVERT_CHECKED(Smi, length, args[1]);
2017 fun->shared()->set_length(length->value());
2018 return length;
2019}
2020
2021
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002022// Creates a local, readonly, property called length with the correct
2023// length (when read by the user). This effectively overwrites the
2024// interceptor used to normally provide the length.
2025RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2026 NoHandleAllocation ha;
2027 ASSERT(args.length() == 2);
2028 CONVERT_CHECKED(JSFunction, fun, args[0]);
2029 CONVERT_CHECKED(Smi, length, args[1]);
2030 MaybeObject* maybe_name =
2031 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2032 String* name;
2033 if (!maybe_name->To(&name)) return maybe_name;
2034 PropertyAttributes attr =
2035 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2036 return fun->AddProperty(name, length, attr, kNonStrictMode);
2037}
2038
2039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002040RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002041 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002042 ASSERT(args.length() == 2);
2043
2044 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002045 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002046 Object* obj;
2047 { MaybeObject* maybe_obj =
2048 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2049 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2050 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051 return args[0]; // return TOS
2052}
2053
2054
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002055RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2056 NoHandleAllocation ha;
2057 RUNTIME_ASSERT(args.length() == 1);
2058 CONVERT_CHECKED(JSFunction, function, args[0]);
2059
2060 MaybeObject* maybe_name =
2061 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2062 String* name;
2063 if (!maybe_name->To(&name)) return maybe_name;
2064
2065 if (function->HasFastProperties()) {
2066 // Construct a new field descriptor with updated attributes.
2067 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2068 int index = instance_desc->Search(name);
2069 ASSERT(index != DescriptorArray::kNotFound);
2070 PropertyDetails details(instance_desc->GetDetails(index));
2071 CallbacksDescriptor new_desc(name,
2072 instance_desc->GetValue(index),
2073 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2074 details.index());
2075 // Construct a new field descriptors array containing the new descriptor.
2076 Object* descriptors_unchecked;
2077 { MaybeObject* maybe_descriptors_unchecked =
2078 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2079 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2080 return maybe_descriptors_unchecked;
2081 }
2082 }
2083 DescriptorArray* new_descriptors =
2084 DescriptorArray::cast(descriptors_unchecked);
2085 // Create a new map featuring the new field descriptors array.
2086 Object* map_unchecked;
2087 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2088 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2089 return maybe_map_unchecked;
2090 }
2091 }
2092 Map* new_map = Map::cast(map_unchecked);
2093 new_map->set_instance_descriptors(new_descriptors);
2094 function->set_map(new_map);
2095 } else { // Dictionary properties.
2096 // Directly manipulate the property details.
2097 int entry = function->property_dictionary()->FindEntry(name);
2098 ASSERT(entry != StringDictionary::kNotFound);
2099 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2100 PropertyDetails new_details(
2101 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2102 details.type(),
2103 details.index());
2104 function->property_dictionary()->DetailsAtPut(entry, new_details);
2105 }
2106 return function;
2107}
2108
2109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002110RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002111 NoHandleAllocation ha;
2112 ASSERT(args.length() == 1);
2113
2114 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002115 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002116}
2117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002119RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002120 NoHandleAllocation ha;
2121 ASSERT(args.length() == 1);
2122
2123 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002124 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002125}
2126
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002128RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002129 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002130 ASSERT(args.length() == 2);
2131
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002132 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002133 Handle<Object> code = args.at<Object>(1);
2134
2135 Handle<Context> context(target->context());
2136
2137 if (!code->IsNull()) {
2138 RUNTIME_ASSERT(code->IsJSFunction());
2139 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002140 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002141
2142 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002143 return Failure::Exception();
2144 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002145 // Since we don't store the source for this we should never
2146 // optimize this.
2147 shared->code()->set_optimizable(false);
2148
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002149 // Set the code, scope info, formal parameter count,
2150 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002151 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002152 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002153 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002154 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002155 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002156 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002157 // Set the source code of the target function to undefined.
2158 // SetCode is only used for built-in constructors like String,
2159 // Array, and Object, and some web code
2160 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002161 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002162 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002163 // Clear the optimization hints related to the compiled code as these are no
2164 // longer valid when the code is overwritten.
2165 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002166 context = Handle<Context>(fun->context());
2167
2168 // Make sure we get a fresh copy of the literal vector to avoid
2169 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002170 int number_of_literals = fun->NumberOfLiterals();
2171 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002172 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002174 // Insert the object, regexp and array functions in the literals
2175 // array prefix. These are the functions that will be used when
2176 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002177 literals->set(JSFunction::kLiteralGlobalContextIndex,
2178 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002179 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002180 // It's okay to skip the write barrier here because the literals
2181 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002182 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002183 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 }
2185
2186 target->set_context(*context);
2187 return *target;
2188}
2189
2190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002191RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002192 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002193 ASSERT(args.length() == 2);
2194 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002195 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002196 RUNTIME_ASSERT(num >= 0);
2197 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002198 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002199}
2200
2201
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002202MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2203 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002204 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002205 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002206 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002207 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002208 }
2209 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002210 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002211}
2212
2213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002214RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002215 NoHandleAllocation ha;
2216 ASSERT(args.length() == 2);
2217
2218 CONVERT_CHECKED(String, subject, args[0]);
2219 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002220 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002221
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002222 uint32_t i = 0;
2223 if (index->IsSmi()) {
2224 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002225 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002226 i = value;
2227 } else {
2228 ASSERT(index->IsHeapNumber());
2229 double value = HeapNumber::cast(index)->value();
2230 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002231 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002232
2233 // Flatten the string. If someone wants to get a char at an index
2234 // in a cons string, it is likely that more indices will be
2235 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002236 Object* flat;
2237 { MaybeObject* maybe_flat = subject->TryFlatten();
2238 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2239 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002240 subject = String::cast(flat);
2241
2242 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002244 }
2245
2246 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002247}
2248
2249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002250RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002251 NoHandleAllocation ha;
2252 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002253 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002254}
2255
lrn@chromium.org25156de2010-04-06 13:10:27 +00002256
2257class FixedArrayBuilder {
2258 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002259 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2260 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002261 length_(0) {
2262 // Require a non-zero initial size. Ensures that doubling the size to
2263 // extend the array will work.
2264 ASSERT(initial_capacity > 0);
2265 }
2266
2267 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2268 : array_(backing_store),
2269 length_(0) {
2270 // Require a non-zero initial size. Ensures that doubling the size to
2271 // extend the array will work.
2272 ASSERT(backing_store->length() > 0);
2273 }
2274
2275 bool HasCapacity(int elements) {
2276 int length = array_->length();
2277 int required_length = length_ + elements;
2278 return (length >= required_length);
2279 }
2280
2281 void EnsureCapacity(int elements) {
2282 int length = array_->length();
2283 int required_length = length_ + elements;
2284 if (length < required_length) {
2285 int new_length = length;
2286 do {
2287 new_length *= 2;
2288 } while (new_length < required_length);
2289 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002290 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002291 array_->CopyTo(0, *extended_array, 0, length_);
2292 array_ = extended_array;
2293 }
2294 }
2295
2296 void Add(Object* value) {
2297 ASSERT(length_ < capacity());
2298 array_->set(length_, value);
2299 length_++;
2300 }
2301
2302 void Add(Smi* value) {
2303 ASSERT(length_ < capacity());
2304 array_->set(length_, value);
2305 length_++;
2306 }
2307
2308 Handle<FixedArray> array() {
2309 return array_;
2310 }
2311
2312 int length() {
2313 return length_;
2314 }
2315
2316 int capacity() {
2317 return array_->length();
2318 }
2319
2320 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002321 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002322 result_array->set_length(Smi::FromInt(length_));
2323 return result_array;
2324 }
2325
2326 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2327 target_array->set_elements(*array_);
2328 target_array->set_length(Smi::FromInt(length_));
2329 return target_array;
2330 }
2331
2332 private:
2333 Handle<FixedArray> array_;
2334 int length_;
2335};
2336
2337
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002338// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002339const int kStringBuilderConcatHelperLengthBits = 11;
2340const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002341
2342template <typename schar>
2343static inline void StringBuilderConcatHelper(String*,
2344 schar*,
2345 FixedArray*,
2346 int);
2347
lrn@chromium.org25156de2010-04-06 13:10:27 +00002348typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2349 StringBuilderSubstringLength;
2350typedef BitField<int,
2351 kStringBuilderConcatHelperLengthBits,
2352 kStringBuilderConcatHelperPositionBits>
2353 StringBuilderSubstringPosition;
2354
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002355
2356class ReplacementStringBuilder {
2357 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002358 ReplacementStringBuilder(Heap* heap,
2359 Handle<String> subject,
2360 int estimated_part_count)
2361 : heap_(heap),
2362 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002363 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002364 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002365 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002366 // Require a non-zero initial size. Ensures that doubling the size to
2367 // extend the array will work.
2368 ASSERT(estimated_part_count > 0);
2369 }
2370
lrn@chromium.org25156de2010-04-06 13:10:27 +00002371 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2372 int from,
2373 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002374 ASSERT(from >= 0);
2375 int length = to - from;
2376 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002377 if (StringBuilderSubstringLength::is_valid(length) &&
2378 StringBuilderSubstringPosition::is_valid(from)) {
2379 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2380 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002381 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002382 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002383 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002384 builder->Add(Smi::FromInt(-length));
2385 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002386 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002387 }
2388
2389
2390 void EnsureCapacity(int elements) {
2391 array_builder_.EnsureCapacity(elements);
2392 }
2393
2394
2395 void AddSubjectSlice(int from, int to) {
2396 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002397 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002398 }
2399
2400
2401 void AddString(Handle<String> string) {
2402 int length = string->length();
2403 ASSERT(length > 0);
2404 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002405 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 is_ascii_ = false;
2407 }
2408 IncrementCharacterCount(length);
2409 }
2410
2411
2412 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002413 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002414 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002415 }
2416
2417 Handle<String> joined_string;
2418 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002419 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002420 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002421 char* char_buffer = seq->GetChars();
2422 StringBuilderConcatHelper(*subject_,
2423 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002424 *array_builder_.array(),
2425 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002426 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 } else {
2428 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002429 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002430 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002431 uc16* char_buffer = seq->GetChars();
2432 StringBuilderConcatHelper(*subject_,
2433 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002434 *array_builder_.array(),
2435 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002436 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002437 }
2438 return joined_string;
2439 }
2440
2441
2442 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002443 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 V8::FatalProcessOutOfMemory("String.replace result too large.");
2445 }
2446 character_count_ += by;
2447 }
2448
lrn@chromium.org25156de2010-04-06 13:10:27 +00002449 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002450 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002451 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002452
lrn@chromium.org25156de2010-04-06 13:10:27 +00002453 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002454 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2455 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 }
2457
2458
ager@chromium.org04921a82011-06-27 13:21:41 +00002459 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2460 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002461 }
2462
2463
2464 void AddElement(Object* element) {
2465 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002466 ASSERT(array_builder_.capacity() > array_builder_.length());
2467 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 }
2469
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002470 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002471 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002472 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 int character_count_;
2474 bool is_ascii_;
2475};
2476
2477
2478class CompiledReplacement {
2479 public:
2480 CompiledReplacement()
2481 : parts_(1), replacement_substrings_(0) {}
2482
2483 void Compile(Handle<String> replacement,
2484 int capture_count,
2485 int subject_length);
2486
2487 void Apply(ReplacementStringBuilder* builder,
2488 int match_from,
2489 int match_to,
2490 Handle<JSArray> last_match_info);
2491
2492 // Number of distinct parts of the replacement pattern.
2493 int parts() {
2494 return parts_.length();
2495 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002496
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 private:
2498 enum PartType {
2499 SUBJECT_PREFIX = 1,
2500 SUBJECT_SUFFIX,
2501 SUBJECT_CAPTURE,
2502 REPLACEMENT_SUBSTRING,
2503 REPLACEMENT_STRING,
2504
2505 NUMBER_OF_PART_TYPES
2506 };
2507
2508 struct ReplacementPart {
2509 static inline ReplacementPart SubjectMatch() {
2510 return ReplacementPart(SUBJECT_CAPTURE, 0);
2511 }
2512 static inline ReplacementPart SubjectCapture(int capture_index) {
2513 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2514 }
2515 static inline ReplacementPart SubjectPrefix() {
2516 return ReplacementPart(SUBJECT_PREFIX, 0);
2517 }
2518 static inline ReplacementPart SubjectSuffix(int subject_length) {
2519 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2520 }
2521 static inline ReplacementPart ReplacementString() {
2522 return ReplacementPart(REPLACEMENT_STRING, 0);
2523 }
2524 static inline ReplacementPart ReplacementSubString(int from, int to) {
2525 ASSERT(from >= 0);
2526 ASSERT(to > from);
2527 return ReplacementPart(-from, to);
2528 }
2529
2530 // If tag <= 0 then it is the negation of a start index of a substring of
2531 // the replacement pattern, otherwise it's a value from PartType.
2532 ReplacementPart(int tag, int data)
2533 : tag(tag), data(data) {
2534 // Must be non-positive or a PartType value.
2535 ASSERT(tag < NUMBER_OF_PART_TYPES);
2536 }
2537 // Either a value of PartType or a non-positive number that is
2538 // the negation of an index into the replacement string.
2539 int tag;
2540 // The data value's interpretation depends on the value of tag:
2541 // tag == SUBJECT_PREFIX ||
2542 // tag == SUBJECT_SUFFIX: data is unused.
2543 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2544 // tag == REPLACEMENT_SUBSTRING ||
2545 // tag == REPLACEMENT_STRING: data is index into array of substrings
2546 // of the replacement string.
2547 // tag <= 0: Temporary representation of the substring of the replacement
2548 // string ranging over -tag .. data.
2549 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2550 // substring objects.
2551 int data;
2552 };
2553
2554 template<typename Char>
2555 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2556 Vector<Char> characters,
2557 int capture_count,
2558 int subject_length) {
2559 int length = characters.length();
2560 int last = 0;
2561 for (int i = 0; i < length; i++) {
2562 Char c = characters[i];
2563 if (c == '$') {
2564 int next_index = i + 1;
2565 if (next_index == length) { // No next character!
2566 break;
2567 }
2568 Char c2 = characters[next_index];
2569 switch (c2) {
2570 case '$':
2571 if (i > last) {
2572 // There is a substring before. Include the first "$".
2573 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2574 last = next_index + 1; // Continue after the second "$".
2575 } else {
2576 // Let the next substring start with the second "$".
2577 last = next_index;
2578 }
2579 i = next_index;
2580 break;
2581 case '`':
2582 if (i > last) {
2583 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2584 }
2585 parts->Add(ReplacementPart::SubjectPrefix());
2586 i = next_index;
2587 last = i + 1;
2588 break;
2589 case '\'':
2590 if (i > last) {
2591 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2592 }
2593 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2594 i = next_index;
2595 last = i + 1;
2596 break;
2597 case '&':
2598 if (i > last) {
2599 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2600 }
2601 parts->Add(ReplacementPart::SubjectMatch());
2602 i = next_index;
2603 last = i + 1;
2604 break;
2605 case '0':
2606 case '1':
2607 case '2':
2608 case '3':
2609 case '4':
2610 case '5':
2611 case '6':
2612 case '7':
2613 case '8':
2614 case '9': {
2615 int capture_ref = c2 - '0';
2616 if (capture_ref > capture_count) {
2617 i = next_index;
2618 continue;
2619 }
2620 int second_digit_index = next_index + 1;
2621 if (second_digit_index < length) {
2622 // Peek ahead to see if we have two digits.
2623 Char c3 = characters[second_digit_index];
2624 if ('0' <= c3 && c3 <= '9') { // Double digits.
2625 int double_digit_ref = capture_ref * 10 + c3 - '0';
2626 if (double_digit_ref <= capture_count) {
2627 next_index = second_digit_index;
2628 capture_ref = double_digit_ref;
2629 }
2630 }
2631 }
2632 if (capture_ref > 0) {
2633 if (i > last) {
2634 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2635 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002636 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002637 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2638 last = next_index + 1;
2639 }
2640 i = next_index;
2641 break;
2642 }
2643 default:
2644 i = next_index;
2645 break;
2646 }
2647 }
2648 }
2649 if (length > last) {
2650 if (last == 0) {
2651 parts->Add(ReplacementPart::ReplacementString());
2652 } else {
2653 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2654 }
2655 }
2656 }
2657
2658 ZoneList<ReplacementPart> parts_;
2659 ZoneList<Handle<String> > replacement_substrings_;
2660};
2661
2662
2663void CompiledReplacement::Compile(Handle<String> replacement,
2664 int capture_count,
2665 int subject_length) {
2666 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002667 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002668 AssertNoAllocation no_alloc;
2669 ParseReplacementPattern(&parts_,
2670 replacement->ToAsciiVector(),
2671 capture_count,
2672 subject_length);
2673 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002674 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002675 AssertNoAllocation no_alloc;
2676
2677 ParseReplacementPattern(&parts_,
2678 replacement->ToUC16Vector(),
2679 capture_count,
2680 subject_length);
2681 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002682 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002683 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002684 int substring_index = 0;
2685 for (int i = 0, n = parts_.length(); i < n; i++) {
2686 int tag = parts_[i].tag;
2687 if (tag <= 0) { // A replacement string slice.
2688 int from = -tag;
2689 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002690 replacement_substrings_.Add(
2691 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002692 parts_[i].tag = REPLACEMENT_SUBSTRING;
2693 parts_[i].data = substring_index;
2694 substring_index++;
2695 } else if (tag == REPLACEMENT_STRING) {
2696 replacement_substrings_.Add(replacement);
2697 parts_[i].data = substring_index;
2698 substring_index++;
2699 }
2700 }
2701}
2702
2703
2704void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2705 int match_from,
2706 int match_to,
2707 Handle<JSArray> last_match_info) {
2708 for (int i = 0, n = parts_.length(); i < n; i++) {
2709 ReplacementPart part = parts_[i];
2710 switch (part.tag) {
2711 case SUBJECT_PREFIX:
2712 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2713 break;
2714 case SUBJECT_SUFFIX: {
2715 int subject_length = part.data;
2716 if (match_to < subject_length) {
2717 builder->AddSubjectSlice(match_to, subject_length);
2718 }
2719 break;
2720 }
2721 case SUBJECT_CAPTURE: {
2722 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002723 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002724 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2725 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2726 if (from >= 0 && to > from) {
2727 builder->AddSubjectSlice(from, to);
2728 }
2729 break;
2730 }
2731 case REPLACEMENT_SUBSTRING:
2732 case REPLACEMENT_STRING:
2733 builder->AddString(replacement_substrings_[part.data]);
2734 break;
2735 default:
2736 UNREACHABLE();
2737 }
2738 }
2739}
2740
2741
2742
lrn@chromium.org303ada72010-10-27 09:33:13 +00002743MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002744 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002745 String* subject,
2746 JSRegExp* regexp,
2747 String* replacement,
2748 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002749 ASSERT(subject->IsFlat());
2750 ASSERT(replacement->IsFlat());
2751
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002752 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002753
2754 int length = subject->length();
2755 Handle<String> subject_handle(subject);
2756 Handle<JSRegExp> regexp_handle(regexp);
2757 Handle<String> replacement_handle(replacement);
2758 Handle<JSArray> last_match_info_handle(last_match_info);
2759 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2760 subject_handle,
2761 0,
2762 last_match_info_handle);
2763 if (match.is_null()) {
2764 return Failure::Exception();
2765 }
2766 if (match->IsNull()) {
2767 return *subject_handle;
2768 }
2769
2770 int capture_count = regexp_handle->CaptureCount();
2771
2772 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002773 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002774 CompiledReplacement compiled_replacement;
2775 compiled_replacement.Compile(replacement_handle,
2776 capture_count,
2777 length);
2778
2779 bool is_global = regexp_handle->GetFlags().is_global();
2780
2781 // Guessing the number of parts that the final result string is built
2782 // from. Global regexps can match any number of times, so we guess
2783 // conservatively.
2784 int expected_parts =
2785 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002786 ReplacementStringBuilder builder(isolate->heap(),
2787 subject_handle,
2788 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002789
2790 // Index of end of last match.
2791 int prev = 0;
2792
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002793 // Number of parts added by compiled replacement plus preceeding
2794 // string and possibly suffix after last match. It is possible for
2795 // all components to use two elements when encoded as two smis.
2796 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002797 bool matched = true;
2798 do {
2799 ASSERT(last_match_info_handle->HasFastElements());
2800 // Increase the capacity of the builder before entering local handle-scope,
2801 // so its internal buffer can safely allocate a new handle if it grows.
2802 builder.EnsureCapacity(parts_added_per_loop);
2803
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002804 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002805 int start, end;
2806 {
2807 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002808 FixedArray* match_info_array =
2809 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002810
2811 ASSERT_EQ(capture_count * 2 + 2,
2812 RegExpImpl::GetLastCaptureCount(match_info_array));
2813 start = RegExpImpl::GetCapture(match_info_array, 0);
2814 end = RegExpImpl::GetCapture(match_info_array, 1);
2815 }
2816
2817 if (prev < start) {
2818 builder.AddSubjectSlice(prev, start);
2819 }
2820 compiled_replacement.Apply(&builder,
2821 start,
2822 end,
2823 last_match_info_handle);
2824 prev = end;
2825
2826 // Only continue checking for global regexps.
2827 if (!is_global) break;
2828
2829 // Continue from where the match ended, unless it was an empty match.
2830 int next = end;
2831 if (start == end) {
2832 next = end + 1;
2833 if (next > length) break;
2834 }
2835
2836 match = RegExpImpl::Exec(regexp_handle,
2837 subject_handle,
2838 next,
2839 last_match_info_handle);
2840 if (match.is_null()) {
2841 return Failure::Exception();
2842 }
2843 matched = !match->IsNull();
2844 } while (matched);
2845
2846 if (prev < length) {
2847 builder.AddSubjectSlice(prev, length);
2848 }
2849
2850 return *(builder.ToString());
2851}
2852
2853
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002854template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002855MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002856 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002857 String* subject,
2858 JSRegExp* regexp,
2859 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002860 ASSERT(subject->IsFlat());
2861
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002862 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002863
2864 Handle<String> subject_handle(subject);
2865 Handle<JSRegExp> regexp_handle(regexp);
2866 Handle<JSArray> last_match_info_handle(last_match_info);
2867 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2868 subject_handle,
2869 0,
2870 last_match_info_handle);
2871 if (match.is_null()) return Failure::Exception();
2872 if (match->IsNull()) return *subject_handle;
2873
2874 ASSERT(last_match_info_handle->HasFastElements());
2875
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002876 int start, end;
2877 {
2878 AssertNoAllocation match_info_array_is_not_in_a_handle;
2879 FixedArray* match_info_array =
2880 FixedArray::cast(last_match_info_handle->elements());
2881
2882 start = RegExpImpl::GetCapture(match_info_array, 0);
2883 end = RegExpImpl::GetCapture(match_info_array, 1);
2884 }
2885
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002886 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002887 int new_length = length - (end - start);
2888 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002889 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002890 }
2891 Handle<ResultSeqString> answer;
2892 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002893 answer = Handle<ResultSeqString>::cast(
2894 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002895 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002896 answer = Handle<ResultSeqString>::cast(
2897 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002898 }
2899
2900 // If the regexp isn't global, only match once.
2901 if (!regexp_handle->GetFlags().is_global()) {
2902 if (start > 0) {
2903 String::WriteToFlat(*subject_handle,
2904 answer->GetChars(),
2905 0,
2906 start);
2907 }
2908 if (end < length) {
2909 String::WriteToFlat(*subject_handle,
2910 answer->GetChars() + start,
2911 end,
2912 length);
2913 }
2914 return *answer;
2915 }
2916
2917 int prev = 0; // Index of end of last match.
2918 int next = 0; // Start of next search (prev unless last match was empty).
2919 int position = 0;
2920
2921 do {
2922 if (prev < start) {
2923 // Add substring subject[prev;start] to answer string.
2924 String::WriteToFlat(*subject_handle,
2925 answer->GetChars() + position,
2926 prev,
2927 start);
2928 position += start - prev;
2929 }
2930 prev = end;
2931 next = end;
2932 // Continue from where the match ended, unless it was an empty match.
2933 if (start == end) {
2934 next++;
2935 if (next > length) break;
2936 }
2937 match = RegExpImpl::Exec(regexp_handle,
2938 subject_handle,
2939 next,
2940 last_match_info_handle);
2941 if (match.is_null()) return Failure::Exception();
2942 if (match->IsNull()) break;
2943
2944 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002945 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002946 {
2947 AssertNoAllocation match_info_array_is_not_in_a_handle;
2948 FixedArray* match_info_array =
2949 FixedArray::cast(last_match_info_handle->elements());
2950 start = RegExpImpl::GetCapture(match_info_array, 0);
2951 end = RegExpImpl::GetCapture(match_info_array, 1);
2952 }
2953 } while (true);
2954
2955 if (prev < length) {
2956 // Add substring subject[prev;length] to answer string.
2957 String::WriteToFlat(*subject_handle,
2958 answer->GetChars() + position,
2959 prev,
2960 length);
2961 position += length - prev;
2962 }
2963
2964 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002965 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002966 }
2967
2968 // Shorten string and fill
2969 int string_size = ResultSeqString::SizeFor(position);
2970 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2971 int delta = allocated_string_size - string_size;
2972
2973 answer->set_length(position);
2974 if (delta == 0) return *answer;
2975
2976 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002977 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002978
2979 return *answer;
2980}
2981
2982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002983RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002984 ASSERT(args.length() == 4);
2985
2986 CONVERT_CHECKED(String, subject, args[0]);
2987 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002988 Object* flat_subject;
2989 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2990 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2991 return maybe_flat_subject;
2992 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002993 }
2994 subject = String::cast(flat_subject);
2995 }
2996
2997 CONVERT_CHECKED(String, replacement, args[2]);
2998 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002999 Object* flat_replacement;
3000 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3001 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3002 return maybe_flat_replacement;
3003 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003004 }
3005 replacement = String::cast(flat_replacement);
3006 }
3007
3008 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3009 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3010
3011 ASSERT(last_match_info->HasFastElements());
3012
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003013 if (replacement->length() == 0) {
3014 if (subject->HasOnlyAsciiChars()) {
3015 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003016 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003017 } else {
3018 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003019 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003020 }
3021 }
3022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003023 return StringReplaceRegExpWithString(isolate,
3024 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003025 regexp,
3026 replacement,
3027 last_match_info);
3028}
3029
3030
ager@chromium.org7c537e22008-10-16 08:43:32 +00003031// Perform string match of pattern on subject, starting at start index.
3032// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003033// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003034int Runtime::StringMatch(Isolate* isolate,
3035 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003036 Handle<String> pat,
3037 int start_index) {
3038 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003039 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003040
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003041 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003042 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003043
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003044 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003045 if (start_index + pattern_length > subject_length) return -1;
3046
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003047 if (!sub->IsFlat()) FlattenString(sub);
3048 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003049
ager@chromium.org7c537e22008-10-16 08:43:32 +00003050 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003051 // Extract flattened substrings of cons strings before determining asciiness.
3052 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003053 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003054 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003055 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003056
ager@chromium.org7c537e22008-10-16 08:43:32 +00003057 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003058 if (seq_pat->IsAsciiRepresentation()) {
3059 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
3060 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003061 return SearchString(isolate,
3062 seq_sub->ToAsciiVector(),
3063 pat_vector,
3064 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003065 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003066 return SearchString(isolate,
3067 seq_sub->ToUC16Vector(),
3068 pat_vector,
3069 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003070 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003071 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
3072 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003073 return SearchString(isolate,
3074 seq_sub->ToAsciiVector(),
3075 pat_vector,
3076 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003077 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003078 return SearchString(isolate,
3079 seq_sub->ToUC16Vector(),
3080 pat_vector,
3081 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003082}
3083
3084
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003085RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003086 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003087 ASSERT(args.length() == 3);
3088
ager@chromium.org7c537e22008-10-16 08:43:32 +00003089 CONVERT_ARG_CHECKED(String, sub, 0);
3090 CONVERT_ARG_CHECKED(String, pat, 1);
3091
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003092 Object* index = args[2];
3093 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003094 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003095
ager@chromium.org870a0b62008-11-04 11:43:05 +00003096 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003097 int position =
3098 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003099 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003100}
3101
3102
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003103template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003104static int StringMatchBackwards(Vector<const schar> subject,
3105 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003106 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003107 int pattern_length = pattern.length();
3108 ASSERT(pattern_length >= 1);
3109 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003110
3111 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003112 for (int i = 0; i < pattern_length; i++) {
3113 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003114 if (c > String::kMaxAsciiCharCode) {
3115 return -1;
3116 }
3117 }
3118 }
3119
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003120 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003121 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003122 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003123 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003124 while (j < pattern_length) {
3125 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003126 break;
3127 }
3128 j++;
3129 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003130 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003131 return i;
3132 }
3133 }
3134 return -1;
3135}
3136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003137RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003139 ASSERT(args.length() == 3);
3140
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003141 CONVERT_ARG_CHECKED(String, sub, 0);
3142 CONVERT_ARG_CHECKED(String, pat, 1);
3143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003144 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003145 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003146 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003147
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003148 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003149 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003150
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003151 if (start_index + pat_length > sub_length) {
3152 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003153 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003154
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003155 if (pat_length == 0) {
3156 return Smi::FromInt(start_index);
3157 }
3158
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003159 if (!sub->IsFlat()) FlattenString(sub);
3160 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003161
3162 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3163
3164 int position = -1;
3165
3166 if (pat->IsAsciiRepresentation()) {
3167 Vector<const char> pat_vector = pat->ToAsciiVector();
3168 if (sub->IsAsciiRepresentation()) {
3169 position = StringMatchBackwards(sub->ToAsciiVector(),
3170 pat_vector,
3171 start_index);
3172 } else {
3173 position = StringMatchBackwards(sub->ToUC16Vector(),
3174 pat_vector,
3175 start_index);
3176 }
3177 } else {
3178 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3179 if (sub->IsAsciiRepresentation()) {
3180 position = StringMatchBackwards(sub->ToAsciiVector(),
3181 pat_vector,
3182 start_index);
3183 } else {
3184 position = StringMatchBackwards(sub->ToUC16Vector(),
3185 pat_vector,
3186 start_index);
3187 }
3188 }
3189
3190 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003191}
3192
3193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003194RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003195 NoHandleAllocation ha;
3196 ASSERT(args.length() == 2);
3197
3198 CONVERT_CHECKED(String, str1, args[0]);
3199 CONVERT_CHECKED(String, str2, args[1]);
3200
3201 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003202 int str1_length = str1->length();
3203 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003204
3205 // Decide trivial cases without flattening.
3206 if (str1_length == 0) {
3207 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3208 return Smi::FromInt(-str2_length);
3209 } else {
3210 if (str2_length == 0) return Smi::FromInt(str1_length);
3211 }
3212
3213 int end = str1_length < str2_length ? str1_length : str2_length;
3214
3215 // No need to flatten if we are going to find the answer on the first
3216 // character. At this point we know there is at least one character
3217 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003218 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003219 if (d != 0) return Smi::FromInt(d);
3220
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003221 str1->TryFlatten();
3222 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003223
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003224 StringInputBuffer& buf1 =
3225 *isolate->runtime_state()->string_locale_compare_buf1();
3226 StringInputBuffer& buf2 =
3227 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003228
3229 buf1.Reset(str1);
3230 buf2.Reset(str2);
3231
3232 for (int i = 0; i < end; i++) {
3233 uint16_t char1 = buf1.GetNext();
3234 uint16_t char2 = buf2.GetNext();
3235 if (char1 != char2) return Smi::FromInt(char1 - char2);
3236 }
3237
3238 return Smi::FromInt(str1_length - str2_length);
3239}
3240
3241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003242RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003243 NoHandleAllocation ha;
3244 ASSERT(args.length() == 3);
3245
3246 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003247 int start, end;
3248 // We have a fast integer-only case here to avoid a conversion to double in
3249 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003250 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3251 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3252 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3253 start = from_number;
3254 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003255 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003256 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3257 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003258 start = FastD2I(from_number);
3259 end = FastD2I(to_number);
3260 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003261 RUNTIME_ASSERT(end >= start);
3262 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003263 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003264 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003265 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003266}
3267
3268
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003269RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003270 ASSERT_EQ(3, args.length());
3271
3272 CONVERT_ARG_CHECKED(String, subject, 0);
3273 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3274 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3275 HandleScope handles;
3276
3277 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3278
3279 if (match.is_null()) {
3280 return Failure::Exception();
3281 }
3282 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003283 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003284 }
3285 int length = subject->length();
3286
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003287 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003288 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003289 int start;
3290 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003291 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003292 {
3293 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003294 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003295 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3296 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3297 }
3298 offsets.Add(start);
3299 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003300 if (start == end) if (++end > length) break;
3301 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003302 if (match.is_null()) {
3303 return Failure::Exception();
3304 }
3305 } while (!match->IsNull());
3306 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003307 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003308 Handle<String> substring = isolate->factory()->
3309 NewSubString(subject, offsets.at(0), offsets.at(1));
3310 elements->set(0, *substring);
3311 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003312 int from = offsets.at(i * 2);
3313 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003314 Handle<String> substring = isolate->factory()->
3315 NewProperSubString(subject, from, to);
3316 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003317 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003318 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003319 result->set_length(Smi::FromInt(matches));
3320 return *result;
3321}
3322
3323
lrn@chromium.org25156de2010-04-06 13:10:27 +00003324// Two smis before and after the match, for very long strings.
3325const int kMaxBuilderEntriesPerRegExpMatch = 5;
3326
3327
3328static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3329 Handle<JSArray> last_match_info,
3330 int match_start,
3331 int match_end) {
3332 // Fill last_match_info with a single capture.
3333 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3334 AssertNoAllocation no_gc;
3335 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3336 RegExpImpl::SetLastCaptureCount(elements, 2);
3337 RegExpImpl::SetLastInput(elements, *subject);
3338 RegExpImpl::SetLastSubject(elements, *subject);
3339 RegExpImpl::SetCapture(elements, 0, match_start);
3340 RegExpImpl::SetCapture(elements, 1, match_end);
3341}
3342
3343
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003344template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003345static bool SearchStringMultiple(Isolate* isolate,
3346 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003347 Vector<const PatternChar> pattern,
3348 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003349 FixedArrayBuilder* builder,
3350 int* match_pos) {
3351 int pos = *match_pos;
3352 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003353 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003354 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003355 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003356 while (pos <= max_search_start) {
3357 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3358 *match_pos = pos;
3359 return false;
3360 }
3361 // Position of end of previous match.
3362 int match_end = pos + pattern_length;
3363 int new_pos = search.Search(subject, match_end);
3364 if (new_pos >= 0) {
3365 // A match.
3366 if (new_pos > match_end) {
3367 ReplacementStringBuilder::AddSubjectSlice(builder,
3368 match_end,
3369 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003370 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003371 pos = new_pos;
3372 builder->Add(pattern_string);
3373 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003374 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003375 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003376 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003377
lrn@chromium.org25156de2010-04-06 13:10:27 +00003378 if (pos < max_search_start) {
3379 ReplacementStringBuilder::AddSubjectSlice(builder,
3380 pos + pattern_length,
3381 subject_length);
3382 }
3383 *match_pos = pos;
3384 return true;
3385}
3386
3387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003388static bool SearchStringMultiple(Isolate* isolate,
3389 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003390 Handle<String> pattern,
3391 Handle<JSArray> last_match_info,
3392 FixedArrayBuilder* builder) {
3393 ASSERT(subject->IsFlat());
3394 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003395
3396 // Treating as if a previous match was before first character.
3397 int match_pos = -pattern->length();
3398
3399 for (;;) { // Break when search complete.
3400 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3401 AssertNoAllocation no_gc;
3402 if (subject->IsAsciiRepresentation()) {
3403 Vector<const char> subject_vector = subject->ToAsciiVector();
3404 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003405 if (SearchStringMultiple(isolate,
3406 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003407 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003408 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003409 builder,
3410 &match_pos)) break;
3411 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003412 if (SearchStringMultiple(isolate,
3413 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003414 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003415 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003416 builder,
3417 &match_pos)) break;
3418 }
3419 } else {
3420 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3421 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003422 if (SearchStringMultiple(isolate,
3423 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003424 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003425 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003426 builder,
3427 &match_pos)) break;
3428 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003429 if (SearchStringMultiple(isolate,
3430 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003431 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003432 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003433 builder,
3434 &match_pos)) break;
3435 }
3436 }
3437 }
3438
3439 if (match_pos >= 0) {
3440 SetLastMatchInfoNoCaptures(subject,
3441 last_match_info,
3442 match_pos,
3443 match_pos + pattern->length());
3444 return true;
3445 }
3446 return false; // No matches at all.
3447}
3448
3449
3450static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003451 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003452 Handle<String> subject,
3453 Handle<JSRegExp> regexp,
3454 Handle<JSArray> last_match_array,
3455 FixedArrayBuilder* builder) {
3456 ASSERT(subject->IsFlat());
3457 int match_start = -1;
3458 int match_end = 0;
3459 int pos = 0;
3460 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3461 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3462
3463 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003464 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003465 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003466 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003467
3468 for (;;) { // Break on failure, return on exception.
3469 RegExpImpl::IrregexpResult result =
3470 RegExpImpl::IrregexpExecOnce(regexp,
3471 subject,
3472 pos,
3473 register_vector);
3474 if (result == RegExpImpl::RE_SUCCESS) {
3475 match_start = register_vector[0];
3476 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3477 if (match_end < match_start) {
3478 ReplacementStringBuilder::AddSubjectSlice(builder,
3479 match_end,
3480 match_start);
3481 }
3482 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003483 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003484 if (!first) {
3485 builder->Add(*isolate->factory()->NewProperSubString(subject,
3486 match_start,
3487 match_end));
3488 } else {
3489 builder->Add(*isolate->factory()->NewSubString(subject,
3490 match_start,
3491 match_end));
3492 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003493 if (match_start != match_end) {
3494 pos = match_end;
3495 } else {
3496 pos = match_end + 1;
3497 if (pos > subject_length) break;
3498 }
3499 } else if (result == RegExpImpl::RE_FAILURE) {
3500 break;
3501 } else {
3502 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3503 return result;
3504 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003505 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003506 }
3507
3508 if (match_start >= 0) {
3509 if (match_end < subject_length) {
3510 ReplacementStringBuilder::AddSubjectSlice(builder,
3511 match_end,
3512 subject_length);
3513 }
3514 SetLastMatchInfoNoCaptures(subject,
3515 last_match_array,
3516 match_start,
3517 match_end);
3518 return RegExpImpl::RE_SUCCESS;
3519 } else {
3520 return RegExpImpl::RE_FAILURE; // No matches at all.
3521 }
3522}
3523
3524
3525static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003526 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003527 Handle<String> subject,
3528 Handle<JSRegExp> regexp,
3529 Handle<JSArray> last_match_array,
3530 FixedArrayBuilder* builder) {
3531
3532 ASSERT(subject->IsFlat());
3533 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3534 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3535
3536 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003537 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003538
3539 RegExpImpl::IrregexpResult result =
3540 RegExpImpl::IrregexpExecOnce(regexp,
3541 subject,
3542 0,
3543 register_vector);
3544
3545 int capture_count = regexp->CaptureCount();
3546 int subject_length = subject->length();
3547
3548 // Position to search from.
3549 int pos = 0;
3550 // End of previous match. Differs from pos if match was empty.
3551 int match_end = 0;
3552 if (result == RegExpImpl::RE_SUCCESS) {
3553 // Need to keep a copy of the previous match for creating last_match_info
3554 // at the end, so we have two vectors that we swap between.
3555 OffsetsVector registers2(required_registers);
3556 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003557 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003558 do {
3559 int match_start = register_vector[0];
3560 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3561 if (match_end < match_start) {
3562 ReplacementStringBuilder::AddSubjectSlice(builder,
3563 match_end,
3564 match_start);
3565 }
3566 match_end = register_vector[1];
3567
3568 {
3569 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003570 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003571 // Arguments array to replace function is match, captures, index and
3572 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003573 Handle<FixedArray> elements =
3574 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003575 Handle<String> match;
3576 if (!first) {
3577 match = isolate->factory()->NewProperSubString(subject,
3578 match_start,
3579 match_end);
3580 } else {
3581 match = isolate->factory()->NewSubString(subject,
3582 match_start,
3583 match_end);
3584 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003585 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003586 for (int i = 1; i <= capture_count; i++) {
3587 int start = register_vector[i * 2];
3588 if (start >= 0) {
3589 int end = register_vector[i * 2 + 1];
3590 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003591 Handle<String> substring;
3592 if (!first) {
3593 substring = isolate->factory()->NewProperSubString(subject,
3594 start,
3595 end);
3596 } else {
3597 substring = isolate->factory()->NewSubString(subject, start, end);
3598 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003599 elements->set(i, *substring);
3600 } else {
3601 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003603 }
3604 }
3605 elements->set(capture_count + 1, Smi::FromInt(match_start));
3606 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003607 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003608 }
3609 // Swap register vectors, so the last successful match is in
3610 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003611 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003612 prev_register_vector = register_vector;
3613 register_vector = tmp;
3614
3615 if (match_end > match_start) {
3616 pos = match_end;
3617 } else {
3618 pos = match_end + 1;
3619 if (pos > subject_length) {
3620 break;
3621 }
3622 }
3623
3624 result = RegExpImpl::IrregexpExecOnce(regexp,
3625 subject,
3626 pos,
3627 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003628 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003629 } while (result == RegExpImpl::RE_SUCCESS);
3630
3631 if (result != RegExpImpl::RE_EXCEPTION) {
3632 // Finished matching, with at least one match.
3633 if (match_end < subject_length) {
3634 ReplacementStringBuilder::AddSubjectSlice(builder,
3635 match_end,
3636 subject_length);
3637 }
3638
3639 int last_match_capture_count = (capture_count + 1) * 2;
3640 int last_match_array_size =
3641 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3642 last_match_array->EnsureSize(last_match_array_size);
3643 AssertNoAllocation no_gc;
3644 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3645 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3646 RegExpImpl::SetLastSubject(elements, *subject);
3647 RegExpImpl::SetLastInput(elements, *subject);
3648 for (int i = 0; i < last_match_capture_count; i++) {
3649 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3650 }
3651 return RegExpImpl::RE_SUCCESS;
3652 }
3653 }
3654 // No matches at all, return failure or exception result directly.
3655 return result;
3656}
3657
3658
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003659RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003660 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003661 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003662
3663 CONVERT_ARG_CHECKED(String, subject, 1);
3664 if (!subject->IsFlat()) { FlattenString(subject); }
3665 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3666 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3667 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3668
3669 ASSERT(last_match_info->HasFastElements());
3670 ASSERT(regexp->GetFlags().is_global());
3671 Handle<FixedArray> result_elements;
3672 if (result_array->HasFastElements()) {
3673 result_elements =
3674 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003675 }
3676 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003677 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003678 }
3679 FixedArrayBuilder builder(result_elements);
3680
3681 if (regexp->TypeTag() == JSRegExp::ATOM) {
3682 Handle<String> pattern(
3683 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003684 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685 if (SearchStringMultiple(isolate, subject, pattern,
3686 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003687 return *builder.ToJSArray(result_array);
3688 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003689 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003690 }
3691
3692 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3693
3694 RegExpImpl::IrregexpResult result;
3695 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003696 result = SearchRegExpNoCaptureMultiple(isolate,
3697 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003698 regexp,
3699 last_match_info,
3700 &builder);
3701 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003702 result = SearchRegExpMultiple(isolate,
3703 subject,
3704 regexp,
3705 last_match_info,
3706 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003707 }
3708 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003709 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003710 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3711 return Failure::Exception();
3712}
3713
3714
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003715RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003716 NoHandleAllocation ha;
3717 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003718 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003719 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003721 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003722 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003723 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003724 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003725 // Character array used for conversion.
3726 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003727 return isolate->heap()->
3728 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003729 }
3730 }
3731
3732 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003733 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003734 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003735 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003736 }
3737 if (isinf(value)) {
3738 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003739 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003740 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003741 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003742 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003743 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003744 MaybeObject* result =
3745 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003746 DeleteArray(str);
3747 return result;
3748}
3749
3750
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003751RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003752 NoHandleAllocation ha;
3753 ASSERT(args.length() == 2);
3754
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003755 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003756 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003757 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003758 }
3759 if (isinf(value)) {
3760 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003761 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003762 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003763 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003765 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766 int f = FastD2I(f_number);
3767 RUNTIME_ASSERT(f >= 0);
3768 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003769 MaybeObject* res =
3770 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003771 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003772 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003773}
3774
3775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003776RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777 NoHandleAllocation ha;
3778 ASSERT(args.length() == 2);
3779
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003780 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003781 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003782 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003783 }
3784 if (isinf(value)) {
3785 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003786 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003787 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003788 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003789 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003790 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003791 int f = FastD2I(f_number);
3792 RUNTIME_ASSERT(f >= -1 && f <= 20);
3793 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 MaybeObject* res =
3795 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003796 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003797 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003798}
3799
3800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003801RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003802 NoHandleAllocation ha;
3803 ASSERT(args.length() == 2);
3804
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003805 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003806 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003807 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003808 }
3809 if (isinf(value)) {
3810 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003811 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003812 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003813 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003814 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003815 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003816 int f = FastD2I(f_number);
3817 RUNTIME_ASSERT(f >= 1 && f <= 21);
3818 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003819 MaybeObject* res =
3820 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003821 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003822 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003823}
3824
3825
3826// Returns a single character string where first character equals
3827// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003828static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003829 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003830 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003831 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003832 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003833 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003834 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003835}
3836
3837
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003838MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3839 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003840 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003841 // Handle [] indexing on Strings
3842 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003843 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3844 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003845 }
3846
3847 // Handle [] indexing on String objects
3848 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003849 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3850 Handle<Object> result =
3851 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3852 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003853 }
3854
3855 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003856 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003857 return prototype->GetElement(index);
3858 }
3859
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003860 return GetElement(object, index);
3861}
3862
3863
lrn@chromium.org303ada72010-10-27 09:33:13 +00003864MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003865 return object->GetElement(index);
3866}
3867
3868
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003869MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3870 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003871 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003872 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003873
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003874 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003875 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003876 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003877 isolate->factory()->NewTypeError("non_object_property_load",
3878 HandleVector(args, 2));
3879 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003880 }
3881
3882 // Check if the given key is an array index.
3883 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003884 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003885 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003886 }
3887
3888 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003889 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003890 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003891 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003892 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003893 bool has_pending_exception = false;
3894 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003895 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003896 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003897 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003898 }
3899
ager@chromium.org32912102009-01-16 10:38:43 +00003900 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003901 // the element if so.
3902 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003903 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003904 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003905 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003906 }
3907}
3908
3909
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003910RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003911 NoHandleAllocation ha;
3912 ASSERT(args.length() == 2);
3913
3914 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003915 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003916
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003917 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003918}
3919
3920
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003921// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003922RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003923 NoHandleAllocation ha;
3924 ASSERT(args.length() == 2);
3925
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003926 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003927 // itself.
3928 //
3929 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003930 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003931 // global proxy object never has properties. This is the case
3932 // because the global proxy object forwards everything to its hidden
3933 // prototype including local lookups.
3934 //
3935 // Additionally, we need to make sure that we do not cache results
3936 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003937 if (args[0]->IsJSObject() &&
3938 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003939 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003940 args[1]->IsString()) {
3941 JSObject* receiver = JSObject::cast(args[0]);
3942 String* key = String::cast(args[1]);
3943 if (receiver->HasFastProperties()) {
3944 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003945 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003946 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3947 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003948 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003949 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003950 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003951 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003952 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003953 LookupResult result;
3954 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003955 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003956 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003957 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003958 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003959 }
3960 } else {
3961 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003962 StringDictionary* dictionary = receiver->property_dictionary();
3963 int entry = dictionary->FindEntry(key);
3964 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003965 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003966 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003967 if (!receiver->IsGlobalObject()) return value;
3968 value = JSGlobalPropertyCell::cast(value)->value();
3969 if (!value->IsTheHole()) return value;
3970 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003971 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003972 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003973 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3974 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003975 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003976 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003977 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003978 if (index >= 0 && index < str->length()) {
3979 Handle<Object> result = GetCharAt(str, index);
3980 return *result;
3981 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003982 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003983
3984 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003985 return Runtime::GetObjectProperty(isolate,
3986 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003987 args.at<Object>(1));
3988}
3989
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003990// Implements part of 8.12.9 DefineOwnProperty.
3991// There are 3 cases that lead here:
3992// Step 4b - define a new accessor property.
3993// Steps 9c & 12 - replace an existing data property with an accessor property.
3994// Step 12 - update an existing accessor property with an accessor or generic
3995// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003996RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003997 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003998 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003999 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4000 CONVERT_CHECKED(String, name, args[1]);
4001 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004002 Object* fun = args[3];
4003 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004004 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4005 int unchecked = flag_attr->value();
4006 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4007 RUNTIME_ASSERT(!obj->IsNull());
4008 LookupResult result;
4009 obj->LocalLookupRealNamedProperty(name, &result);
4010
4011 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4012 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4013 // delete it to avoid running into trouble in DefineAccessor, which
4014 // handles this incorrectly if the property is readonly (does nothing)
4015 if (result.IsProperty() &&
4016 (result.type() == FIELD || result.type() == NORMAL
4017 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004018 Object* ok;
4019 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004020 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004021 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4022 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004023 }
4024 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4025}
4026
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004027// Implements part of 8.12.9 DefineOwnProperty.
4028// There are 3 cases that lead here:
4029// Step 4a - define a new data property.
4030// Steps 9b & 12 - replace an existing accessor property with a data property.
4031// Step 12 - update an existing data property with a data or generic
4032// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004033RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004034 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004035 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004036 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4037 CONVERT_ARG_CHECKED(String, name, 1);
4038 Handle<Object> obj_value = args.at<Object>(2);
4039
4040 CONVERT_CHECKED(Smi, flag, args[3]);
4041 int unchecked = flag->value();
4042 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4043
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004044 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4045
4046 // Check if this is an element.
4047 uint32_t index;
4048 bool is_element = name->AsArrayIndex(&index);
4049
4050 // Special case for elements if any of the flags are true.
4051 // If elements are in fast case we always implicitly assume that:
4052 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4053 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
4054 is_element) {
4055 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004056 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004057 // We do not need to do access checks here since these has already
4058 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004059 Handle<Object> proto(js_object->GetPrototype());
4060 // If proxy is detached, ignore the assignment. Alternatively,
4061 // we could throw an exception.
4062 if (proto->IsNull()) return *obj_value;
4063 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004064 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004065 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004066 // Make sure that we never go back to fast case.
4067 dictionary->set_requires_slow_elements();
4068 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004069 Handle<NumberDictionary> extended_dictionary =
4070 NumberDictionarySet(dictionary, index, obj_value, details);
4071 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004072 if (js_object->GetElementsKind() ==
4073 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
4074 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4075 } else {
4076 js_object->set_elements(*extended_dictionary);
4077 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004078 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004079 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004080 }
4081
ager@chromium.org5c838252010-02-19 08:53:10 +00004082 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004083 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004084
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004085 // To be compatible with safari we do not change the value on API objects
4086 // in defineProperty. Firefox disagrees here, and actually changes the value.
4087 if (result.IsProperty() &&
4088 (result.type() == CALLBACKS) &&
4089 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004090 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004091 }
4092
ager@chromium.org5c838252010-02-19 08:53:10 +00004093 // Take special care when attributes are different and there is already
4094 // a property. For simplicity we normalize the property which enables us
4095 // to not worry about changing the instance_descriptor and creating a new
4096 // map. The current version of SetObjectProperty does not handle attributes
4097 // correctly in the case where a property is a field and is reset with
4098 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004099 if (result.IsProperty() &&
4100 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004101 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004102 if (js_object->IsJSGlobalProxy()) {
4103 // Since the result is a property, the prototype will exist so
4104 // we don't have to check for null.
4105 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004106 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004107 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004108 // Use IgnoreAttributes version since a readonly property may be
4109 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004110 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4111 *obj_value,
4112 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004113 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004114
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004115 return Runtime::ForceSetObjectProperty(isolate,
4116 js_object,
4117 name,
4118 obj_value,
4119 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004120}
4121
4122
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004123// Special case for elements if any of the flags are true.
4124// If elements are in fast case we always implicitly assume that:
4125// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4126static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4127 Handle<JSObject> js_object,
4128 uint32_t index,
4129 Handle<Object> value,
4130 PropertyAttributes attr) {
4131 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004132 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004133 // Make sure that we never go back to fast case.
4134 dictionary->set_requires_slow_elements();
4135 PropertyDetails details = PropertyDetails(attr, NORMAL);
4136 Handle<NumberDictionary> extended_dictionary =
4137 NumberDictionarySet(dictionary, index, value, details);
4138 if (*extended_dictionary != *dictionary) {
4139 js_object->set_elements(*extended_dictionary);
4140 }
4141 return *value;
4142}
4143
4144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004145MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4146 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004147 Handle<Object> key,
4148 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004149 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004150 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004151 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004152
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004153 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004154 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004156 isolate->factory()->NewTypeError("non_object_property_store",
4157 HandleVector(args, 2));
4158 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004159 }
4160
4161 // If the object isn't a JavaScript object, we ignore the store.
4162 if (!object->IsJSObject()) return *value;
4163
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004164 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166 // Check if the given key is an array index.
4167 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004168 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4170 // of a string using [] notation. We need to support this too in
4171 // JavaScript.
4172 // In the case of a String object we just need to redirect the assignment to
4173 // the underlying string if the index is in range. Since the underlying
4174 // string does nothing with the assignment then we can ignore such
4175 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004176 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004178 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004179
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004180 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4181 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4182 }
4183
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004184 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004185 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004186 return *value;
4187 }
4188
4189 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004190 Handle<Object> result;
4191 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004192 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4193 return NormalizeObjectSetElement(isolate,
4194 js_object,
4195 index,
4196 value,
4197 attr);
4198 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004199 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004201 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004202 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004203 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004204 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004205 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206 return *value;
4207 }
4208
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004209 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004210 bool has_pending_exception = false;
4211 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4212 if (has_pending_exception) return Failure::Exception();
4213 Handle<String> name = Handle<String>::cast(converted);
4214
4215 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004216 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004217 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004218 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219 }
4220}
4221
4222
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004223MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4224 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004225 Handle<Object> key,
4226 Handle<Object> value,
4227 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004228 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004229
4230 // Check if the given key is an array index.
4231 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004232 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004233 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4234 // of a string using [] notation. We need to support this too in
4235 // JavaScript.
4236 // In the case of a String object we just need to redirect the assignment to
4237 // the underlying string if the index is in range. Since the underlying
4238 // string does nothing with the assignment then we can ignore such
4239 // assignments.
4240 if (js_object->IsStringObjectWithCharacterAt(index)) {
4241 return *value;
4242 }
4243
whesse@chromium.org7b260152011-06-20 15:33:18 +00004244 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004245 }
4246
4247 if (key->IsString()) {
4248 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004249 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004250 } else {
4251 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004252 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004253 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4254 *value,
4255 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004256 }
4257 }
4258
4259 // Call-back into JavaScript to convert the key to a string.
4260 bool has_pending_exception = false;
4261 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4262 if (has_pending_exception) return Failure::Exception();
4263 Handle<String> name = Handle<String>::cast(converted);
4264
4265 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004266 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004267 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004268 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004269 }
4270}
4271
4272
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004273MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004274 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004275 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004276 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004277
4278 // Check if the given key is an array index.
4279 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004280 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004281 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4282 // characters of a string using [] notation. In the case of a
4283 // String object we just need to redirect the deletion to the
4284 // underlying string if the index is in range. Since the
4285 // underlying string does nothing with the deletion, we can ignore
4286 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004287 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004288 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004289 }
4290
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004291 return JSObject::cast(*receiver)->DeleteElement(
4292 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004293 }
4294
4295 Handle<String> key_string;
4296 if (key->IsString()) {
4297 key_string = Handle<String>::cast(key);
4298 } else {
4299 // Call-back into JavaScript to convert the key to a string.
4300 bool has_pending_exception = false;
4301 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4302 if (has_pending_exception) return Failure::Exception();
4303 key_string = Handle<String>::cast(converted);
4304 }
4305
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004306 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004307 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004308}
4309
4310
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004311RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004312 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004313 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004314
4315 Handle<Object> object = args.at<Object>(0);
4316 Handle<Object> key = args.at<Object>(1);
4317 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004318 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004319 RUNTIME_ASSERT(
4320 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004321 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004322 PropertyAttributes attributes =
4323 static_cast<PropertyAttributes>(unchecked_attributes);
4324
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004325 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004326 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004327 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004328 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4329 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004330 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004331 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004332
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004333 return Runtime::SetObjectProperty(isolate,
4334 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004335 key,
4336 value,
4337 attributes,
4338 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004339}
4340
4341
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004342// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004343// This is used to decide if we should transform null and undefined
4344// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004345RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004346 NoHandleAllocation ha;
4347 RUNTIME_ASSERT(args.length() == 1);
4348
4349 Handle<Object> object = args.at<Object>(0);
4350
4351 if (object->IsJSFunction()) {
4352 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004353 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004354 }
4355 return isolate->heap()->undefined_value();
4356}
4357
4358
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004359// Set a local property, even if it is READ_ONLY. If the property does not
4360// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004361RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004362 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004363 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004364 CONVERT_CHECKED(JSObject, object, args[0]);
4365 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004366 // Compute attributes.
4367 PropertyAttributes attributes = NONE;
4368 if (args.length() == 4) {
4369 CONVERT_CHECKED(Smi, value_obj, args[3]);
4370 int unchecked_value = value_obj->value();
4371 // Only attribute bits should be set.
4372 RUNTIME_ASSERT(
4373 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4374 attributes = static_cast<PropertyAttributes>(unchecked_value);
4375 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004376
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004377 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004378 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004379}
4380
4381
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004382RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004383 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004384 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004385
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004386 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004387 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004388 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004389 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004390 ? JSReceiver::STRICT_DELETION
4391 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004392}
4393
4394
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004395static Object* HasLocalPropertyImplementation(Isolate* isolate,
4396 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004397 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004398 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004399 // Handle hidden prototypes. If there's a hidden prototype above this thing
4400 // then we have to check it for properties, because they are supposed to
4401 // look like they are on this object.
4402 Handle<Object> proto(object->GetPrototype());
4403 if (proto->IsJSObject() &&
4404 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004405 return HasLocalPropertyImplementation(isolate,
4406 Handle<JSObject>::cast(proto),
4407 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004408 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004409 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004410}
4411
4412
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004413RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004414 NoHandleAllocation ha;
4415 ASSERT(args.length() == 2);
4416 CONVERT_CHECKED(String, key, args[1]);
4417
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004418 uint32_t index;
4419 const bool key_is_array_index = key->AsArrayIndex(&index);
4420
ager@chromium.org9085a012009-05-11 19:22:57 +00004421 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004423 if (obj->IsJSObject()) {
4424 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004425 // Fast case: either the key is a real named property or it is not
4426 // an array index and there are no interceptors or hidden
4427 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004428 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004429 Map* map = object->map();
4430 if (!key_is_array_index &&
4431 !map->has_named_interceptor() &&
4432 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4433 return isolate->heap()->false_value();
4434 }
4435 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004436 HandleScope scope(isolate);
4437 return HasLocalPropertyImplementation(isolate,
4438 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004439 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004440 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004441 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004442 String* string = String::cast(obj);
4443 if (index < static_cast<uint32_t>(string->length())) {
4444 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004445 }
4446 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004447 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004448}
4449
4450
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004451RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004452 NoHandleAllocation na;
4453 ASSERT(args.length() == 2);
4454
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004455 // Only JS receivers can have properties.
4456 if (args[0]->IsJSReceiver()) {
4457 JSReceiver* receiver = JSReceiver::cast(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004458 CONVERT_CHECKED(String, key, args[1]);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004459 if (receiver->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004460 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004461 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004462}
4463
4464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004465RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004466 NoHandleAllocation na;
4467 ASSERT(args.length() == 2);
4468
4469 // Only JS objects can have elements.
4470 if (args[0]->IsJSObject()) {
4471 JSObject* object = JSObject::cast(args[0]);
4472 CONVERT_CHECKED(Smi, index_obj, args[1]);
4473 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004474 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004475 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004476 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477}
4478
4479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004480RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481 NoHandleAllocation ha;
4482 ASSERT(args.length() == 2);
4483
4484 CONVERT_CHECKED(JSObject, object, args[0]);
4485 CONVERT_CHECKED(String, key, args[1]);
4486
4487 uint32_t index;
4488 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004489 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 }
4491
ager@chromium.org870a0b62008-11-04 11:43:05 +00004492 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004493 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004494}
4495
4496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004497RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004498 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004500 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004501 return *GetKeysFor(object);
4502}
4503
4504
4505// Returns either a FixedArray as Runtime_GetPropertyNames,
4506// or, if the given object has an enum cache that contains
4507// all enumerable properties of the object and its prototypes
4508// have none, the map of the object. This is used to speed up
4509// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004510RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004511 ASSERT(args.length() == 1);
4512
4513 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4514
4515 if (raw_object->IsSimpleEnum()) return raw_object->map();
4516
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004517 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004518 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004519 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4520 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521
4522 // Test again, since cache may have been built by preceding call.
4523 if (object->IsSimpleEnum()) return object->map();
4524
4525 return *content;
4526}
4527
4528
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004529// Find the length of the prototype chain that is to to handled as one. If a
4530// prototype object is hidden it is to be viewed as part of the the object it
4531// is prototype for.
4532static int LocalPrototypeChainLength(JSObject* obj) {
4533 int count = 1;
4534 Object* proto = obj->GetPrototype();
4535 while (proto->IsJSObject() &&
4536 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4537 count++;
4538 proto = JSObject::cast(proto)->GetPrototype();
4539 }
4540 return count;
4541}
4542
4543
4544// Return the names of the local named properties.
4545// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004546RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004547 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004548 ASSERT(args.length() == 1);
4549 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004550 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004551 }
4552 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4553
4554 // Skip the global proxy as it has no properties and always delegates to the
4555 // real global object.
4556 if (obj->IsJSGlobalProxy()) {
4557 // Only collect names if access is permitted.
4558 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004559 !isolate->MayNamedAccess(*obj,
4560 isolate->heap()->undefined_value(),
4561 v8::ACCESS_KEYS)) {
4562 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4563 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004564 }
4565 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4566 }
4567
4568 // Find the number of objects making up this.
4569 int length = LocalPrototypeChainLength(*obj);
4570
4571 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004572 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004573 int total_property_count = 0;
4574 Handle<JSObject> jsproto = obj;
4575 for (int i = 0; i < length; i++) {
4576 // Only collect names if access is permitted.
4577 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 !isolate->MayNamedAccess(*jsproto,
4579 isolate->heap()->undefined_value(),
4580 v8::ACCESS_KEYS)) {
4581 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4582 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004583 }
4584 int n;
4585 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4586 local_property_count[i] = n;
4587 total_property_count += n;
4588 if (i < length - 1) {
4589 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4590 }
4591 }
4592
4593 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004594 Handle<FixedArray> names =
4595 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004596
4597 // Get the property names.
4598 jsproto = obj;
4599 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004600 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004601 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004602 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4603 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004604 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004605 proto_with_hidden_properties++;
4606 }
4607 if (i < length - 1) {
4608 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4609 }
4610 }
4611
4612 // Filter out name of hidden propeties object.
4613 if (proto_with_hidden_properties > 0) {
4614 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004615 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004616 names->length() - proto_with_hidden_properties);
4617 int dest_pos = 0;
4618 for (int i = 0; i < total_property_count; i++) {
4619 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004620 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004621 continue;
4622 }
4623 names->set(dest_pos++, name);
4624 }
4625 }
4626
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004627 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004628}
4629
4630
4631// Return the names of the local indexed properties.
4632// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004633RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004634 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004635 ASSERT(args.length() == 1);
4636 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004637 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004638 }
4639 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4640
4641 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004642 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004643 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004644 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004645}
4646
4647
4648// Return information on whether an object has a named or indexed interceptor.
4649// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004650RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004651 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004652 ASSERT(args.length() == 1);
4653 if (!args[0]->IsJSObject()) {
4654 return Smi::FromInt(0);
4655 }
4656 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4657
4658 int result = 0;
4659 if (obj->HasNamedInterceptor()) result |= 2;
4660 if (obj->HasIndexedInterceptor()) result |= 1;
4661
4662 return Smi::FromInt(result);
4663}
4664
4665
4666// Return property names from named interceptor.
4667// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004668RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004669 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004670 ASSERT(args.length() == 1);
4671 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4672
4673 if (obj->HasNamedInterceptor()) {
4674 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4675 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4676 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004677 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004678}
4679
4680
4681// Return element names from indexed interceptor.
4682// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004683RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004684 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004685 ASSERT(args.length() == 1);
4686 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4687
4688 if (obj->HasIndexedInterceptor()) {
4689 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4690 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4691 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004692 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004693}
4694
4695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004696RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004697 ASSERT_EQ(args.length(), 1);
4698 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004699 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004700 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004701
4702 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004703 // Do access checks before going to the global object.
4704 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004705 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004706 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004707 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4708 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004709 }
4710
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004711 Handle<Object> proto(object->GetPrototype());
4712 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004713 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004714 object = Handle<JSObject>::cast(proto);
4715 }
4716
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004717 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4718 LOCAL_ONLY);
4719 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4720 // property array and since the result is mutable we have to create
4721 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004722 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004723 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004724 for (int i = 0; i < length; i++) {
4725 Object* entry = contents->get(i);
4726 if (entry->IsString()) {
4727 copy->set(i, entry);
4728 } else {
4729 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004730 HandleScope scope(isolate);
4731 Handle<Object> entry_handle(entry, isolate);
4732 Handle<Object> entry_str =
4733 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004734 copy->set(i, *entry_str);
4735 }
4736 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004737 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004738}
4739
4740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004741RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742 NoHandleAllocation ha;
4743 ASSERT(args.length() == 1);
4744
4745 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004746 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747 it.AdvanceToArgumentsFrame();
4748 JavaScriptFrame* frame = it.frame();
4749
4750 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004751 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004752
4753 // Try to convert the key to an index. If successful and within
4754 // index return the the argument from the frame.
4755 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004756 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757 return frame->GetParameter(index);
4758 }
4759
4760 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004761 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762 bool exception = false;
4763 Handle<Object> converted =
4764 Execution::ToString(args.at<Object>(0), &exception);
4765 if (exception) return Failure::Exception();
4766 Handle<String> key = Handle<String>::cast(converted);
4767
4768 // Try to convert the string key into an array index.
4769 if (key->AsArrayIndex(&index)) {
4770 if (index < n) {
4771 return frame->GetParameter(index);
4772 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004773 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774 }
4775 }
4776
4777 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004778 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4779 if (key->Equals(isolate->heap()->callee_symbol())) {
4780 Object* function = frame->function();
4781 if (function->IsJSFunction() &&
4782 JSFunction::cast(function)->shared()->strict_mode()) {
4783 return isolate->Throw(*isolate->factory()->NewTypeError(
4784 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4785 }
4786 return function;
4787 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004788
4789 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004790 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004791}
4792
4793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004794RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004795 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004796
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004797 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004798 Handle<Object> object = args.at<Object>(0);
4799 if (object->IsJSObject()) {
4800 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004801 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004802 MaybeObject* ok = js_object->TransformToFastProperties(0);
4803 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004804 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004805 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004806 return *object;
4807}
4808
4809
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004810RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004811 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004812
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004813 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004814 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004815 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004816 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004817 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004818 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004819 return *object;
4820}
4821
4822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004823RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004824 NoHandleAllocation ha;
4825 ASSERT(args.length() == 1);
4826
4827 return args[0]->ToBoolean();
4828}
4829
4830
4831// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4832// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004833RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004834 NoHandleAllocation ha;
4835
4836 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004837 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004838 HeapObject* heap_obj = HeapObject::cast(obj);
4839
4840 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004841 if (heap_obj->map()->is_undetectable()) {
4842 return isolate->heap()->undefined_symbol();
4843 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004844
4845 InstanceType instance_type = heap_obj->map()->instance_type();
4846 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004847 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848 }
4849
4850 switch (instance_type) {
4851 case ODDBALL_TYPE:
4852 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004853 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004854 }
4855 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004856 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004857 }
4858 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004859 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004860 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004861 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004862 default:
4863 // For any kind of object not handled above, the spec rule for
4864 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004865 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866 }
4867}
4868
4869
lrn@chromium.org25156de2010-04-06 13:10:27 +00004870static bool AreDigits(const char*s, int from, int to) {
4871 for (int i = from; i < to; i++) {
4872 if (s[i] < '0' || s[i] > '9') return false;
4873 }
4874
4875 return true;
4876}
4877
4878
4879static int ParseDecimalInteger(const char*s, int from, int to) {
4880 ASSERT(to - from < 10); // Overflow is not possible.
4881 ASSERT(from < to);
4882 int d = s[from] - '0';
4883
4884 for (int i = from + 1; i < to; i++) {
4885 d = 10 * d + (s[i] - '0');
4886 }
4887
4888 return d;
4889}
4890
4891
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004892RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893 NoHandleAllocation ha;
4894 ASSERT(args.length() == 1);
4895 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004896 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004897
4898 // Fast case: short integer or some sorts of junk values.
4899 int len = subject->length();
4900 if (subject->IsSeqAsciiString()) {
4901 if (len == 0) return Smi::FromInt(0);
4902
4903 char const* data = SeqAsciiString::cast(subject)->GetChars();
4904 bool minus = (data[0] == '-');
4905 int start_pos = (minus ? 1 : 0);
4906
4907 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004908 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004909 } else if (data[start_pos] > '9') {
4910 // Fast check for a junk value. A valid string may start from a
4911 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4912 // the 'I' character ('Infinity'). All of that have codes not greater than
4913 // '9' except 'I'.
4914 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004915 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004916 }
4917 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4918 // The maximal/minimal smi has 10 digits. If the string has less digits we
4919 // know it will fit into the smi-data type.
4920 int d = ParseDecimalInteger(data, start_pos, len);
4921 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004922 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004923 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004924 } else if (!subject->HasHashCode() &&
4925 len <= String::kMaxArrayIndexSize &&
4926 (len == 1 || data[0] != '0')) {
4927 // String hash is not calculated yet but all the data are present.
4928 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004929 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004930#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004931 subject->Hash(); // Force hash calculation.
4932 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4933 static_cast<int>(hash));
4934#endif
4935 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004936 }
4937 return Smi::FromInt(d);
4938 }
4939 }
4940
4941 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004942 return isolate->heap()->NumberFromDouble(
4943 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004944}
4945
4946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004947RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004948 NoHandleAllocation ha;
4949 ASSERT(args.length() == 1);
4950
4951 CONVERT_CHECKED(JSArray, codes, args[0]);
4952 int length = Smi::cast(codes->length())->value();
4953
4954 // Check if the string can be ASCII.
4955 int i;
4956 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004957 Object* element;
4958 { MaybeObject* maybe_element = codes->GetElement(i);
4959 // We probably can't get an exception here, but just in order to enforce
4960 // the checking of inputs in the runtime calls we check here.
4961 if (!maybe_element->ToObject(&element)) return maybe_element;
4962 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004963 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4964 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4965 break;
4966 }
4967
lrn@chromium.org303ada72010-10-27 09:33:13 +00004968 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004969 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004970 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004971 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004972 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004973 }
4974
lrn@chromium.org303ada72010-10-27 09:33:13 +00004975 Object* object = NULL;
4976 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004977 String* result = String::cast(object);
4978 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004979 Object* element;
4980 { MaybeObject* maybe_element = codes->GetElement(i);
4981 if (!maybe_element->ToObject(&element)) return maybe_element;
4982 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004983 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004984 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004985 }
4986 return result;
4987}
4988
4989
4990// kNotEscaped is generated by the following:
4991//
4992// #!/bin/perl
4993// for (my $i = 0; $i < 256; $i++) {
4994// print "\n" if $i % 16 == 0;
4995// my $c = chr($i);
4996// my $escaped = 1;
4997// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4998// print $escaped ? "0, " : "1, ";
4999// }
5000
5001
5002static bool IsNotEscaped(uint16_t character) {
5003 // Only for 8 bit characters, the rest are always escaped (in a different way)
5004 ASSERT(character < 256);
5005 static const char kNotEscaped[256] = {
5006 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5007 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5008 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5009 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5010 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5011 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5012 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5013 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5014 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5015 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5016 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5017 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5018 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5019 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5020 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5021 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5022 };
5023 return kNotEscaped[character] != 0;
5024}
5025
5026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005027RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005028 const char hex_chars[] = "0123456789ABCDEF";
5029 NoHandleAllocation ha;
5030 ASSERT(args.length() == 1);
5031 CONVERT_CHECKED(String, source, args[0]);
5032
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005033 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005034
5035 int escaped_length = 0;
5036 int length = source->length();
5037 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005038 Access<StringInputBuffer> buffer(
5039 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005040 buffer->Reset(source);
5041 while (buffer->has_more()) {
5042 uint16_t character = buffer->GetNext();
5043 if (character >= 256) {
5044 escaped_length += 6;
5045 } else if (IsNotEscaped(character)) {
5046 escaped_length++;
5047 } else {
5048 escaped_length += 3;
5049 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005050 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005051 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005052 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005053 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005054 return Failure::OutOfMemoryException();
5055 }
5056 }
5057 }
5058 // No length change implies no change. Return original string if no change.
5059 if (escaped_length == length) {
5060 return source;
5061 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005062 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005063 { MaybeObject* maybe_o =
5064 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005065 if (!maybe_o->ToObject(&o)) return maybe_o;
5066 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005067 String* destination = String::cast(o);
5068 int dest_position = 0;
5069
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005070 Access<StringInputBuffer> buffer(
5071 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005072 buffer->Rewind();
5073 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005074 uint16_t chr = buffer->GetNext();
5075 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005076 destination->Set(dest_position, '%');
5077 destination->Set(dest_position+1, 'u');
5078 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5079 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5080 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5081 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005082 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005083 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005084 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005085 dest_position++;
5086 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005087 destination->Set(dest_position, '%');
5088 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5089 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005090 dest_position += 3;
5091 }
5092 }
5093 return destination;
5094}
5095
5096
5097static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5098 static const signed char kHexValue['g'] = {
5099 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5100 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5101 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5102 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5103 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5104 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5105 -1, 10, 11, 12, 13, 14, 15 };
5106
5107 if (character1 > 'f') return -1;
5108 int hi = kHexValue[character1];
5109 if (hi == -1) return -1;
5110 if (character2 > 'f') return -1;
5111 int lo = kHexValue[character2];
5112 if (lo == -1) return -1;
5113 return (hi << 4) + lo;
5114}
5115
5116
ager@chromium.org870a0b62008-11-04 11:43:05 +00005117static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005118 int i,
5119 int length,
5120 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005121 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005122 int32_t hi = 0;
5123 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005124 if (character == '%' &&
5125 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005126 source->Get(i + 1) == 'u' &&
5127 (hi = TwoDigitHex(source->Get(i + 2),
5128 source->Get(i + 3))) != -1 &&
5129 (lo = TwoDigitHex(source->Get(i + 4),
5130 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005131 *step = 6;
5132 return (hi << 8) + lo;
5133 } else if (character == '%' &&
5134 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005135 (lo = TwoDigitHex(source->Get(i + 1),
5136 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005137 *step = 3;
5138 return lo;
5139 } else {
5140 *step = 1;
5141 return character;
5142 }
5143}
5144
5145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005146RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005147 NoHandleAllocation ha;
5148 ASSERT(args.length() == 1);
5149 CONVERT_CHECKED(String, source, args[0]);
5150
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005151 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005152
5153 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005154 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005155
5156 int unescaped_length = 0;
5157 for (int i = 0; i < length; unescaped_length++) {
5158 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005159 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005160 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005161 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005162 i += step;
5163 }
5164
5165 // No length change implies no change. Return original string if no change.
5166 if (unescaped_length == length)
5167 return source;
5168
lrn@chromium.org303ada72010-10-27 09:33:13 +00005169 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005170 { MaybeObject* maybe_o =
5171 ascii ?
5172 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5173 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005174 if (!maybe_o->ToObject(&o)) return maybe_o;
5175 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005176 String* destination = String::cast(o);
5177
5178 int dest_position = 0;
5179 for (int i = 0; i < length; dest_position++) {
5180 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005181 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005182 i += step;
5183 }
5184 return destination;
5185}
5186
5187
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005188static const unsigned int kQuoteTableLength = 128u;
5189
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005190static const int kJsonQuotesCharactersPerEntry = 8;
5191static const char* const JsonQuotes =
5192 "\\u0000 \\u0001 \\u0002 \\u0003 "
5193 "\\u0004 \\u0005 \\u0006 \\u0007 "
5194 "\\b \\t \\n \\u000b "
5195 "\\f \\r \\u000e \\u000f "
5196 "\\u0010 \\u0011 \\u0012 \\u0013 "
5197 "\\u0014 \\u0015 \\u0016 \\u0017 "
5198 "\\u0018 \\u0019 \\u001a \\u001b "
5199 "\\u001c \\u001d \\u001e \\u001f "
5200 " ! \\\" # "
5201 "$ % & ' "
5202 "( ) * + "
5203 ", - . / "
5204 "0 1 2 3 "
5205 "4 5 6 7 "
5206 "8 9 : ; "
5207 "< = > ? "
5208 "@ A B C "
5209 "D E F G "
5210 "H I J K "
5211 "L M N O "
5212 "P Q R S "
5213 "T U V W "
5214 "X Y Z [ "
5215 "\\\\ ] ^ _ "
5216 "` a b c "
5217 "d e f g "
5218 "h i j k "
5219 "l m n o "
5220 "p q r s "
5221 "t u v w "
5222 "x y z { "
5223 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005224
5225
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005226// For a string that is less than 32k characters it should always be
5227// possible to allocate it in new space.
5228static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5229
5230
5231// Doing JSON quoting cannot make the string more than this many times larger.
5232static const int kJsonQuoteWorstCaseBlowup = 6;
5233
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005234static const int kSpaceForQuotesAndComma = 3;
5235static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005236
5237// Covers the entire ASCII range (all other characters are unchanged by JSON
5238// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005239static const byte JsonQuoteLengths[kQuoteTableLength] = {
5240 6, 6, 6, 6, 6, 6, 6, 6,
5241 2, 2, 2, 6, 2, 2, 6, 6,
5242 6, 6, 6, 6, 6, 6, 6, 6,
5243 6, 6, 6, 6, 6, 6, 6, 6,
5244 1, 1, 2, 1, 1, 1, 1, 1,
5245 1, 1, 1, 1, 1, 1, 1, 1,
5246 1, 1, 1, 1, 1, 1, 1, 1,
5247 1, 1, 1, 1, 1, 1, 1, 1,
5248 1, 1, 1, 1, 1, 1, 1, 1,
5249 1, 1, 1, 1, 1, 1, 1, 1,
5250 1, 1, 1, 1, 1, 1, 1, 1,
5251 1, 1, 1, 1, 2, 1, 1, 1,
5252 1, 1, 1, 1, 1, 1, 1, 1,
5253 1, 1, 1, 1, 1, 1, 1, 1,
5254 1, 1, 1, 1, 1, 1, 1, 1,
5255 1, 1, 1, 1, 1, 1, 1, 1,
5256};
5257
5258
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005259template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005260MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005261
5262
5263template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005264MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5265 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005266}
5267
5268
5269template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005270MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5271 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005272}
5273
5274
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005275template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005276static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5277 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005278 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005279 const Char* read_cursor = characters.start();
5280 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005281 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005282 int quoted_length = kSpaceForQuotes;
5283 while (read_cursor < end) {
5284 Char c = *(read_cursor++);
5285 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5286 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005287 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005288 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005289 }
5290 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005291 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5292 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005293 Object* new_object;
5294 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005295 return new_alloc;
5296 }
5297 StringType* new_string = StringType::cast(new_object);
5298
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005299 Char* write_cursor = reinterpret_cast<Char*>(
5300 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005301 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005302 *(write_cursor++) = '"';
5303
5304 read_cursor = characters.start();
5305 while (read_cursor < end) {
5306 Char c = *(read_cursor++);
5307 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5308 *(write_cursor++) = c;
5309 } else {
5310 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5311 const char* replacement = JsonQuotes +
5312 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5313 for (int i = 0; i < len; i++) {
5314 *write_cursor++ = *replacement++;
5315 }
5316 }
5317 }
5318 *(write_cursor++) = '"';
5319 return new_string;
5320}
5321
5322
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005323template <typename SinkChar, typename SourceChar>
5324static inline SinkChar* WriteQuoteJsonString(
5325 Isolate* isolate,
5326 SinkChar* write_cursor,
5327 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005328 // SinkChar is only char if SourceChar is guaranteed to be char.
5329 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005330 const SourceChar* read_cursor = characters.start();
5331 const SourceChar* end = read_cursor + characters.length();
5332 *(write_cursor++) = '"';
5333 while (read_cursor < end) {
5334 SourceChar c = *(read_cursor++);
5335 if (sizeof(SourceChar) > 1u &&
5336 static_cast<unsigned>(c) >= kQuoteTableLength) {
5337 *(write_cursor++) = static_cast<SinkChar>(c);
5338 } else {
5339 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5340 const char* replacement = JsonQuotes +
5341 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5342 write_cursor[0] = replacement[0];
5343 if (len > 1) {
5344 write_cursor[1] = replacement[1];
5345 if (len > 2) {
5346 ASSERT(len == 6);
5347 write_cursor[2] = replacement[2];
5348 write_cursor[3] = replacement[3];
5349 write_cursor[4] = replacement[4];
5350 write_cursor[5] = replacement[5];
5351 }
5352 }
5353 write_cursor += len;
5354 }
5355 }
5356 *(write_cursor++) = '"';
5357 return write_cursor;
5358}
5359
5360
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005361template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005362static MaybeObject* QuoteJsonString(Isolate* isolate,
5363 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005364 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005365 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005366 int worst_case_length =
5367 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005368 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005369 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005370 }
5371
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005372 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5373 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005374 Object* new_object;
5375 if (!new_alloc->ToObject(&new_object)) {
5376 return new_alloc;
5377 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005378 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005379 // Even if our string is small enough to fit in new space we still have to
5380 // handle it being allocated in old space as may happen in the third
5381 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5382 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005383 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005384 }
5385 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005386 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005387
5388 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5389 Char* write_cursor = reinterpret_cast<Char*>(
5390 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005391 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005392 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5393 write_cursor,
5394 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005395 int final_length = static_cast<int>(
5396 write_cursor - reinterpret_cast<Char*>(
5397 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005398 isolate->heap()->new_space()->
5399 template ShrinkStringAtAllocationBoundary<StringType>(
5400 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005401 return new_string;
5402}
5403
5404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005405RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005406 NoHandleAllocation ha;
5407 CONVERT_CHECKED(String, str, args[0]);
5408 if (!str->IsFlat()) {
5409 MaybeObject* try_flatten = str->TryFlatten();
5410 Object* flat;
5411 if (!try_flatten->ToObject(&flat)) {
5412 return try_flatten;
5413 }
5414 str = String::cast(flat);
5415 ASSERT(str->IsFlat());
5416 }
5417 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005418 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5419 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005420 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005421 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5422 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005423 }
5424}
5425
5426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005427RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005428 NoHandleAllocation ha;
5429 CONVERT_CHECKED(String, str, args[0]);
5430 if (!str->IsFlat()) {
5431 MaybeObject* try_flatten = str->TryFlatten();
5432 Object* flat;
5433 if (!try_flatten->ToObject(&flat)) {
5434 return try_flatten;
5435 }
5436 str = String::cast(flat);
5437 ASSERT(str->IsFlat());
5438 }
5439 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005440 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5441 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005442 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005443 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5444 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005445 }
5446}
5447
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005448
5449template <typename Char, typename StringType>
5450static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5451 FixedArray* array,
5452 int worst_case_length) {
5453 int length = array->length();
5454
5455 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5456 worst_case_length);
5457 Object* new_object;
5458 if (!new_alloc->ToObject(&new_object)) {
5459 return new_alloc;
5460 }
5461 if (!isolate->heap()->new_space()->Contains(new_object)) {
5462 // Even if our string is small enough to fit in new space we still have to
5463 // handle it being allocated in old space as may happen in the third
5464 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5465 // CEntryStub::GenerateCore.
5466 return isolate->heap()->undefined_value();
5467 }
5468 AssertNoAllocation no_gc;
5469 StringType* new_string = StringType::cast(new_object);
5470 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5471
5472 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5473 Char* write_cursor = reinterpret_cast<Char*>(
5474 new_string->address() + SeqAsciiString::kHeaderSize);
5475 *(write_cursor++) = '[';
5476 for (int i = 0; i < length; i++) {
5477 if (i != 0) *(write_cursor++) = ',';
5478 String* str = String::cast(array->get(i));
5479 if (str->IsTwoByteRepresentation()) {
5480 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5481 write_cursor,
5482 str->ToUC16Vector());
5483 } else {
5484 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5485 write_cursor,
5486 str->ToAsciiVector());
5487 }
5488 }
5489 *(write_cursor++) = ']';
5490
5491 int final_length = static_cast<int>(
5492 write_cursor - reinterpret_cast<Char*>(
5493 new_string->address() + SeqAsciiString::kHeaderSize));
5494 isolate->heap()->new_space()->
5495 template ShrinkStringAtAllocationBoundary<StringType>(
5496 new_string, final_length);
5497 return new_string;
5498}
5499
5500
5501RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5502 NoHandleAllocation ha;
5503 ASSERT(args.length() == 1);
5504 CONVERT_CHECKED(JSArray, array, args[0]);
5505
5506 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5507 FixedArray* elements = FixedArray::cast(array->elements());
5508 int n = elements->length();
5509 bool ascii = true;
5510 int total_length = 0;
5511
5512 for (int i = 0; i < n; i++) {
5513 Object* elt = elements->get(i);
5514 if (!elt->IsString()) return isolate->heap()->undefined_value();
5515 String* element = String::cast(elt);
5516 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5517 total_length += element->length();
5518 if (ascii && element->IsTwoByteRepresentation()) {
5519 ascii = false;
5520 }
5521 }
5522
5523 int worst_case_length =
5524 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5525 + total_length * kJsonQuoteWorstCaseBlowup;
5526
5527 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5528 return isolate->heap()->undefined_value();
5529 }
5530
5531 if (ascii) {
5532 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5533 elements,
5534 worst_case_length);
5535 } else {
5536 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5537 elements,
5538 worst_case_length);
5539 }
5540}
5541
5542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005543RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005544 NoHandleAllocation ha;
5545
5546 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005547 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005548
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005549 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005550
lrn@chromium.org25156de2010-04-06 13:10:27 +00005551 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005552 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005553 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005554}
5555
5556
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005557RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005558 NoHandleAllocation ha;
5559 CONVERT_CHECKED(String, str, args[0]);
5560
5561 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005562 double value = StringToDouble(isolate->unicode_cache(),
5563 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005564
5565 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005566 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005567}
5568
5569
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005570template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005571MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005572 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005573 String* s,
5574 int length,
5575 int input_string_length,
5576 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005577 // We try this twice, once with the assumption that the result is no longer
5578 // than the input and, if that assumption breaks, again with the exact
5579 // length. This may not be pretty, but it is nicer than what was here before
5580 // and I hereby claim my vaffel-is.
5581 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005582 // Allocate the resulting string.
5583 //
5584 // NOTE: This assumes that the upper/lower case of an ascii
5585 // character is also ascii. This is currently the case, but it
5586 // might break in the future if we implement more context and locale
5587 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005588 Object* o;
5589 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005590 ? isolate->heap()->AllocateRawAsciiString(length)
5591 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005592 if (!maybe_o->ToObject(&o)) return maybe_o;
5593 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005594 String* result = String::cast(o);
5595 bool has_changed_character = false;
5596
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005597 // Convert all characters to upper case, assuming that they will fit
5598 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005599 Access<StringInputBuffer> buffer(
5600 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005601 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005602 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005603 // We can assume that the string is not empty
5604 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005605 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005606 bool has_next = buffer->has_more();
5607 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005608 int char_length = mapping->get(current, next, chars);
5609 if (char_length == 0) {
5610 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005611 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005612 i++;
5613 } else if (char_length == 1) {
5614 // Common case: converting the letter resulted in one character.
5615 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005616 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005617 has_changed_character = true;
5618 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005619 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005620 // We've assumed that the result would be as long as the
5621 // input but here is a character that converts to several
5622 // characters. No matter, we calculate the exact length
5623 // of the result and try the whole thing again.
5624 //
5625 // Note that this leaves room for optimization. We could just
5626 // memcpy what we already have to the result string. Also,
5627 // the result string is the last object allocated we could
5628 // "realloc" it and probably, in the vast majority of cases,
5629 // extend the existing string to be able to hold the full
5630 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005631 int next_length = 0;
5632 if (has_next) {
5633 next_length = mapping->get(next, 0, chars);
5634 if (next_length == 0) next_length = 1;
5635 }
5636 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005637 while (buffer->has_more()) {
5638 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005639 // NOTE: we use 0 as the next character here because, while
5640 // the next character may affect what a character converts to,
5641 // it does not in any case affect the length of what it convert
5642 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005643 int char_length = mapping->get(current, 0, chars);
5644 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005645 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005646 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005647 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005648 return Failure::OutOfMemoryException();
5649 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005650 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005651 // Try again with the real length.
5652 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005653 } else {
5654 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005655 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005656 i++;
5657 }
5658 has_changed_character = true;
5659 }
5660 current = next;
5661 }
5662 if (has_changed_character) {
5663 return result;
5664 } else {
5665 // If we didn't actually change anything in doing the conversion
5666 // we simple return the result and let the converted string
5667 // become garbage; there is no reason to keep two identical strings
5668 // alive.
5669 return s;
5670 }
5671}
5672
5673
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005674namespace {
5675
lrn@chromium.org303ada72010-10-27 09:33:13 +00005676static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5677
5678
5679// Given a word and two range boundaries returns a word with high bit
5680// set in every byte iff the corresponding input byte was strictly in
5681// the range (m, n). All the other bits in the result are cleared.
5682// This function is only useful when it can be inlined and the
5683// boundaries are statically known.
5684// Requires: all bytes in the input word and the boundaries must be
5685// ascii (less than 0x7F).
5686static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5687 // Every byte in an ascii string is less than or equal to 0x7F.
5688 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5689 // Use strict inequalities since in edge cases the function could be
5690 // further simplified.
5691 ASSERT(0 < m && m < n && n < 0x7F);
5692 // Has high bit set in every w byte less than n.
5693 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5694 // Has high bit set in every w byte greater than m.
5695 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5696 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5697}
5698
5699
5700enum AsciiCaseConversion {
5701 ASCII_TO_LOWER,
5702 ASCII_TO_UPPER
5703};
5704
5705
5706template <AsciiCaseConversion dir>
5707struct FastAsciiConverter {
5708 static bool Convert(char* dst, char* src, int length) {
5709#ifdef DEBUG
5710 char* saved_dst = dst;
5711 char* saved_src = src;
5712#endif
5713 // We rely on the distance between upper and lower case letters
5714 // being a known power of 2.
5715 ASSERT('a' - 'A' == (1 << 5));
5716 // Boundaries for the range of input characters than require conversion.
5717 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5718 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5719 bool changed = false;
5720 char* const limit = src + length;
5721#ifdef V8_HOST_CAN_READ_UNALIGNED
5722 // Process the prefix of the input that requires no conversion one
5723 // (machine) word at a time.
5724 while (src <= limit - sizeof(uintptr_t)) {
5725 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5726 if (AsciiRangeMask(w, lo, hi) != 0) {
5727 changed = true;
5728 break;
5729 }
5730 *reinterpret_cast<uintptr_t*>(dst) = w;
5731 src += sizeof(uintptr_t);
5732 dst += sizeof(uintptr_t);
5733 }
5734 // Process the remainder of the input performing conversion when
5735 // required one word at a time.
5736 while (src <= limit - sizeof(uintptr_t)) {
5737 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5738 uintptr_t m = AsciiRangeMask(w, lo, hi);
5739 // The mask has high (7th) bit set in every byte that needs
5740 // conversion and we know that the distance between cases is
5741 // 1 << 5.
5742 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5743 src += sizeof(uintptr_t);
5744 dst += sizeof(uintptr_t);
5745 }
5746#endif
5747 // Process the last few bytes of the input (or the whole input if
5748 // unaligned access is not supported).
5749 while (src < limit) {
5750 char c = *src;
5751 if (lo < c && c < hi) {
5752 c ^= (1 << 5);
5753 changed = true;
5754 }
5755 *dst = c;
5756 ++src;
5757 ++dst;
5758 }
5759#ifdef DEBUG
5760 CheckConvert(saved_dst, saved_src, length, changed);
5761#endif
5762 return changed;
5763 }
5764
5765#ifdef DEBUG
5766 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5767 bool expected_changed = false;
5768 for (int i = 0; i < length; i++) {
5769 if (dst[i] == src[i]) continue;
5770 expected_changed = true;
5771 if (dir == ASCII_TO_LOWER) {
5772 ASSERT('A' <= src[i] && src[i] <= 'Z');
5773 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5774 } else {
5775 ASSERT(dir == ASCII_TO_UPPER);
5776 ASSERT('a' <= src[i] && src[i] <= 'z');
5777 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5778 }
5779 }
5780 ASSERT(expected_changed == changed);
5781 }
5782#endif
5783};
5784
5785
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005786struct ToLowerTraits {
5787 typedef unibrow::ToLowercase UnibrowConverter;
5788
lrn@chromium.org303ada72010-10-27 09:33:13 +00005789 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005790};
5791
5792
5793struct ToUpperTraits {
5794 typedef unibrow::ToUppercase UnibrowConverter;
5795
lrn@chromium.org303ada72010-10-27 09:33:13 +00005796 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005797};
5798
5799} // namespace
5800
5801
5802template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005803MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005804 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005805 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005806 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005807 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005808 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005809 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005810
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005811 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005812 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005813 if (length == 0) return s;
5814
5815 // Simpler handling of ascii strings.
5816 //
5817 // NOTE: This assumes that the upper/lower case of an ascii
5818 // character is also ascii. This is currently the case, but it
5819 // might break in the future if we implement more context and locale
5820 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005821 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005822 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005823 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005824 if (!maybe_o->ToObject(&o)) return maybe_o;
5825 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005826 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005827 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005828 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005829 return has_changed_character ? result : s;
5830 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005831
lrn@chromium.org303ada72010-10-27 09:33:13 +00005832 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005833 { MaybeObject* maybe_answer =
5834 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005835 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5836 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005837 if (answer->IsSmi()) {
5838 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005839 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005840 ConvertCaseHelper(isolate,
5841 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005842 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5843 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005844 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005845 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005846}
5847
5848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005849RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005850 return ConvertCase<ToLowerTraits>(
5851 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005852}
5853
5854
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005855RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005856 return ConvertCase<ToUpperTraits>(
5857 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005858}
5859
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005860
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005861static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5862 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5863}
5864
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005866RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005867 NoHandleAllocation ha;
5868 ASSERT(args.length() == 3);
5869
5870 CONVERT_CHECKED(String, s, args[0]);
5871 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5872 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5873
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005874 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005875 int length = s->length();
5876
5877 int left = 0;
5878 if (trimLeft) {
5879 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5880 left++;
5881 }
5882 }
5883
5884 int right = length;
5885 if (trimRight) {
5886 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5887 right--;
5888 }
5889 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005890 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005891}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005892
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005893
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005894void FindAsciiStringIndices(Vector<const char> subject,
5895 char pattern,
5896 ZoneList<int>* indices,
5897 unsigned int limit) {
5898 ASSERT(limit > 0);
5899 // Collect indices of pattern in subject using memchr.
5900 // Stop after finding at most limit values.
5901 const char* subject_start = reinterpret_cast<const char*>(subject.start());
5902 const char* subject_end = subject_start + subject.length();
5903 const char* pos = subject_start;
5904 while (limit > 0) {
5905 pos = reinterpret_cast<const char*>(
5906 memchr(pos, pattern, subject_end - pos));
5907 if (pos == NULL) return;
5908 indices->Add(static_cast<int>(pos - subject_start));
5909 pos++;
5910 limit--;
5911 }
5912}
5913
5914
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005915template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005916void FindStringIndices(Isolate* isolate,
5917 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005918 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005919 ZoneList<int>* indices,
5920 unsigned int limit) {
5921 ASSERT(limit > 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005922 // Collect indices of pattern in subject.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005923 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005924 int pattern_length = pattern.length();
5925 int index = 0;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005926 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005927 while (limit > 0) {
5928 index = search.Search(subject, index);
5929 if (index < 0) return;
5930 indices->Add(index);
5931 index += pattern_length;
5932 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005933 }
5934}
5935
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005937RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005938 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005939 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005940 CONVERT_ARG_CHECKED(String, subject, 0);
5941 CONVERT_ARG_CHECKED(String, pattern, 1);
5942 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5943
5944 int subject_length = subject->length();
5945 int pattern_length = pattern->length();
5946 RUNTIME_ASSERT(pattern_length > 0);
5947
5948 // The limit can be very large (0xffffffffu), but since the pattern
5949 // isn't empty, we can never create more parts than ~half the length
5950 // of the subject.
5951
5952 if (!subject->IsFlat()) FlattenString(subject);
5953
5954 static const int kMaxInitialListCapacity = 16;
5955
danno@chromium.org40cb8782011-05-25 07:58:50 +00005956 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005957
5958 // Find (up to limit) indices of separator and end-of-string in subject
5959 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5960 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005961 if (!pattern->IsFlat()) FlattenString(pattern);
5962
5963 // No allocation block.
5964 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005965 AssertNoAllocation nogc;
5966 if (subject->IsAsciiRepresentation()) {
5967 Vector<const char> subject_vector = subject->ToAsciiVector();
5968 if (pattern->IsAsciiRepresentation()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005969 Vector<const char> pattern_vector = pattern->ToAsciiVector();
5970 if (pattern_vector.length() == 1) {
5971 FindAsciiStringIndices(subject_vector,
5972 pattern_vector[0],
5973 &indices,
5974 limit);
5975 } else {
5976 FindStringIndices(isolate,
5977 subject_vector,
5978 pattern_vector,
5979 &indices,
5980 limit);
5981 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005982 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005983 FindStringIndices(isolate,
5984 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005985 pattern->ToUC16Vector(),
5986 &indices,
5987 limit);
5988 }
5989 } else {
5990 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5991 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005992 FindStringIndices(isolate,
5993 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005994 pattern->ToAsciiVector(),
5995 &indices,
5996 limit);
5997 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005998 FindStringIndices(isolate,
5999 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006000 pattern->ToUC16Vector(),
6001 &indices,
6002 limit);
6003 }
6004 }
6005 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006006
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006007 if (static_cast<uint32_t>(indices.length()) < limit) {
6008 indices.Add(subject_length);
6009 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006010
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006011 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006012
6013 // Create JSArray of substrings separated by separator.
6014 int part_count = indices.length();
6015
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006016 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006017 result->set_length(Smi::FromInt(part_count));
6018
6019 ASSERT(result->HasFastElements());
6020
6021 if (part_count == 1 && indices.at(0) == subject_length) {
6022 FixedArray::cast(result->elements())->set(0, *subject);
6023 return *result;
6024 }
6025
6026 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6027 int part_start = 0;
6028 for (int i = 0; i < part_count; i++) {
6029 HandleScope local_loop_handle;
6030 int part_end = indices.at(i);
6031 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006032 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006033 elements->set(i, *substring);
6034 part_start = part_end + pattern_length;
6035 }
6036
6037 return *result;
6038}
6039
6040
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006041// Copies ascii characters to the given fixed array looking up
6042// one-char strings in the cache. Gives up on the first char that is
6043// not in the cache and fills the remainder with smi zeros. Returns
6044// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006045static int CopyCachedAsciiCharsToArray(Heap* heap,
6046 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006047 FixedArray* elements,
6048 int length) {
6049 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006050 FixedArray* ascii_cache = heap->single_character_string_cache();
6051 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006052 int i;
6053 for (i = 0; i < length; ++i) {
6054 Object* value = ascii_cache->get(chars[i]);
6055 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006056 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006057 elements->set(i, value, SKIP_WRITE_BARRIER);
6058 }
6059 if (i < length) {
6060 ASSERT(Smi::FromInt(0) == 0);
6061 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6062 }
6063#ifdef DEBUG
6064 for (int j = 0; j < length; ++j) {
6065 Object* element = elements->get(j);
6066 ASSERT(element == Smi::FromInt(0) ||
6067 (element->IsString() && String::cast(element)->LooksValid()));
6068 }
6069#endif
6070 return i;
6071}
6072
6073
6074// Converts a String to JSArray.
6075// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006076RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006077 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006078 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006079 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006080 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006081
6082 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006083 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006084
6085 Handle<FixedArray> elements;
6086 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006087 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006088 { MaybeObject* maybe_obj =
6089 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006090 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6091 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006092 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006093
6094 Vector<const char> chars = s->ToAsciiVector();
6095 // Note, this will initialize all elements (not only the prefix)
6096 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006097 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
6098 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006099 *elements,
6100 length);
6101
6102 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006103 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
6104 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006105 }
6106 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006107 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006108 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006109 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6110 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006111 }
6112 }
6113
6114#ifdef DEBUG
6115 for (int i = 0; i < length; ++i) {
6116 ASSERT(String::cast(elements->get(i))->length() == 1);
6117 }
6118#endif
6119
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006120 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006121}
6122
6123
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006124RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006125 NoHandleAllocation ha;
6126 ASSERT(args.length() == 1);
6127 CONVERT_CHECKED(String, value, args[0]);
6128 return value->ToObject();
6129}
6130
6131
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006132bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006133 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006134 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006135 return char_length == 0;
6136}
6137
6138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006139RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006140 NoHandleAllocation ha;
6141 ASSERT(args.length() == 1);
6142
6143 Object* number = args[0];
6144 RUNTIME_ASSERT(number->IsNumber());
6145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006146 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006147}
6148
6149
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006150RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006151 NoHandleAllocation ha;
6152 ASSERT(args.length() == 1);
6153
6154 Object* number = args[0];
6155 RUNTIME_ASSERT(number->IsNumber());
6156
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006157 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006158}
6159
6160
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006161RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006162 NoHandleAllocation ha;
6163 ASSERT(args.length() == 1);
6164
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006165 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006166
6167 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6168 if (number > 0 && number <= Smi::kMaxValue) {
6169 return Smi::FromInt(static_cast<int>(number));
6170 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006171 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006172}
6173
6174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006175RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006176 NoHandleAllocation ha;
6177 ASSERT(args.length() == 1);
6178
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006179 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006180
6181 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6182 if (number > 0 && number <= Smi::kMaxValue) {
6183 return Smi::FromInt(static_cast<int>(number));
6184 }
6185
6186 double double_value = DoubleToInteger(number);
6187 // Map both -0 and +0 to +0.
6188 if (double_value == 0) double_value = 0;
6189
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006190 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006191}
6192
6193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006194RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006195 NoHandleAllocation ha;
6196 ASSERT(args.length() == 1);
6197
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006198 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006199 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006200}
6201
6202
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006203RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006204 NoHandleAllocation ha;
6205 ASSERT(args.length() == 1);
6206
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006207 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006208
6209 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6210 if (number > 0 && number <= Smi::kMaxValue) {
6211 return Smi::FromInt(static_cast<int>(number));
6212 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006213 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006214}
6215
6216
ager@chromium.org870a0b62008-11-04 11:43:05 +00006217// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6218// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006219RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006220 NoHandleAllocation ha;
6221 ASSERT(args.length() == 1);
6222
6223 Object* obj = args[0];
6224 if (obj->IsSmi()) {
6225 return obj;
6226 }
6227 if (obj->IsHeapNumber()) {
6228 double value = HeapNumber::cast(obj)->value();
6229 int int_value = FastD2I(value);
6230 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6231 return Smi::FromInt(int_value);
6232 }
6233 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006234 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006235}
6236
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006238RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006239 NoHandleAllocation ha;
6240 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006241 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006242}
6243
6244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006245RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006246 NoHandleAllocation ha;
6247 ASSERT(args.length() == 2);
6248
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006249 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6250 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006251 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252}
6253
6254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006255RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006256 NoHandleAllocation ha;
6257 ASSERT(args.length() == 2);
6258
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006259 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6260 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006261 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262}
6263
6264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006265RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006266 NoHandleAllocation ha;
6267 ASSERT(args.length() == 2);
6268
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006269 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6270 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006271 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006272}
6273
6274
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006275RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006276 NoHandleAllocation ha;
6277 ASSERT(args.length() == 1);
6278
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006279 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006280 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006281}
6282
6283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006284RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006285 NoHandleAllocation ha;
6286 ASSERT(args.length() == 0);
6287
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006288 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006289}
6290
6291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006292RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006293 NoHandleAllocation ha;
6294 ASSERT(args.length() == 2);
6295
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006296 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6297 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006298 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006299}
6300
6301
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006302RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006303 NoHandleAllocation ha;
6304 ASSERT(args.length() == 2);
6305
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006306 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6307 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006308
ager@chromium.org3811b432009-10-28 14:53:37 +00006309 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006310 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006311 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006312}
6313
6314
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006315RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006316 NoHandleAllocation ha;
6317 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006318 CONVERT_CHECKED(String, str1, args[0]);
6319 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006320 isolate->counters()->string_add_runtime()->Increment();
6321 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006322}
6323
6324
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006325template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006326static inline void StringBuilderConcatHelper(String* special,
6327 sinkchar* sink,
6328 FixedArray* fixed_array,
6329 int array_length) {
6330 int position = 0;
6331 for (int i = 0; i < array_length; i++) {
6332 Object* element = fixed_array->get(i);
6333 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006334 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006335 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006336 int pos;
6337 int len;
6338 if (encoded_slice > 0) {
6339 // Position and length encoded in one smi.
6340 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6341 len = StringBuilderSubstringLength::decode(encoded_slice);
6342 } else {
6343 // Position and length encoded in two smis.
6344 Object* obj = fixed_array->get(++i);
6345 ASSERT(obj->IsSmi());
6346 pos = Smi::cast(obj)->value();
6347 len = -encoded_slice;
6348 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006349 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006350 sink + position,
6351 pos,
6352 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006353 position += len;
6354 } else {
6355 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006356 int element_length = string->length();
6357 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006358 position += element_length;
6359 }
6360 }
6361}
6362
6363
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006364RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006365 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006366 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006367 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006368 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006369 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006370 return Failure::OutOfMemoryException();
6371 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006372 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006373 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006374
6375 // This assumption is used by the slice encoding in one or two smis.
6376 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6377
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006378 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006379 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006380 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006381 }
6382 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006383 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006384 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006385 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006386
6387 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006388 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006389 } else if (array_length == 1) {
6390 Object* first = fixed_array->get(0);
6391 if (first->IsString()) return first;
6392 }
6393
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006394 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006395 int position = 0;
6396 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006397 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006398 Object* elt = fixed_array->get(i);
6399 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006400 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006401 int smi_value = Smi::cast(elt)->value();
6402 int pos;
6403 int len;
6404 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006405 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006406 pos = StringBuilderSubstringPosition::decode(smi_value);
6407 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006408 } else {
6409 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006410 len = -smi_value;
6411 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006412 i++;
6413 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006414 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006415 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006416 Object* next_smi = fixed_array->get(i);
6417 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006418 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006419 }
6420 pos = Smi::cast(next_smi)->value();
6421 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006422 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006423 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006424 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006425 ASSERT(pos >= 0);
6426 ASSERT(len >= 0);
6427 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006428 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006429 }
6430 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006431 } else if (elt->IsString()) {
6432 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006433 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006434 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006435 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006436 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006437 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006438 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006439 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006440 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006441 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006442 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006443 return Failure::OutOfMemoryException();
6444 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006445 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006446 }
6447
6448 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006449 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006450
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006451 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006452 { MaybeObject* maybe_object =
6453 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006454 if (!maybe_object->ToObject(&object)) return maybe_object;
6455 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006456 SeqAsciiString* answer = SeqAsciiString::cast(object);
6457 StringBuilderConcatHelper(special,
6458 answer->GetChars(),
6459 fixed_array,
6460 array_length);
6461 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006462 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006463 { MaybeObject* maybe_object =
6464 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006465 if (!maybe_object->ToObject(&object)) return maybe_object;
6466 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006467 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6468 StringBuilderConcatHelper(special,
6469 answer->GetChars(),
6470 fixed_array,
6471 array_length);
6472 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006473 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006474}
6475
6476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006477RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006478 NoHandleAllocation ha;
6479 ASSERT(args.length() == 3);
6480 CONVERT_CHECKED(JSArray, array, args[0]);
6481 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006482 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006483 return Failure::OutOfMemoryException();
6484 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006485 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006486 CONVERT_CHECKED(String, separator, args[2]);
6487
6488 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006489 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006490 }
6491 FixedArray* fixed_array = FixedArray::cast(array->elements());
6492 if (fixed_array->length() < array_length) {
6493 array_length = fixed_array->length();
6494 }
6495
6496 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006497 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006498 } else if (array_length == 1) {
6499 Object* first = fixed_array->get(0);
6500 if (first->IsString()) return first;
6501 }
6502
6503 int separator_length = separator->length();
6504 int max_nof_separators =
6505 (String::kMaxLength + separator_length - 1) / separator_length;
6506 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006507 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006508 return Failure::OutOfMemoryException();
6509 }
6510 int length = (array_length - 1) * separator_length;
6511 for (int i = 0; i < array_length; i++) {
6512 Object* element_obj = fixed_array->get(i);
6513 if (!element_obj->IsString()) {
6514 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006515 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006516 }
6517 String* element = String::cast(element_obj);
6518 int increment = element->length();
6519 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006520 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006521 return Failure::OutOfMemoryException();
6522 }
6523 length += increment;
6524 }
6525
6526 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006527 { MaybeObject* maybe_object =
6528 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006529 if (!maybe_object->ToObject(&object)) return maybe_object;
6530 }
6531 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6532
6533 uc16* sink = answer->GetChars();
6534#ifdef DEBUG
6535 uc16* end = sink + length;
6536#endif
6537
6538 String* first = String::cast(fixed_array->get(0));
6539 int first_length = first->length();
6540 String::WriteToFlat(first, sink, 0, first_length);
6541 sink += first_length;
6542
6543 for (int i = 1; i < array_length; i++) {
6544 ASSERT(sink + separator_length <= end);
6545 String::WriteToFlat(separator, sink, 0, separator_length);
6546 sink += separator_length;
6547
6548 String* element = String::cast(fixed_array->get(i));
6549 int element_length = element->length();
6550 ASSERT(sink + element_length <= end);
6551 String::WriteToFlat(element, sink, 0, element_length);
6552 sink += element_length;
6553 }
6554 ASSERT(sink == end);
6555
6556 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6557 return answer;
6558}
6559
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006560template <typename Char>
6561static void JoinSparseArrayWithSeparator(FixedArray* elements,
6562 int elements_length,
6563 uint32_t array_length,
6564 String* separator,
6565 Vector<Char> buffer) {
6566 int previous_separator_position = 0;
6567 int separator_length = separator->length();
6568 int cursor = 0;
6569 for (int i = 0; i < elements_length; i += 2) {
6570 int position = NumberToInt32(elements->get(i));
6571 String* string = String::cast(elements->get(i + 1));
6572 int string_length = string->length();
6573 if (string->length() > 0) {
6574 while (previous_separator_position < position) {
6575 String::WriteToFlat<Char>(separator, &buffer[cursor],
6576 0, separator_length);
6577 cursor += separator_length;
6578 previous_separator_position++;
6579 }
6580 String::WriteToFlat<Char>(string, &buffer[cursor],
6581 0, string_length);
6582 cursor += string->length();
6583 }
6584 }
6585 if (separator_length > 0) {
6586 // Array length must be representable as a signed 32-bit number,
6587 // otherwise the total string length would have been too large.
6588 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6589 int last_array_index = static_cast<int>(array_length - 1);
6590 while (previous_separator_position < last_array_index) {
6591 String::WriteToFlat<Char>(separator, &buffer[cursor],
6592 0, separator_length);
6593 cursor += separator_length;
6594 previous_separator_position++;
6595 }
6596 }
6597 ASSERT(cursor <= buffer.length());
6598}
6599
6600
6601RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6602 NoHandleAllocation ha;
6603 ASSERT(args.length() == 3);
6604 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6605 RUNTIME_ASSERT(elements_array->HasFastElements());
6606 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6607 CONVERT_CHECKED(String, separator, args[2]);
6608 // elements_array is fast-mode JSarray of alternating positions
6609 // (increasing order) and strings.
6610 // array_length is length of original array (used to add separators);
6611 // separator is string to put between elements. Assumed to be non-empty.
6612
6613 // Find total length of join result.
6614 int string_length = 0;
6615 bool is_ascii = true;
6616 int max_string_length = SeqAsciiString::kMaxLength;
6617 bool overflow = false;
6618 CONVERT_NUMBER_CHECKED(int, elements_length,
6619 Int32, elements_array->length());
6620 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6621 FixedArray* elements = FixedArray::cast(elements_array->elements());
6622 for (int i = 0; i < elements_length; i += 2) {
6623 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6624 CONVERT_CHECKED(String, string, elements->get(i + 1));
6625 int length = string->length();
6626 if (is_ascii && !string->IsAsciiRepresentation()) {
6627 is_ascii = false;
6628 max_string_length = SeqTwoByteString::kMaxLength;
6629 }
6630 if (length > max_string_length ||
6631 max_string_length - length < string_length) {
6632 overflow = true;
6633 break;
6634 }
6635 string_length += length;
6636 }
6637 int separator_length = separator->length();
6638 if (!overflow && separator_length > 0) {
6639 if (array_length <= 0x7fffffffu) {
6640 int separator_count = static_cast<int>(array_length) - 1;
6641 int remaining_length = max_string_length - string_length;
6642 if ((remaining_length / separator_length) >= separator_count) {
6643 string_length += separator_length * (array_length - 1);
6644 } else {
6645 // Not room for the separators within the maximal string length.
6646 overflow = true;
6647 }
6648 } else {
6649 // Nonempty separator and at least 2^31-1 separators necessary
6650 // means that the string is too large to create.
6651 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6652 overflow = true;
6653 }
6654 }
6655 if (overflow) {
6656 // Throw OutOfMemory exception for creating too large a string.
6657 V8::FatalProcessOutOfMemory("Array join result too large.");
6658 }
6659
6660 if (is_ascii) {
6661 MaybeObject* result_allocation =
6662 isolate->heap()->AllocateRawAsciiString(string_length);
6663 if (result_allocation->IsFailure()) return result_allocation;
6664 SeqAsciiString* result_string =
6665 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6666 JoinSparseArrayWithSeparator<char>(elements,
6667 elements_length,
6668 array_length,
6669 separator,
6670 Vector<char>(result_string->GetChars(),
6671 string_length));
6672 return result_string;
6673 } else {
6674 MaybeObject* result_allocation =
6675 isolate->heap()->AllocateRawTwoByteString(string_length);
6676 if (result_allocation->IsFailure()) return result_allocation;
6677 SeqTwoByteString* result_string =
6678 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6679 JoinSparseArrayWithSeparator<uc16>(elements,
6680 elements_length,
6681 array_length,
6682 separator,
6683 Vector<uc16>(result_string->GetChars(),
6684 string_length));
6685 return result_string;
6686 }
6687}
6688
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006689
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006690RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006691 NoHandleAllocation ha;
6692 ASSERT(args.length() == 2);
6693
6694 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6695 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006696 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006697}
6698
6699
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006700RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006701 NoHandleAllocation ha;
6702 ASSERT(args.length() == 2);
6703
6704 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6705 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006706 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006707}
6708
6709
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006710RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006711 NoHandleAllocation ha;
6712 ASSERT(args.length() == 2);
6713
6714 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6715 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006716 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006717}
6718
6719
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006720RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006721 NoHandleAllocation ha;
6722 ASSERT(args.length() == 1);
6723
6724 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006725 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006726}
6727
6728
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006729RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006730 NoHandleAllocation ha;
6731 ASSERT(args.length() == 2);
6732
6733 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6734 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006735 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006736}
6737
6738
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006739RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 NoHandleAllocation ha;
6741 ASSERT(args.length() == 2);
6742
6743 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6744 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006745 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006746}
6747
6748
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006749RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750 NoHandleAllocation ha;
6751 ASSERT(args.length() == 2);
6752
6753 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6754 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006755 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006756}
6757
6758
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006759RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006760 NoHandleAllocation ha;
6761 ASSERT(args.length() == 2);
6762
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006763 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6764 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006765 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6766 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6767 if (x == y) return Smi::FromInt(EQUAL);
6768 Object* result;
6769 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6770 result = Smi::FromInt(EQUAL);
6771 } else {
6772 result = Smi::FromInt(NOT_EQUAL);
6773 }
6774 return result;
6775}
6776
6777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006778RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006779 NoHandleAllocation ha;
6780 ASSERT(args.length() == 2);
6781
6782 CONVERT_CHECKED(String, x, args[0]);
6783 CONVERT_CHECKED(String, y, args[1]);
6784
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006785 bool not_equal = !x->Equals(y);
6786 // This is slightly convoluted because the value that signifies
6787 // equality is 0 and inequality is 1 so we have to negate the result
6788 // from String::Equals.
6789 ASSERT(not_equal == 0 || not_equal == 1);
6790 STATIC_CHECK(EQUAL == 0);
6791 STATIC_CHECK(NOT_EQUAL == 1);
6792 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006793}
6794
6795
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006796RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006797 NoHandleAllocation ha;
6798 ASSERT(args.length() == 3);
6799
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006800 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6801 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006802 if (isnan(x) || isnan(y)) return args[2];
6803 if (x == y) return Smi::FromInt(EQUAL);
6804 if (isless(x, y)) return Smi::FromInt(LESS);
6805 return Smi::FromInt(GREATER);
6806}
6807
6808
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006809// Compare two Smis as if they were converted to strings and then
6810// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006811RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006812 NoHandleAllocation ha;
6813 ASSERT(args.length() == 2);
6814
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006815 // Extract the integer values from the Smis.
6816 CONVERT_CHECKED(Smi, x, args[0]);
6817 CONVERT_CHECKED(Smi, y, args[1]);
6818 int x_value = x->value();
6819 int y_value = y->value();
6820
6821 // If the integers are equal so are the string representations.
6822 if (x_value == y_value) return Smi::FromInt(EQUAL);
6823
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006824 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006825 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006826 if (x_value == 0 || y_value == 0)
6827 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006828
ager@chromium.org32912102009-01-16 10:38:43 +00006829 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006830 // smallest because the char code of '-' is less than the char code
6831 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006832
6833 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6834 // architectures using 32-bit Smis.
6835 uint32_t x_scaled = x_value;
6836 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006837 if (x_value < 0 || y_value < 0) {
6838 if (y_value >= 0) return Smi::FromInt(LESS);
6839 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006840 x_scaled = -x_value;
6841 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006842 }
6843
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006844 static const uint32_t kPowersOf10[] = {
6845 1, 10, 100, 1000, 10*1000, 100*1000,
6846 1000*1000, 10*1000*1000, 100*1000*1000,
6847 1000*1000*1000
6848 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006849
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006850 // If the integers have the same number of decimal digits they can be
6851 // compared directly as the numeric order is the same as the
6852 // lexicographic order. If one integer has fewer digits, it is scaled
6853 // by some power of 10 to have the same number of digits as the longer
6854 // integer. If the scaled integers are equal it means the shorter
6855 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006856
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006857 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6858 int x_log2 = IntegerLog2(x_scaled);
6859 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6860 x_log10 -= x_scaled < kPowersOf10[x_log10];
6861
6862 int y_log2 = IntegerLog2(y_scaled);
6863 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6864 y_log10 -= y_scaled < kPowersOf10[y_log10];
6865
6866 int tie = EQUAL;
6867
6868 if (x_log10 < y_log10) {
6869 // X has fewer digits. We would like to simply scale up X but that
6870 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6871 // be scaled up to 9_000_000_000. So we scale up by the next
6872 // smallest power and scale down Y to drop one digit. It is OK to
6873 // drop one digit from the longer integer since the final digit is
6874 // past the length of the shorter integer.
6875 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6876 y_scaled /= 10;
6877 tie = LESS;
6878 } else if (y_log10 < x_log10) {
6879 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6880 x_scaled /= 10;
6881 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006882 }
6883
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006884 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6885 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6886 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006887}
6888
6889
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006890static Object* StringInputBufferCompare(RuntimeState* state,
6891 String* x,
6892 String* y) {
6893 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6894 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006895 bufx.Reset(x);
6896 bufy.Reset(y);
6897 while (bufx.has_more() && bufy.has_more()) {
6898 int d = bufx.GetNext() - bufy.GetNext();
6899 if (d < 0) return Smi::FromInt(LESS);
6900 else if (d > 0) return Smi::FromInt(GREATER);
6901 }
6902
6903 // x is (non-trivial) prefix of y:
6904 if (bufy.has_more()) return Smi::FromInt(LESS);
6905 // y is prefix of x:
6906 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6907}
6908
6909
6910static Object* FlatStringCompare(String* x, String* y) {
6911 ASSERT(x->IsFlat());
6912 ASSERT(y->IsFlat());
6913 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6914 int prefix_length = x->length();
6915 if (y->length() < prefix_length) {
6916 prefix_length = y->length();
6917 equal_prefix_result = Smi::FromInt(GREATER);
6918 } else if (y->length() > prefix_length) {
6919 equal_prefix_result = Smi::FromInt(LESS);
6920 }
6921 int r;
6922 if (x->IsAsciiRepresentation()) {
6923 Vector<const char> x_chars = x->ToAsciiVector();
6924 if (y->IsAsciiRepresentation()) {
6925 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006926 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006927 } else {
6928 Vector<const uc16> y_chars = y->ToUC16Vector();
6929 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6930 }
6931 } else {
6932 Vector<const uc16> x_chars = x->ToUC16Vector();
6933 if (y->IsAsciiRepresentation()) {
6934 Vector<const char> y_chars = y->ToAsciiVector();
6935 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6936 } else {
6937 Vector<const uc16> y_chars = y->ToUC16Vector();
6938 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6939 }
6940 }
6941 Object* result;
6942 if (r == 0) {
6943 result = equal_prefix_result;
6944 } else {
6945 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6946 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006947 ASSERT(result ==
6948 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006949 return result;
6950}
6951
6952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006953RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006954 NoHandleAllocation ha;
6955 ASSERT(args.length() == 2);
6956
6957 CONVERT_CHECKED(String, x, args[0]);
6958 CONVERT_CHECKED(String, y, args[1]);
6959
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006960 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006961
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006962 // A few fast case tests before we flatten.
6963 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006964 if (y->length() == 0) {
6965 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006966 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006967 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006968 return Smi::FromInt(LESS);
6969 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006970
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006971 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006972 if (d < 0) return Smi::FromInt(LESS);
6973 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006974
lrn@chromium.org303ada72010-10-27 09:33:13 +00006975 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006976 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006977 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6978 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006979 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006980 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6981 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006982
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006983 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006984 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006985}
6986
6987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006988RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006989 NoHandleAllocation ha;
6990 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006991 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006992
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006993 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006994 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006995}
6996
6997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006998RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006999 NoHandleAllocation ha;
7000 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007001 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007002
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007003 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007004 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007005}
7006
7007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007008RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007009 NoHandleAllocation ha;
7010 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007011 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007012
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007013 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007014 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007015}
7016
7017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007018static const double kPiDividedBy4 = 0.78539816339744830962;
7019
7020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007021RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022 NoHandleAllocation ha;
7023 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007024 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007025
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007026 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7027 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007028 double result;
7029 if (isinf(x) && isinf(y)) {
7030 // Make sure that the result in case of two infinite arguments
7031 // is a multiple of Pi / 4. The sign of the result is determined
7032 // by the first argument (x) and the sign of the second argument
7033 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007034 int multiplier = (x < 0) ? -1 : 1;
7035 if (y < 0) multiplier *= 3;
7036 result = multiplier * kPiDividedBy4;
7037 } else {
7038 result = atan2(x, y);
7039 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007040 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007041}
7042
7043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007044RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045 NoHandleAllocation ha;
7046 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007047 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007048
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007049 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007050 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007051}
7052
7053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007054RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007055 NoHandleAllocation ha;
7056 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007057 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007059 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007060 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061}
7062
7063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007064RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007065 NoHandleAllocation ha;
7066 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007067 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007069 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007070 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071}
7072
7073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007074RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007075 NoHandleAllocation ha;
7076 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007077 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007078
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007079 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007080 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007081}
7082
7083
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007084RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007085 NoHandleAllocation ha;
7086 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007087 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007088
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007089 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007090 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007091}
7092
7093
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007094RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007095 NoHandleAllocation ha;
7096 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007097 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007098
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007099 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007100
7101 // If the second argument is a smi, it is much faster to call the
7102 // custom powi() function than the generic pow().
7103 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007104 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007105 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007106 }
7107
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007108 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007109 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110}
7111
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007112// Fast version of Math.pow if we know that y is not an integer and
7113// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007114RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007115 NoHandleAllocation ha;
7116 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007117 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7118 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007119 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007120 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007121 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007122 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007123 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007124 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007125 }
7126}
7127
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007129RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007130 NoHandleAllocation ha;
7131 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007132 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007133
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007134 if (!args[0]->IsHeapNumber()) {
7135 // Must be smi. Return the argument unchanged for all the other types
7136 // to make fuzz-natives test happy.
7137 return args[0];
7138 }
7139
7140 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7141
7142 double value = number->value();
7143 int exponent = number->get_exponent();
7144 int sign = number->get_sign();
7145
danno@chromium.org160a7b02011-04-18 15:51:38 +00007146 if (exponent < -1) {
7147 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7148 if (sign) return isolate->heap()->minus_zero_value();
7149 return Smi::FromInt(0);
7150 }
7151
7152 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7153 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7154 // agument holds for 32-bit smis).
7155 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007156 return Smi::FromInt(static_cast<int>(value + 0.5));
7157 }
7158
7159 // If the magnitude is big enough, there's no place for fraction part. If we
7160 // try to add 0.5 to this number, 1.0 will be added instead.
7161 if (exponent >= 52) {
7162 return number;
7163 }
7164
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007165 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007166
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007167 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007168 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007169}
7170
7171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007172RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007173 NoHandleAllocation ha;
7174 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007175 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007176
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007177 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007178 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007179}
7180
7181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007182RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007183 NoHandleAllocation ha;
7184 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007185 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007186
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007187 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007188 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007189}
7190
7191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007192RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007193 NoHandleAllocation ha;
7194 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007195 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007196
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007197 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007198 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007199}
7200
7201
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007202static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007203 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7204 181, 212, 243, 273, 304, 334};
7205 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7206 182, 213, 244, 274, 305, 335};
7207
7208 year += month / 12;
7209 month %= 12;
7210 if (month < 0) {
7211 year--;
7212 month += 12;
7213 }
7214
7215 ASSERT(month >= 0);
7216 ASSERT(month < 12);
7217
7218 // year_delta is an arbitrary number such that:
7219 // a) year_delta = -1 (mod 400)
7220 // b) year + year_delta > 0 for years in the range defined by
7221 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7222 // Jan 1 1970. This is required so that we don't run into integer
7223 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007224 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007225 // operations.
7226 static const int year_delta = 399999;
7227 static const int base_day = 365 * (1970 + year_delta) +
7228 (1970 + year_delta) / 4 -
7229 (1970 + year_delta) / 100 +
7230 (1970 + year_delta) / 400;
7231
7232 int year1 = year + year_delta;
7233 int day_from_year = 365 * year1 +
7234 year1 / 4 -
7235 year1 / 100 +
7236 year1 / 400 -
7237 base_day;
7238
7239 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007240 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007241 }
7242
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007243 return day_from_year + day_from_month_leap[month] + day - 1;
7244}
7245
7246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007247RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007248 NoHandleAllocation ha;
7249 ASSERT(args.length() == 3);
7250
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007251 CONVERT_SMI_ARG_CHECKED(year, 0);
7252 CONVERT_SMI_ARG_CHECKED(month, 1);
7253 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007254
7255 return Smi::FromInt(MakeDay(year, month, date));
7256}
7257
7258
7259static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7260static const int kDaysIn4Years = 4 * 365 + 1;
7261static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7262static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7263static const int kDays1970to2000 = 30 * 365 + 7;
7264static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7265 kDays1970to2000;
7266static const int kYearsOffset = 400000;
7267
7268static const char kDayInYear[] = {
7269 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7270 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7271 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7272 22, 23, 24, 25, 26, 27, 28,
7273 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7274 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7275 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7276 22, 23, 24, 25, 26, 27, 28, 29, 30,
7277 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7278 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7279 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7280 22, 23, 24, 25, 26, 27, 28, 29, 30,
7281 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7282 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7283 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7284 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7285 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7286 22, 23, 24, 25, 26, 27, 28, 29, 30,
7287 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7288 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7289 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7290 22, 23, 24, 25, 26, 27, 28, 29, 30,
7291 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7292 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7293
7294 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7295 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7296 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7297 22, 23, 24, 25, 26, 27, 28,
7298 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7299 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7300 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7301 22, 23, 24, 25, 26, 27, 28, 29, 30,
7302 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7303 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7304 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7305 22, 23, 24, 25, 26, 27, 28, 29, 30,
7306 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7307 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7308 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7309 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7310 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7311 22, 23, 24, 25, 26, 27, 28, 29, 30,
7312 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7313 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7314 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7315 22, 23, 24, 25, 26, 27, 28, 29, 30,
7316 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7317 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7318
7319 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7320 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7321 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7322 22, 23, 24, 25, 26, 27, 28, 29,
7323 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7324 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7325 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7326 22, 23, 24, 25, 26, 27, 28, 29, 30,
7327 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7328 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7329 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7330 22, 23, 24, 25, 26, 27, 28, 29, 30,
7331 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7332 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7333 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7334 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7335 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7336 22, 23, 24, 25, 26, 27, 28, 29, 30,
7337 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7338 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7339 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7340 22, 23, 24, 25, 26, 27, 28, 29, 30,
7341 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7342 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7343
7344 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7345 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7346 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7347 22, 23, 24, 25, 26, 27, 28,
7348 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7349 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7350 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7351 22, 23, 24, 25, 26, 27, 28, 29, 30,
7352 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7353 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7354 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7355 22, 23, 24, 25, 26, 27, 28, 29, 30,
7356 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7357 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7358 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7359 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7360 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7361 22, 23, 24, 25, 26, 27, 28, 29, 30,
7362 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7363 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7364 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7365 22, 23, 24, 25, 26, 27, 28, 29, 30,
7366 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7367 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7368
7369static const char kMonthInYear[] = {
7370 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,
7371 0, 0, 0, 0, 0, 0,
7372 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,
7373 1, 1, 1,
7374 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,
7375 2, 2, 2, 2, 2, 2,
7376 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,
7377 3, 3, 3, 3, 3,
7378 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,
7379 4, 4, 4, 4, 4, 4,
7380 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,
7381 5, 5, 5, 5, 5,
7382 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,
7383 6, 6, 6, 6, 6, 6,
7384 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,
7385 7, 7, 7, 7, 7, 7,
7386 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,
7387 8, 8, 8, 8, 8,
7388 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,
7389 9, 9, 9, 9, 9, 9,
7390 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7391 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7392 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7393 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7394
7395 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,
7396 0, 0, 0, 0, 0, 0,
7397 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,
7398 1, 1, 1,
7399 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,
7400 2, 2, 2, 2, 2, 2,
7401 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,
7402 3, 3, 3, 3, 3,
7403 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,
7404 4, 4, 4, 4, 4, 4,
7405 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,
7406 5, 5, 5, 5, 5,
7407 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,
7408 6, 6, 6, 6, 6, 6,
7409 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,
7410 7, 7, 7, 7, 7, 7,
7411 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,
7412 8, 8, 8, 8, 8,
7413 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,
7414 9, 9, 9, 9, 9, 9,
7415 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7416 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7417 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7418 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7419
7420 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,
7421 0, 0, 0, 0, 0, 0,
7422 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,
7423 1, 1, 1, 1,
7424 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,
7425 2, 2, 2, 2, 2, 2,
7426 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,
7427 3, 3, 3, 3, 3,
7428 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,
7429 4, 4, 4, 4, 4, 4,
7430 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,
7431 5, 5, 5, 5, 5,
7432 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,
7433 6, 6, 6, 6, 6, 6,
7434 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,
7435 7, 7, 7, 7, 7, 7,
7436 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,
7437 8, 8, 8, 8, 8,
7438 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,
7439 9, 9, 9, 9, 9, 9,
7440 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7441 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7442 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7443 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7444
7445 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,
7446 0, 0, 0, 0, 0, 0,
7447 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,
7448 1, 1, 1,
7449 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,
7450 2, 2, 2, 2, 2, 2,
7451 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,
7452 3, 3, 3, 3, 3,
7453 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,
7454 4, 4, 4, 4, 4, 4,
7455 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,
7456 5, 5, 5, 5, 5,
7457 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,
7458 6, 6, 6, 6, 6, 6,
7459 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,
7460 7, 7, 7, 7, 7, 7,
7461 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,
7462 8, 8, 8, 8, 8,
7463 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,
7464 9, 9, 9, 9, 9, 9,
7465 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7466 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7467 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7468 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7469
7470
7471// This function works for dates from 1970 to 2099.
7472static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007473 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007474#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007475 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007476#endif
7477
7478 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7479 date %= kDaysIn4Years;
7480
7481 month = kMonthInYear[date];
7482 day = kDayInYear[date];
7483
7484 ASSERT(MakeDay(year, month, day) == save_date);
7485}
7486
7487
7488static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007489 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007490#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007491 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007492#endif
7493
7494 date += kDaysOffset;
7495 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7496 date %= kDaysIn400Years;
7497
7498 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7499
7500 date--;
7501 int yd1 = date / kDaysIn100Years;
7502 date %= kDaysIn100Years;
7503 year += 100 * yd1;
7504
7505 date++;
7506 int yd2 = date / kDaysIn4Years;
7507 date %= kDaysIn4Years;
7508 year += 4 * yd2;
7509
7510 date--;
7511 int yd3 = date / 365;
7512 date %= 365;
7513 year += yd3;
7514
7515 bool is_leap = (!yd1 || yd2) && !yd3;
7516
7517 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007518 ASSERT(is_leap || (date >= 0));
7519 ASSERT((date < 365) || (is_leap && (date < 366)));
7520 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7521 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7522 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007523
7524 if (is_leap) {
7525 day = kDayInYear[2*365 + 1 + date];
7526 month = kMonthInYear[2*365 + 1 + date];
7527 } else {
7528 day = kDayInYear[date];
7529 month = kMonthInYear[date];
7530 }
7531
7532 ASSERT(MakeDay(year, month, day) == save_date);
7533}
7534
7535
7536static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007537 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007538 if (date >= 0 && date < 32 * kDaysIn4Years) {
7539 DateYMDFromTimeAfter1970(date, year, month, day);
7540 } else {
7541 DateYMDFromTimeSlow(date, year, month, day);
7542 }
7543}
7544
7545
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007546RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007547 NoHandleAllocation ha;
7548 ASSERT(args.length() == 2);
7549
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007550 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007551 CONVERT_CHECKED(JSArray, res_array, args[1]);
7552
7553 int year, month, day;
7554 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7555
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007556 RUNTIME_ASSERT(res_array->elements()->map() ==
7557 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007558 FixedArray* elms = FixedArray::cast(res_array->elements());
7559 RUNTIME_ASSERT(elms->length() == 3);
7560
7561 elms->set(0, Smi::FromInt(year));
7562 elms->set(1, Smi::FromInt(month));
7563 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007564
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007565 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007566}
7567
7568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007569RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007570 HandleScope scope(isolate);
7571 ASSERT(args.length() == 3);
7572
7573 Handle<JSFunction> callee = args.at<JSFunction>(0);
7574 Object** parameters = reinterpret_cast<Object**>(args[1]);
7575 const int argument_count = Smi::cast(args[2])->value();
7576
7577 Handle<JSObject> result =
7578 isolate->factory()->NewArgumentsObject(callee, argument_count);
7579 // Allocate the elements if needed.
7580 int parameter_count = callee->shared()->formal_parameter_count();
7581 if (argument_count > 0) {
7582 if (parameter_count > 0) {
7583 int mapped_count = Min(argument_count, parameter_count);
7584 Handle<FixedArray> parameter_map =
7585 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7586 parameter_map->set_map(
7587 isolate->heap()->non_strict_arguments_elements_map());
7588
7589 Handle<Map> old_map(result->map());
7590 Handle<Map> new_map =
7591 isolate->factory()->CopyMapDropTransitions(old_map);
7592 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7593
7594 result->set_map(*new_map);
7595 result->set_elements(*parameter_map);
7596
7597 // Store the context and the arguments array at the beginning of the
7598 // parameter map.
7599 Handle<Context> context(isolate->context());
7600 Handle<FixedArray> arguments =
7601 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7602 parameter_map->set(0, *context);
7603 parameter_map->set(1, *arguments);
7604
7605 // Loop over the actual parameters backwards.
7606 int index = argument_count - 1;
7607 while (index >= mapped_count) {
7608 // These go directly in the arguments array and have no
7609 // corresponding slot in the parameter map.
7610 arguments->set(index, *(parameters - index - 1));
7611 --index;
7612 }
7613
7614 ScopeInfo<> scope_info(callee->shared()->scope_info());
7615 while (index >= 0) {
7616 // Detect duplicate names to the right in the parameter list.
7617 Handle<String> name = scope_info.parameter_name(index);
7618 int context_slot_count = scope_info.number_of_context_slots();
7619 bool duplicate = false;
7620 for (int j = index + 1; j < parameter_count; ++j) {
7621 if (scope_info.parameter_name(j).is_identical_to(name)) {
7622 duplicate = true;
7623 break;
7624 }
7625 }
7626
7627 if (duplicate) {
7628 // This goes directly in the arguments array with a hole in the
7629 // parameter map.
7630 arguments->set(index, *(parameters - index - 1));
7631 parameter_map->set_the_hole(index + 2);
7632 } else {
7633 // The context index goes in the parameter map with a hole in the
7634 // arguments array.
7635 int context_index = -1;
7636 for (int j = Context::MIN_CONTEXT_SLOTS;
7637 j < context_slot_count;
7638 ++j) {
7639 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7640 context_index = j;
7641 break;
7642 }
7643 }
7644 ASSERT(context_index >= 0);
7645 arguments->set_the_hole(index);
7646 parameter_map->set(index + 2, Smi::FromInt(context_index));
7647 }
7648
7649 --index;
7650 }
7651 } else {
7652 // If there is no aliasing, the arguments object elements are not
7653 // special in any way.
7654 Handle<FixedArray> elements =
7655 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7656 result->set_elements(*elements);
7657 for (int i = 0; i < argument_count; ++i) {
7658 elements->set(i, *(parameters - i - 1));
7659 }
7660 }
7661 }
7662 return *result;
7663}
7664
7665
7666RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007667 NoHandleAllocation ha;
7668 ASSERT(args.length() == 3);
7669
7670 JSFunction* callee = JSFunction::cast(args[0]);
7671 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007672 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007673
lrn@chromium.org303ada72010-10-27 09:33:13 +00007674 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007675 { MaybeObject* maybe_result =
7676 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007677 if (!maybe_result->ToObject(&result)) return maybe_result;
7678 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007679 // Allocate the elements if needed.
7680 if (length > 0) {
7681 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007682 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007683 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007684 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7685 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007686
7687 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007688 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007689 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007690 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007691
7692 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007693 for (int i = 0; i < length; i++) {
7694 array->set(i, *--parameters, mode);
7695 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007696 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007697 }
7698 return result;
7699}
7700
7701
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007702RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007703 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007704 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007705 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007706 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007707 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007708
whesse@chromium.org7b260152011-06-20 15:33:18 +00007709 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007710 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007711 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007712 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007713 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7714 context,
7715 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007716 return *result;
7717}
7718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007719
7720static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7721 int* total_argc) {
7722 // Find frame containing arguments passed to the caller.
7723 JavaScriptFrameIterator it;
7724 JavaScriptFrame* frame = it.frame();
7725 List<JSFunction*> functions(2);
7726 frame->GetFunctions(&functions);
7727 if (functions.length() > 1) {
7728 int inlined_frame_index = functions.length() - 1;
7729 JSFunction* inlined_function = functions[inlined_frame_index];
7730 int args_count = inlined_function->shared()->formal_parameter_count();
7731 ScopedVector<SlotRef> args_slots(args_count);
7732 SlotRef::ComputeSlotMappingForArguments(frame,
7733 inlined_frame_index,
7734 &args_slots);
7735
7736 *total_argc = bound_argc + args_count;
7737 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7738 for (int i = 0; i < args_count; i++) {
7739 Handle<Object> val = args_slots[i].GetValue();
7740 param_data[bound_argc + i] = val.location();
7741 }
7742 return param_data;
7743 } else {
7744 it.AdvanceToArgumentsFrame();
7745 frame = it.frame();
7746 int args_count = frame->ComputeParametersCount();
7747
7748 *total_argc = bound_argc + args_count;
7749 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7750 for (int i = 0; i < args_count; i++) {
7751 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7752 param_data[bound_argc + i] = val.location();
7753 }
7754 return param_data;
7755 }
7756}
7757
7758
7759RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007760 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007761 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007762 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007763 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007764
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007765 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007766 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007767 int bound_argc = 0;
7768 if (!args[1]->IsNull()) {
7769 CONVERT_ARG_CHECKED(JSArray, params, 1);
7770 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007771 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007772 bound_argc = Smi::cast(params->length())->value();
7773 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007775 int total_argc = 0;
7776 SmartPointer<Object**> param_data =
7777 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007778 for (int i = 0; i < bound_argc; i++) {
7779 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007780 param_data[i] = val.location();
7781 }
7782
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007783 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007784 Handle<Object> result =
7785 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007786 if (exception) {
7787 return Failure::Exception();
7788 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007789
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007790 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007791 return *result;
7792}
7793
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007794
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007795static void TrySettingInlineConstructStub(Isolate* isolate,
7796 Handle<JSFunction> function) {
7797 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007798 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007799 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007800 }
7801 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007802 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007803 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007804 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007805 function->shared()->set_construct_stub(
7806 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007807 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007808 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007809}
7810
7811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007812RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007813 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007814 ASSERT(args.length() == 1);
7815
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007816 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007817
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007818 // If the constructor isn't a proper function we throw a type error.
7819 if (!constructor->IsJSFunction()) {
7820 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7821 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007822 isolate->factory()->NewTypeError("not_constructor", arguments);
7823 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007824 }
7825
7826 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007827
7828 // If function should not have prototype, construction is not allowed. In this
7829 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007830 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007831 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7832 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007833 isolate->factory()->NewTypeError("not_constructor", arguments);
7834 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007835 }
7836
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007837#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007838 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007839 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007840 if (debug->StepInActive()) {
7841 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007842 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007843#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007844
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007845 if (function->has_initial_map()) {
7846 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007847 // The 'Function' function ignores the receiver object when
7848 // called using 'new' and creates a new JSFunction object that
7849 // is returned. The receiver object is only used for error
7850 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007851 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007852 // allocate JSFunctions since it does not properly initialize
7853 // the shared part of the function. Since the receiver is
7854 // ignored anyway, we use the global object as the receiver
7855 // instead of a new JSFunction object. This way, errors are
7856 // reported the same way whether or not 'Function' is called
7857 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007858 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007859 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007860 }
7861
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007862 // The function should be compiled for the optimization hints to be
7863 // available. We cannot use EnsureCompiled because that forces a
7864 // compilation through the shared function info which makes it
7865 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007866 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007867 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007868
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007869 if (!function->has_initial_map() &&
7870 shared->IsInobjectSlackTrackingInProgress()) {
7871 // The tracking is already in progress for another function. We can only
7872 // track one initial_map at a time, so we force the completion before the
7873 // function is called as a constructor for the first time.
7874 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007875 }
7876
7877 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007878 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7879 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007880 // Delay setting the stub if inobject slack tracking is in progress.
7881 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007882 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007883 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007884
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007885 isolate->counters()->constructed_objects()->Increment();
7886 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007887
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007888 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007889}
7890
7891
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007892RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007893 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007894 ASSERT(args.length() == 1);
7895
7896 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7897 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007898 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007899
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007900 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007901}
7902
7903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007904RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007905 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007906 ASSERT(args.length() == 1);
7907
7908 Handle<JSFunction> function = args.at<JSFunction>(0);
7909#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007910 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007911 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007912 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007913 PrintF("]\n");
7914 }
7915#endif
7916
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007917 // Compile the target function. Here we compile using CompileLazyInLoop in
7918 // order to get the optimized version. This helps code like delta-blue
7919 // that calls performance-critical routines through constructors. A
7920 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7921 // direct call. Since the in-loop tracking takes place through CallICs
7922 // this means that things called through constructors are never known to
7923 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007924 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007925 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007926 return Failure::Exception();
7927 }
7928
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007929 // All done. Return the compiled code.
7930 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007931 return function->code();
7932}
7933
7934
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007935RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007936 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007937 ASSERT(args.length() == 1);
7938 Handle<JSFunction> function = args.at<JSFunction>(0);
7939 // If the function is not optimizable or debugger is active continue using the
7940 // code from the full compiler.
7941 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007942 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007943 if (FLAG_trace_opt) {
7944 PrintF("[failed to optimize ");
7945 function->PrintName();
7946 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7947 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007948 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007949 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007950 function->ReplaceCode(function->shared()->code());
7951 return function->code();
7952 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007953 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007954 return function->code();
7955 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007956 if (FLAG_trace_opt) {
7957 PrintF("[failed to optimize ");
7958 function->PrintName();
7959 PrintF(": optimized compilation failed]\n");
7960 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007961 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007962 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007963}
7964
7965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007966RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007967 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007968 ASSERT(args.length() == 1);
7969 RUNTIME_ASSERT(args[0]->IsSmi());
7970 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007971 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007972 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7973 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007974 int frames = deoptimizer->output_count();
7975
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007976 deoptimizer->MaterializeHeapNumbers();
7977 delete deoptimizer;
7978
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007979 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007980 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007981 for (int i = 0; i < frames - 1; i++) it.Advance();
7982 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007983
7984 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007985 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007986 Handle<Object> arguments;
7987 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007988 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007989 if (arguments.is_null()) {
7990 // FunctionGetArguments can't throw an exception, so cast away the
7991 // doubt with an assert.
7992 arguments = Handle<Object>(
7993 Accessors::FunctionGetArguments(*function,
7994 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007995 ASSERT(*arguments != isolate->heap()->null_value());
7996 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007997 }
7998 frame->SetExpression(i, *arguments);
7999 }
8000 }
8001
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008002 if (type == Deoptimizer::EAGER) {
8003 RUNTIME_ASSERT(function->IsOptimized());
8004 } else {
8005 RUNTIME_ASSERT(!function->IsOptimized());
8006 }
8007
8008 // Avoid doing too much work when running with --always-opt and keep
8009 // the optimized code around.
8010 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008011 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008012 }
8013
8014 // Count the number of optimized activations of the function.
8015 int activations = 0;
8016 while (!it.done()) {
8017 JavaScriptFrame* frame = it.frame();
8018 if (frame->is_optimized() && frame->function() == *function) {
8019 activations++;
8020 }
8021 it.Advance();
8022 }
8023
8024 // TODO(kasperl): For now, we cannot support removing the optimized
8025 // code when we have recursive invocations of the same function.
8026 if (activations == 0) {
8027 if (FLAG_trace_deopt) {
8028 PrintF("[removing optimized code for: ");
8029 function->PrintName();
8030 PrintF("]\n");
8031 }
8032 function->ReplaceCode(function->shared()->code());
8033 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008034 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008035}
8036
8037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008038RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008039 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008040 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008041 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008042}
8043
8044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008045RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008046 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008047 ASSERT(args.length() == 1);
8048 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008049 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008050
8051 Deoptimizer::DeoptimizeFunction(*function);
8052
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008053 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008054}
8055
8056
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008057RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8058#if defined(USE_SIMULATOR)
8059 return isolate->heap()->true_value();
8060#else
8061 return isolate->heap()->false_value();
8062#endif
8063}
8064
8065
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008066RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8067 HandleScope scope(isolate);
8068 ASSERT(args.length() == 1);
8069 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8070 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8071 function->MarkForLazyRecompilation();
8072 return isolate->heap()->undefined_value();
8073}
8074
8075
lrn@chromium.org1c092762011-05-09 09:42:16 +00008076RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8077 HandleScope scope(isolate);
8078 ASSERT(args.length() == 1);
8079 if (!V8::UseCrankshaft()) {
8080 return Smi::FromInt(4); // 4 == "never".
8081 }
8082 if (FLAG_always_opt) {
8083 return Smi::FromInt(3); // 3 == "always".
8084 }
8085 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8086 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8087 : Smi::FromInt(2); // 2 == "no".
8088}
8089
8090
8091RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8092 HandleScope scope(isolate);
8093 ASSERT(args.length() == 1);
8094 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8095 return Smi::FromInt(function->shared()->opt_count());
8096}
8097
8098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008099RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008100 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008101 ASSERT(args.length() == 1);
8102 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8103
8104 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008105 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008106
8107 // We have hit a back edge in an unoptimized frame for a function that was
8108 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008109 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008110 // Keep track of whether we've succeeded in optimizing.
8111 bool succeeded = unoptimized->optimizable();
8112 if (succeeded) {
8113 // If we are trying to do OSR when there are already optimized
8114 // activations of the function, it means (a) the function is directly or
8115 // indirectly recursive and (b) an optimized invocation has been
8116 // deoptimized so that we are currently in an unoptimized activation.
8117 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008118 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008119 while (succeeded && !it.done()) {
8120 JavaScriptFrame* frame = it.frame();
8121 succeeded = !frame->is_optimized() || frame->function() != *function;
8122 it.Advance();
8123 }
8124 }
8125
8126 int ast_id = AstNode::kNoNumber;
8127 if (succeeded) {
8128 // The top JS function is this one, the PC is somewhere in the
8129 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008130 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008131 JavaScriptFrame* frame = it.frame();
8132 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008133 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008134 ASSERT(unoptimized->contains(frame->pc()));
8135
8136 // Use linear search of the unoptimized code's stack check table to find
8137 // the AST id matching the PC.
8138 Address start = unoptimized->instruction_start();
8139 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008140 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008141 uint32_t table_length = Memory::uint32_at(table_cursor);
8142 table_cursor += kIntSize;
8143 for (unsigned i = 0; i < table_length; ++i) {
8144 // Table entries are (AST id, pc offset) pairs.
8145 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8146 if (pc_offset == target_pc_offset) {
8147 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8148 break;
8149 }
8150 table_cursor += 2 * kIntSize;
8151 }
8152 ASSERT(ast_id != AstNode::kNoNumber);
8153 if (FLAG_trace_osr) {
8154 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8155 function->PrintName();
8156 PrintF("]\n");
8157 }
8158
8159 // Try to compile the optimized code. A true return value from
8160 // CompileOptimized means that compilation succeeded, not necessarily
8161 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008162 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8163 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008164 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8165 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008166 if (data->OsrPcOffset()->value() >= 0) {
8167 if (FLAG_trace_osr) {
8168 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008169 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008170 }
8171 ASSERT(data->OsrAstId()->value() == ast_id);
8172 } else {
8173 // We may never generate the desired OSR entry if we emit an
8174 // early deoptimize.
8175 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008176 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008177 } else {
8178 succeeded = false;
8179 }
8180 }
8181
8182 // Revert to the original stack checks in the original unoptimized code.
8183 if (FLAG_trace_osr) {
8184 PrintF("[restoring original stack checks in ");
8185 function->PrintName();
8186 PrintF("]\n");
8187 }
8188 StackCheckStub check_stub;
8189 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008190 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008191 Deoptimizer::RevertStackCheckCode(*unoptimized,
8192 *check_code,
8193 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008194
8195 // Allow OSR only at nesting level zero again.
8196 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8197
8198 // If the optimization attempt succeeded, return the AST id tagged as a
8199 // smi. This tells the builtin that we need to translate the unoptimized
8200 // frame to an optimized one.
8201 if (succeeded) {
8202 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8203 return Smi::FromInt(ast_id);
8204 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008205 if (function->IsMarkedForLazyRecompilation()) {
8206 function->ReplaceCode(function->shared()->code());
8207 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008208 return Smi::FromInt(-1);
8209 }
8210}
8211
8212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008213RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008214 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008215 ASSERT(args.length() == 1);
8216 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8217 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8218}
8219
8220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008221RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008222 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008223 ASSERT(args.length() == 1);
8224 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8225 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8226}
8227
8228
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008229RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008230 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008231 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008232
kasper.lund7276f142008-07-30 08:49:36 +00008233 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008234 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008235 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008236 { MaybeObject* maybe_result =
8237 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008238 if (!maybe_result->ToObject(&result)) return maybe_result;
8239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008240
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008241 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008242
kasper.lund7276f142008-07-30 08:49:36 +00008243 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008244}
8245
lrn@chromium.org303ada72010-10-27 09:33:13 +00008246
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008247RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8248 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008249 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008250 JSObject* extension_object;
8251 if (args[0]->IsJSObject()) {
8252 extension_object = JSObject::cast(args[0]);
8253 } else {
8254 // Convert the object to a proper JavaScript object.
8255 MaybeObject* maybe_js_object = args[0]->ToObject();
8256 if (!maybe_js_object->To(&extension_object)) {
8257 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8258 HandleScope scope(isolate);
8259 Handle<Object> handle = args.at<Object>(0);
8260 Handle<Object> result =
8261 isolate->factory()->NewTypeError("with_expression",
8262 HandleVector(&handle, 1));
8263 return isolate->Throw(*result);
8264 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008265 return maybe_js_object;
8266 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008267 }
8268 }
8269
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008270 JSFunction* function;
8271 if (args[1]->IsSmi()) {
8272 // A smi sentinel indicates a context nested inside global code rather
8273 // than some function. There is a canonical empty function that can be
8274 // gotten from the global context.
8275 function = isolate->context()->global_context()->closure();
8276 } else {
8277 function = JSFunction::cast(args[1]);
8278 }
8279
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008280 Context* context;
8281 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008282 isolate->heap()->AllocateWithContext(function,
8283 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008284 extension_object);
8285 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008286 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008287 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008288}
8289
8290
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008291RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008292 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008293 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008294 String* name = String::cast(args[0]);
8295 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008296 JSFunction* function;
8297 if (args[2]->IsSmi()) {
8298 // A smi sentinel indicates a context nested inside global code rather
8299 // than some function. There is a canonical empty function that can be
8300 // gotten from the global context.
8301 function = isolate->context()->global_context()->closure();
8302 } else {
8303 function = JSFunction::cast(args[2]);
8304 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008305 Context* context;
8306 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008307 isolate->heap()->AllocateCatchContext(function,
8308 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008309 name,
8310 thrown_object);
8311 if (!maybe_context->To(&context)) return maybe_context;
8312 isolate->set_context(context);
8313 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008314}
8315
8316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008317RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008318 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008319 ASSERT(args.length() == 2);
8320
8321 CONVERT_ARG_CHECKED(Context, context, 0);
8322 CONVERT_ARG_CHECKED(String, name, 1);
8323
8324 int index;
8325 PropertyAttributes attributes;
8326 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008327 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008328
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008329 // If the slot was not found the result is true.
8330 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008331 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008332 }
8333
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008334 // If the slot was found in a context, it should be DONT_DELETE.
8335 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008336 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008337 }
8338
8339 // The slot was found in a JSObject, either a context extension object,
8340 // the global object, or an arguments object. Try to delete it
8341 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8342 // which allows deleting all parameters in functions that mention
8343 // 'arguments', we do this even for the case of slots found on an
8344 // arguments object. The slot was found on an arguments object if the
8345 // index is non-negative.
8346 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8347 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008348 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008349 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008350 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008351 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008352}
8353
8354
ager@chromium.orga1645e22009-09-09 19:27:10 +00008355// A mechanism to return a pair of Object pointers in registers (if possible).
8356// How this is achieved is calling convention-dependent.
8357// All currently supported x86 compiles uses calling conventions that are cdecl
8358// variants where a 64-bit value is returned in two 32-bit registers
8359// (edx:eax on ia32, r1:r0 on ARM).
8360// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8361// In Win64 calling convention, a struct of two pointers is returned in memory,
8362// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008363#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008364struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008365 MaybeObject* x;
8366 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008367};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008368
lrn@chromium.org303ada72010-10-27 09:33:13 +00008369static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008370 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008371 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8372 // In Win64 they are assigned to a hidden first argument.
8373 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008374}
8375#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008376typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008377static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008378 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008379 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008380}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008381#endif
8382
8383
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008384static inline MaybeObject* Unhole(Heap* heap,
8385 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008386 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008387 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8388 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008389 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008390}
8391
8392
danno@chromium.org40cb8782011-05-25 07:58:50 +00008393static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8394 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008395 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008396 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008397 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008398 JSFunction* context_extension_function =
8399 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008400 // If the holder isn't a context extension object, we just return it
8401 // as the receiver. This allows arguments objects to be used as
8402 // receivers, but only if they are put in the context scope chain
8403 // explicitly via a with-statement.
8404 Object* constructor = holder->map()->constructor();
8405 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008406 // Fall back to using the global object as the implicit receiver if
8407 // the property turns out to be a local variable allocated in a
8408 // context extension object - introduced via eval. Implicit global
8409 // receivers are indicated with the hole value.
8410 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008411}
8412
8413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008414static ObjectPair LoadContextSlotHelper(Arguments args,
8415 Isolate* isolate,
8416 bool throw_error) {
8417 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008418 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008419
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008420 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008421 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008422 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008423 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008424 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008425
8426 int index;
8427 PropertyAttributes attributes;
8428 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008429 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008430
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008431 // If the index is non-negative, the slot has been found in a local
8432 // variable or a parameter. Read it from the context object or the
8433 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008434 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008435 // If the "property" we were looking for is a local variable or an
8436 // argument in a context, the receiver is the global object; see
8437 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008438 //
8439 // Use the hole as the receiver to signal that the receiver is
8440 // implicit and that the global receiver should be used.
8441 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008442 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008443 ? Context::cast(*holder)->get(index)
8444 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008445 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008446 }
8447
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008448 // If the holder is found, we read the property from it.
8449 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008450 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008451 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008452 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008453 if (object->IsGlobalObject()) {
8454 receiver = GlobalObject::cast(object)->global_receiver();
8455 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008456 // Use the hole as the receiver to signal that the receiver is
8457 // implicit and that the global receiver should be used.
8458 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008459 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008460 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008461 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008462
8463 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008464 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008465
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008466 // No need to unhole the value here. This is taken care of by the
8467 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008468 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008469 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008470 }
8471
8472 if (throw_error) {
8473 // The property doesn't exist - throw exception.
8474 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008475 isolate->factory()->NewReferenceError("not_defined",
8476 HandleVector(&name, 1));
8477 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008478 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008479 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008480 return MakePair(isolate->heap()->undefined_value(),
8481 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008482 }
8483}
8484
8485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008486RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008487 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008488}
8489
8490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008491RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008492 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008493}
8494
8495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008496RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008497 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008498 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008500 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008501 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008502 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008503 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008504 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8505 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008506 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008507
8508 int index;
8509 PropertyAttributes attributes;
8510 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008511 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008512
8513 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008514 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008515 // Ignore if read_only variable.
8516 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008517 // Context is a fixed array and set cannot fail.
8518 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008519 } else if (strict_mode == kStrictMode) {
8520 // Setting read only property in strict mode.
8521 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008522 isolate->factory()->NewTypeError("strict_cannot_assign",
8523 HandleVector(&name, 1));
8524 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008525 }
8526 } else {
8527 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008528 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008529 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008530 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008531 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008532 return Failure::Exception();
8533 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008534 }
8535 return *value;
8536 }
8537
8538 // Slow case: The property is not in a FixedArray context.
8539 // It is either in an JSObject extension context or it was not found.
8540 Handle<JSObject> context_ext;
8541
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008542 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008543 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008544 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008545 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008546 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008547 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008548
8549 if (strict_mode == kStrictMode) {
8550 // Throw in strict mode (assignment to undefined variable).
8551 Handle<Object> error =
8552 isolate->factory()->NewReferenceError(
8553 "not_defined", HandleVector(&name, 1));
8554 return isolate->Throw(*error);
8555 }
8556 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008557 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008558 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008559 }
8560
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008561 // Set the property, but ignore if read_only variable on the context
8562 // extension object itself.
8563 if ((attributes & READ_ONLY) == 0 ||
8564 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008565 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008566 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008567 SetProperty(context_ext, name, value, NONE, strict_mode));
8568 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008569 // Setting read only property in strict mode.
8570 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008571 isolate->factory()->NewTypeError(
8572 "strict_cannot_assign", HandleVector(&name, 1));
8573 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008574 }
8575 return *value;
8576}
8577
8578
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008579RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008580 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008581 ASSERT(args.length() == 1);
8582
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008583 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008584}
8585
8586
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008587RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008588 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008589 ASSERT(args.length() == 1);
8590
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008591 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008592}
8593
8594
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008595RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008596 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008597 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008598}
8599
8600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008601RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008602 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008603 ASSERT(args.length() == 1);
8604
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008605 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008606 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008607 isolate->factory()->NewReferenceError("not_defined",
8608 HandleVector(&name, 1));
8609 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008610}
8611
8612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008613RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008614 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008615
8616 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008617 if (isolate->stack_guard()->IsStackOverflow()) {
8618 NoHandleAllocation na;
8619 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008620 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008621
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008622 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008623}
8624
8625
8626// NOTE: These PrintXXX functions are defined for all builds (not just
8627// DEBUG builds) because we may want to be able to trace function
8628// calls in all modes.
8629static void PrintString(String* str) {
8630 // not uncommon to have empty strings
8631 if (str->length() > 0) {
8632 SmartPointer<char> s =
8633 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8634 PrintF("%s", *s);
8635 }
8636}
8637
8638
8639static void PrintObject(Object* obj) {
8640 if (obj->IsSmi()) {
8641 PrintF("%d", Smi::cast(obj)->value());
8642 } else if (obj->IsString() || obj->IsSymbol()) {
8643 PrintString(String::cast(obj));
8644 } else if (obj->IsNumber()) {
8645 PrintF("%g", obj->Number());
8646 } else if (obj->IsFailure()) {
8647 PrintF("<failure>");
8648 } else if (obj->IsUndefined()) {
8649 PrintF("<undefined>");
8650 } else if (obj->IsNull()) {
8651 PrintF("<null>");
8652 } else if (obj->IsTrue()) {
8653 PrintF("<true>");
8654 } else if (obj->IsFalse()) {
8655 PrintF("<false>");
8656 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008657 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008658 }
8659}
8660
8661
8662static int StackSize() {
8663 int n = 0;
8664 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8665 return n;
8666}
8667
8668
8669static void PrintTransition(Object* result) {
8670 // indentation
8671 { const int nmax = 80;
8672 int n = StackSize();
8673 if (n <= nmax)
8674 PrintF("%4d:%*s", n, n, "");
8675 else
8676 PrintF("%4d:%*s", n, nmax, "...");
8677 }
8678
8679 if (result == NULL) {
8680 // constructor calls
8681 JavaScriptFrameIterator it;
8682 JavaScriptFrame* frame = it.frame();
8683 if (frame->IsConstructor()) PrintF("new ");
8684 // function name
8685 Object* fun = frame->function();
8686 if (fun->IsJSFunction()) {
8687 PrintObject(JSFunction::cast(fun)->shared()->name());
8688 } else {
8689 PrintObject(fun);
8690 }
8691 // function arguments
8692 // (we are intentionally only printing the actually
8693 // supplied parameters, not all parameters required)
8694 PrintF("(this=");
8695 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008696 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008697 for (int i = 0; i < length; i++) {
8698 PrintF(", ");
8699 PrintObject(frame->GetParameter(i));
8700 }
8701 PrintF(") {\n");
8702
8703 } else {
8704 // function result
8705 PrintF("} -> ");
8706 PrintObject(result);
8707 PrintF("\n");
8708 }
8709}
8710
8711
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008712RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008713 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008714 NoHandleAllocation ha;
8715 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008716 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008717}
8718
8719
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008720RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008721 NoHandleAllocation ha;
8722 PrintTransition(args[0]);
8723 return args[0]; // return TOS
8724}
8725
8726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008727RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008728 NoHandleAllocation ha;
8729 ASSERT(args.length() == 1);
8730
8731#ifdef DEBUG
8732 if (args[0]->IsString()) {
8733 // If we have a string, assume it's a code "marker"
8734 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008735 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008736 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008737 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8738 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008739 } else {
8740 PrintF("DebugPrint: ");
8741 }
8742 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008743 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008744 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008745 HeapObject::cast(args[0])->map()->Print();
8746 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008747#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008748 // ShortPrint is available in release mode. Print is not.
8749 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008750#endif
8751 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008752 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008753
8754 return args[0]; // return TOS
8755}
8756
8757
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008758RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008759 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008760 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008761 isolate->PrintStack();
8762 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008763}
8764
8765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008766RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008767 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008768 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008769
8770 // According to ECMA-262, section 15.9.1, page 117, the precision of
8771 // the number in a Date object representing a particular instant in
8772 // time is milliseconds. Therefore, we floor the result of getting
8773 // the OS time.
8774 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008775 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008776}
8777
8778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008779RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008780 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008781 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008782
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008783 CONVERT_ARG_CHECKED(String, str, 0);
8784 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008785
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008786 CONVERT_ARG_CHECKED(JSArray, output, 1);
8787 RUNTIME_ASSERT(output->HasFastElements());
8788
8789 AssertNoAllocation no_allocation;
8790
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008791 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008792 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8793 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008794 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008795 result = DateParser::Parse(str->ToAsciiVector(),
8796 output_array,
8797 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008798 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008799 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008800 result = DateParser::Parse(str->ToUC16Vector(),
8801 output_array,
8802 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008803 }
8804
8805 if (result) {
8806 return *output;
8807 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008808 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008809 }
8810}
8811
8812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008813RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008814 NoHandleAllocation ha;
8815 ASSERT(args.length() == 1);
8816
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008817 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008818 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008819 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008820}
8821
8822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008823RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008824 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008825 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008826
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008827 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008828}
8829
8830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008831RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008832 NoHandleAllocation ha;
8833 ASSERT(args.length() == 1);
8834
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008835 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008836 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008837}
8838
8839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008840RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008841 ASSERT(args.length() == 1);
8842 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008843 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008844 return JSGlobalObject::cast(global)->global_receiver();
8845}
8846
8847
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008848RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008849 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008850 ASSERT_EQ(1, args.length());
8851 CONVERT_ARG_CHECKED(String, source, 0);
8852
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008853 source = Handle<String>(source->TryFlattenGetString());
8854 // Optimized fast case where we only have ascii characters.
8855 Handle<Object> result;
8856 if (source->IsSeqAsciiString()) {
8857 result = JsonParser<true>::Parse(source);
8858 } else {
8859 result = JsonParser<false>::Parse(source);
8860 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008861 if (result.is_null()) {
8862 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008863 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008864 return Failure::Exception();
8865 }
8866 return *result;
8867}
8868
8869
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008870bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8871 Handle<Context> context) {
8872 if (context->allow_code_gen_from_strings()->IsFalse()) {
8873 // Check with callback if set.
8874 AllowCodeGenerationFromStringsCallback callback =
8875 isolate->allow_code_gen_callback();
8876 if (callback == NULL) {
8877 // No callback set and code generation disallowed.
8878 return false;
8879 } else {
8880 // Callback set. Let it decide if code generation is allowed.
8881 VMState state(isolate, EXTERNAL);
8882 return callback(v8::Utils::ToLocal(context));
8883 }
8884 }
8885 return true;
8886}
8887
8888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008889RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008890 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008891 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008892 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008893
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008894 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008895 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008896
8897 // Check if global context allows code generation from
8898 // strings. Throw an exception if it doesn't.
8899 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8900 return isolate->Throw(*isolate->factory()->NewError(
8901 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8902 }
8903
8904 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008905 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8906 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008907 true,
8908 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008909 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008910 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008911 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8912 context,
8913 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008914 return *fun;
8915}
8916
8917
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008918static ObjectPair CompileGlobalEval(Isolate* isolate,
8919 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008920 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008921 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008922 Handle<Context> context = Handle<Context>(isolate->context());
8923 Handle<Context> global_context = Handle<Context>(context->global_context());
8924
8925 // Check if global context allows code generation from
8926 // strings. Throw an exception if it doesn't.
8927 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8928 isolate->Throw(*isolate->factory()->NewError(
8929 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8930 return MakePair(Failure::Exception(), NULL);
8931 }
8932
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008933 // Deal with a normal eval call with a string argument. Compile it
8934 // and return the compiled function bound in the local context.
8935 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8936 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008937 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008938 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008939 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008940 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008941 Handle<JSFunction> compiled =
8942 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008943 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008944 return MakePair(*compiled, *receiver);
8945}
8946
8947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008948RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008949 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008950
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008951 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008952 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008953 Handle<Object> receiver; // Will be overwritten.
8954
8955 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008956 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008957#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008958 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008959 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008960 StackFrameLocator locator;
8961 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008962 ASSERT(Context::cast(frame->context()) == *context);
8963#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008964
8965 // Find where the 'eval' symbol is bound. It is unaliased only if
8966 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008967 int index = -1;
8968 PropertyAttributes attributes = ABSENT;
8969 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008970 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8971 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008972 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008973 // Stop search when eval is found or when the global context is
8974 // reached.
8975 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008976 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008977 }
8978
iposva@chromium.org245aa852009-02-10 00:49:54 +00008979 // If eval could not be resolved, it has been deleted and we need to
8980 // throw a reference error.
8981 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008982 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008983 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008984 isolate->factory()->NewReferenceError("not_defined",
8985 HandleVector(&name, 1));
8986 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008987 }
8988
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008989 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008990 // 'eval' is not bound in the global context. Just call the function
8991 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008992 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008993 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008994 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008995 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008996 }
8997
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008998 // 'eval' is bound in the global context, but it may have been overwritten.
8999 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009000 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009001 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009002 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009003 }
9004
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009005 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009006 return CompileGlobalEval(isolate,
9007 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009008 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009009 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009010}
9011
9012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009013RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009014 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009015
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009016 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009017 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009018
9019 // 'eval' is bound in the global context, but it may have been overwritten.
9020 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009021 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009022 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009023 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009024 }
9025
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009026 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009027 return CompileGlobalEval(isolate,
9028 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009029 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009030 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009031}
9032
9033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009034RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009035 // This utility adjusts the property attributes for newly created Function
9036 // object ("new Function(...)") by changing the map.
9037 // All it does is changing the prototype property to enumerable
9038 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009039 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009040 ASSERT(args.length() == 1);
9041 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009042
9043 Handle<Map> map = func->shared()->strict_mode()
9044 ? isolate->strict_mode_function_instance_map()
9045 : isolate->function_instance_map();
9046
9047 ASSERT(func->map()->instance_type() == map->instance_type());
9048 ASSERT(func->map()->instance_size() == map->instance_size());
9049 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009050 return *func;
9051}
9052
9053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009054RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009055 // Allocate a block of memory in NewSpace (filled with a filler).
9056 // Use as fallback for allocation in generated code when NewSpace
9057 // is full.
9058 ASSERT(args.length() == 1);
9059 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9060 int size = size_smi->value();
9061 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9062 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009063 Heap* heap = isolate->heap();
9064 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009065 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009066 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009067 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009068 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009069 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009070 }
9071 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009072 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009073}
9074
9075
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009076// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009077// array. Returns true if the element was pushed on the stack and
9078// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009079RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009080 ASSERT(args.length() == 2);
9081 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009082 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009083 RUNTIME_ASSERT(array->HasFastElements());
9084 int length = Smi::cast(array->length())->value();
9085 FixedArray* elements = FixedArray::cast(array->elements());
9086 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009087 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009088 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009089 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009090 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009091 { MaybeObject* maybe_obj =
9092 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009093 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9094 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009095 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009096}
9097
9098
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009099/**
9100 * A simple visitor visits every element of Array's.
9101 * The backend storage can be a fixed array for fast elements case,
9102 * or a dictionary for sparse array. Since Dictionary is a subtype
9103 * of FixedArray, the class can be used by both fast and slow cases.
9104 * The second parameter of the constructor, fast_elements, specifies
9105 * whether the storage is a FixedArray or Dictionary.
9106 *
9107 * An index limit is used to deal with the situation that a result array
9108 * length overflows 32-bit non-negative integer.
9109 */
9110class ArrayConcatVisitor {
9111 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009112 ArrayConcatVisitor(Isolate* isolate,
9113 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009114 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009115 isolate_(isolate),
9116 storage_(Handle<FixedArray>::cast(
9117 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009118 index_offset_(0u),
9119 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009120
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009121 ~ArrayConcatVisitor() {
9122 clear_storage();
9123 }
9124
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009125 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009126 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009127 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009128
9129 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009130 if (index < static_cast<uint32_t>(storage_->length())) {
9131 storage_->set(index, *elm);
9132 return;
9133 }
9134 // Our initial estimate of length was foiled, possibly by
9135 // getters on the arrays increasing the length of later arrays
9136 // during iteration.
9137 // This shouldn't happen in anything but pathological cases.
9138 SetDictionaryMode(index);
9139 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009140 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009141 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009142 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009143 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009144 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009145 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009146 // Dictionary needed to grow.
9147 clear_storage();
9148 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009149 }
9150}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009151
9152 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009153 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9154 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009155 } else {
9156 index_offset_ += delta;
9157 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009158 }
9159
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009160 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009161 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009162 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009163 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009164 Handle<Map> map;
9165 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009166 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009167 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009168 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009169 }
9170 array->set_map(*map);
9171 array->set_length(*length);
9172 array->set_elements(*storage_);
9173 return array;
9174 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009175
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009176 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009177 // Convert storage to dictionary mode.
9178 void SetDictionaryMode(uint32_t index) {
9179 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009180 Handle<FixedArray> current_storage(*storage_);
9181 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009182 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009183 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9184 for (uint32_t i = 0; i < current_length; i++) {
9185 HandleScope loop_scope;
9186 Handle<Object> element(current_storage->get(i));
9187 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009188 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009189 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009190 if (!new_storage.is_identical_to(slow_storage)) {
9191 slow_storage = loop_scope.CloseAndEscape(new_storage);
9192 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009193 }
9194 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009195 clear_storage();
9196 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009197 fast_elements_ = false;
9198 }
9199
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009200 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009201 isolate_->global_handles()->Destroy(
9202 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009203 }
9204
9205 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009206 storage_ = Handle<FixedArray>::cast(
9207 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009208 }
9209
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009210 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009211 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009212 // Index after last seen index. Always less than or equal to
9213 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009214 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009215 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009216};
9217
9218
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009219static uint32_t EstimateElementCount(Handle<JSArray> array) {
9220 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9221 int element_count = 0;
9222 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009223 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009224 // Fast elements can't have lengths that are not representable by
9225 // a 32-bit signed integer.
9226 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9227 int fast_length = static_cast<int>(length);
9228 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9229 for (int i = 0; i < fast_length; i++) {
9230 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009231 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009232 break;
9233 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009234 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009235 Handle<NumberDictionary> dictionary(
9236 NumberDictionary::cast(array->elements()));
9237 int capacity = dictionary->Capacity();
9238 for (int i = 0; i < capacity; i++) {
9239 Handle<Object> key(dictionary->KeyAt(i));
9240 if (dictionary->IsKey(*key)) {
9241 element_count++;
9242 }
9243 }
9244 break;
9245 }
9246 default:
9247 // External arrays are always dense.
9248 return length;
9249 }
9250 // As an estimate, we assume that the prototype doesn't contain any
9251 // inherited elements.
9252 return element_count;
9253}
9254
9255
9256
9257template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009258static void IterateExternalArrayElements(Isolate* isolate,
9259 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009260 bool elements_are_ints,
9261 bool elements_are_guaranteed_smis,
9262 ArrayConcatVisitor* visitor) {
9263 Handle<ExternalArrayClass> array(
9264 ExternalArrayClass::cast(receiver->elements()));
9265 uint32_t len = static_cast<uint32_t>(array->length());
9266
9267 ASSERT(visitor != NULL);
9268 if (elements_are_ints) {
9269 if (elements_are_guaranteed_smis) {
9270 for (uint32_t j = 0; j < len; j++) {
9271 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009272 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009273 visitor->visit(j, e);
9274 }
9275 } else {
9276 for (uint32_t j = 0; j < len; j++) {
9277 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009278 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009279 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9280 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9281 visitor->visit(j, e);
9282 } else {
9283 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009284 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009285 visitor->visit(j, e);
9286 }
9287 }
9288 }
9289 } else {
9290 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009291 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009292 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009293 visitor->visit(j, e);
9294 }
9295 }
9296}
9297
9298
9299// Used for sorting indices in a List<uint32_t>.
9300static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9301 uint32_t a = *ap;
9302 uint32_t b = *bp;
9303 return (a == b) ? 0 : (a < b) ? -1 : 1;
9304}
9305
9306
9307static void CollectElementIndices(Handle<JSObject> object,
9308 uint32_t range,
9309 List<uint32_t>* indices) {
9310 JSObject::ElementsKind kind = object->GetElementsKind();
9311 switch (kind) {
9312 case JSObject::FAST_ELEMENTS: {
9313 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9314 uint32_t length = static_cast<uint32_t>(elements->length());
9315 if (range < length) length = range;
9316 for (uint32_t i = 0; i < length; i++) {
9317 if (!elements->get(i)->IsTheHole()) {
9318 indices->Add(i);
9319 }
9320 }
9321 break;
9322 }
9323 case JSObject::DICTIONARY_ELEMENTS: {
9324 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009325 uint32_t capacity = dict->Capacity();
9326 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009327 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009328 Handle<Object> k(dict->KeyAt(j));
9329 if (dict->IsKey(*k)) {
9330 ASSERT(k->IsNumber());
9331 uint32_t index = static_cast<uint32_t>(k->Number());
9332 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009333 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009334 }
9335 }
9336 }
9337 break;
9338 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009339 default: {
9340 int dense_elements_length;
9341 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009342 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009343 dense_elements_length =
9344 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009345 break;
9346 }
9347 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009348 dense_elements_length =
9349 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009350 break;
9351 }
9352 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009353 dense_elements_length =
9354 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009355 break;
9356 }
9357 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009358 dense_elements_length =
9359 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009360 break;
9361 }
9362 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009363 dense_elements_length =
9364 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009365 break;
9366 }
9367 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009368 dense_elements_length =
9369 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009370 break;
9371 }
9372 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009373 dense_elements_length =
9374 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009375 break;
9376 }
9377 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009378 dense_elements_length =
9379 ExternalFloatArray::cast(object->elements())->length();
9380 break;
9381 }
9382 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9383 dense_elements_length =
9384 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009385 break;
9386 }
9387 default:
9388 UNREACHABLE();
9389 dense_elements_length = 0;
9390 break;
9391 }
9392 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9393 if (range <= length) {
9394 length = range;
9395 // We will add all indices, so we might as well clear it first
9396 // and avoid duplicates.
9397 indices->Clear();
9398 }
9399 for (uint32_t i = 0; i < length; i++) {
9400 indices->Add(i);
9401 }
9402 if (length == range) return; // All indices accounted for already.
9403 break;
9404 }
9405 }
9406
9407 Handle<Object> prototype(object->GetPrototype());
9408 if (prototype->IsJSObject()) {
9409 // The prototype will usually have no inherited element indices,
9410 // but we have to check.
9411 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9412 }
9413}
9414
9415
9416/**
9417 * A helper function that visits elements of a JSArray in numerical
9418 * order.
9419 *
9420 * The visitor argument called for each existing element in the array
9421 * with the element index and the element's value.
9422 * Afterwards it increments the base-index of the visitor by the array
9423 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009424 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009425 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009426static bool IterateElements(Isolate* isolate,
9427 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009428 ArrayConcatVisitor* visitor) {
9429 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9430 switch (receiver->GetElementsKind()) {
9431 case JSObject::FAST_ELEMENTS: {
9432 // Run through the elements FixedArray and use HasElement and GetElement
9433 // to check the prototype for missing elements.
9434 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9435 int fast_length = static_cast<int>(length);
9436 ASSERT(fast_length <= elements->length());
9437 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009438 HandleScope loop_scope(isolate);
9439 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009440 if (!element_value->IsTheHole()) {
9441 visitor->visit(j, element_value);
9442 } else if (receiver->HasElement(j)) {
9443 // Call GetElement on receiver, not its prototype, or getters won't
9444 // have the correct receiver.
9445 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009446 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009447 visitor->visit(j, element_value);
9448 }
9449 }
9450 break;
9451 }
9452 case JSObject::DICTIONARY_ELEMENTS: {
9453 Handle<NumberDictionary> dict(receiver->element_dictionary());
9454 List<uint32_t> indices(dict->Capacity() / 2);
9455 // Collect all indices in the object and the prototypes less
9456 // than length. This might introduce duplicates in the indices list.
9457 CollectElementIndices(receiver, length, &indices);
9458 indices.Sort(&compareUInt32);
9459 int j = 0;
9460 int n = indices.length();
9461 while (j < n) {
9462 HandleScope loop_scope;
9463 uint32_t index = indices[j];
9464 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009465 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009466 visitor->visit(index, element);
9467 // Skip to next different index (i.e., omit duplicates).
9468 do {
9469 j++;
9470 } while (j < n && indices[j] == index);
9471 }
9472 break;
9473 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009474 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9475 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9476 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009477 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009478 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009479 visitor->visit(j, e);
9480 }
9481 break;
9482 }
9483 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9484 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009485 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009486 break;
9487 }
9488 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9489 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009490 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009491 break;
9492 }
9493 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9494 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009495 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009496 break;
9497 }
9498 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9499 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009500 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009501 break;
9502 }
9503 case JSObject::EXTERNAL_INT_ELEMENTS: {
9504 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009505 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009506 break;
9507 }
9508 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9509 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009510 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009511 break;
9512 }
9513 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9514 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009515 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009516 break;
9517 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009518 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9519 IterateExternalArrayElements<ExternalDoubleArray, double>(
9520 isolate, receiver, false, false, visitor);
9521 break;
9522 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009523 default:
9524 UNREACHABLE();
9525 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009526 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009527 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009528 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009529}
9530
9531
9532/**
9533 * Array::concat implementation.
9534 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009535 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009536 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009537 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009538RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009539 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009540 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009541
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009542 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9543 int argument_count = static_cast<int>(arguments->length()->Number());
9544 RUNTIME_ASSERT(arguments->HasFastElements());
9545 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009546
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009547 // Pass 1: estimate the length and number of elements of the result.
9548 // The actual length can be larger if any of the arguments have getters
9549 // that mutate other arguments (but will otherwise be precise).
9550 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009551
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009552 uint32_t estimate_result_length = 0;
9553 uint32_t estimate_nof_elements = 0;
9554 {
9555 for (int i = 0; i < argument_count; i++) {
9556 HandleScope loop_scope;
9557 Handle<Object> obj(elements->get(i));
9558 uint32_t length_estimate;
9559 uint32_t element_estimate;
9560 if (obj->IsJSArray()) {
9561 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9562 length_estimate =
9563 static_cast<uint32_t>(array->length()->Number());
9564 element_estimate =
9565 EstimateElementCount(array);
9566 } else {
9567 length_estimate = 1;
9568 element_estimate = 1;
9569 }
9570 // Avoid overflows by capping at kMaxElementCount.
9571 if (JSObject::kMaxElementCount - estimate_result_length <
9572 length_estimate) {
9573 estimate_result_length = JSObject::kMaxElementCount;
9574 } else {
9575 estimate_result_length += length_estimate;
9576 }
9577 if (JSObject::kMaxElementCount - estimate_nof_elements <
9578 element_estimate) {
9579 estimate_nof_elements = JSObject::kMaxElementCount;
9580 } else {
9581 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009582 }
9583 }
9584 }
9585
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009586 // If estimated number of elements is more than half of length, a
9587 // fixed array (fast case) is more time and space-efficient than a
9588 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009589 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009590
9591 Handle<FixedArray> storage;
9592 if (fast_case) {
9593 // The backing storage array must have non-existing elements to
9594 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009595 storage = isolate->factory()->NewFixedArrayWithHoles(
9596 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009597 } else {
9598 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9599 uint32_t at_least_space_for = estimate_nof_elements +
9600 (estimate_nof_elements >> 2);
9601 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009602 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009603 }
9604
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009605 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009606
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009607 for (int i = 0; i < argument_count; i++) {
9608 Handle<Object> obj(elements->get(i));
9609 if (obj->IsJSArray()) {
9610 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009611 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009612 return Failure::Exception();
9613 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009614 } else {
9615 visitor.visit(0, obj);
9616 visitor.increase_index_offset(1);
9617 }
9618 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009619
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009620 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009621}
9622
9623
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009624// This will not allocate (flatten the string), but it may run
9625// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009626RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009627 NoHandleAllocation ha;
9628 ASSERT(args.length() == 1);
9629
9630 CONVERT_CHECKED(String, string, args[0]);
9631 StringInputBuffer buffer(string);
9632 while (buffer.has_more()) {
9633 uint16_t character = buffer.GetNext();
9634 PrintF("%c", character);
9635 }
9636 return string;
9637}
9638
ager@chromium.org5ec48922009-05-05 07:25:34 +00009639// Moves all own elements of an object, that are below a limit, to positions
9640// starting at zero. All undefined values are placed after non-undefined values,
9641// and are followed by non-existing element. Does not change the length
9642// property.
9643// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009644RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009645 ASSERT(args.length() == 2);
9646 CONVERT_CHECKED(JSObject, object, args[0]);
9647 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9648 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009649}
9650
9651
9652// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009653RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009654 ASSERT(args.length() == 2);
9655 CONVERT_CHECKED(JSArray, from, args[0]);
9656 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009657 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009658 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009659 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9660 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009661 maybe_new_map = to->map()->GetFastElementsMap();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009662 } else if (new_elements->map() ==
9663 isolate->heap()->fixed_double_array_map()) {
9664 maybe_new_map = to->map()->GetFastDoubleElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009665 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009666 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009667 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009668 Object* new_map;
9669 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009670 to->set_map(Map::cast(new_map));
9671 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009672 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009673 Object* obj;
9674 { MaybeObject* maybe_obj = from->ResetElements();
9675 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9676 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009677 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009678 return to;
9679}
9680
9681
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009682// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009683RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009684 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009685 CONVERT_CHECKED(JSObject, object, args[0]);
9686 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009687 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009688 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009689 } else if (object->IsJSArray()) {
9690 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009691 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009692 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009693 }
9694}
9695
9696
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009697RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009698 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009699
9700 ASSERT_EQ(3, args.length());
9701
ager@chromium.orgac091b72010-05-05 07:34:42 +00009702 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009703 Handle<Object> key1 = args.at<Object>(1);
9704 Handle<Object> key2 = args.at<Object>(2);
9705
9706 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009707 if (!key1->ToArrayIndex(&index1)
9708 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009709 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009710 }
9711
ager@chromium.orgac091b72010-05-05 07:34:42 +00009712 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9713 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009714 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009715 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009716 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009717
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009718 RETURN_IF_EMPTY_HANDLE(isolate,
9719 SetElement(jsobject, index1, tmp2, kStrictMode));
9720 RETURN_IF_EMPTY_HANDLE(isolate,
9721 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009722
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009723 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009724}
9725
9726
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009727// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009728// might have elements. Can either return keys (positive integers) or
9729// intervals (pair of a negative integer (-start-1) followed by a
9730// positive (length)) or undefined values.
9731// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009732RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009733 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009734 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009735 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009736 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009737 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009738 // Create an array and get all the keys into it, then remove all the
9739 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009740 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009741 int keys_length = keys->length();
9742 for (int i = 0; i < keys_length; i++) {
9743 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009744 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009745 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009746 // Zap invalid keys.
9747 keys->set_undefined(i);
9748 }
9749 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009750 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009751 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009752 ASSERT(array->HasFastElements() || array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009753 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009754 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009755 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009756 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009757 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009758 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009759 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009760 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009761 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009762 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009763 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009764 }
9765}
9766
9767
9768// DefineAccessor takes an optional final argument which is the
9769// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9770// to the way accessors are implemented, it is set for both the getter
9771// and setter on the first call to DefineAccessor and ignored on
9772// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009773RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009774 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9775 // Compute attributes.
9776 PropertyAttributes attributes = NONE;
9777 if (args.length() == 5) {
9778 CONVERT_CHECKED(Smi, attrs, args[4]);
9779 int value = attrs->value();
9780 // Only attribute bits should be set.
9781 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9782 attributes = static_cast<PropertyAttributes>(value);
9783 }
9784
9785 CONVERT_CHECKED(JSObject, obj, args[0]);
9786 CONVERT_CHECKED(String, name, args[1]);
9787 CONVERT_CHECKED(Smi, flag, args[2]);
9788 CONVERT_CHECKED(JSFunction, fun, args[3]);
9789 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9790}
9791
9792
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009793RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009794 ASSERT(args.length() == 3);
9795 CONVERT_CHECKED(JSObject, obj, args[0]);
9796 CONVERT_CHECKED(String, name, args[1]);
9797 CONVERT_CHECKED(Smi, flag, args[2]);
9798 return obj->LookupAccessor(name, flag->value() == 0);
9799}
9800
9801
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009802#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009803RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009804 ASSERT(args.length() == 0);
9805 return Execution::DebugBreakHelper();
9806}
9807
9808
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009809// Helper functions for wrapping and unwrapping stack frame ids.
9810static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009811 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009812 return Smi::FromInt(id >> 2);
9813}
9814
9815
9816static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9817 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9818}
9819
9820
9821// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009822// args[0]: debug event listener function to set or null or undefined for
9823// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009824// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009825RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009826 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009827 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9828 args[0]->IsUndefined() ||
9829 args[0]->IsNull());
9830 Handle<Object> callback = args.at<Object>(0);
9831 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009832 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009833
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009834 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009835}
9836
9837
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009838RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009839 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009840 isolate->stack_guard()->DebugBreak();
9841 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009842}
9843
9844
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009845static MaybeObject* DebugLookupResultValue(Heap* heap,
9846 Object* receiver,
9847 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009848 LookupResult* result,
9849 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009850 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009851 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009852 case NORMAL:
9853 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009854 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009855 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009856 }
9857 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009858 case FIELD:
9859 value =
9860 JSObject::cast(
9861 result->holder())->FastPropertyAt(result->GetFieldIndex());
9862 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009863 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009864 }
9865 return value;
9866 case CONSTANT_FUNCTION:
9867 return result->GetConstantFunction();
9868 case CALLBACKS: {
9869 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009870 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009871 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009872 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009873 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009874 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009875 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009876 maybe_value = heap->isolate()->pending_exception();
9877 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009878 if (caught_exception != NULL) {
9879 *caught_exception = true;
9880 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009881 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009882 }
9883 return value;
9884 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009885 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009886 }
9887 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009888 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009889 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009890 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009891 case CONSTANT_TRANSITION:
9892 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009893 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009894 default:
9895 UNREACHABLE();
9896 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009897 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009898 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009899}
9900
9901
ager@chromium.org32912102009-01-16 10:38:43 +00009902// Get debugger related details for an object property.
9903// args[0]: object holding property
9904// args[1]: name of the property
9905//
9906// The array returned contains the following information:
9907// 0: Property value
9908// 1: Property details
9909// 2: Property value is exception
9910// 3: Getter function if defined
9911// 4: Setter function if defined
9912// Items 2-4 are only filled if the property has either a getter or a setter
9913// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009914RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009915 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009916
9917 ASSERT(args.length() == 2);
9918
9919 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9920 CONVERT_ARG_CHECKED(String, name, 1);
9921
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009922 // Make sure to set the current context to the context before the debugger was
9923 // entered (if the debugger is entered). The reason for switching context here
9924 // is that for some property lookups (accessors and interceptors) callbacks
9925 // into the embedding application can occour, and the embedding application
9926 // could have the assumption that its own global context is the current
9927 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009928 SaveContext save(isolate);
9929 if (isolate->debug()->InDebugger()) {
9930 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009931 }
9932
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009933 // Skip the global proxy as it has no properties and always delegates to the
9934 // real global object.
9935 if (obj->IsJSGlobalProxy()) {
9936 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9937 }
9938
9939
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009940 // Check if the name is trivially convertible to an index and get the element
9941 // if so.
9942 uint32_t index;
9943 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009944 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009945 Object* element_or_char;
9946 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009947 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009948 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9949 return maybe_element_or_char;
9950 }
9951 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009952 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009953 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009954 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009955 }
9956
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009957 // Find the number of objects making up this.
9958 int length = LocalPrototypeChainLength(*obj);
9959
9960 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009961 Handle<JSObject> jsproto = obj;
9962 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009963 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009964 jsproto->LocalLookup(*name, &result);
9965 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009966 // LookupResult is not GC safe as it holds raw object pointers.
9967 // GC can happen later in this code so put the required fields into
9968 // local variables using handles when required for later use.
9969 PropertyType result_type = result.type();
9970 Handle<Object> result_callback_obj;
9971 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009972 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9973 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009974 }
9975 Smi* property_details = result.GetPropertyDetails().AsSmi();
9976 // DebugLookupResultValue can cause GC so details from LookupResult needs
9977 // to be copied to handles before this.
9978 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009979 Object* raw_value;
9980 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009981 DebugLookupResultValue(isolate->heap(), *obj, *name,
9982 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009983 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9984 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009985 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009986
9987 // If the callback object is a fixed array then it contains JavaScript
9988 // getter and/or setter.
9989 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9990 result_callback_obj->IsFixedArray();
9991 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009992 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009993 details->set(0, *value);
9994 details->set(1, property_details);
9995 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009996 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009997 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9998 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9999 }
10000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010001 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010002 }
10003 if (i < length - 1) {
10004 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10005 }
10006 }
10007
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010008 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010009}
10010
10011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010012RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010013 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010014
10015 ASSERT(args.length() == 2);
10016
10017 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10018 CONVERT_ARG_CHECKED(String, name, 1);
10019
10020 LookupResult result;
10021 obj->Lookup(*name, &result);
10022 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010023 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010024 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010025 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010026}
10027
10028
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010029// Return the property type calculated from the property details.
10030// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010031RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010032 ASSERT(args.length() == 1);
10033 CONVERT_CHECKED(Smi, details, args[0]);
10034 PropertyType type = PropertyDetails(details).type();
10035 return Smi::FromInt(static_cast<int>(type));
10036}
10037
10038
10039// Return the property attribute calculated from the property details.
10040// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010041RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010042 ASSERT(args.length() == 1);
10043 CONVERT_CHECKED(Smi, details, args[0]);
10044 PropertyAttributes attributes = PropertyDetails(details).attributes();
10045 return Smi::FromInt(static_cast<int>(attributes));
10046}
10047
10048
10049// Return the property insertion index calculated from the property details.
10050// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010051RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010052 ASSERT(args.length() == 1);
10053 CONVERT_CHECKED(Smi, details, args[0]);
10054 int index = PropertyDetails(details).index();
10055 return Smi::FromInt(index);
10056}
10057
10058
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010059// Return property value from named interceptor.
10060// args[0]: object
10061// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010062RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010063 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010064 ASSERT(args.length() == 2);
10065 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10066 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10067 CONVERT_ARG_CHECKED(String, name, 1);
10068
10069 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010070 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010071}
10072
10073
10074// Return element value from indexed interceptor.
10075// args[0]: object
10076// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010077RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010078 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010079 ASSERT(args.length() == 2);
10080 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10081 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10082 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10083
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010084 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010085}
10086
10087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010088RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010089 ASSERT(args.length() >= 1);
10090 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010091 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010092 if (isolate->debug()->break_id() == 0 ||
10093 break_id != isolate->debug()->break_id()) {
10094 return isolate->Throw(
10095 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010096 }
10097
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010098 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010099}
10100
10101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010102RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010103 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010104 ASSERT(args.length() == 1);
10105
10106 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010107 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010108 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10109 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010110 if (!maybe_result->ToObject(&result)) return maybe_result;
10111 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010112
10113 // Count all frames which are relevant to debugging stack trace.
10114 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010115 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010116 if (id == StackFrame::NO_ID) {
10117 // If there is no JavaScript stack frame count is 0.
10118 return Smi::FromInt(0);
10119 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010120
10121 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10122 n += it.frame()->GetInlineCount();
10123 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010124 return Smi::FromInt(n);
10125}
10126
10127
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010128class FrameInspector {
10129 public:
10130 FrameInspector(JavaScriptFrame* frame,
10131 int inlined_frame_index,
10132 Isolate* isolate)
10133 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10134 // Calculate the deoptimized frame.
10135 if (frame->is_optimized()) {
10136 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10137 frame, inlined_frame_index, isolate);
10138 }
10139 has_adapted_arguments_ = frame_->has_adapted_arguments();
10140 is_optimized_ = frame_->is_optimized();
10141 }
10142
10143 ~FrameInspector() {
10144 // Get rid of the calculated deoptimized frame if any.
10145 if (deoptimized_frame_ != NULL) {
10146 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10147 isolate_);
10148 }
10149 }
10150
10151 int GetParametersCount() {
10152 return is_optimized_
10153 ? deoptimized_frame_->parameters_count()
10154 : frame_->ComputeParametersCount();
10155 }
10156 int expression_count() { return deoptimized_frame_->expression_count(); }
10157 Object* GetFunction() {
10158 return is_optimized_
10159 ? deoptimized_frame_->GetFunction()
10160 : frame_->function();
10161 }
10162 Object* GetParameter(int index) {
10163 return is_optimized_
10164 ? deoptimized_frame_->GetParameter(index)
10165 : frame_->GetParameter(index);
10166 }
10167 Object* GetExpression(int index) {
10168 return is_optimized_
10169 ? deoptimized_frame_->GetExpression(index)
10170 : frame_->GetExpression(index);
10171 }
10172
10173 // To inspect all the provided arguments the frame might need to be
10174 // replaced with the arguments frame.
10175 void SetArgumentsFrame(JavaScriptFrame* frame) {
10176 ASSERT(has_adapted_arguments_);
10177 frame_ = frame;
10178 is_optimized_ = frame_->is_optimized();
10179 ASSERT(!is_optimized_);
10180 }
10181
10182 private:
10183 JavaScriptFrame* frame_;
10184 DeoptimizedFrameInfo* deoptimized_frame_;
10185 Isolate* isolate_;
10186 bool is_optimized_;
10187 bool has_adapted_arguments_;
10188
10189 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10190};
10191
10192
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010193static const int kFrameDetailsFrameIdIndex = 0;
10194static const int kFrameDetailsReceiverIndex = 1;
10195static const int kFrameDetailsFunctionIndex = 2;
10196static const int kFrameDetailsArgumentCountIndex = 3;
10197static const int kFrameDetailsLocalCountIndex = 4;
10198static const int kFrameDetailsSourcePositionIndex = 5;
10199static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010200static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010201static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010202static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010203
10204// Return an array with frame details
10205// args[0]: number: break id
10206// args[1]: number: frame index
10207//
10208// The array returned contains the following information:
10209// 0: Frame id
10210// 1: Receiver
10211// 2: Function
10212// 3: Argument count
10213// 4: Local count
10214// 5: Source position
10215// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010216// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010217// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010218// Arguments name, value
10219// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010220// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010221RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010222 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010223 ASSERT(args.length() == 2);
10224
10225 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010226 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010227 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10228 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010229 if (!maybe_check->ToObject(&check)) return maybe_check;
10230 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010231 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010232 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010233
10234 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010235 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010236 if (id == StackFrame::NO_ID) {
10237 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010238 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010239 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010240
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010241 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010242
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010243 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010244 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010246 if (index < count + it.frame()->GetInlineCount()) break;
10247 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010248 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010249 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010250
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010251 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010252 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010253 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010254 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010255 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010256
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010257 // Traverse the saved contexts chain to find the active context for the
10258 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010259 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010260 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010261 save = save->prev();
10262 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010263 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264
10265 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010266 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010267
10268 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010269 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010270 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010271
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010272 // Check for constructor frame. Inlined frames cannot be construct calls.
10273 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010274 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010275 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010276
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010277 // Get scope info and read from it for local variable information.
10278 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010279 Handle<SharedFunctionInfo> shared(function->shared());
10280 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010281 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010282 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010283
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284 // Get the locals names and values into a temporary array.
10285 //
10286 // TODO(1240907): Hide compiler-introduced stack variables
10287 // (e.g. .result)? For users of the debugger, they will probably be
10288 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010289 Handle<FixedArray> locals =
10290 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010291
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010292 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010293 int i = 0;
10294 for (; i < info.number_of_stack_slots(); ++i) {
10295 // Use the value from the stack.
10296 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010297 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010298 }
10299 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010300 // Get the context containing declarations.
10301 Handle<Context> context(
10302 Context::cast(it.frame()->context())->declaration_context());
10303 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010304 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010305 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010306 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010307 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010308 }
10309 }
10310
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010311 // Check whether this frame is positioned at return. If not top
10312 // frame or if the frame is optimized it cannot be at a return.
10313 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010314 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010315 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010316 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010317
10318 // If positioned just before return find the value to be returned and add it
10319 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010320 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010321 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010322 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010323 Address internal_frame_sp = NULL;
10324 while (!it2.done()) {
10325 if (it2.frame()->is_internal()) {
10326 internal_frame_sp = it2.frame()->sp();
10327 } else {
10328 if (it2.frame()->is_java_script()) {
10329 if (it2.frame()->id() == it.frame()->id()) {
10330 // The internal frame just before the JavaScript frame contains the
10331 // value to return on top. A debug break at return will create an
10332 // internal frame to store the return value (eax/rax/r0) before
10333 // entering the debug break exit frame.
10334 if (internal_frame_sp != NULL) {
10335 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010336 Handle<Object>(Memory::Object_at(internal_frame_sp),
10337 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010338 break;
10339 }
10340 }
10341 }
10342
10343 // Indicate that the previous frame was not an internal frame.
10344 internal_frame_sp = NULL;
10345 }
10346 it2.Advance();
10347 }
10348 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010349
10350 // Now advance to the arguments adapter frame (if any). It contains all
10351 // the provided parameters whereas the function frame always have the number
10352 // of arguments matching the functions parameters. The rest of the
10353 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010354 if (it.frame()->has_adapted_arguments()) {
10355 it.AdvanceToArgumentsFrame();
10356 frame_inspector.SetArgumentsFrame(it.frame());
10357 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010358
10359 // Find the number of arguments to fill. At least fill the number of
10360 // parameters for the function and fill more if more parameters are provided.
10361 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010362 if (argument_count < frame_inspector.GetParametersCount()) {
10363 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010364 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010365#ifdef DEBUG
10366 if (it.frame()->is_optimized()) {
10367 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10368 }
10369#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010370
10371 // Calculate the size of the result.
10372 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010373 2 * (argument_count + info.NumberOfLocals()) +
10374 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010375 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010376
10377 // Add the frame id.
10378 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10379
10380 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010381 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010382
10383 // Add the arguments count.
10384 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10385
10386 // Add the locals count
10387 details->set(kFrameDetailsLocalCountIndex,
10388 Smi::FromInt(info.NumberOfLocals()));
10389
10390 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010391 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010392 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10393 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010394 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010395 }
10396
10397 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010398 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010399
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010400 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010401 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010402
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010403 // Add flags to indicate information on whether this frame is
10404 // bit 0: invoked in the debugger context.
10405 // bit 1: optimized frame.
10406 // bit 2: inlined in optimized frame
10407 int flags = 0;
10408 if (*save->context() == *isolate->debug()->debug_context()) {
10409 flags |= 1 << 0;
10410 }
10411 if (it.frame()->is_optimized()) {
10412 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010413 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010414 }
10415 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010416
10417 // Fill the dynamic part.
10418 int details_index = kFrameDetailsFirstDynamicIndex;
10419
10420 // Add arguments name and value.
10421 for (int i = 0; i < argument_count; i++) {
10422 // Name of the argument.
10423 if (i < info.number_of_parameters()) {
10424 details->set(details_index++, *info.parameter_name(i));
10425 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010426 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010427 }
10428
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010429 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010430 if (i < it.frame()->ComputeParametersCount()) {
10431 // Get the value from the stack.
10432 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010433 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010434 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010435 }
10436 }
10437
10438 // Add locals name and value from the temporary copy from the function frame.
10439 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10440 details->set(details_index++, locals->get(i));
10441 }
10442
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010443 // Add the value being returned.
10444 if (at_return) {
10445 details->set(details_index++, *return_value);
10446 }
10447
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010448 // Add the receiver (same as in function frame).
10449 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10450 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010451 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010452 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10453 // If the receiver is not a JSObject and the function is not a
10454 // builtin or strict-mode we have hit an optimization where a
10455 // value object is not converted into a wrapped JS objects. To
10456 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010457 // by creating correct wrapper object based on the calling frame's
10458 // global context.
10459 it.Advance();
10460 Handle<Context> calling_frames_global_context(
10461 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010462 receiver =
10463 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010464 }
10465 details->set(kFrameDetailsReceiverIndex, *receiver);
10466
10467 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010468 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010469}
10470
10471
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010472// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010473static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010474 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010475 Handle<SerializedScopeInfo> serialized_scope_info,
10476 ScopeInfo<>& scope_info,
10477 Handle<Context> context,
10478 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010479 // Fill all context locals to the context extension.
10480 for (int i = Context::MIN_CONTEXT_SLOTS;
10481 i < scope_info.number_of_context_slots();
10482 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010483 int context_index = serialized_scope_info->ContextSlotIndex(
10484 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010485
whesse@chromium.org7b260152011-06-20 15:33:18 +000010486 RETURN_IF_EMPTY_HANDLE_VALUE(
10487 isolate,
10488 SetProperty(scope_object,
10489 scope_info.context_slot_name(i),
10490 Handle<Object>(context->get(context_index), isolate),
10491 NONE,
10492 kNonStrictMode),
10493 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010494 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010495
10496 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010497}
10498
10499
10500// Create a plain JSObject which materializes the local scope for the specified
10501// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010502static Handle<JSObject> MaterializeLocalScope(
10503 Isolate* isolate,
10504 JavaScriptFrame* frame,
10505 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010506 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010507 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010508 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10509 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010510 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010511
10512 // Allocate and initialize a JSObject with all the arguments, stack locals
10513 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010514 Handle<JSObject> local_scope =
10515 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010516
10517 // First fill all parameters.
10518 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010519 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010520 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010521 SetProperty(local_scope,
10522 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010523 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010524 NONE,
10525 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010526 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010527 }
10528
10529 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010530 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010531 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010532 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010533 SetProperty(local_scope,
10534 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010535 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010536 NONE,
10537 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010538 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010539 }
10540
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010541 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10542 // Third fill all context locals.
10543 Handle<Context> frame_context(Context::cast(frame->context()));
10544 Handle<Context> function_context(frame_context->declaration_context());
10545 if (!CopyContextLocalsToScopeObject(isolate,
10546 serialized_scope_info, scope_info,
10547 function_context, local_scope)) {
10548 return Handle<JSObject>();
10549 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010550
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010551 // Finally copy any properties from the function context extension.
10552 // These will be variables introduced by eval.
10553 if (function_context->closure() == *function) {
10554 if (function_context->has_extension() &&
10555 !function_context->IsGlobalContext()) {
10556 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10557 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10558 for (int i = 0; i < keys->length(); i++) {
10559 // Names of variables introduced by eval are strings.
10560 ASSERT(keys->get(i)->IsString());
10561 Handle<String> key(String::cast(keys->get(i)));
10562 RETURN_IF_EMPTY_HANDLE_VALUE(
10563 isolate,
10564 SetProperty(local_scope,
10565 key,
10566 GetProperty(ext, key),
10567 NONE,
10568 kNonStrictMode),
10569 Handle<JSObject>());
10570 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010571 }
10572 }
10573 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010574
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010575 return local_scope;
10576}
10577
10578
10579// Create a plain JSObject which materializes the closure content for the
10580// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010581static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10582 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010583 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010584
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010585 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010586 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10587 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010588
10589 // Allocate and initialize a JSObject with all the content of theis function
10590 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010591 Handle<JSObject> closure_scope =
10592 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010593
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010594 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010595 if (!CopyContextLocalsToScopeObject(isolate,
10596 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010597 context, closure_scope)) {
10598 return Handle<JSObject>();
10599 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010600
10601 // Finally copy any properties from the function context extension. This will
10602 // be variables introduced by eval.
10603 if (context->has_extension()) {
10604 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010605 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010606 for (int i = 0; i < keys->length(); i++) {
10607 // Names of variables introduced by eval are strings.
10608 ASSERT(keys->get(i)->IsString());
10609 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010610 RETURN_IF_EMPTY_HANDLE_VALUE(
10611 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010612 SetProperty(closure_scope,
10613 key,
10614 GetProperty(ext, key),
10615 NONE,
10616 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010617 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010618 }
10619 }
10620
10621 return closure_scope;
10622}
10623
10624
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010625// Create a plain JSObject which materializes the scope for the specified
10626// catch context.
10627static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10628 Handle<Context> context) {
10629 ASSERT(context->IsCatchContext());
10630 Handle<String> name(String::cast(context->extension()));
10631 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10632 Handle<JSObject> catch_scope =
10633 isolate->factory()->NewJSObject(isolate->object_function());
10634 RETURN_IF_EMPTY_HANDLE_VALUE(
10635 isolate,
10636 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10637 Handle<JSObject>());
10638 return catch_scope;
10639}
10640
10641
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010642// Iterate over the actual scopes visible from a stack frame. All scopes are
10643// backed by an actual context except the local scope, which is inserted
10644// "artifically" in the context chain.
10645class ScopeIterator {
10646 public:
10647 enum ScopeType {
10648 ScopeTypeGlobal = 0,
10649 ScopeTypeLocal,
10650 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010651 ScopeTypeClosure,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010652 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010653 };
10654
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010655 ScopeIterator(Isolate* isolate,
10656 JavaScriptFrame* frame,
10657 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010658 : isolate_(isolate),
10659 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010660 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010661 function_(JSFunction::cast(frame->function())),
10662 context_(Context::cast(frame->context())),
10663 local_done_(false),
10664 at_local_(false) {
10665
10666 // Check whether the first scope is actually a local scope.
10667 if (context_->IsGlobalContext()) {
10668 // If there is a stack slot for .result then this local scope has been
10669 // created for evaluating top level code and it is not a real local scope.
10670 // Checking for the existence of .result seems fragile, but the scope info
10671 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010672 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010673 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010674 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010675 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010676 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010677 } else if (context_->closure() != *function_) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010678 // The context_ is a with or catch block from the outer function.
10679 ASSERT(context_->IsWithContext() || context_->IsCatchContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010680 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010681 }
10682 }
10683
10684 // More scopes?
10685 bool Done() { return context_.is_null(); }
10686
10687 // Move to the next scope.
10688 void Next() {
10689 // If at a local scope mark the local scope as passed.
10690 if (at_local_) {
10691 at_local_ = false;
10692 local_done_ = true;
10693
10694 // If the current context is not associated with the local scope the
10695 // current context is the next real scope, so don't move to the next
10696 // context in this case.
10697 if (context_->closure() != *function_) {
10698 return;
10699 }
10700 }
10701
10702 // The global scope is always the last in the chain.
10703 if (context_->IsGlobalContext()) {
10704 context_ = Handle<Context>();
10705 return;
10706 }
10707
10708 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010709 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010710
10711 // If passing the local scope indicate that the current scope is now the
10712 // local scope.
10713 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010714 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010715 at_local_ = true;
10716 }
10717 }
10718
10719 // Return the type of the current scope.
10720 int Type() {
10721 if (at_local_) {
10722 return ScopeTypeLocal;
10723 }
10724 if (context_->IsGlobalContext()) {
10725 ASSERT(context_->global()->IsGlobalObject());
10726 return ScopeTypeGlobal;
10727 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010728 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010729 return ScopeTypeClosure;
10730 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010731 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010732 return ScopeTypeCatch;
10733 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010734 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010735 return ScopeTypeWith;
10736 }
10737
10738 // Return the JavaScript object with the content of the current scope.
10739 Handle<JSObject> ScopeObject() {
10740 switch (Type()) {
10741 case ScopeIterator::ScopeTypeGlobal:
10742 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010743 case ScopeIterator::ScopeTypeLocal:
10744 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010745 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010746 case ScopeIterator::ScopeTypeWith:
10747 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010748 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10749 case ScopeIterator::ScopeTypeCatch:
10750 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010751 case ScopeIterator::ScopeTypeClosure:
10752 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010753 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010754 }
10755 UNREACHABLE();
10756 return Handle<JSObject>();
10757 }
10758
10759 // Return the context for this scope. For the local context there might not
10760 // be an actual context.
10761 Handle<Context> CurrentContext() {
10762 if (at_local_ && context_->closure() != *function_) {
10763 return Handle<Context>();
10764 }
10765 return context_;
10766 }
10767
10768#ifdef DEBUG
10769 // Debug print of the content of the current scope.
10770 void DebugPrint() {
10771 switch (Type()) {
10772 case ScopeIterator::ScopeTypeGlobal:
10773 PrintF("Global:\n");
10774 CurrentContext()->Print();
10775 break;
10776
10777 case ScopeIterator::ScopeTypeLocal: {
10778 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010779 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010780 scope_info.Print();
10781 if (!CurrentContext().is_null()) {
10782 CurrentContext()->Print();
10783 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010784 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010785 if (extension->IsJSContextExtensionObject()) {
10786 extension->Print();
10787 }
10788 }
10789 }
10790 break;
10791 }
10792
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010793 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010794 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010795 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010796 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010797
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010798 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010799 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010800 CurrentContext()->extension()->Print();
10801 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010802 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010803
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010804 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010805 PrintF("Closure:\n");
10806 CurrentContext()->Print();
10807 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010808 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010809 if (extension->IsJSContextExtensionObject()) {
10810 extension->Print();
10811 }
10812 }
10813 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010814
10815 default:
10816 UNREACHABLE();
10817 }
10818 PrintF("\n");
10819 }
10820#endif
10821
10822 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010823 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010824 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010825 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010826 Handle<JSFunction> function_;
10827 Handle<Context> context_;
10828 bool local_done_;
10829 bool at_local_;
10830
10831 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10832};
10833
10834
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010835RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010836 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010837 ASSERT(args.length() == 2);
10838
10839 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010840 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010841 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10842 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010843 if (!maybe_check->ToObject(&check)) return maybe_check;
10844 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010845 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10846
10847 // Get the frame where the debugging is performed.
10848 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010849 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010850 JavaScriptFrame* frame = it.frame();
10851
10852 // Count the visible scopes.
10853 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010854 for (ScopeIterator it(isolate, frame, 0);
10855 !it.Done();
10856 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010857 n++;
10858 }
10859
10860 return Smi::FromInt(n);
10861}
10862
10863
10864static const int kScopeDetailsTypeIndex = 0;
10865static const int kScopeDetailsObjectIndex = 1;
10866static const int kScopeDetailsSize = 2;
10867
10868// Return an array with scope details
10869// args[0]: number: break id
10870// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010871// args[2]: number: inlined frame index
10872// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010873//
10874// The array returned contains the following information:
10875// 0: Scope type
10876// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010877RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010878 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010879 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010880
10881 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010882 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010883 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10884 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010885 if (!maybe_check->ToObject(&check)) return maybe_check;
10886 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010887 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010888 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
10889 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010890
10891 // Get the frame where the debugging is performed.
10892 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010893 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010894 JavaScriptFrame* frame = frame_it.frame();
10895
10896 // Find the requested scope.
10897 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010898 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010899 for (; !it.Done() && n < index; it.Next()) {
10900 n++;
10901 }
10902 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010903 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010904 }
10905
10906 // Calculate the size of the result.
10907 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010908 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010909
10910 // Fill in scope details.
10911 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010912 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010913 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010914 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010916 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010917}
10918
10919
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010920RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010921 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010922 ASSERT(args.length() == 0);
10923
10924#ifdef DEBUG
10925 // Print the scopes for the top frame.
10926 StackFrameLocator locator;
10927 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010928 for (ScopeIterator it(isolate, frame, 0);
10929 !it.Done();
10930 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010931 it.DebugPrint();
10932 }
10933#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010934 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010935}
10936
10937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010938RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010939 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010940 ASSERT(args.length() == 1);
10941
10942 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010943 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010944 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10945 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010946 if (!maybe_result->ToObject(&result)) return maybe_result;
10947 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010948
10949 // Count all archived V8 threads.
10950 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010951 for (ThreadState* thread =
10952 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010953 thread != NULL;
10954 thread = thread->Next()) {
10955 n++;
10956 }
10957
10958 // Total number of threads is current thread and archived threads.
10959 return Smi::FromInt(n + 1);
10960}
10961
10962
10963static const int kThreadDetailsCurrentThreadIndex = 0;
10964static const int kThreadDetailsThreadIdIndex = 1;
10965static const int kThreadDetailsSize = 2;
10966
10967// Return an array with thread details
10968// args[0]: number: break id
10969// args[1]: number: thread index
10970//
10971// The array returned contains the following information:
10972// 0: Is current thread?
10973// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010974RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010975 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010976 ASSERT(args.length() == 2);
10977
10978 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010979 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010980 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10981 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010982 if (!maybe_check->ToObject(&check)) return maybe_check;
10983 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010984 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10985
10986 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010987 Handle<FixedArray> details =
10988 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010989
10990 // Thread index 0 is current thread.
10991 if (index == 0) {
10992 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010993 details->set(kThreadDetailsCurrentThreadIndex,
10994 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010995 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010996 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010997 } else {
10998 // Find the thread with the requested index.
10999 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011000 ThreadState* thread =
11001 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011002 while (index != n && thread != NULL) {
11003 thread = thread->Next();
11004 n++;
11005 }
11006 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011007 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011008 }
11009
11010 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011011 details->set(kThreadDetailsCurrentThreadIndex,
11012 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011013 details->set(kThreadDetailsThreadIdIndex,
11014 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011015 }
11016
11017 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011018 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011019}
11020
11021
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011022// Sets the disable break state
11023// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011024RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011025 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011026 ASSERT(args.length() == 1);
11027 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011028 isolate->debug()->set_disable_break(disable_break);
11029 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011030}
11031
11032
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011033RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011034 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011035 ASSERT(args.length() == 1);
11036
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011037 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11038 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011039 // Find the number of break points
11040 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011041 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011042 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011043 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011044 Handle<FixedArray>::cast(break_locations));
11045}
11046
11047
11048// Set a break point in a function
11049// args[0]: function
11050// args[1]: number: break source position (within the function source)
11051// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011052RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011053 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011054 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011055 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11056 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011057 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11058 RUNTIME_ASSERT(source_position >= 0);
11059 Handle<Object> break_point_object_arg = args.at<Object>(2);
11060
11061 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011062 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11063 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011064
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011065 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011066}
11067
11068
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011069Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11070 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011071 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011072 // Iterate the heap looking for SharedFunctionInfo generated from the
11073 // script. The inner most SharedFunctionInfo containing the source position
11074 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011075 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011076 // which is found is not compiled it is compiled and the heap is iterated
11077 // again as the compilation might create inner functions from the newly
11078 // compiled function and the actual requested break point might be in one of
11079 // these functions.
11080 bool done = false;
11081 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011082 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011083 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011084 while (!done) {
11085 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011086 for (HeapObject* obj = iterator.next();
11087 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011088 if (obj->IsSharedFunctionInfo()) {
11089 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11090 if (shared->script() == *script) {
11091 // If the SharedFunctionInfo found has the requested script data and
11092 // contains the source position it is a candidate.
11093 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000011094 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011095 start_position = shared->start_position();
11096 }
11097 if (start_position <= position &&
11098 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000011099 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011100 // candidate this is the new candidate.
11101 if (target.is_null()) {
11102 target_start_position = start_position;
11103 target = shared;
11104 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011105 if (target_start_position == start_position &&
11106 shared->end_position() == target->end_position()) {
11107 // If a top-level function contain only one function
11108 // declartion the source for the top-level and the function is
11109 // the same. In that case prefer the non top-level function.
11110 if (!shared->is_toplevel()) {
11111 target_start_position = start_position;
11112 target = shared;
11113 }
11114 } else if (target_start_position <= start_position &&
11115 shared->end_position() <= target->end_position()) {
11116 // This containment check includes equality as a function inside
11117 // a top-level function can share either start or end position
11118 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011119 target_start_position = start_position;
11120 target = shared;
11121 }
11122 }
11123 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011124 }
11125 }
11126 }
11127
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011128 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011129 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011130 }
11131
11132 // If the candidate found is compiled we are done. NOTE: when lazy
11133 // compilation of inner functions is introduced some additional checking
11134 // needs to be done here to compile inner functions.
11135 done = target->is_compiled();
11136 if (!done) {
11137 // If the candidate is not compiled compile it to reveal any inner
11138 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011139 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011140 }
11141 }
11142
11143 return *target;
11144}
11145
11146
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011147// Changes the state of a break point in a script and returns source position
11148// where break point was set. NOTE: Regarding performance see the NOTE for
11149// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011150// args[0]: script to set break point in
11151// args[1]: number: break source position (within the script source)
11152// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011153RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011154 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011155 ASSERT(args.length() == 3);
11156 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11157 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11158 RUNTIME_ASSERT(source_position >= 0);
11159 Handle<Object> break_point_object_arg = args.at<Object>(2);
11160
11161 // Get the script from the script wrapper.
11162 RUNTIME_ASSERT(wrapper->value()->IsScript());
11163 Handle<Script> script(Script::cast(wrapper->value()));
11164
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011165 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011166 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011167 if (!result->IsUndefined()) {
11168 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11169 // Find position within function. The script position might be before the
11170 // source position of the first function.
11171 int position;
11172 if (shared->start_position() > source_position) {
11173 position = 0;
11174 } else {
11175 position = source_position - shared->start_position();
11176 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011177 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011178 position += shared->start_position();
11179 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011180 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011181 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011182}
11183
11184
11185// Clear a break point
11186// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011187RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011188 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011189 ASSERT(args.length() == 1);
11190 Handle<Object> break_point_object_arg = args.at<Object>(0);
11191
11192 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011193 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011194
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011195 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011196}
11197
11198
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011199// Change the state of break on exceptions.
11200// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11201// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011202RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011203 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011204 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011205 RUNTIME_ASSERT(args[0]->IsNumber());
11206 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011207
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011208 // If the number doesn't match an enum value, the ChangeBreakOnException
11209 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011210 ExceptionBreakType type =
11211 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011212 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011213 isolate->debug()->ChangeBreakOnException(type, enable);
11214 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011215}
11216
11217
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011218// Returns the state of break on exceptions
11219// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011220RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011221 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011222 ASSERT(args.length() == 1);
11223 RUNTIME_ASSERT(args[0]->IsNumber());
11224
11225 ExceptionBreakType type =
11226 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011227 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011228 return Smi::FromInt(result);
11229}
11230
11231
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011232// Prepare for stepping
11233// args[0]: break id for checking execution state
11234// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011235// args[2]: number of times to perform the step, for step out it is the number
11236// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011237RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011238 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011239 ASSERT(args.length() == 3);
11240 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011241 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011242 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11243 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011244 if (!maybe_check->ToObject(&check)) return maybe_check;
11245 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011246 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011247 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011248 }
11249
11250 // Get the step action and check validity.
11251 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11252 if (step_action != StepIn &&
11253 step_action != StepNext &&
11254 step_action != StepOut &&
11255 step_action != StepInMin &&
11256 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011257 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011258 }
11259
11260 // Get the number of steps.
11261 int step_count = NumberToInt32(args[2]);
11262 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011263 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011264 }
11265
ager@chromium.orga1645e22009-09-09 19:27:10 +000011266 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011267 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011268
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011269 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011270 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11271 step_count);
11272 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011273}
11274
11275
11276// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011277RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011278 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011279 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011280 isolate->debug()->ClearStepping();
11281 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011282}
11283
11284
11285// Creates a copy of the with context chain. The copy of the context chain is
11286// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011287static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011288 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011289 Handle<Context> current,
11290 Handle<Context> base) {
11291 // At the end of the chain. Return the base context to link to.
11292 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11293 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011294 }
11295
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011296 // Recursively copy the with and catch contexts.
11297 HandleScope scope(isolate);
11298 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011299 Handle<Context> new_previous =
11300 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011301 Handle<Context> new_current;
11302 if (current->IsCatchContext()) {
11303 Handle<String> name(String::cast(current->extension()));
11304 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11305 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011306 isolate->factory()->NewCatchContext(function,
11307 new_previous,
11308 name,
11309 thrown_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011310 } else {
11311 Handle<JSObject> extension(JSObject::cast(current->extension()));
11312 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011313 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011314 }
11315 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011316}
11317
11318
11319// Helper function to find or create the arguments object for
11320// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011321static Handle<Object> GetArgumentsObject(Isolate* isolate,
11322 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011323 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011324 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011325 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011326 const ScopeInfo<>* sinfo,
11327 Handle<Context> function_context) {
11328 // Try to find the value of 'arguments' to pass as parameter. If it is not
11329 // found (that is the debugged function does not reference 'arguments' and
11330 // does not support eval) then create an 'arguments' object.
11331 int index;
11332 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011333 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011334 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011335 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011336 }
11337 }
11338
11339 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011340 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11341 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011342 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011343 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011344 }
11345 }
11346
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011347 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11348
11349 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011350 Handle<JSObject> arguments =
11351 isolate->factory()->NewArgumentsObject(function, length);
11352 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011353
11354 AssertNoAllocation no_gc;
11355 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011356 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011357 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011358 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011359 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011360 return arguments;
11361}
11362
11363
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011364static const char kSourceStr[] =
11365 "(function(arguments,__source__){return eval(__source__);})";
11366
11367
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011368// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011369// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011370// extension part has all the parameters and locals of the function on the
11371// stack frame. A function which calls eval with the code to evaluate is then
11372// compiled in this context and called in this context. As this context
11373// replaces the context of the function on the stack frame a new (empty)
11374// function is created as well to be used as the closure for the context.
11375// This function and the context acts as replacements for the function on the
11376// stack frame presenting the same view of the values of parameters and
11377// local variables as if the piece of JavaScript was evaluated at the point
11378// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011379RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011380 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011381
11382 // Check the execution state and decode arguments frame and source to be
11383 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011384 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011385 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011386 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11387 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011388 if (!maybe_check_result->ToObject(&check_result)) {
11389 return maybe_check_result;
11390 }
11391 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011392 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011393 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11394 CONVERT_ARG_CHECKED(String, source, 3);
11395 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11396 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011397
11398 // Handle the processing of break.
11399 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011400
11401 // Get the frame where the debugging is performed.
11402 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011403 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011404 JavaScriptFrame* frame = it.frame();
11405 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011406 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011407 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011408
11409 // Traverse the saved contexts chain to find the active context for the
11410 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011411 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011412 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011413 save = save->prev();
11414 }
11415 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011416 SaveContext savex(isolate);
11417 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011418
11419 // Create the (empty) function replacing the function on the stack frame for
11420 // the purpose of evaluating in the context created below. It is important
11421 // that this function does not describe any parameters and local variables
11422 // in the context. If it does then this will cause problems with the lookup
11423 // in Context::Lookup, where context slots for parameters and local variables
11424 // are looked at before the extension object.
11425 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011426 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11427 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011428 go_between->set_context(function->context());
11429#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011430 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011431 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11432 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11433#endif
11434
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011435 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011436 Handle<JSObject> local_scope = MaterializeLocalScope(
11437 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011438 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011439
11440 // Allocate a new context for the debug evaluation and set the extension
11441 // object build.
11442 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011443 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11444 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011445 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011446 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011447 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011448 Handle<Context> function_context;
11449 // Get the function's context if it has one.
11450 if (scope_info->HasHeapAllocatedLocals()) {
11451 function_context = Handle<Context>(frame_context->declaration_context());
11452 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011453 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011454
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011455 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011456 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011457 context =
11458 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011459 }
11460
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011461 // Wrap the evaluation statement in a new function compiled in the newly
11462 // created context. The function has one parameter which has to be called
11463 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011464 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011465 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011466
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011467 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011468 isolate->factory()->NewStringFromAscii(
11469 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011470
11471 // Currently, the eval code will be executed in non-strict mode,
11472 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011473 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011474 Compiler::CompileEval(function_source,
11475 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011476 context->IsGlobalContext(),
11477 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011478 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011479 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011480 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011481
11482 // Invoke the result of the compilation to get the evaluation function.
11483 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011484 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011485 Handle<Object> evaluation_function =
11486 Execution::Call(compiled_function, receiver, 0, NULL,
11487 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011488 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011489
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011490 Handle<Object> arguments = GetArgumentsObject(isolate,
11491 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011492 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011493 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011494
11495 // Invoke the evaluation function and return the result.
11496 const int argc = 2;
11497 Object** argv[argc] = { arguments.location(),
11498 Handle<Object>::cast(source).location() };
11499 Handle<Object> result =
11500 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11501 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011502 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011503
11504 // Skip the global proxy as it has no properties and always delegates to the
11505 // real global object.
11506 if (result->IsJSGlobalProxy()) {
11507 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11508 }
11509
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011510 return *result;
11511}
11512
11513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011514RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011515 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011516
11517 // Check the execution state and decode arguments frame and source to be
11518 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011519 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011520 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011521 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11522 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011523 if (!maybe_check_result->ToObject(&check_result)) {
11524 return maybe_check_result;
11525 }
11526 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011527 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011528 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011529 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011530
11531 // Handle the processing of break.
11532 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011533
11534 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011535 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011536 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011537 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011538 top = top->prev();
11539 }
11540 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011541 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011542 }
11543
11544 // Get the global context now set to the top context from before the
11545 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011546 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011547
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011548 bool is_global = true;
11549
11550 if (additional_context->IsJSObject()) {
11551 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011552 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11553 isolate->factory()->empty_string(),
11554 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011555 go_between->set_context(*context);
11556 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011557 isolate->factory()->NewFunctionContext(
11558 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011559 context->set_extension(JSObject::cast(*additional_context));
11560 is_global = false;
11561 }
11562
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011563 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011564 // Currently, the eval code will be executed in non-strict mode,
11565 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011566 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011567 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011568 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011569 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011570 Handle<JSFunction>(
11571 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11572 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011573
11574 // Invoke the result of the compilation to get the evaluation function.
11575 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011576 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011577 Handle<Object> result =
11578 Execution::Call(compiled_function, receiver, 0, NULL,
11579 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011580 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011581 return *result;
11582}
11583
11584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011585RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011586 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011587 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011588
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011589 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011590 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011591
11592 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011593 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011594 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11595 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11596 // because using
11597 // instances->set(i, *GetScriptWrapper(script))
11598 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11599 // already have deferenced the instances handle.
11600 Handle<JSValue> wrapper = GetScriptWrapper(script);
11601 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011602 }
11603
11604 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011605 Handle<JSObject> result =
11606 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011607 Handle<JSArray>::cast(result)->SetContent(*instances);
11608 return *result;
11609}
11610
11611
11612// Helper function used by Runtime_DebugReferencedBy below.
11613static int DebugReferencedBy(JSObject* target,
11614 Object* instance_filter, int max_references,
11615 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011616 JSFunction* arguments_function) {
11617 NoHandleAllocation ha;
11618 AssertNoAllocation no_alloc;
11619
11620 // Iterate the heap.
11621 int count = 0;
11622 JSObject* last = NULL;
11623 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011624 HeapObject* heap_obj = NULL;
11625 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011626 (max_references == 0 || count < max_references)) {
11627 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011628 if (heap_obj->IsJSObject()) {
11629 // Skip context extension objects and argument arrays as these are
11630 // checked in the context of functions using them.
11631 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011632 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011633 obj->map()->constructor() == arguments_function) {
11634 continue;
11635 }
11636
11637 // Check if the JS object has a reference to the object looked for.
11638 if (obj->ReferencesObject(target)) {
11639 // Check instance filter if supplied. This is normally used to avoid
11640 // references from mirror objects (see Runtime_IsInPrototypeChain).
11641 if (!instance_filter->IsUndefined()) {
11642 Object* V = obj;
11643 while (true) {
11644 Object* prototype = V->GetPrototype();
11645 if (prototype->IsNull()) {
11646 break;
11647 }
11648 if (instance_filter == prototype) {
11649 obj = NULL; // Don't add this object.
11650 break;
11651 }
11652 V = prototype;
11653 }
11654 }
11655
11656 if (obj != NULL) {
11657 // Valid reference found add to instance array if supplied an update
11658 // count.
11659 if (instances != NULL && count < instances_size) {
11660 instances->set(count, obj);
11661 }
11662 last = obj;
11663 count++;
11664 }
11665 }
11666 }
11667 }
11668
11669 // Check for circular reference only. This can happen when the object is only
11670 // referenced from mirrors and has a circular reference in which case the
11671 // object is not really alive and would have been garbage collected if not
11672 // referenced from the mirror.
11673 if (count == 1 && last == target) {
11674 count = 0;
11675 }
11676
11677 // Return the number of referencing objects found.
11678 return count;
11679}
11680
11681
11682// Scan the heap for objects with direct references to an object
11683// args[0]: the object to find references to
11684// args[1]: constructor function for instances to exclude (Mirror)
11685// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011686RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011687 ASSERT(args.length() == 3);
11688
11689 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011690 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011691
11692 // Check parameters.
11693 CONVERT_CHECKED(JSObject, target, args[0]);
11694 Object* instance_filter = args[1];
11695 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11696 instance_filter->IsJSObject());
11697 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11698 RUNTIME_ASSERT(max_references >= 0);
11699
11700 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011701 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011702 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011703 JSFunction* arguments_function =
11704 JSFunction::cast(arguments_boilerplate->map()->constructor());
11705
11706 // Get the number of referencing objects.
11707 int count;
11708 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011709 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011710
11711 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011712 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011713 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011714 if (!maybe_object->ToObject(&object)) return maybe_object;
11715 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011716 FixedArray* instances = FixedArray::cast(object);
11717
11718 // Fill the referencing objects.
11719 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011720 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011721
11722 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011723 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011724 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11725 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011726 if (!maybe_result->ToObject(&result)) return maybe_result;
11727 }
11728 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011729 return result;
11730}
11731
11732
11733// Helper function used by Runtime_DebugConstructedBy below.
11734static int DebugConstructedBy(JSFunction* constructor, int max_references,
11735 FixedArray* instances, int instances_size) {
11736 AssertNoAllocation no_alloc;
11737
11738 // Iterate the heap.
11739 int count = 0;
11740 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011741 HeapObject* heap_obj = NULL;
11742 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011743 (max_references == 0 || count < max_references)) {
11744 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011745 if (heap_obj->IsJSObject()) {
11746 JSObject* obj = JSObject::cast(heap_obj);
11747 if (obj->map()->constructor() == constructor) {
11748 // Valid reference found add to instance array if supplied an update
11749 // count.
11750 if (instances != NULL && count < instances_size) {
11751 instances->set(count, obj);
11752 }
11753 count++;
11754 }
11755 }
11756 }
11757
11758 // Return the number of referencing objects found.
11759 return count;
11760}
11761
11762
11763// Scan the heap for objects constructed by a specific function.
11764// args[0]: the constructor to find instances of
11765// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011766RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011767 ASSERT(args.length() == 2);
11768
11769 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011770 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011771
11772 // Check parameters.
11773 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11774 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11775 RUNTIME_ASSERT(max_references >= 0);
11776
11777 // Get the number of referencing objects.
11778 int count;
11779 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11780
11781 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011782 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011783 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011784 if (!maybe_object->ToObject(&object)) return maybe_object;
11785 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011786 FixedArray* instances = FixedArray::cast(object);
11787
11788 // Fill the referencing objects.
11789 count = DebugConstructedBy(constructor, max_references, instances, count);
11790
11791 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011792 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011793 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11794 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011795 if (!maybe_result->ToObject(&result)) return maybe_result;
11796 }
11797 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011798 return result;
11799}
11800
11801
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011802// Find the effective prototype object as returned by __proto__.
11803// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011804RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011805 ASSERT(args.length() == 1);
11806
11807 CONVERT_CHECKED(JSObject, obj, args[0]);
11808
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011809 // Use the __proto__ accessor.
11810 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011811}
11812
11813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011814RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011815 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011816 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011817 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011818}
11819
11820
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011821RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011822#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011823 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011824 ASSERT(args.length() == 1);
11825 // Get the function and make sure it is compiled.
11826 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011827 Handle<SharedFunctionInfo> shared(func->shared());
11828 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011829 return Failure::Exception();
11830 }
11831 func->code()->PrintLn();
11832#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011833 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011834}
ager@chromium.org9085a012009-05-11 19:22:57 +000011835
11836
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011837RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011838#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011839 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011840 ASSERT(args.length() == 1);
11841 // Get the function and make sure it is compiled.
11842 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011843 Handle<SharedFunctionInfo> shared(func->shared());
11844 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011845 return Failure::Exception();
11846 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011847 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011848#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011849 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011850}
11851
11852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011853RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011854 NoHandleAllocation ha;
11855 ASSERT(args.length() == 1);
11856
11857 CONVERT_CHECKED(JSFunction, f, args[0]);
11858 return f->shared()->inferred_name();
11859}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011860
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011861
11862static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011863 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011864 AssertNoAllocation no_allocations;
11865
11866 int counter = 0;
11867 int buffer_size = buffer->length();
11868 HeapIterator iterator;
11869 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11870 ASSERT(obj != NULL);
11871 if (!obj->IsSharedFunctionInfo()) {
11872 continue;
11873 }
11874 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11875 if (shared->script() != script) {
11876 continue;
11877 }
11878 if (counter < buffer_size) {
11879 buffer->set(counter, shared);
11880 }
11881 counter++;
11882 }
11883 return counter;
11884}
11885
11886// For a script finds all SharedFunctionInfo's in the heap that points
11887// to this script. Returns JSArray of SharedFunctionInfo wrapped
11888// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011889RUNTIME_FUNCTION(MaybeObject*,
11890 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011891 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011892 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011893 CONVERT_CHECKED(JSValue, script_value, args[0]);
11894
11895 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11896
11897 const int kBufferSize = 32;
11898
11899 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011900 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011901 int number = FindSharedFunctionInfosForScript(*script, *array);
11902 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011903 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011904 FindSharedFunctionInfosForScript(*script, *array);
11905 }
11906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011907 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011908 result->set_length(Smi::FromInt(number));
11909
11910 LiveEdit::WrapSharedFunctionInfos(result);
11911
11912 return *result;
11913}
11914
11915// For a script calculates compilation information about all its functions.
11916// The script source is explicitly specified by the second argument.
11917// The source of the actual script is not used, however it is important that
11918// all generated code keeps references to this particular instance of script.
11919// Returns a JSArray of compilation infos. The array is ordered so that
11920// each function with all its descendant is always stored in a continues range
11921// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011922RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011923 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011924 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011925 CONVERT_CHECKED(JSValue, script, args[0]);
11926 CONVERT_ARG_CHECKED(String, source, 1);
11927 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11928
11929 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11930
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011931 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011932 return Failure::Exception();
11933 }
11934
11935 return result;
11936}
11937
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011938// Changes the source of the script to a new_source.
11939// If old_script_name is provided (i.e. is a String), also creates a copy of
11940// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011941RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011942 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011943 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011944 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11945 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011946 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011947
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011948 CONVERT_CHECKED(Script, original_script_pointer,
11949 original_script_value->value());
11950 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011951
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011952 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11953 new_source,
11954 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011955
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011956 if (old_script->IsScript()) {
11957 Handle<Script> script_handle(Script::cast(old_script));
11958 return *(GetScriptWrapper(script_handle));
11959 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011960 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011961 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011962}
11963
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011964
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011965RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011966 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011967 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011968 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11969 return LiveEdit::FunctionSourceUpdated(shared_info);
11970}
11971
11972
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011973// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011974RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011975 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011976 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011977 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11978 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11979
ager@chromium.orgac091b72010-05-05 07:34:42 +000011980 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011981}
11982
11983// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011984RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011985 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011986 HandleScope scope(isolate);
11987 Handle<Object> function_object(args[0], isolate);
11988 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011989
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011990 if (function_object->IsJSValue()) {
11991 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11992 if (script_object->IsJSValue()) {
11993 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011994 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011995 }
11996
11997 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11998 } else {
11999 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12000 // and we check it in this function.
12001 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012002
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012003 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012004}
12005
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012006
12007// In a code of a parent function replaces original function as embedded object
12008// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012009RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012010 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012011 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012012
12013 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12014 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12015 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12016
12017 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12018 subst_wrapper);
12019
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012020 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012021}
12022
12023
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012024// Updates positions of a shared function info (first parameter) according
12025// to script source change. Text change is described in second parameter as
12026// array of groups of 3 numbers:
12027// (change_begin, change_end, change_end_new_position).
12028// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012029RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012030 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012031 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012032 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12033 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12034
ager@chromium.orgac091b72010-05-05 07:34:42 +000012035 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012036}
12037
12038
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012039// For array of SharedFunctionInfo's (each wrapped in JSValue)
12040// checks that none of them have activations on stacks (of any thread).
12041// Returns array of the same length with corresponding results of
12042// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012043RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012044 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012045 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012046 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012047 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012048
ager@chromium.org357bf652010-04-12 11:30:10 +000012049 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012050}
12051
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012052// Compares 2 strings line-by-line, then token-wise and returns diff in form
12053// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12054// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012055RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012056 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012057 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012058 CONVERT_ARG_CHECKED(String, s1, 0);
12059 CONVERT_ARG_CHECKED(String, s2, 1);
12060
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012061 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012062}
12063
12064
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012065// A testing entry. Returns statement position which is the closest to
12066// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012067RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012068 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012069 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012070 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12071 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12072
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012073 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012074
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012075 if (code->kind() != Code::FUNCTION &&
12076 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012077 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012078 }
12079
12080 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012081 int closest_pc = 0;
12082 int distance = kMaxInt;
12083 while (!it.done()) {
12084 int statement_position = static_cast<int>(it.rinfo()->data());
12085 // Check if this break point is closer that what was previously found.
12086 if (source_position <= statement_position &&
12087 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012088 closest_pc =
12089 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012090 distance = statement_position - source_position;
12091 // Check whether we can't get any closer.
12092 if (distance == 0) break;
12093 }
12094 it.next();
12095 }
12096
12097 return Smi::FromInt(closest_pc);
12098}
12099
12100
ager@chromium.org357bf652010-04-12 11:30:10 +000012101// Calls specified function with or without entering the debugger.
12102// This is used in unit tests to run code as if debugger is entered or simply
12103// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012104RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012105 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012106 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012107 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12108 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12109
12110 Handle<Object> result;
12111 bool pending_exception;
12112 {
12113 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012114 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012115 &pending_exception);
12116 } else {
12117 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012118 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012119 &pending_exception);
12120 }
12121 }
12122 if (!pending_exception) {
12123 return *result;
12124 } else {
12125 return Failure::Exception();
12126 }
12127}
12128
12129
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012130// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012131RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012132 CONVERT_CHECKED(String, arg, args[0]);
12133 SmartPointer<char> flags =
12134 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12135 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012136 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012137}
12138
12139
12140// Performs a GC.
12141// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012142RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012143 isolate->heap()->CollectAllGarbage(true);
12144 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012145}
12146
12147
12148// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012149RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012150 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012151 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012152 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012153 }
12154 return Smi::FromInt(usage);
12155}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012156
12157
12158// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012159RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012160#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012161 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012162#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012163 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012164#endif
12165}
12166
12167
12168// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012169RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012170#ifdef LIVE_OBJECT_LIST
12171 return LiveObjectList::Capture();
12172#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012173 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012174#endif
12175}
12176
12177
12178// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012179RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012180#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012181 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012182 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012183 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012184#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012185 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012186#endif
12187}
12188
12189
12190// Generates the response to a debugger request for a dump of the objects
12191// contained in the difference between the captured live object lists
12192// specified by id1 and id2.
12193// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12194// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012195RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012196#ifdef LIVE_OBJECT_LIST
12197 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012198 CONVERT_SMI_ARG_CHECKED(id1, 0);
12199 CONVERT_SMI_ARG_CHECKED(id2, 1);
12200 CONVERT_SMI_ARG_CHECKED(start, 2);
12201 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012202 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12203 EnterDebugger enter_debugger;
12204 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12205#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012206 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012207#endif
12208}
12209
12210
12211// Gets the specified object as requested by the debugger.
12212// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012213RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012214#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012215 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012216 Object* result = LiveObjectList::GetObj(obj_id);
12217 return result;
12218#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012219 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012220#endif
12221}
12222
12223
12224// Gets the obj id for the specified address if valid.
12225// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012226RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012227#ifdef LIVE_OBJECT_LIST
12228 HandleScope scope;
12229 CONVERT_ARG_CHECKED(String, address, 0);
12230 Object* result = LiveObjectList::GetObjId(address);
12231 return result;
12232#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012233 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012234#endif
12235}
12236
12237
12238// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012239RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012240#ifdef LIVE_OBJECT_LIST
12241 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012242 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012243 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12244 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12245 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12246 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12247 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12248
12249 Handle<JSObject> instance_filter;
12250 if (args[1]->IsJSObject()) {
12251 instance_filter = args.at<JSObject>(1);
12252 }
12253 bool verbose = false;
12254 if (args[2]->IsBoolean()) {
12255 verbose = args[2]->IsTrue();
12256 }
12257 int start = 0;
12258 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012259 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012260 }
12261 int limit = Smi::kMaxValue;
12262 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012263 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012264 }
12265
12266 return LiveObjectList::GetObjRetainers(obj_id,
12267 instance_filter,
12268 verbose,
12269 start,
12270 limit,
12271 filter_obj);
12272#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012273 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012274#endif
12275}
12276
12277
12278// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012279RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012280#ifdef LIVE_OBJECT_LIST
12281 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012282 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12283 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012284 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12285
12286 Handle<JSObject> instance_filter;
12287 if (args[2]->IsJSObject()) {
12288 instance_filter = args.at<JSObject>(2);
12289 }
12290
12291 Object* result =
12292 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12293 return result;
12294#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012295 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012296#endif
12297}
12298
12299
12300// Generates the response to a debugger request for a list of all
12301// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012302RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012303#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012304 CONVERT_SMI_ARG_CHECKED(start, 0);
12305 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012306 return LiveObjectList::Info(start, count);
12307#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012308 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012309#endif
12310}
12311
12312
12313// Gets a dump of the specified object as requested by the debugger.
12314// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012315RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012316#ifdef LIVE_OBJECT_LIST
12317 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012318 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012319 Object* result = LiveObjectList::PrintObj(obj_id);
12320 return result;
12321#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012322 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012323#endif
12324}
12325
12326
12327// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012328RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012329#ifdef LIVE_OBJECT_LIST
12330 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012331 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012332#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012333 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012334#endif
12335}
12336
12337
12338// Generates the response to a debugger request for a summary of the types
12339// of objects in the difference between the captured live object lists
12340// specified by id1 and id2.
12341// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12342// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012343RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012344#ifdef LIVE_OBJECT_LIST
12345 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012346 CONVERT_SMI_ARG_CHECKED(id1, 0);
12347 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012348 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12349
12350 EnterDebugger enter_debugger;
12351 return LiveObjectList::Summarize(id1, id2, filter_obj);
12352#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012353 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012354#endif
12355}
12356
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012357#endif // ENABLE_DEBUGGER_SUPPORT
12358
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012360RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012361 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012362 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012363 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012364}
12365
12366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012367RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012368 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012369 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012370 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012371}
12372
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012373
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012374// Finds the script object from the script data. NOTE: This operation uses
12375// heap traversal to find the function generated for the source position
12376// for the requested break point. For lazily compiled functions several heap
12377// traversals might be required rendering this operation as a rather slow
12378// operation. However for setting break points which is normally done through
12379// some kind of user interaction the performance is not crucial.
12380static Handle<Object> Runtime_GetScriptFromScriptName(
12381 Handle<String> script_name) {
12382 // Scan the heap for Script objects to find the script with the requested
12383 // script data.
12384 Handle<Script> script;
12385 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012386 HeapObject* obj = NULL;
12387 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012388 // If a script is found check if it has the script data requested.
12389 if (obj->IsScript()) {
12390 if (Script::cast(obj)->name()->IsString()) {
12391 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12392 script = Handle<Script>(Script::cast(obj));
12393 }
12394 }
12395 }
12396 }
12397
12398 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012399 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012400
12401 // Return the script found.
12402 return GetScriptWrapper(script);
12403}
12404
12405
12406// Get the script object from script data. NOTE: Regarding performance
12407// see the NOTE for GetScriptFromScriptData.
12408// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012409RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012410 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012411
12412 ASSERT(args.length() == 1);
12413
12414 CONVERT_CHECKED(String, script_name, args[0]);
12415
12416 // Find the requested script.
12417 Handle<Object> result =
12418 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12419 return *result;
12420}
12421
12422
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012423// Determines whether the given stack frame should be displayed in
12424// a stack trace. The caller is the error constructor that asked
12425// for the stack trace to be collected. The first time a construct
12426// call to this function is encountered it is skipped. The seen_caller
12427// in/out parameter is used to remember if the caller has been seen
12428// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012429static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12430 Object* caller,
12431 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012432 // Only display JS frames.
12433 if (!raw_frame->is_java_script())
12434 return false;
12435 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12436 Object* raw_fun = frame->function();
12437 // Not sure when this can happen but skip it just in case.
12438 if (!raw_fun->IsJSFunction())
12439 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012440 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012441 *seen_caller = true;
12442 return false;
12443 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012444 // Skip all frames until we've seen the caller.
12445 if (!(*seen_caller)) return false;
12446 // Also, skip the most obvious builtin calls. We recognize builtins
12447 // as (1) functions called with the builtins object as the receiver and
12448 // as (2) functions from native scripts called with undefined as the
12449 // receiver (direct calls to helper functions in the builtins
12450 // code). Some builtin calls (such as Number.ADD which is invoked
12451 // using 'call') are very difficult to recognize so we're leaving
12452 // them in for now.
12453 if (frame->receiver()->IsJSBuiltinsObject()) {
12454 return false;
12455 }
12456 JSFunction* fun = JSFunction::cast(raw_fun);
12457 Object* raw_script = fun->shared()->script();
12458 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12459 int script_type = Script::cast(raw_script)->type()->value();
12460 return script_type != Script::TYPE_NATIVE;
12461 }
12462 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012463}
12464
12465
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012466// Collect the raw data for a stack trace. Returns an array of 4
12467// element segments each containing a receiver, function, code and
12468// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012469RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012470 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012471 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012472 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12473
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012474 HandleScope scope(isolate);
12475 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012476
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012477 limit = Max(limit, 0); // Ensure that limit is not negative.
12478 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012479 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012480 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012481
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012482 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012483 // If the caller parameter is a function we skip frames until we're
12484 // under it before starting to collect.
12485 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012486 int cursor = 0;
12487 int frames_seen = 0;
12488 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012489 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012490 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012491 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012492 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012493 // Set initial size to the maximum inlining level + 1 for the outermost
12494 // function.
12495 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012496 frame->Summarize(&frames);
12497 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012498 if (cursor + 4 > elements->length()) {
12499 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12500 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012501 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012502 for (int i = 0; i < cursor; i++) {
12503 new_elements->set(i, elements->get(i));
12504 }
12505 elements = new_elements;
12506 }
12507 ASSERT(cursor + 4 <= elements->length());
12508
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012509 Handle<Object> recv = frames[i].receiver();
12510 Handle<JSFunction> fun = frames[i].function();
12511 Handle<Code> code = frames[i].code();
12512 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012513 elements->set(cursor++, *recv);
12514 elements->set(cursor++, *fun);
12515 elements->set(cursor++, *code);
12516 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012517 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012518 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012519 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012520 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012521 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012522 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012523 return *result;
12524}
12525
12526
ager@chromium.org3811b432009-10-28 14:53:37 +000012527// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012528RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012529 ASSERT_EQ(args.length(), 0);
12530
12531 NoHandleAllocation ha;
12532
12533 const char* version_string = v8::V8::GetVersion();
12534
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012535 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12536 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012537}
12538
12539
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012540RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012541 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012542 OS::PrintError("abort: %s\n",
12543 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012544 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012545 OS::Abort();
12546 UNREACHABLE();
12547 return NULL;
12548}
12549
12550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012551RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012552 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012553 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012554 Object* key = args[1];
12555
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012556 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012557 Object* o = cache->get(finger_index);
12558 if (o == key) {
12559 // The fastest case: hit the same place again.
12560 return cache->get(finger_index + 1);
12561 }
12562
12563 for (int i = finger_index - 2;
12564 i >= JSFunctionResultCache::kEntriesIndex;
12565 i -= 2) {
12566 o = cache->get(i);
12567 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012568 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012569 return cache->get(i + 1);
12570 }
12571 }
12572
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012573 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012574 ASSERT(size <= cache->length());
12575
12576 for (int i = size - 2; i > finger_index; i -= 2) {
12577 o = cache->get(i);
12578 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012579 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012580 return cache->get(i + 1);
12581 }
12582 }
12583
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012584 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012585 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012586
12587 Handle<JSFunctionResultCache> cache_handle(cache);
12588 Handle<Object> key_handle(key);
12589 Handle<Object> value;
12590 {
12591 Handle<JSFunction> factory(JSFunction::cast(
12592 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12593 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012594 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012595 // This handle is nor shared, nor used later, so it's safe.
12596 Object** argv[] = { key_handle.location() };
12597 bool pending_exception = false;
12598 value = Execution::Call(factory,
12599 receiver,
12600 1,
12601 argv,
12602 &pending_exception);
12603 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012604 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012605
12606#ifdef DEBUG
12607 cache_handle->JSFunctionResultCacheVerify();
12608#endif
12609
12610 // Function invocation may have cleared the cache. Reread all the data.
12611 finger_index = cache_handle->finger_index();
12612 size = cache_handle->size();
12613
12614 // If we have spare room, put new data into it, otherwise evict post finger
12615 // entry which is likely to be the least recently used.
12616 int index = -1;
12617 if (size < cache_handle->length()) {
12618 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12619 index = size;
12620 } else {
12621 index = finger_index + JSFunctionResultCache::kEntrySize;
12622 if (index == cache_handle->length()) {
12623 index = JSFunctionResultCache::kEntriesIndex;
12624 }
12625 }
12626
12627 ASSERT(index % 2 == 0);
12628 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12629 ASSERT(index < cache_handle->length());
12630
12631 cache_handle->set(index, *key_handle);
12632 cache_handle->set(index + 1, *value);
12633 cache_handle->set_finger_index(index);
12634
12635#ifdef DEBUG
12636 cache_handle->JSFunctionResultCacheVerify();
12637#endif
12638
12639 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012640}
12641
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012642
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012643RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012644 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012645 CONVERT_ARG_CHECKED(String, type, 0);
12646 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012647 return *isolate->factory()->NewJSMessageObject(
12648 type,
12649 arguments,
12650 0,
12651 0,
12652 isolate->factory()->undefined_value(),
12653 isolate->factory()->undefined_value(),
12654 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012655}
12656
12657
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012658RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012659 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12660 return message->type();
12661}
12662
12663
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012664RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012665 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12666 return message->arguments();
12667}
12668
12669
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012670RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012671 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12672 return Smi::FromInt(message->start_position());
12673}
12674
12675
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012676RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012677 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12678 return message->script();
12679}
12680
12681
kasper.lund44510672008-07-25 07:37:58 +000012682#ifdef DEBUG
12683// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12684// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012685RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012686 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012687 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012688#define COUNT_ENTRY(Name, argc, ressize) + 1
12689 int entry_count = 0
12690 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12691 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12692 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12693#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012694 Factory* factory = isolate->factory();
12695 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012696 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012697 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012698#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012699 { \
12700 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012701 Handle<String> name; \
12702 /* Inline runtime functions have an underscore in front of the name. */ \
12703 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012704 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012705 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12706 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012707 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012708 Vector<const char>(#Name, StrLength(#Name))); \
12709 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012710 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012711 pair_elements->set(0, *name); \
12712 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012713 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012714 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012715 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012716 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012717 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012718 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012719 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012720 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012721#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012722 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012723 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012724 return *result;
12725}
kasper.lund44510672008-07-25 07:37:58 +000012726#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012727
12728
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012729RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012730 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012731 CONVERT_CHECKED(String, format, args[0]);
12732 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012733 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012734 LOGGER->LogRuntime(chars, elms);
12735 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012736}
12737
12738
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012739RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012740 UNREACHABLE(); // implemented as macro in the parser
12741 return NULL;
12742}
12743
12744
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012745#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
12746 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
12747 CONVERT_CHECKED(JSObject, obj, args[0]); \
12748 return isolate->heap()->ToBoolean(obj->Has##Name()); \
12749 }
12750
12751ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
12752ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
12753ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
12754ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
12755ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
12756ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
12757ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
12758ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
12759ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
12760ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
12761ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
12762ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
12763ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
12764
12765#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
12766
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012767// ----------------------------------------------------------------------------
12768// Implementation of Runtime
12769
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012770#define F(name, number_of_args, result_size) \
12771 { Runtime::k##name, Runtime::RUNTIME, #name, \
12772 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012773
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012774
12775#define I(name, number_of_args, result_size) \
12776 { Runtime::kInline##name, Runtime::INLINE, \
12777 "_" #name, NULL, number_of_args, result_size },
12778
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012779static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012780 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012781 INLINE_FUNCTION_LIST(I)
12782 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012783};
12784
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012785
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012786MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12787 Object* dictionary) {
12788 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012789 ASSERT(dictionary != NULL);
12790 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12791 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012792 Object* name_symbol;
12793 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012794 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012795 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12796 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012797 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012798 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12799 String::cast(name_symbol),
12800 Smi::FromInt(i),
12801 PropertyDetails(NONE, NORMAL));
12802 if (!maybe_dictionary->ToObject(&dictionary)) {
12803 // Non-recoverable failure. Calling code must restart heap
12804 // initialization.
12805 return maybe_dictionary;
12806 }
12807 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012808 }
12809 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012810}
12811
12812
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012813const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12814 Heap* heap = name->GetHeap();
12815 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012816 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012817 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012818 int function_index = Smi::cast(smi_index)->value();
12819 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012820 }
12821 return NULL;
12822}
12823
12824
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012825const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012826 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12827}
12828
12829
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012830void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012831 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012832 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012833 if (failure->IsRetryAfterGC()) {
12834 // Try to do a garbage collection; ignore it if it fails. The C
12835 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012836 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012837 } else {
12838 // Handle last resort GC and make sure to allow future allocations
12839 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012840 isolate->counters()->gc_last_resort_from_js()->Increment();
12841 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012842 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012843}
12844
12845
12846} } // namespace v8::internal